|
1 | 1 | /* |
2 | | - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
35 | 35 | import java.util.Optional; |
36 | 36 | import java.util.WeakHashMap; |
37 | 37 | import java.util.stream.Collectors; |
38 | | - |
| 38 | +import javafx.application.Platform; |
39 | 39 | import javafx.beans.InvalidationListener; |
40 | 40 | import javafx.beans.property.DoubleProperty; |
41 | 41 | import javafx.beans.property.ObjectProperty; |
|
77 | 77 | import javafx.stage.Stage; |
78 | 78 | import javafx.stage.Window; |
79 | 79 | import javafx.util.Pair; |
80 | | - |
| 80 | +import javafx.util.Subscription; |
81 | 81 | import com.sun.javafx.menu.MenuBase; |
82 | 82 | import com.sun.javafx.scene.ParentHelper; |
83 | 83 | import com.sun.javafx.scene.SceneHelper; |
@@ -130,7 +130,7 @@ public class MenuBarSkin extends SkinBase<MenuBar> { |
130 | 130 | private WeakChangeListener<Boolean> weakMenuVisibilityChangeListener; |
131 | 131 | private ListenerHelper sceneListenerHelper; |
132 | 132 | private IDisconnectable windowFocusHelper; |
133 | | - |
| 133 | + private volatile Subscription windowSubscription; |
134 | 134 | private boolean pendingDismiss = false; |
135 | 135 | private boolean altKeyPressed = false; |
136 | 136 |
|
@@ -229,17 +229,36 @@ public MenuBarSkin(final MenuBar control) { |
229 | 229 |
|
230 | 230 | ListenerHelper lh = ListenerHelper.get(this); |
231 | 231 |
|
| 232 | + if (Platform.isFxApplicationThread()) { |
| 233 | + if (Toolkit.getToolkit().getSystemMenu().isSupported()) { |
| 234 | + lh.addInvalidationListener(control.useSystemMenuBarProperty(), (v) -> { |
| 235 | + rebuildUI(); |
| 236 | + }); |
| 237 | + } |
| 238 | + } else { |
| 239 | + // delay rebuildUI() until after MenuBar becomes a part of the scene graph |
| 240 | + // this subscription will be removed by cleanUpListeners() |
| 241 | + windowSubscription = getSkinnable() |
| 242 | + .sceneProperty() |
| 243 | + .flatMap(Scene::windowProperty) |
| 244 | + .subscribe(w -> { |
| 245 | + if (w != null) { |
| 246 | + if (Toolkit.getToolkit().getSystemMenu().isSupported()) { |
| 247 | + lh.addInvalidationListener(control.useSystemMenuBarProperty(), (v) -> { |
| 248 | + rebuildUI(); |
| 249 | + }); |
| 250 | + } |
| 251 | + // this method will unsubscribe on first run |
| 252 | + rebuildUI(); |
| 253 | + } |
| 254 | + }); |
| 255 | + } |
| 256 | + |
232 | 257 | rebuildUI(); |
233 | 258 | lh.addListChangeListener(control.getMenus(), (v) -> { |
234 | 259 | rebuildUI(); |
235 | 260 | }); |
236 | 261 |
|
237 | | - if (Toolkit.getToolkit().getSystemMenu().isSupported()) { |
238 | | - lh.addInvalidationListener(control.useSystemMenuBarProperty(), (v) -> { |
239 | | - rebuildUI(); |
240 | | - }); |
241 | | - } |
242 | | - |
243 | 262 | // When the mouse leaves the menu, the last hovered item should lose |
244 | 263 | // it's focus so that it is no longer selected. This code returns focus |
245 | 264 | // to the MenuBar itself, such that keyboard navigation can continue. |
@@ -783,6 +802,12 @@ private void updateActionListeners(MenuItem item, boolean add) { |
783 | 802 | } |
784 | 803 |
|
785 | 804 | private void cleanUpListeners() { |
| 805 | + Subscription sub = windowSubscription; |
| 806 | + if (sub != null) { |
| 807 | + sub.unsubscribe(); |
| 808 | + windowSubscription = null; |
| 809 | + } |
| 810 | + |
786 | 811 | getSkinnable().focusedProperty().removeListener(weakMenuBarFocusedPropertyListener); |
787 | 812 |
|
788 | 813 | for (Menu m : getSkinnable().getMenus()) { |
@@ -817,6 +842,9 @@ private void cleanUpListeners() { |
817 | 842 | } |
818 | 843 |
|
819 | 844 | private void rebuildUI() { |
| 845 | + if (!Platform.isFxApplicationThread()) { |
| 846 | + return; |
| 847 | + } |
820 | 848 | cleanUpListeners(); |
821 | 849 |
|
822 | 850 | if (Toolkit.getToolkit().getSystemMenu().isSupported()) { |
|
0 commit comments