]> code.delx.au - gnu-emacs/blobdiff - src/macmenu.c
(x_produce_glyphs): Fix last change.
[gnu-emacs] / src / macmenu.c
index 3958be9668d3e29a817f0da0db35edc57b8a2d66..f0696a497740962d58cf1b415fccd4223e7193d0 100644 (file)
@@ -1,5 +1,5 @@
 /* Menu support for GNU Emacs on the for Mac OS.
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -35,34 +35,7 @@ Boston, MA 02111-1307, USA.  */
 #include "charset.h"
 #include "coding.h"
 
-#ifdef MAC_OSX
-#undef mktime
-#undef DEBUG
-#undef Z
-#undef free
-#undef malloc
-#undef realloc
-/* Macros max and min defined in lisp.h conflict with those in
-   precompiled header Carbon.h.  */
-#undef max
-#undef min
-#undef init_process
-#include <Carbon/Carbon.h>
-#undef Z
-#define Z (current_buffer->text->z)
-#undef free
-#define free unexec_free
-#undef malloc
-#define malloc unexec_malloc
-#undef realloc
-#define realloc unexec_realloc
-#undef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#undef max
-#define max(a, b) ((a) > (b) ? (a) : (b))
-#undef init_process
-#define init_process emacs_init_process
-#else /* not MAC_OSX */
+#ifndef MAC_OSX
 #include <MacTypes.h>
 #include <Menus.h>
 #include <QuickDraw.h>
@@ -117,10 +90,12 @@ enum button_type
 typedef struct _widget_value
 {
   /* name of widget */
+  Lisp_Object   lname;
   char*                name;
   /* value (meaning depend on widget type) */
   char*                value;
   /* keyboard equivalent. no implications for XtTranslations */
+  Lisp_Object   lkey;
   char*                key;
   /* Help string or nil if none.
      GC finds this string through the frame's menu_bar_vector
@@ -190,6 +165,12 @@ extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
 
 extern Lisp_Object Qmenu_bar_update_hook;
 
+#if TARGET_API_MAC_CARBON
+#define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
+#else
+#define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
+#endif
+
 void set_frame_menubar ();
 
 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
@@ -732,10 +713,8 @@ cached information about equivalent key sequences.  */)
          CHECK_LIVE_WINDOW (window);
          f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
 
-         xpos = (FONT_WIDTH (FRAME_FONT (f))
-                 * XFASTINT (XWINDOW (window)->left));
-         ypos = (FRAME_LINE_HEIGHT (f)
-                 * XFASTINT (XWINDOW (window)->top));
+         xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
+         ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
        }
       else
        /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
@@ -1037,6 +1016,7 @@ menubar_selection_callback (FRAME_PTR f, int client_data)
              int j;
              struct input_event buf;
              Lisp_Object frame;
+             EVENT_INIT (buf);
 
              XSETFRAME (frame, f);
              buf.kind = MENU_BAR_EVENT;
@@ -1243,12 +1223,9 @@ single_submenu (item_key, item_name, maps)
                save_wv->next = wv;
              else
                first_wv->contents = wv;
-             wv->name = pane_string;
-             /* Ignore the @ that means "separate pane".
-                This is a kludge, but this isn't worth more time.  */
-             if (!NILP (prefix) && wv->name[0] == '@')
-               wv->name++;
-             wv->value = 0;
+             wv->lname = pane_name;
+              /* Set value to 1 so update_submenu_strings can handle '@'  */
+             wv->value = (char *)1;
              wv->enabled = 1;
              wv->button_type = BUTTON_TYPE_NONE;
              wv->help = Qnil;
@@ -1274,13 +1251,13 @@ single_submenu (item_key, item_name, maps)
 #ifndef HAVE_MULTILINGUAL_MENU
          if (STRING_MULTIBYTE (item_name))
            {
-             item_name = ENCODE_SYSTEM (item_name);
+             item_name = ENCODE_MENU_STRING (item_name);
              AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
            }
 
          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
            {
-             descrip = ENCODE_SYSTEM (descrip);
+             descrip = ENCODE_MENU_STRING (descrip);
              AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
            }
 #endif /* not HAVE_MULTILINGUAL_MENU */
@@ -1291,9 +1268,9 @@ single_submenu (item_key, item_name, maps)
          else
            save_wv->contents = wv;
 
-         wv->name = (char *) SDATA (item_name);
+         wv->lname = item_name;
          if (!NILP (descrip))
-           wv->key = (char *) SDATA (descrip);
+           wv->lkey = descrip;
          wv->value = 0;
          /* The EMACS_INT cast avoids a warning.  There's no problem
             as long as pointers have enough bits to hold small integers.  */
@@ -1332,6 +1309,41 @@ single_submenu (item_key, item_name, maps)
 
   return first_wv;
 }
+/* Walk through the widget_value tree starting at FIRST_WV and update
+   the char * pointers from the corresponding lisp values.
+   We do this after building the whole tree, since GC may happen while the
+   tree is constructed, and small strings are relocated.  So we must wait
+   until no GC can happen before storing pointers into lisp values.  */
+static void
+update_submenu_strings (first_wv)
+     widget_value *first_wv;
+{
+  widget_value *wv;
+
+  for (wv = first_wv; wv; wv = wv->next)
+    {
+      if (STRINGP (wv->lname))
+        {
+          wv->name = SDATA (wv->lname);
+
+          /* Ignore the @ that means "separate pane".
+             This is a kludge, but this isn't worth more time.  */
+          if (wv->value == (char *)1)
+            {
+              if (wv->name[0] == '@')
+               wv->name++;
+              wv->value = 0;
+            }
+        }
+
+      if (STRINGP (wv->lkey))
+        wv->key = SDATA (wv->lkey);
+
+      if (wv->contents)
+        update_submenu_strings (wv->contents);
+    }
+}
+
 \f
 /* Set the contents of the menubar widgets of frame F.
    The argument FIRST_TIME is currently ignored;
@@ -1410,8 +1422,6 @@ set_frame_menubar (f, first_time, deep_p)
 
       items = FRAME_MENU_BAR_ITEMS (f);
 
-      inhibit_garbage_collection ();
-
       /* Save the frame's previous menu bar contents data.  */
       if (previous_menu_items_used)
        bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
@@ -1452,7 +1462,8 @@ set_frame_menubar (f, first_time, deep_p)
 
       for (i = 0; i < previous_menu_items_used; i++)
        if (menu_items_used == i
-           || (!Fequal (previous_items[i], XVECTOR (menu_items)->contents[i])))
+           || (NILP (Fequal (previous_items[i],
+                             XVECTOR (menu_items)->contents[i]))))
          break;
       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
        {
@@ -1475,6 +1486,7 @@ set_frame_menubar (f, first_time, deep_p)
          if (NILP (string))
            break;
          wv->name = (char *) SDATA (string);
+          update_submenu_strings (wv->contents);
          wv = wv->next;
        }
 
@@ -1732,12 +1744,12 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
 #ifndef HAVE_MULTILINGUAL_MENU
           if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
            {
-             item_name = ENCODE_SYSTEM (item_name);
+             item_name = ENCODE_MENU_STRING (item_name);
              AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
            }
           if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
             {
-             descrip = ENCODE_SYSTEM (descrip);
+             descrip = ENCODE_MENU_STRING (descrip);
              AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
            }
 #endif /* not HAVE_MULTILINGUAL_MENU */
@@ -1791,7 +1803,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
 
 #ifndef HAVE_MULTILINGUAL_MENU
       if (STRING_MULTIBYTE (title))
-       title = ENCODE_SYSTEM (title);
+       title = ENCODE_MENU_STRING (title);
 #endif
       wv_title->name = (char *) SDATA (title);
       wv_title->enabled = TRUE;
@@ -1811,11 +1823,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   pos.h = x;
   pos.v = y;
 
-#if TARGET_API_MAC_CARBON
-  SetPort (GetWindowPort (FRAME_MAC_WINDOW (f)));
-#else
-  SetPort (FRAME_MAC_WINDOW (f));
-#endif
+  SetPortWindowPort (FRAME_MAC_WINDOW (f));
 
   LocalToGlobal (&pos);
 
@@ -1832,9 +1840,9 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   /* Get the refcon to find the correct item*/
   if (menu_item_selection)
     {
-      menu = GetMenuHandle (HiWord (menu_item_choice));
-      if (menu) {
-       GetMenuItemRefCon (menu, menu_item_selection, &refcon);
+      MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice));
+      if (sel_menu) {
+       GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon);
       }
     }
 
@@ -1844,6 +1852,10 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   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);
@@ -1852,11 +1864,11 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   {
     int i = MIN_POPUP_SUBMENU_ID;
     MenuHandle submenu = GetMenuHandle (i);
-    while (menu != NULL)
+    while (submenu != NULL)
       {
        DeleteMenu (i);
-       DisposeMenu (menu);
-       menu = GetMenuHandle (++i);
+       DisposeMenu (submenu);
+       submenu = GetMenuHandle (++i);
       }
   }
 
@@ -1969,11 +1981,7 @@ mac_dialog (widget_value *wv)
 
   window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
 
-#if TARGET_API_MAC_CARBON
-  SetPort (GetWindowPort (window_ptr));
-#else
-  SetPort (window_ptr);
-#endif
+  SetPortWindowPort (window_ptr);
 
   TextFont (0);
   /* Left and right margins in the dialog are 13 pixels each.*/
@@ -1991,11 +1999,7 @@ mac_dialog (widget_value *wv)
   SizeWindow (window_ptr, dialog_width, 78, 0);
   ShowWindow (window_ptr);
 
-#if TARGET_API_MAC_CARBON
-  SetPort (GetWindowPort (window_ptr));
-#else
-  SetPort (window_ptr);
-#endif
+  SetPortWindowPort (window_ptr);
 
   TextFont (0);
 
@@ -2236,7 +2240,7 @@ add_menu_item (MenuHandle menu, widget_value *wv, int submenu,
               int force_disable)
 {
   Str255 item_name;
-  int pos, i;
+  int pos;
 
   if (name_is_separator (wv->name))
     AppendMenu (menu, "\p-");
@@ -2258,8 +2262,17 @@ add_menu_item (MenuHandle menu, widget_value *wv, int submenu,
          strncat (item_name, wv->key, 255);
        }
       item_name[255] = 0;
+#if TARGET_API_MAC_CARBON
+      {
+       CFStringRef string = cfstring_create_with_utf8_cstring (item_name);
+
+       SetMenuItemTextWithCFString (menu, pos, string);
+       CFRelease (string);
+      }
+#else
       c2pstr (item_name);
       SetMenuItemText (menu, pos, item_name);
+#endif
 
       if (wv->enabled && !force_disable)
 #if TARGET_API_MAC_CARBON
@@ -2282,9 +2295,9 @@ add_menu_item (MenuHandle menu, widget_value *wv, int submenu,
       else
        SetItemMark (menu, pos, noMark);
       }
-    }
 
-  SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
+      SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
+    }
 
   if (submenu != NULL)
     SetMenuItemHierarchicalID (menu, pos, submenu);
@@ -2375,3 +2388,6 @@ The enable predicate for a menu command should check this variable.  */);
   defsubr (&Sx_popup_dialog);
 #endif
 }
+
+/* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce
+   (do not change this comment) */