From 0545bf392e712308460cdaad766fe0caeb9b428b Mon Sep 17 00:00:00 2001 From: Martin Fox Date: Fri, 21 Jun 2024 12:35:18 -0700 Subject: [PATCH 1/6] Added InputMethodStateManager to coordinate input method usage betwee Popups and their root Scene. --- .../javafx/scene/InputMethodStateManager.java | 163 ++++++++++++++++++ .../com/sun/javafx/scene/SceneHelper.java | 12 ++ .../src/main/java/javafx/scene/Scene.java | 55 +++++- .../main/java/javafx/stage/PopupWindow.java | 28 +++ 4 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java new file mode 100644 index 00000000000..2995eadab69 --- /dev/null +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.javafx.scene; + +import com.sun.javafx.scene.SceneHelper; +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.WeakChangeListener; +import javafx.event.EventHandler; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.input.InputMethodEvent; +import javafx.scene.input.InputMethodRequests; + +/** + * Used to manage a collection of scenes which must coordinate on enabling input + * method events and retrieving InputMethodRequests. This occurs when a stack of + * PopupWindows are present; the PopupWindows do not have the OS focus and rely + * on events first being posted to the root (non-popup) window. + */ +public class InputMethodStateManager { + /** + * The root non-popup scene which the OS sends input method + * events to. + */ + private final WeakReference rootScene; + + /** + * The scene for which we enabled input method events and which + * is presumably processing them. + */ + private Scene currentEventScene; + + /** + * The scene stack including the root. + */ + private final LinkedList scenes = new LinkedList(); + + private final ChangeListener inputMethodRequestsChangedListener = + (obs, old, current) -> updateInputMethodEventEnableState(); + private final ChangeListener> onInputMethodTextChangedListener = + (obs, old, current) -> updateInputMethodEventEnableState(); + + private final WeakChangeListener weakInputMethodRequestsChangedListener = + new WeakChangeListener(inputMethodRequestsChangedListener); + private final WeakChangeListener> weakOnInputMethodTextChangedListener = + new WeakChangeListener(onInputMethodTextChangedListener); + + /** + * Constructs a new instance. + * + * @param scene the root {@link Scene} for which input methods should be enabled and disabled + */ + public InputMethodStateManager(Scene scene) { + this.rootScene = new WeakReference<>(scene); + this.scenes.add(scene); + this.currentEventScene = scene; + } + + /** + * Add a new Scene to the stack. It is assumed that Scenes form a stack + * and leave in LIFO order. + */ + public void addScene(Scene scene) { + if (scenes.contains(scene)) { + System.err.println("Popup scene already present"); + } + scenes.addFirst(scene); + updateInputMethodEventEnableState(); + } + + public void removeScene(Scene scene) { + if (scene != scenes.peekFirst()) { + System.err.println("Popup scene removed out of order"); + } + + /** + * If this scene is going away we should cleanup any composition + * state. This is not normally done when a window is hidden. + */ + SceneHelper.finishInputMethodComposition(rootScene.get()); + + Node focusOwner = scene.getFocusOwner(); + if (focusOwner != null) { + focusOwner.inputMethodRequestsProperty().removeListener(weakInputMethodRequestsChangedListener); + focusOwner.onInputMethodTextChangedProperty().removeListener(weakOnInputMethodTextChangedListener); + } + + scenes.remove(scene); + updateInputMethodEventEnableState(); + } + + /** + * Every Scene is expected to call this when the focusOwner changes. At this + */ + public void focusOwnerChanged(Node oldFocusOwner, Node newFocusOwner) { + if (oldFocusOwner != null) { + oldFocusOwner.inputMethodRequestsProperty().removeListener(weakInputMethodRequestsChangedListener); + oldFocusOwner.onInputMethodTextChangedProperty().removeListener(weakOnInputMethodTextChangedListener); + } + if (newFocusOwner != null) { + newFocusOwner.inputMethodRequestsProperty().addListener(weakInputMethodRequestsChangedListener); + newFocusOwner.onInputMethodTextChangedProperty().addListener(weakOnInputMethodTextChangedListener); + } + updateInputMethodEventEnableState(); + } + + public Scene getRootScene() { + return rootScene.get(); + } + + private void updateInputMethodEventEnableState() { + currentEventScene = null; + // Visit Scenes in order from top to bottom. + for (Scene scene : scenes) { + Node focusOwner = scene.getFocusOwner(); + if ((focusOwner != null) && + (focusOwner.getInputMethodRequests() != null) && + (focusOwner.getOnInputMethodTextChanged() != null)) { + currentEventScene = scene; + break; + } + } + Scene root = rootScene.get(); + if (root != null) { + SceneHelper.enableInputMethodEvents(root, currentEventScene != null); + } + } + + public InputMethodRequests getInputMethodRequests() { + if (currentEventScene != null) { + Node focusOwner = currentEventScene.getFocusOwner(); + if (focusOwner != null) { + return focusOwner.getInputMethodRequests(); + } + } + return null; + } +} diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/SceneHelper.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/SceneHelper.java index 3303d1826f8..fd4ef1235e6 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/SceneHelper.java +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/SceneHelper.java @@ -53,6 +53,14 @@ public static void enableInputMethodEvents(Scene scene, boolean enable) { sceneAccessor.enableInputMethodEvents(scene, enable); } + public static InputMethodStateManager getInputMethodStateManager(Scene scene) { + return sceneAccessor.getInputMethodStateManager(scene); + } + + public static void finishInputMethodComposition(Scene scene) { + sceneAccessor.finishInputMethodComposition(scene); + } + public static void processKeyEvent(Scene scene, KeyEvent e) { sceneAccessor.processKeyEvent(scene, e); } @@ -118,6 +126,10 @@ public static SceneAccessor getSceneAccessor() { public interface SceneAccessor { void enableInputMethodEvents(Scene scene, boolean enable); + InputMethodStateManager getInputMethodStateManager(Scene scene); + + void finishInputMethodComposition(Scene scene); + void processKeyEvent(Scene scene, KeyEvent e); void processMouseEvent(Scene scene, MouseEvent e); diff --git a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java index 94ddcda3563..f5f2921cea2 100644 --- a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java @@ -43,6 +43,7 @@ import com.sun.javafx.scene.LayoutFlags; import com.sun.javafx.scene.SceneEventDispatcher; import com.sun.javafx.scene.SceneHelper; +import com.sun.javafx.scene.InputMethodStateManager; import com.sun.javafx.scene.input.DragboardHelper; import com.sun.javafx.scene.input.ExtendedInputMethodRequests; import com.sun.javafx.scene.input.InputEventUtils; @@ -398,6 +399,19 @@ public void enableInputMethodEvents(Scene scene, boolean enable) { scene.enableInputMethodEvents(enable); } + @Override + public InputMethodStateManager getInputMethodStateManager(Scene scene) { + return scene.getInputMethodStateManager(); + } + + @Override + public void finishInputMethodComposition(Scene scene) { + final TKScene peer = scene.getPeer(); + if (peer != null) { + peer.finishInputMethodComposition(); + } + } + @Override public void processKeyEvent(Scene scene, KeyEvent e) { scene.processKeyEvent(e); @@ -464,6 +478,18 @@ void resizeRootOnSceneSizeChange( double newHeight) { // don't resize } + + @Override + protected InputMethodStateManager getInputMethodStateManager() { + Window rootWindow = getWindow(); + while ((rootWindow != null) && (rootWindow instanceof PopupWindow)) { + rootWindow = ((PopupWindow)rootWindow).getOwnerWindow(); + } + if (rootWindow != null) { + return rootWindow.getScene().getInputMethodStateManager(); + } + return null; + } }; } @@ -2205,6 +2231,20 @@ void requestFocus(Node node, boolean focusVisible) { } } + /** + * A non-popup scene creates a state manager to coordinate input method + * handling with popups. Popups do not create their own state manager + * but use the root scene's manager. + */ + private InputMethodStateManager inputMethodStateManager = null; + + protected InputMethodStateManager getInputMethodStateManager() { + if (inputMethodStateManager == null) { + inputMethodStateManager = new InputMethodStateManager(this); + } + return inputMethodStateManager; + } + /** * The scene's current focus owner node. This node's "focused" * variable might be false if this scene has no window, or if the @@ -2242,9 +2282,10 @@ protected void invalidated() { if (value != null) { value.setFocusQuietly(windowFocused, focusVisible); if (value != oldFocusOwner) { - value.getScene().enableInputMethodEvents( - value.getInputMethodRequests() != null - && value.getOnInputMethodTextChanged() != null); + InputMethodStateManager manager = value.getScene().getInputMethodStateManager(); + if (manager != null) { + manager.focusOwnerChanged(oldFocusOwner, value); + } } } // for the rest of the method we need to update the oldFocusOwner @@ -2288,7 +2329,7 @@ private void setFocusOwner(Node node, boolean focusVisible) { // This needs to be done before the focus owner is switched as it // generates event that needs to be delivered to the old focus owner. if (focusOwner.oldFocusOwner != null) { - final Scene s = focusOwner.oldFocusOwner.getScene(); + final Scene s = getInputMethodStateManager().getRootScene(); if (s != null) { final TKScene peer = s.getPeer(); if (peer != null) { @@ -4230,11 +4271,7 @@ public int getCommittedTextLength() { } private InputMethodRequests getClientRequests() { - Node focusOwner = getFocusOwner(); - if (focusOwner != null) { - return focusOwner.getInputMethodRequests(); - } - return null; + return getInputMethodStateManager().getInputMethodRequests(); } } diff --git a/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java b/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java index f146bd413e9..6c6c8fc9d87 100644 --- a/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java +++ b/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java @@ -74,6 +74,7 @@ import javafx.event.EventType; import javafx.scene.input.KeyCombination; import javafx.scene.input.KeyEvent; +import javafx.scene.input.InputMethodEvent; import javafx.scene.input.MouseEvent; import javafx.scene.input.ScrollEvent; import javafx.scene.layout.Background; @@ -539,6 +540,8 @@ private void doVisibleChanged(boolean visible) { rootWindow = getRootWindow(ownerWindowValue); startMonitorOwnerEvents(ownerWindowValue); + Scene scene = getScene(); + SceneHelper.getInputMethodStateManager(scene).addScene(scene); // currently we consider popup window to be focused when it is // visible and its owner window is focused (we need to track // that through listener on owner window focused property) @@ -549,6 +552,10 @@ private void doVisibleChanged(boolean visible) { handleAutofixActivation(true, isAutoFix()); handleAutohideActivation(true, isAutoHide()); } else { + // This may generate events so it must be done while we're + // still monitoring owner events. + Scene scene = getScene(); + SceneHelper.getInputMethodStateManager(scene).removeScene(scene); stopMonitorOwnerEvents(ownerWindowValue); unbindOwnerFocusedProperty(ownerWindowValue); WindowHelper.setFocused(this, false); @@ -984,6 +991,9 @@ protected void handleRedirectedEvent(final Object eventSource, handleKeyEvent((KeyEvent) event); return; } + else if (event instanceof InputMethodEvent) { + handleInputMethodEvent((InputMethodEvent) event); + } final EventType eventType = event.getEventType(); @@ -1022,6 +1032,24 @@ private void handleKeyEvent(final KeyEvent event) { } } + private void handleInputMethodEvent(final InputMethodEvent event) { + if (event.isConsumed()) { + return; + } + + final Scene scene = popupWindow.getScene(); + if (scene != null) { + final Node sceneFocusOwner = scene.getFocusOwner(); + final EventTarget eventTarget = + (sceneFocusOwner != null) ? sceneFocusOwner : scene; + if (EventUtil.fireEvent(eventTarget, new DirectEvent(event.copyFor(popupWindow, eventTarget))) + == null) { + event.consume(); + return; + } + } + } + private void handleEscapeKeyPressedEvent(final Event event) { if (popupWindow.isHideOnEscape()) { popupWindow.doAutoHide(); From 786201d16cca94e61589d544514eb46f208178df Mon Sep 17 00:00:00 2001 From: Martin Fox Date: Tue, 23 Jul 2024 13:08:23 -0700 Subject: [PATCH 2/6] Updated comments --- .../javafx/scene/InputMethodStateManager.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java index 2995eadab69..0b508886ea3 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java @@ -37,10 +37,13 @@ import javafx.scene.input.InputMethodRequests; /** - * Used to manage a collection of scenes which must coordinate on enabling input - * method events and retrieving InputMethodRequests. This occurs when a stack of - * PopupWindows are present; the PopupWindows do not have the OS focus and rely - * on events first being posted to the root (non-popup) window. + * Used to manage a collection of scenes which must coordinate enabling input + * method events and retrieving InputMethodRequests. PopupWindows do not have + * the OS focus and rely on events being posted first to a root + * (non-popup) scene and then routed through the PopupWindow stack. If any + * PopupWindow requires input method events they must be enabled on the root + * scene and input method requests from that scene must be routed to the + * PopupWindow. */ public class InputMethodStateManager { /** @@ -50,8 +53,7 @@ public class InputMethodStateManager { private final WeakReference rootScene; /** - * The scene for which we enabled input method events and which - * is presumably processing them. + * The scene for which we enabled input method events. */ private Scene currentEventScene; @@ -60,6 +62,10 @@ public class InputMethodStateManager { */ private final LinkedList scenes = new LinkedList(); + /** + * We listen for changes to the input method requests configuration + * on every scene in the stack. + */ private final ChangeListener inputMethodRequestsChangedListener = (obs, old, current) -> updateInputMethodEventEnableState(); private final ChangeListener> onInputMethodTextChangedListener = @@ -71,7 +77,7 @@ public class InputMethodStateManager { new WeakChangeListener(onInputMethodTextChangedListener); /** - * Constructs a new instance. + * Constructs a new instance. Only root (non-popup) scenes should do this. * * @param scene the root {@link Scene} for which input methods should be enabled and disabled */ @@ -100,7 +106,7 @@ public void removeScene(Scene scene) { /** * If this scene is going away we should cleanup any composition - * state. This is not normally done when a window is hidden. + * state. Hiding a window doesn't ensure proper cleanup. */ SceneHelper.finishInputMethodComposition(rootScene.get()); @@ -115,7 +121,7 @@ public void removeScene(Scene scene) { } /** - * Every Scene is expected to call this when the focusOwner changes. At this + * Every Scene must call this when the focusOwner changes. */ public void focusOwnerChanged(Node oldFocusOwner, Node newFocusOwner) { if (oldFocusOwner != null) { From 8369507910757e16873dbf0d866d273b3ea50e51 Mon Sep 17 00:00:00 2001 From: Martin Fox Date: Wed, 24 Jul 2024 08:42:06 -0700 Subject: [PATCH 3/6] finishInputMethodComposition is only called when focus changes on the event scene --- .../javafx/scene/InputMethodStateManager.java | 18 ++++++++++++++++-- .../src/main/java/javafx/scene/Scene.java | 8 +------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java index 0b508886ea3..686d76c1f72 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java @@ -88,8 +88,7 @@ public InputMethodStateManager(Scene scene) { } /** - * Add a new Scene to the stack. It is assumed that Scenes form a stack - * and leave in LIFO order. + * Add a new Scene to the stack. */ public void addScene(Scene scene) { if (scenes.contains(scene)) { @@ -99,6 +98,9 @@ public void addScene(Scene scene) { updateInputMethodEventEnableState(); } + /** + * Remove a Scene from the stack. + */ public void removeScene(Scene scene) { if (scene != scenes.peekFirst()) { System.err.println("Popup scene removed out of order"); @@ -120,6 +122,18 @@ public void removeScene(Scene scene) { updateInputMethodEventEnableState(); } + /** + * Every Scene must call this before the focusOwner changes. + */ + public void focusOwnerWillChangeForScene(Scene scene) { + if (scene == currentEventScene) { + Scene root = rootScene.get(); + if (root != null) { + SceneHelper.finishInputMethodComposition(root); + } + } + } + /** * Every Scene must call this when the focusOwner changes. */ diff --git a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java index f5f2921cea2..8117846352c 100644 --- a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java @@ -2329,13 +2329,7 @@ private void setFocusOwner(Node node, boolean focusVisible) { // This needs to be done before the focus owner is switched as it // generates event that needs to be delivered to the old focus owner. if (focusOwner.oldFocusOwner != null) { - final Scene s = getInputMethodStateManager().getRootScene(); - if (s != null) { - final TKScene peer = s.getPeer(); - if (peer != null) { - peer.finishInputMethodComposition(); - } - } + getInputMethodStateManager().focusOwnerWillChangeForScene(this); } // Store the current focusVisible state of the focus owner in case it needs to be From 43a4e6c440ac77fec3244007a25b8f73222214a8 Mon Sep 17 00:00:00 2001 From: Martin Fox Date: Mon, 11 Nov 2024 11:30:24 -0800 Subject: [PATCH 4/6] Fixed javadoc failure --- modules/javafx.graphics/src/main/java/javafx/scene/Scene.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java index e6f5078dd94..35404975877 100644 --- a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java @@ -2233,7 +2233,7 @@ void requestFocus(Node node, boolean focusVisible) { */ private InputMethodStateManager inputMethodStateManager = null; - protected InputMethodStateManager getInputMethodStateManager() { + InputMethodStateManager getInputMethodStateManager() { if (inputMethodStateManager == null) { inputMethodStateManager = new InputMethodStateManager(this); } From ce980548d520e6c2519445124e43cb7e027be1df Mon Sep 17 00:00:00 2001 From: Martin Fox Date: Mon, 11 Nov 2024 16:31:23 -0800 Subject: [PATCH 5/6] Tweak to satisfy system test. --- .../com/sun/javafx/scene/InputMethodStateManager.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java index 686d76c1f72..76610039e5f 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java @@ -126,7 +126,16 @@ public void removeScene(Scene scene) { * Every Scene must call this before the focusOwner changes. */ public void focusOwnerWillChangeForScene(Scene scene) { - if (scene == currentEventScene) { + /** + * Calling finishInputMethodComposition is only necessary if there's a + * node that accepts IM events. But there's a system test that + * expects finishInputMethodComposition to be called whenever the + * focusOwner changes. To satisfy this test we call + * finishInputMethodComposition even if no IM is enabled + * (so currentEventScene will be null). This will be no-op as far as + * the OS is concerned. + */ + if (scene == currentEventScene || currentEventScene == null) { Scene root = rootScene.get(); if (root != null) { SceneHelper.finishInputMethodComposition(root); From 31ebdcf401b5552daeb26ba8105af71e8d1d4b75 Mon Sep 17 00:00:00 2001 From: Martin Fox Date: Fri, 13 Dec 2024 08:21:54 -0800 Subject: [PATCH 6/6] Removed debug printlns, tidied up some code --- .../java/com/sun/javafx/scene/InputMethodStateManager.java | 7 ------- .../src/main/java/javafx/stage/PopupWindow.java | 3 +-- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java index 76610039e5f..e345c627cce 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/scene/InputMethodStateManager.java @@ -91,9 +91,6 @@ public InputMethodStateManager(Scene scene) { * Add a new Scene to the stack. */ public void addScene(Scene scene) { - if (scenes.contains(scene)) { - System.err.println("Popup scene already present"); - } scenes.addFirst(scene); updateInputMethodEventEnableState(); } @@ -102,10 +99,6 @@ public void addScene(Scene scene) { * Remove a Scene from the stack. */ public void removeScene(Scene scene) { - if (scene != scenes.peekFirst()) { - System.err.println("Popup scene removed out of order"); - } - /** * If this scene is going away we should cleanup any composition * state. Hiding a window doesn't ensure proper cleanup. diff --git a/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java b/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java index 6aa04a0ff5b..63c78e0a716 100644 --- a/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java +++ b/modules/javafx.graphics/src/main/java/javafx/stage/PopupWindow.java @@ -556,11 +556,11 @@ private void doVisibleChanging(boolean visible) { */ private void doVisibleChanged(boolean visible) { final Window ownerWindowValue = getOwnerWindow(); + Scene scene = getScene(); if (visible) { rootWindow = getRootWindow(ownerWindowValue); startMonitorOwnerEvents(ownerWindowValue); - Scene scene = getScene(); SceneHelper.getInputMethodStateManager(scene).addScene(scene); // currently we consider popup window to be focused when it is // visible and its owner window is focused (we need to track @@ -574,7 +574,6 @@ private void doVisibleChanged(boolean visible) { } else { // This may generate events so it must be done while we're // still monitoring owner events. - Scene scene = getScene(); SceneHelper.getInputMethodStateManager(scene).removeScene(scene); stopMonitorOwnerEvents(ownerWindowValue); unbindOwnerFocusedProperty(ownerWindowValue);