From e427468d0f0be995968f18ecc286e5e72f45eb61 Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Wed, 21 Oct 2026 14:05:28 +0200 Subject: [PATCH] [macOS] Refresh the main menu after inserting menu bar items on macOS 27 On macOS 27, items inserted into the main menu are not shown on screen until the mouse hovers over the menu bar or the application is activated again. This happens when the menu bar is swapped while a dialog becomes or stops being the key window, and when an item is added to the active menu bar. It also occurs in plain AppKit applications, so it is a macOS regression whose root cause is unknown. As a workaround, re-assert the main menu by setting it to null and back, which makes AppKit resync the menu bar. NSMenu.update() or setting the same main menu again do not help. The refresh is done asynchronously, since it is sometimes ignored while a shell is still becoming the key window, which also coalesces a series of menu bar item additions. Contributes to https://github.com/eclipse-platform/eclipse.platform.swt/issues/3540 Assisted-by: Claude Opus 5.5 --- .../org/eclipse/swt/widgets/Display.java | 31 +++++++++++++++++++ .../cocoa/org/eclipse/swt/widgets/Menu.java | 1 + 2 files changed, 32 insertions(+) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java index c2524f8e8c9..12f4ca63fae 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java @@ -173,6 +173,7 @@ enum APPEARANCE { NSPanel modalPanel; Menu menuBar; + boolean mainMenuRefreshPending; Menu[] menus, popups; long lastHandledMenuForEventId; @@ -5046,6 +5047,36 @@ void setMenuBar (Menu menu) { nsItem.setEnabled(enabled); } } + refreshMainMenu (); +} + +/* +* Bug in Cocoa on macOS 27: menu bar changes (swapping the menu bar, inserting +* items) are not shown on screen until the mouse hovers over the menu bar. Fix: +* re-assert the main menu to force AppKit to resync with the window server; +* NSMenu.update() and re-setting the same menu don't help. The menu is retained +* since the application may hold the only reference to it. Deferred via asyncExec +* since an immediate refresh is sometimes ignored (e.g. while a sheet is closing), +* and to coalesce bursts of menu bar changes into one refresh. +* +* TODO: Re-evaluate on future macOS releases whether this workaround is still needed. +*/ +void refreshMainMenu () { + if (OS.VERSION < OS.VERSION (27, 0, 0) || mainMenuRefreshPending) { + return; + } + mainMenuRefreshPending = true; + asyncExec (() -> { + mainMenuRefreshPending = false; + NSMenu menubar = application.mainMenu (); + if (menubar == null) { + return; + } + menubar.retain (); + application.setMainMenu (null); + application.setMainMenu (menubar); + menubar.release (); + }); } void setModalDialog (Dialog modalDialog) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java index 9c5bbfab320..9d376b06712 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Menu.java @@ -419,6 +419,7 @@ void createItem (MenuItem item, int index) { if (menubar != null) { nsItem.setMenu(null); menubar.insertItem(nsItem, index + 1); + display.refreshMainMenu (); } } }