X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b89875707ce5b8e88097b7d4d365b480b17733a6..b8dc613f4501331628cc292c65ba0768d6537b2e:/src/macmenu.c diff --git a/src/macmenu.c b/src/macmenu.c index e97a968d92..ab266f6f0b 100644 --- a/src/macmenu.c +++ b/src/macmenu.c @@ -15,8 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ /* Contributed by Andrew Choi (akochoi@mac.com). */ @@ -1356,6 +1356,68 @@ update_submenu_strings (first_wv) } +/* Event handler function that pops down a menu on C-g. We can only pop + down menus if CancelMenuTracking is present (OSX 10.3 or later). */ + +#ifdef HAVE_CANCELMENUTRACKING +static pascal OSStatus +menu_quit_handler (nextHandler, theEvent, userData) + EventHandlerCallRef nextHandler; + EventRef theEvent; + void* userData; +{ + UInt32 keyCode; + UInt32 keyModifiers; + extern int mac_quit_char_modifiers; + extern int mac_quit_char_keycode; + + GetEventParameter (theEvent, kEventParamKeyCode, + typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); + + GetEventParameter (theEvent, kEventParamKeyModifiers, + typeUInt32, NULL, sizeof(UInt32), + NULL, &keyModifiers); + + if (keyCode == mac_quit_char_keycode + && keyModifiers == mac_quit_char_modifiers) + { + MenuRef menu = userData != 0 + ? (MenuRef)userData : AcquireRootMenu (); + + CancelMenuTracking (menu, true, 0); + if (!userData) ReleaseMenu (menu); + return noErr; + } + + return CallNextEventHandler (nextHandler, theEvent); +} +#endif /* HAVE_CANCELMENUTRACKING */ + +/* Add event handler for MENU_HANDLE so we can detect C-g. + If MENU_HANDLE is NULL, install handler for all menus in the menu bar. + If CancelMenuTracking isn't available, do nothing. */ + +static void +install_menu_quit_handler (MenuHandle menu_handle) +{ +#ifdef HAVE_CANCELMENUTRACKING + EventHandlerUPP handler = NewEventHandlerUPP(menu_quit_handler); + UInt32 numTypes = 1; + EventTypeSpec typesList[] = { { kEventClassKeyboard, kEventRawKeyDown } }; + int i = MIN_MENU_ID; + MenuHandle menu = menu_handle ? menu_handle : GetMenuHandle (i); + + while (menu != NULL) + { + InstallMenuEventHandler (menu, handler, GetEventTypeCount (typesList), + typesList, menu_handle, NULL); + if (menu_handle) break; + menu = GetMenuHandle (++i); + } + DisposeEventHandlerUPP (handler); +#endif /* HAVE_CANCELMENUTRACKING */ +} + /* Set the contents of the menubar widgets of frame F. The argument FIRST_TIME is currently ignored; it is set the first time this is called, from initialize_frame_menubar. */ @@ -1413,7 +1475,7 @@ set_frame_menubar (f, first_time, deep_p) because it is not reentrant. */ specbind (Qdebug_on_next_call, Qnil); - record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); + record_unwind_save_match_data (); if (NILP (Voverriding_local_map_menu_flag)) { specbind (Qoverriding_terminal_local_map, Qnil); @@ -1575,6 +1637,8 @@ set_frame_menubar (f, first_time, deep_p) DrawMenuBar (); + /* Add event handler so we can detect C-g. */ + install_menu_quit_handler (NULL); free_menubar_widget_value_tree (first_wv); UNBLOCK_INPUT; @@ -1606,7 +1670,43 @@ free_frame_menubar (f) } -/* mac_menu_show actually displays a menu using the panes and items in +static Lisp_Object +pop_down_menu (arg) + Lisp_Object arg; +{ + struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg)); + struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg)); + + FRAME_PTR f = p1->pointer; + MenuHandle *menu = p2->pointer; + + BLOCK_INPUT; + + /* Must reset this manually because the button release event is not + passed to Emacs event loop. */ + FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0; + + /* delete all menus */ + { + int i = MIN_POPUP_SUBMENU_ID; + MenuHandle submenu = GetMenuHandle (i); + while (submenu != NULL) + { + DeleteMenu (i); + DisposeMenu (submenu); + submenu = GetMenuHandle (++i); + } + } + + DeleteMenu (POPUP_SUBMENU_ID); + DisposeMenu (*menu); + + UNBLOCK_INPUT; + + return Qnil; +} + +/* Mac_menu_show actually displays a menu using the panes and items in menu_items and returns the value selected from it; we assume input is blocked by the caller. */ @@ -1644,6 +1744,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); int submenu_depth = 0; int first_pane; + int specpdl_count = SPECPDL_INDEX (); *error = NULL; @@ -1817,7 +1918,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) title = ENCODE_MENU_STRING (title); #endif wv_title->name = (char *) SDATA (title); - wv_title->enabled = TRUE; + wv_title->enabled = FALSE; wv_title->title = TRUE; wv_title->button_type = BUTTON_TYPE_NONE; wv_title->help = Qnil; @@ -1830,6 +1931,10 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) submenu_id = MIN_POPUP_SUBMENU_ID; fill_submenu (menu, first_wv->contents); + /* Free the widget_value objects we used to specify the + contents. */ + free_menubar_widget_value_tree (first_wv); + /* Adjust coordinates to be root-window-relative. */ pos.h = x; pos.v = y; @@ -1844,11 +1949,18 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) InsertMenu (menu, -1); + record_unwind_protect (pop_down_menu, + Fcons (make_save_value (f, 0), + make_save_value (&menu, 0))); + + /* Add event handler so we can detect C-g. */ + install_menu_quit_handler (menu); + /* Display the menu. */ menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0); menu_item_selection = LoWord (menu_item_choice); - /* Get the refcon to find the correct item*/ + /* Get the refcon to find the correct item */ if (menu_item_selection) { MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice)); @@ -1856,35 +1968,10 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon); } } - -#if 0 - /* Clean up extraneous mouse events which might have been generated - during the call. */ - discard_mouse_events (); -#endif - - /* Must reset this manually because the button release event is not - passed to Emacs event loop. */ - FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0; - - /* Free the widget_value objects we used to specify the - contents. */ - free_menubar_widget_value_tree (first_wv); - - /* delete all menus */ - { - int i = MIN_POPUP_SUBMENU_ID; - MenuHandle submenu = GetMenuHandle (i); - while (submenu != NULL) - { - DeleteMenu (i); - DisposeMenu (submenu); - submenu = GetMenuHandle (++i); - } - } - - DeleteMenu (POPUP_SUBMENU_ID); - DisposeMenu (menu); + else if (! for_click) + /* Make "Cancel" equivalent to C-g unless this menu was popped up by + a mouse press. */ + Fsignal (Qquit, Qnil); /* Find the selected item, and its pane, to return the proper value. */ @@ -1944,6 +2031,8 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) /* Make "Cancel" equivalent to C-g. */ Fsignal (Qquit, Qnil); + unbind_to (specpdl_count, Qnil); + return Qnil; }