title: JavaFX Minimizing Undecorated Stage
body: <p>I have an undecorated JavaFX Stage, and my own minimize, maximize &amp; close buttons. But unfortunately clicking the taskbar icon in Windows 7 does not automatically minimize the stage - compared to the decorated behaviour.</p>
  
  <p>Is there a way to minimize an undecorated stage with pure Java code, by clicking the taskbar icon? If not how can I do this with, say, JNA?</p>
  
  <p><strong>EDIT:</strong>
  OK, I've been trying to solve this with JNA, but having done next to none C/C++/JNA, I have a bit trouble setting this up. I'd be grateful if someone helped me to put the pieces together..</p>
  
  <p>Here's my code so far:</p>
  
  <pre><code>public final class Utils {
  
     static {
      if (PlatformUtil.isWin7OrLater()) {
              Native.register("shell32");
              Native.register("user32");
          }
      }
  
      // Apparently, this is the event I am after
      public static final int WM_ACTIVATEAPP = 0x1C;
  
  
      public static void registerMinimizeHandler(Stage stage) {
         // Hacky way to get a pointer to JavaFX Window
         Pointer pointer = getWindowPointer(stage);
  
         WinDef.HWND hwnd = new WinDef.HWND(pointer);
  
         // Here's my minimize/activate handler
         WinUser.WindowProc windowProc = new MinimizeHandler(stage);
  
         Pointer magicPointer = ... set this to point to windowProc?
  
         // This.. apparently, re-sets the WndProc? But how do I get the "magicPointer" that is "attached" to the windowProc?
         User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, magicPointer);
      }
  }
  
   private static class MinimizeHandler implements WinUser.WindowProc {
  
      private Stage stage;
  
      private MinimizeHandler(Stage stage) {
          this.stage = stage;
      }
  
      @Override
      public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
          if (uMsg == WM_ACTIVATEAPP) {
              System.out.println("ACTIVATE");
          }
          return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam);
      }
  }
  
  private static Pointer getWindowPointer(Stage stage) {
      try {
          TKStage tkStage = stage.impl_getPeer();
          Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow" );
          getPlatformWindow.setAccessible(true);
          Object platformWindow = getPlatformWindow.invoke(tkStage);
          Method getNativeHandle = platformWindow.getClass().getMethod( "getNativeHandle" );
          getNativeHandle.setAccessible(true);
          Object nativeHandle = getNativeHandle.invoke(platformWindow);
          return new Pointer((Long) nativeHandle);
      } catch (Throwable e) {
          System.err.println("Error getting Window Pointer");
          return null;
      }
  }
  </code></pre>
  
  <p><strong>EDIT 2:</strong> I eventually got further on with this one, but as soon as I re-set the WNDPROC, my undecorated window didn't respond to any events.. I'm offering a bounty of 100 reputation for a self-contained example with a working solution. Windows (7+) only is OK, I do not even know how this behaves on other platforms.</p>
  
  <p><strong>EDIT 3:</strong>
  Well, I kind of gave up with this one.. I got everything set up correctly, and received the events, but had problems figuring out the correct event to listen for..</p>
  
  <p>Since there's been some interest in the question, if anyone wants to attempt to continue with this, here's my final code (it hopefully should "work" out-of-box):</p>
  
  <pre><code>public final class Utils {
  
      static interface ExtUser32 extends StdCallLibrary, User32 {
          ExtUser32 INSTANCE = (ExtUser32) Native.loadLibrary(
                          "user32",
                          ExtUser32.class,
                          W32APIOptions.DEFAULT_OPTIONS);
  
          WinDef.LRESULT CallWindowProcW(
                          Pointer lpWndProc,
                          Pointer hWnd,
                          int msg,
                          WinDef.WPARAM wParam,
                          WinDef.LPARAM lParam);
  
          int SetWindowLong(HWND hWnd, int nIndex, com.sun.jna.Callback wndProc) throws LastErrorException;
      }
  
      // Some possible event types
      public static final int WM_ACTIVATE = 0x0006;
      public static final int WM_ACTIVATEAPP = 0x1C;
      public static final int WM_NCACTIVATE = 0x0086;
  
      public static void registerMinimizeHandler(Stage stage) {
          Pointer pointer = getWindowPointer(stage);
          WinDef.HWND hwnd = new WinDef.HWND(pointer);
          long old = ExtUser32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC);
          MinimizeHandler handler = new MinimizeHandler(stage, old);
          ExtUser32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, handler);
      }
  
      private static Pointer getWindowPointer(Stage stage) {
      try {
          TKStage tkStage = stage.impl_getPeer();
          Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow" );
          getPlatformWindow.setAccessible(true);
          Object platformWindow = getPlatformWindow.invoke(tkStage);
          Method getNativeHandle = platformWindow.getClass().getMethod( "getNativeHandle" );
          getNativeHandle.setAccessible(true);
          Object nativeHandle = getNativeHandle.invoke(platformWindow);
          return new Pointer((Long) nativeHandle);
      } catch (Throwable e) {
          System.err.println("Error getting Window Pointer");
          return null;
      }
  }
  
      private static class MinimizeHandler implements WinUser.WindowProc, StdCallLibrary.StdCallCallback {
  
          private Pointer mPrevWndProc32;
  
          private Stage stage;
  
          private MinimizeHandler(Stage stage, long oldPtr) {
              this.stage = stage;
  
              mPrevWndProc32 = new Pointer(oldPtr);
  
              // Set up an event pump to deliver messages for JavaFX to handle
              Thread thread = new Thread() {
                  @Override
                  public void run() {
                      int result;
                      WinUser.MSG msg = new WinUser.MSG();
                      while ((result = User32.INSTANCE.GetMessage(msg, null, 0, 0)) != 0) {
                          if (result == -1) {
                              System.err.println("error in get message");
                              break;
                          }
                          else {
                              System.out.println("got message: " + result);
                              User32.INSTANCE.TranslateMessage(msg);
                              User32.INSTANCE.DispatchMessage(msg);
                          }
                      }
                  }
              };
              thread.start();
          }
  
          @Override
          public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
  
              if (uMsg == WM_ACTIVATEAPP) {
                  // Window deactivated (wParam == 0)... Here's where I got stuck and gave up,
                  // this is probably not the best event to listen to.. the app
                  // does indeed get iconified now by pressing the task-bar button, but it
                  // instantly restores afterwards..
                  if (wParam.intValue() == 0) {
                      stage.setIconified(true);
                  }
                  return new WinDef.LRESULT(0);
              }
  
              // Let JavaFX handle other events
              return ExtUser32.INSTANCE.CallWindowProcW(
                              mPrevWndProc32,
                              hWnd.getPointer(),
                              uMsg,
                              wParam,
                              lParam);
          }
      }
  }
  </code></pre>