diff --git a/devel_update_notes.org b/devel_update_notes.org index c34bff7e6fa..18a81ac4d2d 100644 --- a/devel_update_notes.org +++ b/devel_update_notes.org @@ -159,3 +159,10 @@ To summarize: Compiled a debug build, using lldb to debug. Found that a wide glyph on the first line has its ~pixel_width~ incorrectly reported (or not, just has issues with where the line is wrapped and is off by one char, which can be a wide glyph). +** MacOS Window Menu Bar +In macOS 15, the Window menu allows MacOS keybindings for windows management to work in emacs. See https://support.apple.com/en-is/guide/mac-help/mchl9674d0b0/mac. + +To support this feature: + +In mac-win.el, we've added a "Window" menu-bar. This menu holds MacOS's native Windows Menu Items, along with all native tab commands. See ~mac-window-menu-map~. +In macappkit.m, we look for the "Window" menu-item defined in mac-win.el and bind it to the mac app via ~[NSApp setWindowsMenu]~ diff --git a/lisp/term/mac-win.el b/lisp/term/mac-win.el index 90a54f81b18..ebbeb8d98e7 100644 --- a/lisp/term/mac-win.el +++ b/lisp/term/mac-win.el @@ -91,6 +91,12 @@ (defvar mac-ts-active-input-overlay) (defvar mac-frame-tabbing) + +;; Define the macos-specific Window menu and add it to the global menu-bar map +(defvar-keymap mac-window-menu-map :name "Window") +(bindings--define-key global-map [menu-bar window] + (cons "Window" mac-window-menu-map)) + ;; ;; Standard Mac cursor shapes @@ -2876,6 +2882,11 @@ visibility, then remap this command to `mac-previous-tab'." (interactive) (mac-send-action 'mergeAllWindows)) +(defun mac-raise-all-frames () + "Bring all frames (mac windows) to the front." + (interactive) + (mac-send-action 'arrangeInFront)) + ;;; Window system initialization. @@ -3087,22 +3098,35 @@ standard ones in `x-handle-args'." :button (:toggle . (mac-frame-tab-group-property nil :overview-visible-p))) 'mac-toggle-tab-bar)) - (define-key-after global-buffers-menu-map [mac-separator-tab] + (define-key-after mac-window-menu-map [mac-separator-tab] menu-bar-separator) - (define-key-after global-buffers-menu-map [mac-next-tab] + (define-key-after mac-window-menu-map [mac-next-tab] '(menu-item "Show Next Tab" mac-next-tab-or-toggle-tab-bar :enable (mac-frame-multiple-tabs-p))) (global-set-key [(control tab)] 'mac-next-tab-or-toggle-tab-bar) - (define-key-after global-buffers-menu-map [mac-previous-tab] + (define-key-after mac-window-menu-map [mac-previous-tab] '(menu-item "Show Previous Tab" mac-previous-tab-or-toggle-tab-bar :enable (mac-frame-multiple-tabs-p))) (global-set-key [(control shift tab)] 'mac-previous-tab-or-toggle-tab-bar) - (define-key-after global-buffers-menu-map [mac-move-tab-to-new-frame] + (define-key-after mac-window-menu-map [mac-move-tab-to-new-frame] '(menu-item "Move Tab to New Frame" mac-move-tab-to-new-frame :enable (mac-frame-multiple-tabs-p))) - (define-key-after global-buffers-menu-map [mac-merge-all-frame-tabs] + (define-key-after mac-window-menu-map [mac-merge-all-frame-tabs] '(menu-item "Merge All Frames" mac-merge-all-frame-tabs - :enable (mac-send-action 'mergeAllWindows t)))) + :enable (mac-send-action 'mergeAllWindows t))) + + (define-key-after mac-window-menu-map [mac-separator-tab] + menu-bar-separator) + (define-key-after mac-window-menu-map [mac-merge-all-frame-tabs] + '(menu-item "Bring All to Front" mac-raise-all-frames + :enable (mac-send-action 'arrangeInFront t))) + + ;; In the macos menubar "Window" always comes before "Help"... + ;; Configure menu-bar-final-items to insert window before help. + (unless (memq 'window menu-bar-final-items) + (let* ((post-help (memq 'help-menu menu-bar-final-items)) + (pre-help (butlast menu-bar-final-items (length post-help)))) + (setq menu-bar-final-items (append pre-help '(window) post-help))))) (setq mac-ts-active-input-overlay (make-overlay 1 1)) (overlay-put mac-ts-active-input-overlay 'display "") diff --git a/src/macappkit.m b/src/macappkit.m index e78ba44a095..48a581f8522 100644 --- a/src/macappkit.m +++ b/src/macappkit.m @@ -10647,7 +10647,7 @@ - (NSFontPanelModeMask)validModesForFontPanel:(NSFontPanel *)fontPanel static void update_services_menu_types (void); static void mac_fake_menu_bar_click (EventPriority); -static NSString *localizedMenuTitleForEdit, *localizedMenuTitleForHelp; +static NSString *localizedMenuTitleForEdit, *localizedMenuTitleForHelp, *localizedMenuTitleForWindow; /* Maximum interval time in seconds between key down and modifier key release events when they are recognized part of a synthetic @@ -11268,6 +11268,12 @@ But first we recompute the menu bar contents (the whole tree). action:nil keyEquivalent:@""]]; [NSApp setMainMenu:mainMenu]; + // Tell appkit to manage the Window menu named "Window" + [mainMenu setSubmenu:windowsMenu + forItem:[mainMenu addItemWithTitle:@"Window" + action:nil keyEquivalent:@""]]; + + MRC_RELEASE (mainMenu); MRC_RELEASE (appleMenu); MRC_RELEASE (windowsMenu); @@ -11279,6 +11285,10 @@ But first we recompute the menu bar contents (the whole tree). localizedMenuTitleForHelp = MRC_RETAIN (NSLocalizedStringFromTableInBundle (@"Help", @"HelpManager", appKitBundle, NULL)); + + localizedMenuTitleForWindow = + MRC_RETAIN (NSLocalizedStringFromTableInBundle (@"Window", @"MenuCommands", + appKitBundle, NULL)); } /* Fill menu bar with the items defined by FIRST_WV. If DEEP_P, @@ -11289,7 +11299,7 @@ But first we recompute the menu bar contents (the whole tree). mac_fill_menubar (widget_value *first_wv, bool deep_p) { mac_within_gui (^{ - NSMenu *newMenu, *mainMenu = [NSApp mainMenu], *helpMenu = nil; + NSMenu *newMenu, *mainMenu = [NSApp mainMenu], *helpMenu, *windowMenu = nil; NSInteger index = 1, nitems = [mainMenu numberOfItems]; bool needs_update_p = deep_p; @@ -11308,6 +11318,18 @@ But first we recompute the menu bar contents (the whole tree). 10.5. */ if ([title isEqualToString:@"Help"]) title = localizedMenuTitleForHelp; + + /* To make Input Manager add "Special Characters..." to the + "Edit" menu, we have to localize the menu title. */ + else if ([title isEqualToString:@"Edit"]) + title = localizedMenuTitleForEdit; + + /* Localize Window Menu for consistency with AppKit provided + menu items. */ + else if ([title isEqualToString:@"Window"]) + title = localizedMenuTitleForWindow; + + if (!needs_update_p) { if (index >= nitems) @@ -11323,12 +11345,10 @@ But first we recompute the menu bar contents (the whole tree). submenu = [[NSMenu alloc] initWithTitle:title]; [submenu setAutoenablesItems:NO]; - /* To make Input Manager add "Special Characters..." to the - "Edit" menu, we have to localize the menu title. */ - if ([title isEqualToString:@"Edit"]) - title = localizedMenuTitleForEdit; - else if (title == localizedMenuTitleForHelp) + if (title == localizedMenuTitleForHelp) helpMenu = submenu; + else if (title == localizedMenuTitleForWindow) + windowMenu = submenu; [newMenu setSubmenu:submenu forItem:[newMenu addItemWithTitle:title action:nil @@ -11352,6 +11372,10 @@ But first we recompute the menu bar contents (the whole tree). MRC_RELEASE (appleMenuItem); [NSApp setMainMenu:newMenu]; + + if (windowMenu) + [NSApp setWindowsMenu:windowMenu]; + if (helpMenu) [NSApp setHelpMenu:helpMenu]; }