Skip to content

[Bugfix] Keep the editor's menu bar when SwiftUI installs its own - #156

Merged
untoldengine merged 2 commits into
untoldengine:developfrom
miolabs:bugfix/keep_main_menu
Oct 8, 2026
Merged

untoldengine merged 2 commits into
untoldengine:developfrom
miolabs:bugfix/keep_main_menu

Conversation

@miogds

@miogds miogds commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

What happened

Since #153 the editor is a SwiftUI App, so that it can declare the space the Apple Vision Pro preview shows, while its menus are still built by the AppKit delegate at launch. SwiftUI installs a menu bar of its own from its default commands. On macOS 26 it does so after the delegate has set the editor's, and the bar then reads Untold Engine Studio · Edit · View · Window · Help: no File menu, none of the editor's View items, the app menu named after the Info.plist. On macOS 27 the editor's menu survives whatever happens after launch (checked 8 s in, after activation, after the Settings scene, after asking for the preview), which is why the change was not seen before the merge.

The fix

EditorMainMenuKeeper (Editor/Window/) does not fight over which NSMenu is the main menu. It moves the editor's menus into whatever menu bar is installed, takes that bar's own items out, drops the delegate that fills it in, and keeps the Window menu the editor's, so SwiftUI keeps the object it installed and the user sees the editor's menus. It looks again whenever the main menu changes and after every event the application handles (NSApplication.didUpdate, didBecomeActive, NSWindow.didBecomeKey), so it depends neither on the setter being observable nor on winning a replace war. AppDelegate keeps one instead of assigning NSApp.mainMenu directly.

The first commit put the editor's own NSMenu back through KVO; that did not hold on macOS 26, so the second commit takes the approach above.

Verification

  • EditorMainMenuKeeperTests: nine tests on the real NSApplication: a bar installed before the editor's menus, one installed later, one refilled in place without a setter running, one that fills itself in through its delegate, the Window menu, and one showing that without the keeper another bar stays.
  • Full editor suite: 1243 tests, 0 failures. SwiftFormat clean on the two new files.
  • The symptom only shows on macOS 26, which I cannot run here: @untoldengine, could you confirm the File menu and the View items are back on your Mac? The log should show one line, The menu bar was replaced; the editor's menus are put back.

Since untoldengine#153 the editor is a SwiftUI App, for the space the Apple Vision Pro
preview shows, with its menus still built by the AppKit delegate. SwiftUI
installs a menu bar of its own from its default commands; on macOS 26 it does
so after the delegate has set the editor's, and the bar then reads Edit, View,
Window and Help: no File menu, none of the editor's View items, and the app
menu named after the Info.plist. On macOS 27 the editor's menu survived, which
is why the change was not seen before the merge.

EditorMainMenuKeeper installs the editor's menu and watches the application's
main menu; whenever another menu replaces it, the editor's is put back on the
next turn of the run loop (logged once). Five tests on the real NSApplication,
one of them showing that without the keeper another menu stays.
@miogds
miogds requested a review from untoldengine as a code owner October 7, 2026 17:37
Putting the editor's menu back by KVO did not hold on macOS 26: SwiftUI
keeps the bar it installed. The keeper no longer replaces that NSMenu; it
moves the editor's menus into whatever bar is installed, takes the bar's own
items out, drops the delegate that fills it in, and keeps the Window menu the
editor's. It looks again when the main menu changes and after every event
the application handles (NSApplication.didUpdate, didBecomeActive,
NSWindow.didBecomeKey), so it does not depend on the setter being observable.

Nine tests, on a bar installed before, one installed later, one refilled in
place without a setter, one that fills itself in through its delegate.
@untoldengine
untoldengine merged commit b0f3d2a into untoldengine:develop Oct 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants