]> code.delx.au - gnu-emacs/blobdiff - src/macmenu.c
(syms_of_buffer) <cursor-type>: Doc fix.
[gnu-emacs] / src / macmenu.c
index e97a968d92ddedd761b9255ec93d7a7ca09e9e18..ab266f6f0b566cbfb81840d346213c9a1bdda253 100644 (file)
@@ -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)
 }
 
 \f
+/* 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)
 }
 
 \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;
 }
 \f