From ff9cf991c1608cd2578a66cba41e654a2b5d9144 Mon Sep 17 00:00:00 2001 From: oldosfan Date: Wed, 20 Oct 2021 10:54:27 +0800 Subject: [PATCH] Support opening the toolkit menu bar on NS * src/nsmenu.m (ns_activate_menubar, Fns_open_menubar): New functions. * src/nsterm.m (ns_create_terminal): Add activate_menubar_hook. * lisp/menu-bar.el (menu-bar-open): Use ns-menu-bar-open on Nextstep. --- lisp/menu-bar.el | 8 ++++--- src/nsmenu.m | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ src/nsterm.m | 1 + 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 1a81f1a3d06..e50d4fee487 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -2665,9 +2665,10 @@ first TTY menu-bar menu to be dropped down. Interactively, this is the numeric argument to the command. This function decides which method to use to access the menu depending on FRAME's terminal device. On X displays, it calls -`x-menu-bar-open'; on Windows, `w32-menu-bar-open'; otherwise it -calls either `popup-menu' or `tmm-menubar' depending on whether -`tty-menu-open-use-tmm' is nil or not. +`x-menu-bar-open'; on Windows, `w32-menu-bar-open'; +on NS, `ns-menu-bar-open'; otherwise it calls either `popup-menu' +or `tmm-menubar' depending on whether `tty-menu-open-use-tmm' +is nil or not. If FRAME is nil or not given, use the selected frame." (interactive @@ -2676,6 +2677,7 @@ If FRAME is nil or not given, use the selected frame." (cond ((eq type 'x) (x-menu-bar-open frame)) ((eq type 'w32) (w32-menu-bar-open frame)) + ((eq type 'ns) (ns-menu-bar-open frame)) ((and (null tty-menu-open-use-tmm) (not (zerop (or (frame-parameter nil 'menu-bar-lines) 0)))) ;; Make sure the menu bar is up to date. One situation where diff --git a/src/nsmenu.m b/src/nsmenu.m index 29201e69079..b93d3a79bdc 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -439,6 +439,44 @@ set_frame_menubar (struct frame *f, bool deep_p) ns_update_menubar (f, deep_p); } +void +ns_activate_menubar (struct frame *frame) +{ + if (frame != SELECTED_FRAME () + || !FRAME_EXTERNAL_MENU_BAR (frame)) + return; + + block_input (); + NSApplication *app = [NSApplication sharedApplication]; + NSMenu *menu = [app mainMenu]; + for (NSMenuItem *item in [menu itemArray]) + { + if ([item hasSubmenu]) + { +#ifdef NS_IMPL_GNUSTEP + [[item submenu] display]; +#else + NSWindow *window = [FRAME_NS_VIEW (frame) window]; + NSScreen *screen = [window screen]; + + NSRect screen_frame = [screen frame]; + [app postEvent: [NSEvent mouseEventWithType: NSLeftMouseDown + location: NSMakePoint (NSMinX (screen_frame), + NSMinY (screen_frame) + 10) + modifierFlags: 0 + timestamp: 0 + windowNumber: [window windowNumber] + context: [NSGraphicsContext currentContext] + eventNumber: 0 + clickCount: 1 + pressure: 1.0f] + atStart: YES]; +#endif + break; + } + } + unblock_input (); +} /* ========================================================================== @@ -1916,6 +1954,22 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_ return popup_activated () ? Qt : Qnil; } +DEFUN ("ns-menu-bar-open", Fns_menu_bar_open, Sns_menu_bar_open, 0, 1, "i", + doc: /* Start key navigation of the menu bar in FRAME. +This initially opens the first menu bar item and you can then navigate with the +arrow keys, select a menu entry with the return key or cancel with the +escape key. If FRAME has no menu bar this function does nothing. + +If FRAME is nil or not given, use the selected frame. */) + (Lisp_Object frame) +{ + struct frame *f = decode_window_system_frame (frame); + + ns_activate_menubar (f); + + return Qnil; +} + /* ========================================================================== Lisp interface declaration @@ -1927,6 +1981,7 @@ syms_of_nsmenu (void) { defsubr (&Sns_reset_menu); defsubr (&Smenu_or_popup_active_p); + defsubr (&Sns_menu_bar_open); DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); } diff --git a/src/nsterm.m b/src/nsterm.m index ed0e7a2aae8..4e84e130b89 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -5067,6 +5067,7 @@ ns_create_terminal (struct ns_display_info *dpyinfo) terminal->delete_frame_hook = ns_destroy_window; terminal->delete_terminal_hook = ns_delete_terminal; terminal->change_tab_bar_height_hook = ns_change_tab_bar_height; + terminal->activate_menubar_hook = ns_activate_menubar; /* Other hooks are NULL by default. */ return terminal; -- 2.39.5