**NOTE:** For now I submitted this change as a DRAFT PR in order to get some 
feedback on whether this is the way to fix the problem, as well as to check for 
potential problems with this solution that I might've missed.

___

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.

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

Commit messages:
 - Adjust window focus management for Windows Glass

Changes: https://git.openjdk.org/jfx/pull/1849/files
  Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=1849&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8359899
  Stats: 32 lines in 3 files changed: 15 ins; 1 del; 16 mod
  Patch: https://git.openjdk.org/jfx/pull/1849.diff
  Fetch: git fetch https://git.openjdk.org/jfx.git pull/1849/head:pull/1849

PR: https://git.openjdk.org/jfx/pull/1849

Reply via email to