midi-harbor/specs/015-mac-menus/research.md
2026-09-28 13:59:10 -05:00

49 lines
2.8 KiB
Markdown

# Research: macOS Menus
The investigation behind this spec, under its number in the project-wide research log.
---
## R-102: Menus over a window winit draws
**Status**: **VERIFIED** (2026-09-28), in the direct build. Built as T244.
The menus replace winit's default as the App Store build's did (R-098), now in both builds: the
menus' target object is created in both, and made the app delegate only in App Store mode, so
quitting the direct build stays winit's. What the menus do in the window arrives as a
`ShellAction` on the same channel.
**AppKit's own close and zoom are unavailable.** libcosmic draws its own title bar, so the
window has no close or zoom button, and AppKit disables `performClose:` and `performZoom:` for
it. Close Window and Zoom go to the app instead, which closes the window through iced, as its
own close button does, or toggles it maximized.
**The Edit menu has no responder to send to.** winit's view implements none of `cut:`, `copy:`,
`paste:` or `selectAll:`. libcosmic's text field acts on the keys alone, reading a Command
shortcut from the key event's logical key, or its physical key for a non-Latin one
(`text_input/input.rs`, libcosmic 87ab817). A menu item takes its key equivalent before the
window sees it, so an item bound to ⌘C would swallow the shortcut the field needs. The items
instead hand the shortcut on to the key window's first responder:
- Typed, the event that matched the item is passed to `keyDown:` as it came.
- Clicked, the key is sent pressed and released with Command, then a modifier change with the
modifiers actually held. winit reads the modifiers from each key event
(`winit-appkit/src/view.rs`, `update_modifiers`), so without the last event the window would
go on believing Command was down, and the next letter typed would be a shortcut. A modifier
change with key code 0 carries no key, only the modifiers.
The clicked key uses its ANSI key code. On a layout that moves A, such as AZERTY, a clicked
Select All reaches the field as the letter at that position; the shortcut typed is unaffected.
**Evidence**, the direct build against a scratch daemon, driven through System Events:
- The menu bar read back as contracts/menus.md, every item enabled while the window was key.
- View > Routes and ⌘, showed their pages. File > New Virtual Port… opened its dialog over
Endpoints.
- In the dialog's name field, a clicked Select All then Copy put "Bus Alpha" on the clipboard.
A letter typed next replaced the selection rather than acting as a shortcut. ⌘A, ⌘C, ⌘X,
a clicked Paste and ⌘V each did what the key does alone.
- Zoom filled the screen. Close Window ended the window's process.
**Not checked**: the App Store build, whose menus are built by the same code with its three
differences, and Help, which opens the browser.