]> code.delx.au - gnu-emacs/blobdiff - src/macmenu.c
[TARGET_API_MAC_CARBON]: Don't include headers that are included via
[gnu-emacs] / src / macmenu.c
index 5976dad767db2e70d9b25807e7f767157b71cdf8..35615cc3796885aa5e49448e6da8ae5b6a5458db 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 */
+#if !TARGET_API_MAC_CARBON
 #include <MacTypes.h>
 #include <Menus.h>
 #include <QuickDraw.h>
@@ -74,7 +47,7 @@ Boston, MA 02111-1307, USA.  */
 #if defined (__MRC__) || (__MSL__ >= 0x6000)
 #include <ControlDefinitions.h>
 #endif
-#endif /* not MAC_OSX */
+#endif /* not TARGET_API_MAC_CARBON */
 
 /* This may include sys/types.h, and that somehow loses
    if this is not done before the other system files.  */
@@ -89,6 +62,7 @@ Boston, MA 02111-1307, USA.  */
 #include "dispextern.h"
 
 #define POPUP_SUBMENU_ID 235
+#define MIN_POPUP_SUBMENU_ID 512
 #define MIN_MENU_ID 256
 #define MIN_SUBMENU_ID 1
 
@@ -116,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 */ 
+  /* 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
@@ -189,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,
@@ -205,7 +187,7 @@ static void single_menu_item ();
 static void list_of_panes ();
 static void list_of_items ();
 
-static void fill_submenu (MenuHandle, widget_value *, int);
+static void fill_submenu (MenuHandle, widget_value *);
 static void fill_menubar (widget_value *);
 
 \f
@@ -267,6 +249,9 @@ static int menu_items_submenu_depth;
    Xt on behalf of one of the widget sets.  */
 static int popup_activated_flag;
 
+/* Index of the next submenu */
+static int submenu_id;
+
 static int next_menubar_widget_id;
 
 /* This is set nonzero after the user activates the menu bar, and set
@@ -503,7 +488,7 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
 \f
 /* This is a subroutine of single_keymap_panes that handles one
    keymap entry.
-   KEY is a key in a keymap and ITEM is its binding. 
+   KEY is a key in a keymap and ITEM is its binding.
    PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
    separate panes.
    If NOTREAL is nonzero, only check for equivalent key bindings, don't
@@ -519,7 +504,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
   Lisp_Object map, item_string, enabled;
   struct gcpro gcpro1, gcpro2;
   int res;
-  
+
   /* Parse the menu item and leave the result in item_properties.  */
   GCPRO2 (key, item);
   res = parse_menu_item (item, notreal, 0);
@@ -528,7 +513,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
     return;                    /* Not a menu item.  */
 
   map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
-  
+
   if (notreal)
     {
       /* We don't want to make a menu, just traverse the keymaps to
@@ -539,9 +524,9 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
     }
 
   enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
-  item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; 
+  item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
 
-  if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
+  if (!NILP (map) && SREF (item_string, 0) == '@')
     {
       if (!NILP (enabled))
        /* An enabled separate pane. Remember this to handle it later.  */
@@ -728,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,
@@ -814,7 +797,7 @@ cached information about equivalent key sequences.  */)
 
       keymaps = 0;
     }
-  
+
   if (NILP (position))
     {
       discard_menu_items ();
@@ -967,7 +950,7 @@ on the left of the dialog box and all following items on the right.
    But first we recompute the menu bar contents (the whole tree).
 
    This way we can safely execute Lisp code.  */
-   
+
 void
 x_activate_menubar (f)
      FRAME_PTR f;
@@ -1033,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;
@@ -1178,7 +1162,7 @@ single_submenu (item_key, item_name, maps)
   first_wv = wv;
   save_wv = 0;
   prev_wv = 0;
+
   /* Loop over all panes and items made during this call
      and construct a tree of widget_value objects.
      Ignore the panes and items made by previous calls to
@@ -1223,7 +1207,7 @@ single_submenu (item_key, item_name, maps)
            }
 #endif
          pane_string = (NILP (pane_name)
-                        ? "" : (char *) XSTRING (pane_name)->data);
+                        ? "" : (char *) SDATA (pane_name));
          /* If there is just one top-level pane, put all its items directly
             under the top-level menu.  */
          if (menu_items_n_panes == 1)
@@ -1239,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;
@@ -1270,26 +1251,26 @@ 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 */
 
          wv = xmalloc_widget_value ();
-         if (prev_wv) 
+         if (prev_wv)
            prev_wv->next = wv;
          else
            save_wv->contents = wv;
 
-         wv->name = (char *) XSTRING (item_name)->data;
+         wv->lname = item_name;
          if (!NILP (descrip))
-           wv->key = (char *) XSTRING (descrip)->data;
+           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.  */
@@ -1328,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;
@@ -1369,7 +1385,7 @@ set_frame_menubar (f, first_time, deep_p)
 
       struct buffer *prev = current_buffer;
       Lisp_Object buffer;
-      int specpdl_count = specpdl_ptr - specpdl;
+      int specpdl_count = SPECPDL_INDEX ();
       int previous_menu_items_used = f->menu_bar_items_used;
       Lisp_Object *previous_items
        = (Lisp_Object *) alloca (previous_menu_items_used
@@ -1406,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,
@@ -1428,7 +1442,7 @@ set_frame_menubar (f, first_time, deep_p)
            break;
 
          wv = single_submenu (key, string, maps);
-         if (prev_wv) 
+         if (prev_wv)
            prev_wv->next = wv;
          else
            first_wv->contents = wv;
@@ -1448,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)
        {
@@ -1470,7 +1485,8 @@ set_frame_menubar (f, first_time, deep_p)
          string = XVECTOR (items)->contents[i + 1];
          if (NILP (string))
            break;
-         wv->name = (char *) XSTRING (string)->data;
+         wv->name = (char *) SDATA (string);
+          update_submenu_strings (wv->contents);
          wv = wv->next;
        }
 
@@ -1493,7 +1509,7 @@ set_frame_menubar (f, first_time, deep_p)
            break;
 
          wv = xmalloc_widget_value ();
-         wv->name = (char *) XSTRING (string)->data;
+         wv->name = (char *) SDATA (string);
          wv->value = 0;
          wv->enabled = 1;
          wv->button_type = BUTTON_TYPE_NONE;
@@ -1504,7 +1520,7 @@ set_frame_menubar (f, first_time, deep_p)
             This value just has to be different from small integers.  */
          wv->call_data = (void *) (EMACS_INT) (-1);
 
-         if (prev_wv) 
+         if (prev_wv)
            prev_wv->next = wv;
          else
            first_wv->contents = wv;
@@ -1533,7 +1549,7 @@ set_frame_menubar (f, first_time, deep_p)
        DisposeMenu (menu);
        menu = GetMenuHandle (++i);
       }
-    
+
     i = MIN_SUBMENU_ID;
     menu = GetMenuHandle (i);
     while (menu != NULL)
@@ -1545,9 +1561,9 @@ set_frame_menubar (f, first_time, deep_p)
   }
 
   fill_menubar (first_wv->contents);
-  
+
   DrawMenuBar ();
-  
+
   free_menubar_widget_value_tree (first_wv);
 
   UNBLOCK_INPUT;
@@ -1605,6 +1621,8 @@ 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;
@@ -1634,7 +1652,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
   wv->help = Qnil;
   first_wv = wv;
   first_pane = 1;
+
   /* Loop over all panes and items, filling in the tree.  */
   i = 0;
   while (i < menu_items_used)
@@ -1676,7 +1694,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
            }
 #endif
          pane_string = (NILP (pane_name)
-                        ? "" : (char *) XSTRING (pane_name)->data);
+                        ? "" : (char *) SDATA (pane_name));
          /* If there is just one top-level pane, put all its items directly
             under the top-level menu.  */
          if (menu_items_n_panes == 1)
@@ -1726,24 +1744,24 @@ 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 */
 
          wv = xmalloc_widget_value ();
-         if (prev_wv) 
+         if (prev_wv)
            prev_wv->next = wv;
-         else 
+         else
            save_wv->contents = wv;
-         wv->name = (char *) XSTRING (item_name)->data;
+         wv->name = (char *) SDATA (item_name);
          if (!NILP (descrip))
-           wv->key = (char *) XSTRING (descrip)->data;
+           wv->key = (char *) SDATA (descrip);
          wv->value = 0;
          /* Use the contents index as call_data, since we are
              restricted to 16-bits.  */
@@ -1785,9 +1803,9 @@ 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 *) XSTRING (title)->data;
+      wv_title->name = (char *) SDATA (title);
       wv_title->enabled = TRUE;
       wv_title->title = TRUE;
       wv_title->button_type = BUTTON_TYPE_NONE;
@@ -1798,40 +1816,63 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
 
   /* Actually create the menu.  */
   menu = NewMenu (POPUP_SUBMENU_ID, "\p");
-  fill_submenu (menu, first_wv->contents, 0);
+  submenu_id = MIN_POPUP_SUBMENU_ID;
+  fill_submenu (menu, first_wv->contents);
 
   /* Adjust coordinates to be root-window-relative.  */
   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);
 
   /* No selection has been chosen yet.  */
+  menu_item_choice = 0;
   menu_item_selection = 0;
 
   InsertMenu (menu, -1);
 
   /* Display the menu.  */
-  menu_item_selection = LoWord (PopUpMenuSelect (menu, pos.v, pos.h, 0));
+  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*/
+  if (menu_item_selection)
+    {
+      MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice));
+      if (sel_menu) {
+       GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon);
+      }
+    }
 
-  DeleteMenu (POPUP_SUBMENU_ID);
-  
 #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);
 
   /* Find the selected item, and its pane, to return
@@ -1869,7 +1910,7 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
            {
              entry
                = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
-             if (menu_item_selection == i)
+             if ((int) (EMACS_INT) refcon == i)
                {
                  if (keymaps != 0)
                    {
@@ -1915,13 +1956,13 @@ mac_dialog (widget_value *wv)
   SInt16 part_code;
   int control_part_code;
   Point mouse;
-            
+
   dialog_name = wv->name;
   nb_buttons = dialog_name[1] - '0';
   left_count = nb_buttons - (dialog_name[4] - '0');
   button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
   ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
-  
+
   wv = wv->contents;
   prompt = (char *) alloca (strlen (wv->value) + 1);
   strcpy (prompt, wv->value);
@@ -1940,12 +1981,8 @@ 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.*/
   dialog_width = 14;
@@ -1962,12 +1999,8 @@ 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);
 
   MoveTo (13, 29);
@@ -2005,7 +2038,7 @@ mac_dialog (widget_value *wv)
     }
 
   DisposeWindow (window_ptr);
-  
+
   return i;
 }
 
@@ -2047,7 +2080,7 @@ mac_dialog_show (f, keymaps, title, error)
     pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
     pane_string = (NILP (pane_name)
-                  ? "" : (char *) XSTRING (pane_name)->data);  
+                  ? "" : (char *) SDATA (pane_name));
     prev_wv = xmalloc_widget_value ();
     prev_wv->value = pane_string;
     if (keymaps && !NILP (prefix))
@@ -2056,12 +2089,12 @@ mac_dialog_show (f, keymaps, title, error)
     prev_wv->name = "message";
     prev_wv->help = Qnil;
     first_wv = prev_wv;
+
     /* Loop over all panes and items, filling in the tree.  */
     i = MENU_ITEMS_PANE_LENGTH;
     while (i < menu_items_used)
       {
-       
+
        /* Create a new item within current pane.  */
        Lisp_Object item_name, enable, descrip, help;
 
@@ -2070,7 +2103,7 @@ mac_dialog_show (f, keymaps, title, error)
        descrip
          = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
         help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
-       
+
        if (NILP (item_name))
          {
            free_menubar_widget_value_tree (first_wv);
@@ -2096,8 +2129,8 @@ mac_dialog_show (f, keymaps, title, error)
        prev_wv->next = wv;
        wv->name = (char *) button_names[nb_buttons];
        if (!NILP (descrip))
-         wv->key = (char *) XSTRING (descrip)->data;
-       wv->value = (char *) XSTRING (item_name)->data;
+         wv->key = (char *) SDATA (descrip);
+       wv->value = (char *) SDATA (item_name);
        wv->call_data = (void *) i;
          /* menu item is identified by its index in menu_items table */
        wv->enabled = !NILP (enable);
@@ -2203,18 +2236,18 @@ name_is_separator (name)
 }
 
 static void
-add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent,
+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-");
-  else 
+  else
     {
       AppendMenu (menu, "\pX");
-      
+
 #if TARGET_API_MAC_CARBON
       pos = CountMenuItems (menu);
 #else
@@ -2222,16 +2255,24 @@ add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent,
 #endif
 
       strcpy (item_name, "");
-      for (i = 0; i < indent; i++)
-        strcat (item_name, "    ");
-      strcat (item_name, wv->name);
+      strncat (item_name, wv->name, 255);
       if (wv->key != NULL)
        {
-         strcat (item_name, " ");
-         strcat (item_name, wv->key);
+         strncat (item_name, " ", 255);
+         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
@@ -2254,30 +2295,30 @@ add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent,
       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);
 }
 
-static int submenu_id;
-  
 /* Construct native Mac OS menubar based on widget_value tree.  */
 
 static void
-fill_submenu (MenuHandle menu, widget_value *wv, int indent)
+fill_submenu (MenuHandle menu, widget_value *wv)
 {
   for ( ; wv != NULL; wv = wv->next)
     if (wv->contents)
       {
-        add_menu_item (menu, wv, NULL, indent, 1);
-        
-        fill_submenu (menu, wv->contents, indent + 1);
+       int cur_submenu = submenu_id++;
+        MenuHandle submenu = NewMenu (cur_submenu, "\pX");
+        fill_submenu (submenu, wv->contents);
+        InsertMenu (submenu, -1);
+        add_menu_item (menu, wv, cur_submenu, 0);
       }
     else
-      add_menu_item (menu, wv, NULL, indent, 0);
+      add_menu_item (menu, wv, NULL, 0);
 }
 
 
@@ -2289,14 +2330,14 @@ fill_menu (MenuHandle menu, widget_value *wv)
   for ( ; wv != NULL; wv = wv->next)
     if (wv->contents)
       {
-        MenuHandle submenu = NewMenu (submenu_id, "\pX");
-        fill_submenu (submenu, wv->contents, 0);
+       int cur_submenu = submenu_id++;
+        MenuHandle submenu = NewMenu (cur_submenu, "\pX");
+        fill_submenu (submenu, wv->contents);
         InsertMenu (submenu, -1);
-        add_menu_item (menu, wv, submenu_id, 0, 0);
-        submenu_id++;
+        add_menu_item (menu, wv, cur_submenu, 0);
       }
     else
-      add_menu_item (menu, wv, NULL, 0, 0);
+      add_menu_item (menu, wv, NULL, 0);
 }
 
 /* Construct native Mac OS menubar based on widget_value tree.  */
@@ -2312,14 +2353,15 @@ fill_menubar (widget_value *wv)
     {
       MenuHandle menu;
       Str255 title;
-        
-      strcpy (title, wv->name);
+
+      strncpy (title, wv->name, 255);
+      title[255] = 0;
       c2pstr (title);
       menu = NewMenu (id, title);
 
       if (wv->contents)
         fill_menu (menu, wv->contents);
-      
+
       InsertMenu (menu, 0);
     }
 }
@@ -2346,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) */