]> code.delx.au - gnu-emacs/blobdiff - src/macmenu.c
Merge from emacs--devo--0
[gnu-emacs] / src / macmenu.c
index 1e599c614a62ed6d9dfb63949704b74f7797edfc..1eb0b16cd958bad96ff919042c4afe3701c9b3f1 100644 (file)
@@ -1,6 +1,6 @@
 /* Menu support for GNU Emacs on Mac OS.
    Copyright (C) 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006 Free Software Foundation, Inc.
+                 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -26,10 +26,10 @@ Boston, MA 02110-1301, USA.  */
 #include <stdio.h>
 
 #include "lisp.h"
+#include "frame.h"
 #include "termhooks.h"
 #include "keyboard.h"
 #include "keymap.h"
-#include "frame.h"
 #include "window.h"
 #include "blockinput.h"
 #include "buffer.h"
@@ -200,7 +200,7 @@ static void list_of_items P_ ((Lisp_Object));
 
 static void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
                                              void *));
-static int fill_menu P_ ((MenuHandle, widget_value *, enum mac_menu_kind, int));
+static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
 static void fill_menubar P_ ((widget_value *, int));
 static void dispose_menus P_ ((enum mac_menu_kind, int));
 
@@ -259,6 +259,9 @@ static int menu_items_n_panes;
 /* Current depth within submenus.  */
 static int menu_items_submenu_depth;
 
+/* Nonzero means a menu is currently active.  */
+static int popup_activated_flag;
+
 /* This is set nonzero after the user activates the menu bar, and set
    to zero again after the menu bars are redisplayed by prepare_menu_bar.
    While it is nonzero, all calls to set_frame_menubar go deep.
@@ -717,8 +720,8 @@ no quit occurs and `x-popup-menu' returns nil.  */)
          enum scroll_bar_part part;
          unsigned long time;
 
-         if (mouse_position_hook)
-           (*mouse_position_hook) (&new_f, 1, &bar_window,
+         if (FRAME_TERMINAL (new_f)->mouse_position_hook)
+           (*FRAME_TERMINAL (new_f)->mouse_position_hook) (&new_f, 1, &bar_window,
                                    &part, &x, &y, &time);
          if (new_f != 0)
            XSETFRAME (window, new_f);
@@ -1008,6 +1011,11 @@ for instance using the window manager, then this produces a quit and
       DialogItemIndex item_hit;
       Lisp_Object tem;
 
+      /* Force a redisplay before showing the dialog.  If a frame is
+        created just before showing the dialog, its contents may not
+        have been fully drawn.  */
+      Fredisplay (Qt);
+
       tem = Fstring_match (concat3 (build_string ("\\("),
                                    call0 (intern ("sentence-end")),
                                    build_string ("\\)\n")),
@@ -1141,7 +1149,9 @@ x_activate_menubar (f)
   set_frame_menubar (f, 0, 1);
   BLOCK_INPUT;
 
+  popup_activated_flag = 1;
   menu_choice = MenuSelect (saved_menu_event_location);
+  popup_activated_flag = 0;
   menu_id = HiWord (menu_choice);
   menu_item = LoWord (menu_choice);
 
@@ -1152,7 +1162,7 @@ x_activate_menubar (f)
 #endif
     if (menu_id)
       {
-        MenuHandle menu = GetMenuHandle (menu_id);
+        MenuRef menu = GetMenuRef (menu_id);
 
         if (menu)
           {
@@ -1585,15 +1595,13 @@ menu_target_item_handler (next_handler, event, data)
      EventRef event;
      void *data;
 {
-  OSStatus err, result;
+  OSStatus err;
   MenuRef menu;
   MenuItemIndex menu_item;
   Lisp_Object help;
   GrafPtr port;
   int specpdl_count = SPECPDL_INDEX ();
 
-  result = CallNextEventHandler (next_handler, event);
-
   err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
                           NULL, sizeof (MenuRef), NULL, &menu);
   if (err == noErr)
@@ -1616,30 +1624,21 @@ menu_target_item_handler (next_handler, event, data)
   SetPort (port);
   unbind_to (specpdl_count, Qnil);
 
-  return err == noErr ? noErr : result;
+  return err == noErr ? noErr : eventNotHandledErr;
 }
-#endif
 
 OSStatus
-install_menu_target_item_handler (window)
-     WindowPtr window;
+install_menu_target_item_handler ()
 {
-  OSStatus err = noErr;
-#if TARGET_API_MAC_CARBON
   static const EventTypeSpec specs[] =
     {{kEventClassMenu, kEventMenuTargetItem}};
-  static EventHandlerUPP menu_target_item_handlerUPP = NULL;
-
-  if (menu_target_item_handlerUPP == NULL)
-    menu_target_item_handlerUPP =
-      NewEventHandlerUPP (menu_target_item_handler);
 
-  err = InstallWindowEventHandler (window, menu_target_item_handlerUPP,
-                                  GetEventTypeCount (specs), specs,
-                                  NULL, NULL);
-#endif
-  return err;
+  return InstallApplicationEventHandler (NewEventHandlerUPP
+                                        (menu_target_item_handler),
+                                        GetEventTypeCount (specs),
+                                        specs, NULL, NULL);
 }
+#endif  /* TARGET_API_MAC_CARBON */
 
 /* 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).  */
@@ -1677,15 +1676,15 @@ menu_quit_handler (nextHandler, theEvent, userData)
 }
 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
 
-/* Add event handler to all menus that belong to KIND so we can detect C-g.
-   MENU_HANDLE is the root menu of the tracking session to dismiss
-   when C-g is detected.  NULL means the menu bar.
-   If CancelMenuTracking isn't available, do nothing.  */
+/* Add event handler to all menus that belong to KIND so we can detect
+   C-g.  ROOT_MENU is the root menu of the tracking session to dismiss
+   when C-g is detected.  NULL means the menu bar.  If
+   CancelMenuTracking isn't available, do nothing.  */
 
 static void
-install_menu_quit_handler (kind, menu_handle)
+install_menu_quit_handler (kind, root_menu)
      enum mac_menu_kind kind;
-     MenuHandle menu_handle;
+     MenuRef root_menu;
 {
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
   static const EventTypeSpec typesList[] =
@@ -1698,13 +1697,13 @@ install_menu_quit_handler (kind, menu_handle)
 #endif
   for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
     {
-      MenuHandle menu = GetMenuHandle (id);
+      MenuRef menu = GetMenuRef (id);
 
       if (menu == NULL)
        break;
       InstallMenuEventHandler (menu, menu_quit_handler,
                               GetEventTypeCount (typesList),
-                              typesList, menu_handle, NULL);
+                              typesList, root_menu, NULL);
     }
 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
 }
@@ -1728,10 +1727,13 @@ set_frame_menubar (f, first_time, deep_p)
 
   XSETFRAME (Vmenu_updating_frame, f);
 
+  /* This seems to be unnecessary for Carbon.  */
+#if 0
   if (! menubar_widget)
     deep_p = 1;
   else if (pending_menu_activation && !deep_p)
     deep_p = 1;
+#endif
 
   if (deep_p)
     {
@@ -1968,7 +1970,7 @@ pop_down_menu (arg)
 {
   struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
   FRAME_PTR f = p->pointer;
-  MenuHandle menu = GetMenuHandle (min_menu_id[MAC_MENU_POPUP]);
+  MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
 
   BLOCK_INPUT;
 
@@ -2012,11 +2014,9 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
      char **error;
 {
   int i;
-  UInt32 refcon;
   int menu_item_choice;
-  int menu_item_selection;
-  MenuHandle menu;
-  Point pos;
+  UInt32 menu_item_selection;
+  MenuRef menu;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
   widget_value **submenu_stack
     = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
@@ -2222,14 +2222,10 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   free_menubar_widget_value_tree (first_wv);
 
   /* Adjust coordinates to be root-window-relative.  */
-  pos.h = x;
-  pos.v = y;
-
-  SetPortWindowPort (FRAME_MAC_WINDOW (f));
-  LocalToGlobal (&pos);
+  x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
+  y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
 
   /* No selection has been chosen yet.  */
-  menu_item_choice = 0;
   menu_item_selection = 0;
 
   record_unwind_protect (pop_down_menu, make_save_value (f, 0));
@@ -2239,21 +2235,21 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
 
   /* Display the menu.  */
-  menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0);
-  menu_item_selection = LoWord (menu_item_choice);
+  popup_activated_flag = 1;
+  menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
+  popup_activated_flag = 0;
 
   /* Get the refcon to find the correct item */
-  if (menu_item_selection)
+  if (menu_item_choice)
     {
-      MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice));
-      if (sel_menu) {
-       GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon);
-      }
+      MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
+
+      if (sel_menu)
+       GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
+                          &menu_item_selection);
     }
-  else if (! for_click)
-    /* Make "Cancel" equivalent to C-g unless this menu was popped up by
-       a mouse press.  */
-    Fsignal (Qquit, Qnil);
+
+  unbind_to (specpdl_count, Qnil);
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
@@ -2290,7 +2286,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
            {
              entry
                = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
-             if ((int) (EMACS_INT) refcon == i)
+             if (menu_item_selection == i)
                {
                  if (keymaps != 0)
                    {
@@ -2313,8 +2309,6 @@ 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
@@ -2324,6 +2318,14 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
 
 #if TARGET_API_MAC_CARBON
 
+#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
+#define DIALOG_BUTTON_COMMAND_ID_P(id)                 \
+  (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
+#define DIALOG_BUTTON_COMMAND_ID_VALUE(id)     \
+  ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
+#define DIALOG_BUTTON_MAKE_COMMAND_ID(value)   \
+  ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
+
 static pascal OSStatus
 mac_handle_dialog_event (next_handler, event, data)
      EventHandlerCallRef next_handler;
@@ -2343,7 +2345,7 @@ mac_handle_dialog_event (next_handler, event, data)
                                 typeHICommand, NULL, sizeof (HICommand),
                                 NULL, &command);
        if (err == noErr)
-         if ((command.commandID & ~0xffff) == 'Bt\0\0')
+         if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
            {
              SetWRefCon (window, command.commandID);
              err = QuitAppModalLoopForWindow (window);
@@ -2386,15 +2388,20 @@ mac_handle_dialog_event (next_handler, event, data)
                                           typeUInt32, NULL, sizeof (UInt32),
                                           NULL, &key_code);
                if (err == noErr)
-                 if (mac_quit_char_key_p (modifiers, key_code))
-                   err = QuitAppModalLoopForWindow (window);
-                 else
-                   err = eventNotHandledErr;
+                 {
+                   if (mac_quit_char_key_p (modifiers, key_code))
+                     err = QuitAppModalLoopForWindow (window);
+                   else
+                     err = eventNotHandledErr;
+                 }
              }
              break;
            }
 
-       return err == noErr ? noErr : result;
+       if (err == noErr)
+         result = noErr;
+
+       return result;
       }
       break;
 
@@ -2510,14 +2517,16 @@ create_and_show_dialog (f, first_wv)
            }
          if (err == noErr)
            {
+             UInt32 command_id;
+
              OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
              if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
                rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
              else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
                rects[i].right = DIALOG_MAX_INNER_WIDTH;
 
-             err = SetControlCommandID (buttons[i],
-                                        'Bt\0\0' + (int) wv->call_data);
+             command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
+             err = SetControlCommandID (buttons[i], command_id);
            }
          if (err != noErr)
            break;
@@ -2694,8 +2703,8 @@ create_and_show_dialog (f, first_wv)
     {
       UInt32 command_id = GetWRefCon (window);
 
-      if ((command_id & ~0xffff) == 'Bt\0\0')
-       result = command_id - 'Bt\0\0';
+      if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
+       result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
     }
 
   if (window)
@@ -2716,8 +2725,8 @@ mac_dialog (widget_value *wv)
   int i;
   int dialog_width;
   Rect rect;
-  WindowPtr window_ptr;
-  ControlHandle ch;
+  WindowRef window_ptr;
+  ControlRef ch;
   int left;
   EventRecord event_record;
   SInt16 part_code;
@@ -2746,7 +2755,7 @@ mac_dialog (widget_value *wv)
       wv = wv->next;
     }
 
-  window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
+  window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
 
   SetPortWindowPort (window_ptr);
 
@@ -2940,6 +2949,11 @@ mac_dialog_show (f, keymaps, title, header, error_name)
     first_wv = wv;
   }
 
+  /* Force a redisplay before showing the dialog.  If a frame is created
+     just before showing the dialog, its contents may not have been fully
+     drawn.  */
+  Fredisplay (Qt);
+
   /* Actually create the dialog.  */
 #if TARGET_API_MAC_CARBON
   menu_item_selection = create_and_show_dialog (f, first_wv);
@@ -3018,7 +3032,7 @@ name_is_separator (name)
 
 static void
 add_menu_item (menu, pos, wv)
-     MenuHandle menu;
+     MenuRef menu;
      int pos;
      widget_value *wv;
 {
@@ -3095,7 +3109,7 @@ add_menu_item (menu, pos, wv)
 
 static int
 fill_menu (menu, wv, kind, submenu_id)
-     MenuHandle menu;
+     MenuRef menu;
      widget_value *wv;
      enum mac_menu_kind kind;
      int submenu_id;
@@ -3107,7 +3121,7 @@ fill_menu (menu, wv, kind, submenu_id)
       add_menu_item (menu, pos, wv);
       if (wv->contents && submenu_id < min_menu_id[kind + 1])
        {
-         MenuHandle submenu = NewMenu (submenu_id, "\pX");
+         MenuRef submenu = NewMenu (submenu_id, "\pX");
 
          InsertMenu (submenu, -1);
          SetMenuItemHierarchicalID (menu, pos, submenu_id);
@@ -3126,8 +3140,6 @@ fill_menubar (wv, deep_p)
      int deep_p;
 {
   int id, submenu_id;
-  MenuHandle menu;
-  Str255 title;
 #if !TARGET_API_MAC_CARBON
   int title_changed_p = 0;
 #endif
@@ -3149,45 +3161,75 @@ fill_menubar (wv, deep_p)
        wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
        wv = wv->next, id++)
     {
+      OSStatus err = noErr;
+      MenuRef menu;
+#if TARGET_API_MAC_CARBON
+      CFStringRef title;
+
+      title = CFStringCreateWithCString (NULL, wv->name,
+                                        kCFStringEncodingMacRoman);
+#else
+      Str255 title;
+
       strncpy (title, wv->name, 255);
       title[255] = '\0';
       c2pstr (title);
+#endif
 
-      menu = GetMenuHandle (id);
+      menu = GetMenuRef (id);
       if (menu)
        {
 #if TARGET_API_MAC_CARBON
-         Str255 old_title;
+         CFStringRef old_title;
 
-         GetMenuTitle (menu, old_title);
-         if (!EqualString (title, old_title, false, false))
-           SetMenuTitle (menu, title);
+         err = CopyMenuTitleAsCFString (menu, &old_title);
+         if (err == noErr)
+           {
+             if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
+               err = SetMenuTitleWithCFString (menu, title);
+             CFRelease (old_title);
+           }
+         else
+           err = SetMenuTitleWithCFString (menu, title);
 #else  /* !TARGET_API_MAC_CARBON */
          if (!EqualString (title, (*menu)->menuData, false, false))
            {
              DeleteMenu (id);
              DisposeMenu (menu);
              menu = NewMenu (id, title);
-             InsertMenu (menu, GetMenuHandle (id + 1) ? id + 1 : 0);
+             InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
              title_changed_p = 1;
            }
 #endif  /* !TARGET_API_MAC_CARBON */
        }
       else
        {
+#if TARGET_API_MAC_CARBON
+         err = CreateNewMenu (id, 0, &menu);
+         if (err == noErr)
+           err = SetMenuTitleWithCFString (menu, title);
+#else
          menu = NewMenu (id, title);
-         InsertMenu (menu, 0);
+#endif
+         if (err == noErr)
+           {
+             InsertMenu (menu, 0);
 #if !TARGET_API_MAC_CARBON
-         title_changed_p = 1;
+             title_changed_p = 1;
 #endif
+           }
        }
+#if TARGET_API_MAC_CARBON
+      CFRelease (title);
+#endif
 
-      if (wv->contents)
-        submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
-                               submenu_id);
+      if (err == noErr)
+       if (wv->contents)
+         submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
+                                 submenu_id);
     }
 
-  if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuHandle (id))
+  if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
     {
       dispose_menus (MAC_MENU_MENU_BAR, id);
 #if !TARGET_API_MAC_CARBON
@@ -3211,7 +3253,7 @@ dispose_menus (kind, id)
 {
   for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
     {
-      MenuHandle menu = GetMenuHandle (id);
+      MenuRef menu = GetMenuRef (id);
 
       if (menu == NULL)
        break;
@@ -3222,6 +3264,14 @@ dispose_menus (kind, id)
 
 #endif /* HAVE_MENUS */
 
+/* Detect if a menu is currently active.  */
+
+int
+popup_activated ()
+{
+  return popup_activated_flag;
+}
+
 /* The following is used by delayed window autoselection.  */
 
 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,