RFR: 8359899: Stage.isFocused() returns invalid value when Stage fails to receive focus [v2]

Kevin Rushforth kcr at openjdk.org
Wed Oct 29 21:02:00 UTC 2025


On Tue, 28 Oct 2025 11:33:43 GMT, Lukasz Kostyra <lkostyra at openjdk.org> wrote:

>> This PR fixes `isFocused()` returning invalid value when Stage fails to receive focus after calling `Stage.show()`. This problem is Windows-only.
>> 
>> In Windows the `SetForegroundWindow()` API lists [a set of conditions to successfully grant focus to a Window](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow#remarks). If any of the conditions are not met, the API will return FALSE. JavaFX did not respect that and instead assumed that receiving `WM_ACTIVATE` with our Window being activated is enough to assume the Window is in focus (which in some cases is not true).
>> 
>> I first tried reacting to `WM_SETFOCUS` and `WM_KILLFOCUS` but it seems those messages are not sent when the window is shown for the first time (instead `WM_ACTIVATE` is used).
>> 
>> To correct this behavior, I noticed the following path is the most reliable:
>> - Call `ShowWindow()` using `SW_SHOWNA` instead of `SW_SHOW` - that makes the window visible but does NOT activate it
>> - Call `SetForegroundWindow()` - that will attempt to give the Window focus and will also activate it if it is successful
>>   - If successful, Java `notifyFocus` callback will be called via `WM_ACTIVATE` handler
>>   - If it fails, we call the `notifyFocus` callback manually informing the upper layers the focus is lost. This establishes the correct state of `Window.focused` property.
>> 
>> With this change I observed that all tests pass as intended as long as two conditions are met (these are needed to satisfy `SetForegroundWindow()` restrictions):
>> - Gradle build is ran without the Gradle daemon
>> - The terminal running Gradle test is in foreground
>> 
>> If any of above two conditions is not met, some tests (including canary test from https://github.com/openjdk/jfx/pull/1804) now timeout/fail when checking whether `Window.isFocused()` is true.
>> 
>> Manually started JavaFX apps (ex. Ensemble) run as they used to and still receive focus upon Stage showing.
>
> Lukasz Kostyra has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains two additional commits since the last revision:
> 
>  - Merge remote-tracking branch 'origin/master' into isFocused_fix-8359899
>  - Adjust window focus management for Windows Glass

The code changes look reasonable to me. I did leave one question inline.

What is the best way to test this? Ideally, I'd like a way to locally force the case where a window cannot be made focusable and have that test check the value of `Stage::isFocused`, reporting it (incorrectly) as true without this fix and false with the fix. I would then like to click on the Window (as @beldenfox did), and verify that it now reports as true.

I was able to verify that I get a different failing error message when I run `StageFocusTest` with gradle daemon enabled. Without this fix, two test methods fail when they try to readback the color. With this fix, they report that the window doesn't have focus. So that seems to validate at least part of the fix.

modules/javafx.graphics/src/main/native-glass/win/GlassWindow.cpp line 1959:

> 1957:         }
> 1958: 
> 1959:         ::ShowWindow(hWnd, visible ? SW_SHOWNA : SW_HIDE);

Is this change needed? I presume that the idea behind it is that if it is a focusable window, it will be activated anyway?

-------------

PR Review: https://git.openjdk.org/jfx/pull/1849#pullrequestreview-3396114193
PR Review Comment: https://git.openjdk.org/jfx/pull/1849#discussion_r2475365154


More information about the openjfx-dev mailing list