JDK-8319317 : Linux: Broken Focus/KeyEvents for TextField when repeatedly displayed in new Stage
  • Type: Bug
  • Component: javafx
  • Sub-Component: window-toolkit
  • Affected Version: jfx22
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86_64
  • Submitted: 2023-10-17
  • Updated: 2024-01-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Rocky Linux 9: Linux 5.14.0-284.18.1.el9_2.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jun 22 17:36:46 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
openjdk version "17.0.7" 2023-04-18 LTS
OpenJDK Runtime Environment (Red_Hat-17.0.7.0.7-2) (build 17.0.7+7-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-17.0.7.0.7-2) (build 17.0.7+7-LTS, mixed mode, sharing)
OpenJFX: 17.0.2, 19.0.2, 21, 22-ea+11


Linux 6.1.58-1-lts #1 SMP PREEMPT_DYNAMIC Sun, 15 Oct 2023 18:38:43 +0000 x86_64 GNU/Linux
openjdk 17.0.8.1 2023-08-24
OpenJDK Runtime Environment (build 17.0.8.1+1)
OpenJDK 64-Bit Server VM (build 17.0.8.1+1, mixed mode)
OpenJFX: 22-ea+11

The bug is reproducible 100 % of the time on the mentioned Linux systems. It was NOT reproducible on Windows (Win10, openjdk 17.0.1).

A DESCRIPTION OF THE PROBLEM :
There seems to be a focusing issue for Control when they are repeatedly displayed in a new Stage (e.g. when an existing component is shown repeatedly in a dialog, when a new dialog window is used every time). 
This leads to unexpected visual effects (multiple Controls have the blue focus border), which is a minor inconvenience. 
A major inconvenience is that for TextFields, this bug also prevents KeyEvents (keyboard input) from reaching the affected TextFields, while MouseEvents are still handled as expected.

The bug only occurs if new/different Stages are used. It does not occur if the same Stage is reused every time the components are shown.

If there are problem with reproducing this issue, we can provide screenhots or a short screen capture (video).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
(See code example, this is just a short summary.) 
Create two TextFields (A and B and some RadioButtons (in a ToggleGroup) in a Pane. Display the Pane in a new Stage. Enter some text. While TextField A is focused (blue border), close the Stage. Display the Pane in another NEW Stage. Repeat, but focus on a RadioButton before closing the Stage.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Both TextFields should still accept keyboard input as normal. No preference for whether TextField A should be focused when it is shown for the second, ... time. Only one Control should hold the focus (blue border, blinking cursor for TextFields) at any time). 
ACTUAL -
TextField A appears initially focused (blue border, blinking cursor) and reacts to mouse events (including copy&paste via right-click menu), but does NOT accept keyboard input. Any keyboard input for A lands in TextField B (!). If B is focused, both TextFields have a blue border and a blinking cursor at the same time (!). B behaves as expected. When a RadioButton was focused when the Stage was closed, you can get blue borders for multiple RadioButtons and TextFields at the same time. 

---------- BEGIN SOURCE ----------
    /*
     * Demo for broken focus (esp. keyboard input for TextFields) that are repeatedly shown in *new* Stages.
     * 
     * Demo shows the broken behavior when using new Stages, and the expected behavior when the same stage is being
     * reused. It also demonstrates that the focus problem effects not only TextFields, but also e.g. RadioButtons.
     * There is also a workaround, which can be uncommented to be applied.
     */
    public static class BrokenFocusAndKeyboardInputWhenTextFieldsReusedInNewDialogsDemoApp extends Application {

        public static void main(String[] args) {
            Application.launch(args);
        }

        @Override
        public void start(final Stage stage) {
            final VBox textFieldBox1 = createInputBox();
            final VBox textFieldBox2 = createInputBox();

            final Button openNewDialogButton = new Button("Open NEW dialog (broken)");
            openNewDialogButton.setOnAction(evt -> {
                // Hide/destroy previous dialog
                if (openNewDialogButton.getUserData() instanceof Stage oldDialogStage) {
                    oldDialogStage.hide();
                    openNewDialogButton.setUserData(null);
                }

                final Stage newDialogStage = createDemoDialogStage();
                setContentAndShow(newDialogStage, textFieldBox1);
                openNewDialogButton.setUserData(newDialogStage);
            });

            final Button openExistingDialogButton = new Button("(Re-)Open EXISTING dialog (ok)");
            final Stage reusableDialog = createDemoDialogStage();
            openExistingDialogButton.setOnAction(evt -> {
                setContentAndShow(reusableDialog, textFieldBox2);
            });

            final HBox root = new HBox(openNewDialogButton, openExistingDialogButton);
            final Scene scene = new Scene(root, 500, 200);
            stage.setScene(scene);

            Platform.setImplicitExit(true);
            stage.setTitle("BrokenFocusAndKeyboardInputWhenTextFieldsReusedInNewDialogsDemoApp");
            stage.show();
        }

        private static void setContentAndShow(final Stage dialogStage, final Node content) {
            if (dialogStage.getScene().getRoot() instanceof Pane rootPane) {
                rootPane.getChildren().setAll(content);
            }
            dialogStage.show();
        }

        private static VBox createInputBox() {
            final ToggleGroup toggleGroup = new ToggleGroup();
            final VBox textFieldBox = new VBox(new TextField("a"), new TextField("b"), new TextField("c"),
                    createRadio("d", toggleGroup), createRadio("e", toggleGroup), createRadio("f", toggleGroup));
            textFieldBox.getChildren()
                    .forEach(n -> n.addEventHandler(Event.ANY, event -> System.out.println("Event: " + event)));
            return textFieldBox;
        }

        private static RadioButton createRadio(final String text, final ToggleGroup toggleGroup) {
            final RadioButton rb = new RadioButton(text);
            rb.setToggleGroup(toggleGroup);
            return rb;
        }

        private static Stage createDemoDialogStage() {
            final Stage dialogWindow = new Stage(StageStyle.UTILITY);
            dialogWindow.setTitle("EventFilterCreepDemoApp - Dialog");
            final Pane dialogRoot = new StackPane();
            dialogWindow.setScene(new Scene(dialogRoot));

            // Uncomment for WORKAROUND:
//            dialogWindow.showingProperty().addListener((obs, oldIsShowing, newIsShowing) -> {
//                // Request focus on hiding the Stage (no idea WHY it helps, but it does??)
//                if (!newIsShowing) {
//                    dialogRoot.requestFocus();
//                }
//            });
            // END WORKAROUND

            return dialogWindow;
        }

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
(See code example: There is some code to uncomment there.)
When closing a Stage, request focus on it before discarding the Stage. Then everything behaves as expected. 

FREQUENCY : always


Edit 2023/11/27:
- cannot be reproduced on macOS 13.5.2
- cannot be reproduced on windows 11
Comments
On my setup (Ubuntu 22.04) I see two different problems. Prior to jfx21 the newly created dialog doesn't have focus when it opens. On my system that is blocking me from entering text into the text field even though it has a focus indicator ring. This seems to be fixed in jfx21 and 22. On all versions of JavaFX I see more than one focus indicator when I bring the dialog up the second time. I suspect this is because Linux doesn't send a FOCUS_LOST event when the window is closed. On Mac and Windows we do see FOCUS_LOST and the scene cleans up the focus visibility properties. I'm not sure if this is a glass bug or not; perhaps the scene should always scrub the node state when a window is closed or when a portion of the tree is reparented to a new scene.
09-01-2024

This is likely a window-toolkit (glass) bug.
27-11-2023

Probably not in controls, since macOS and Windows 10/11 work fine.
27-11-2023

[~angorya] please triage and evaluate this issue
27-11-2023

Additional information Received from Submitter =================================== I have attached some screenshots, showing the state of the dialog with multiple text fields appearing focused after the first opening of the dialog (everything still ok), the second opening (bugged) and the third opening (also bugged). <attached Screenshots> If a video clipping is needed as well, please let me know and I'll provide one.
27-11-2023

Mail to submitter: ============= Please can you share screenshots or a short clipping. Provided testcase has a compilation issue, requesting for more info from submitter.
02-11-2023