Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting the window handle of a JavaFX window #706

Open
mainrs opened this issue Sep 20, 2016 · 5 comments
Open

Getting the window handle of a JavaFX window #706

mainrs opened this issue Sep 20, 2016 · 5 comments

Comments

@mainrs
Copy link

mainrs commented Sep 20, 2016

Since the Native class already supports returning the window handle from a Swing Component, it would be nice if the functionality would be extended for JavaFX

@matthiasblaesing
Copy link
Member

As a preparation (this is not code intended for production) - this works with Java 8 and 9:

    private static Long getWindowPointer(Stage stage) {
        try {
            Method tkStageGetter;
            try {
                // java 9
                tkStageGetter = stage.getClass().getSuperclass().getDeclaredMethod("getPeer");
            } catch (NoSuchMethodException ex) {
                // java 8
                tkStageGetter = stage.getClass().getMethod("impl_getPeer");
            }
            tkStageGetter.setAccessible(true);
            TKStage tkStage = (TKStage) tkStageGetter.invoke(stage);
            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 (long) nativeHandle;
        } catch (Throwable e) {
            System.err.println("Error getting Window Pointer");
            e.printStackTrace();
            return null;
        }
    }

For java 9 this needs:

--add-exports javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.glass.ui=ALL-UNNAMED
--add-opens javafx.graphics/javafx.stage=ALL-UNNAMED
--add-opens javafx.graphics/com.sun.javafx.tk.quantum=ALL-UNNAMED

This was only tested on linux, but from my reading of the glass toolkit this should work on windows too. The most important question: Are the module boundaries also enforced for JNI or can they be circumvented there.

@mainrs
Copy link
Author

mainrs commented Mar 5, 2017

I solved it by looking up the window handle using the window's title. After that, you can retrieve the native pointer using Pointer.nativeValue(handle.getPointer()).

@cosmicdan
Copy link

cosmicdan commented Jan 9, 2018

I solved it by looking up the window handle using the window's title. After that, you can retrieve the native pointer using Pointer.nativeValue(handle.getPointer()).

Indeed, it's just a simple case of this...

stage.setTitle(WINDOW_NAME);
WinDef.HWND hWnd = User32.INSTANCE.FindWindow(null, WINDOW_NAME);

Thanks for that simple tip. Much prefer this than relying on reflection of internals.

@adamsiembida
Copy link

adamsiembida commented Aug 6, 2021

I solved it by looking up the window handle using the window's title. After that, you can retrieve the native pointer using Pointer.nativeValue(handle.getPointer()).

EDIT: I just realized this isn't in the JavaFX repo, so maybe I should re-post it there?

@matthiasblaesing

While this works, I don't believe this is a real solution. There are two issues I see:

  1. If a third party application had a window with the same title, you could break your app and break their app.
  2. If you had two instances of your own app open, this could also cause problems, as how does FindWindow know which window to return?

I believe that this issue is much more important than it seems like, maybe even a top priority. If you look at any modern desktop software on Windows, just about all of them use custom window decorations. I know a lot of developers use Macs or Linux, where custom window decorations aren't as important, but on Windows this is just about a requirement to make a professional and modern looking application.

At the moment, the only way to get the handle, which is required for custom window decorations is by breaking Java module boundaries, using reflection on internal APIs, or using hacky and unreliable FindWindow methods.

p.s. I tried using the solution by matthiasblaesing but I couldn't get it working in Gradle, so if anyone knows how to do that please let me know. I think using internal APIs might be less of a big deal in Java 9+ because the module system and packaging tools make it easier to ship a specific version of the JRE packaged with the app.

@matthiasblaesing
Copy link
Member

@adamsiembida for the record, I never said, that you should use the code unmodified - don't shoot the messanger. In the end every JNA solution would look similar the only benefit JNA has, that if you go through the JNI layer, at this point in time, you can break through the module barriers.

I would take this to the OpenJFX mailinglist - there a discussion is running what should be in OpenJFX 18, so now would be a good time for feature request. But be preprared: You are asking to open up internals, you will need to make a very good case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants