Skip to content

feat(macos): the main menu in the menu bar (#784) - #805

Draft
volkovskey wants to merge 2 commits into
storytold:mainfrom
volkovskey:feat/macos-menu-bar
Draft

volkovskey wants to merge 2 commits into
storytold:mainfrom
volkovskey:feat/macos-menu-bar

Conversation

@volkovskey

Copy link
Copy Markdown
Contributor

Closes #784.

On macOS the menu bar shows only winit's default app menu. This puts FigCraft's main menu there, through craft-menu, the shared menu bar crate proposed in storytold/craft-libs#66 (see storytold/craft-libs#65).

Draft: craft-menu is pinned to the craft-libs#66 head (2bff0ab) until that lands. Once it does, the pin moves to the merged rev and this is ready for review.

What it does

  • The same items, labels, translations, shortcuts, and enabled and checked state as the in-window menu, built from catalog::MENU. One source, so the two menus can't drift apart.
  • File ▸ Open recent lists the recent files (greyed out when the file is gone) and Clear recent. The installed plugins' commands head the Plugins menu, as they do in the window.
  • Mac layout from craft-menu:
    • About and Settings move to the FigCraft menu, which also has Services, Hide and Quit, plus a Window menu.
    • Quit goes through the window's close request, so unsaved changes are still asked about.
  • Key equivalents go back to egui, so FigCraft's own key handling still runs them. In text fields ⌘C/⌘V/⌘A edit the text.
  • Menu events wake the app, so a click runs even when the app is idle.

Where it lives

  • ui-egui/src/native_menu.rs (platform-free): builds the craft_menu::MenuBar from the catalog and routes a chosen id (file.recent:<path>, plugin:<id>:<command>, or a catalog id) the way the in-window menu does.
  • apps/figcraft/src/mac_menu.rs (macOS only): installs the bar and syncs it each frame. The bar is rebuilt only after input.
  • New crates in the lock: craft-menu, craft-quit, muda, crossbeam-channel, keyboard-types. craft-menu is a macOS-only dependency of the app; ui-egui uses only its platform-free tree types.

Tests

native_menu_tests.rs (5 tests):

  • the menus come in the in-window order;
  • items carry their shortcuts and enabled/checked state;
  • Open recent lists and clears;
  • chosen items run their commands;
  • the Mac layout moves About and Settings to the app menu.

Shortcuts are asserted for the Mac keymap on every platform, so the tests pass on Linux CI too.

file_access::tests::{links_that_lead_out_of_a_root_are_outside, outside_paths_are_refused_alike_whatever_exists_there} fail locally on macOS, and they fail the same way on a clean main, so this change doesn't cause them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YQxjkNSUJhTkTfY74aNeki

On macOS the menu bar showed only winit's default app menu. The main menu
now goes there through craft-menu (storytold/craft-libs#66), the shared
menu bar of the Craft apps: the same items, labels, translations,
shortcuts and enabled and checked state as the in-window menu, built from
the catalog, with Open recent and the installed plugins' commands.

craft-menu lays it out the Mac way (About and Settings in the FigCraft
menu, Services, Hide, Quit through the window's close request, so unsaved
changes are asked about; a Window menu), wakes the app on every menu
event, and hands key equivalents back to egui, so FigCraft's own key
handling still runs them.

ui-egui builds the tree (`native_menu`, platform-free); the app installs
it on macOS (`mac_menu`) and syncs it each frame. craft-menu is pinned to
the craft-libs#66 head until that lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YQxjkNSUJhTkTfY74aNeki
@coderabbitai

coderabbitai Bot commented Oct 18, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@bflatastic

Copy link
Copy Markdown
Member

Thank you, @volkovskey, this is well built:

  • the bar comes from catalog::MENU and the keymap;
  • items go through menus::invoke;
  • key equivalents go back to egui, so shortcuts don't run twice;
  • the menu only rebuilds after input;
  • Quit still asks about unsaved changes;
  • there's no unsafe.

It's held for a maintainer decision on the dependency: craft-menu is pinned to the head of an open, unmerged craft-libs PR (craft-libs#66) from another account's fork, and it brings muda 0.21.2 (caret, while the sibling apps pin =0.21.1). That PR needs to be reviewed and merged first, and the pin moved to the merged rev. Fixes needed either way:

  • Several windows: with a second window in front, ⌘ shortcuts can go to the main window's input, and menu clicks act on the main window's file. Feed menu keys only into the focused viewport, and run and build the menu for app.windows.focused (e.g. via windows::as_window). This needs a check on a Mac with two windows.
  • Translations: the app-menu labels ("About {app}", "Hide {app}", "Quit {app}", "Services", "Show All", "Window"…) need catalog entries in every full catalog. About currently loses its German translation.
  • Duplication: use menus::TOP_MENUS instead of the TOPS copy, and reuse plugins_ui::menu for the plugin rows (it also has the Widgets submenu, which is missing here).

…menu (storytold#784)

Review fixes for the native menu bar:

- Several windows: the menu bar is built for and runs its items in the
  window in front (`windows::as_window` on `windows.focused`), and its key
  equivalents go only into that window's input. A key equivalent that
  arrives while the main window draws is queued for the window in front,
  and a paste the menu bar asks of the main window goes on to it.
- Translations: the labels the Mac layout writes (About, Hide and Quit
  FigCraft, Hide Others, Show All, Services, Settings…, Window, Bring All
  to Front, Close Window) are catalog keys, translated in every full
  catalog. A test checks the layout asks for no label outside them.
- Duplication: the bar's menus are `menus::TOP_MENUS`, and the plugin rows
  come from `plugins_ui::menu_entries`, which the in-window Plugins menu
  now draws from too, so the bar gains the Widgets submenu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YQxjkNSUJhTkTfY74aNeki
@volkovskey

Copy link
Copy Markdown
Contributor Author

Thanks for the review, @bflatastic. The fixes are in 2c6f24e:

  • Several windows: the bar is built for and runs its items in windows.focused, through windows::as_window. Its key equivalents go only into the input of the window in front. Two cases go on to that window through its input queue:

    • a key equivalent that arrives while the main window draws;
    • the paste that the menu bar's ⌘V asks of the main window.

    Tests cover these with two windows. The check by hand on a Mac with two windows is still to come.

  • Translations: the labels the Mac layout writes are now catalog keys (native_menu::MAC_LABELS), translated in every full catalog: About, Hide and Quit {app}, Hide Others, Show All, Services, Settings…, Window, Bring All to Front, Close Window. So German About reads "Über FigCraft" again. A test checks that the layout asks for no label outside the list and that every full catalog has each one.

  • Duplication: the bar uses menus::TOP_MENUS. The plugin rows come from plugins_ui::menu_entries, and the in-window Plugins menu now draws from it too, so the bar has the Widgets submenu.

Understood on the dependency. The pin stays until craft-libs#66 is reviewed and merged (including the muda version), then it moves to the merged rev.

@bflatastic

Copy link
Copy Markdown
Member

Thanks @volkovskey! The pinned craft-libs rev 2bff0abb isn't on craft-libs' main (and isn't the current head of craft-libs#66). FigCraft can only depend on a craft-libs commit that's on its main, so this waits for #66 to merge; then please re-pin.

@bflatastic

Copy link
Copy Markdown
Member

A status update: this stays open, and here's what would let it land. craft-menu (craft-libs#66) is merged now, which unblocks this. Please:

This branch has not been deployed

No deployments
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.

macOS: Should populate system menu bar

2 participants