On Mon, 16 Jun 2025 16:24:40 GMT, Kevin Rushforth <k...@openjdk.org> wrote:

>> Originally this issue was supposed to resolve problems with some system 
>> tests (`MenuDoubleShortcutTest`, `TextAreaBehaviorTest` and others) failing 
>> on my Windows machine. In the process of figuring this out I found out the 
>> problem is Windows `::SetForegroundWindow()` API refusing to give focus to 
>> JFX Stage upon calling `Stage.show()`.
>> 
>> The problem happened only when running system tests via Gradle, and with 
>> more investigation it turned out the culprit is actually running tests via a 
>> Gradle Daemon, which is the default behavior. According to 
>> [SetForegroundWindow API 
>> remarks](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow)
>>  there is a list of conditions a process must meet to be granted a privilege 
>> of receiving focus, which is supposed to prevent focus stealing. While we do 
>> meet the required conditions, we don't meet "one of" additional conditions 
>> listed in the reference:
>> - Gradle daemon is a background process, so tests started by it do not meet 
>> `The calling process is the foreground process.` and `The calling process 
>> was started by the foreground process.` conditions
>> - We most probably run the tests from the terminal, so `There is currently 
>> no foreground window, and thus no foreground process.` condition fails - the 
>> foreground window is the Terminal itself.
>> - Each test has fresh-started JFX stage so `The calling process received the 
>> last input event.` condition cannot be met and would require either Robot 
>> workarounds or manual interaction before each test case.
>> - There is no debugger involved in the process (at least most of the time) 
>> so `Either the foreground process or the calling process is being debugged.` 
>> is also not met.
>> 
>> As such, Windows refuses to grant JFX Stage focus, which fails some system 
>> tests relying on it.
>> 
>> While we cannot remedy these conditions in-code (outside of hacky solutions 
>> I found with `AttachThreadInput` API which I am not a fan of) the only 
>> solution seems to be running the tests on Windows via either `gradle 
>> --no-daemon` or by setting `org.gradle.daemon=false` property somewhere in 
>> `gradle.properties`.
>> 
>> In the process of debugging this problem I wrote a canary test to detect 
>> whether a Stage receives focus right after calling `show()`. I ran this test 
>> on all (accessible to me) platforms (Windows, Linux, macOS) - on both Linux 
>> and macOS the test passes regardless of whether the Gradle deamon is used or 
>> not. On my Windows machine (Win 11 24H2) it fails when testing...
>
> tests/system/src/test/java/test/robot/javafx/stage/StageFocusTest.java line 
> 56:
> 
>> 54:     static final double STAGE_Y = 100;
>> 55: 
>> 56:     static boolean receivedEvent = false;
> 
> Should this be volatile? It is set on one thread and read from another; 
> unless you know that this is synchronously set by the robot key press call, I 
> don't think you can be sure that the write `happens-before` the read.

or better an `AtomicBoolean`

> tests/system/src/test/java/test/robot/javafx/stage/StageFocusTest.java line 
> 113:
> 
>> 111:             robot.keyPress(KeyCode.A);
>> 112:         });
>> 113:         assertTrue(receivedEvent, "Expected key press has NOT been 
>> received! Stage did not have focus after showing. Some tests might fail 
>> because of this." +
> 
> Do you need to sleep before the assertion to ensure that the event has been 
> delivered?

Perhaps we ought to have a utility (latch?) to ensure the sequence?

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

PR Review Comment: https://git.openjdk.org/jfx/pull/1804#discussion_r2150522663
PR Review Comment: https://git.openjdk.org/jfx/pull/1804#discussion_r2150522303

Reply via email to