changeset 67715:69a961190da1

(Qmac_apple_event): Add extern. (set_frame_menubar, mac_menu_show keymp_panes) (single_keymap_panes, list_of_panes, list_of_item) (single_menu_item): Add argument types to prototypes. (mac_dialog_show) [HAVE_DIALOGS]: Likewise. (struct skp): New struct (from xmenu.c). (single_keymap_panes, single_menu_item, list_of_panes) (list_of_item): Sync with xmenu.c. (Fx_popup_menu, Fx_popup_dialog): Likewise. Don't get window from POSITION if it is mac-apple-event event. (menubar_selection_callback): Don't use menu_command_in_progress. (set_frame_menubar): First parse all submenus, then make widget_value trees from them. Don't allocate any widget_value objects until we are done with the parsing. (parse_single_submenu, digest_single_submenu): New functions. (single_submenu): Function deleted, replaced by those two. (install_menu_quit_handler) [HAVE_CANCELMENUTRACKING]: Don't create or dispose of EventHandlerUPP. Install hander to all submenus. (mac_menu_show) [!HAVE_MULTILINGUAL_MENU]: Use ENCODE_MENU_STRING instead of ENCODE_SYSTEM. (free_frame_menubar, fill_submenu, fill_menu): Don't use NULL for integer values. [HAVE_DIALOGS] (mac_dialog_show): Sync with xdialog_show (in xmenu.c). (add_menu_item) [TARGET_API_MAC_CARBON]: Use CFString functions to format menu item string. Don't use NULL for integer value.
author YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
date Wed, 21 Dec 2005 12:31:02 +0000
parents dda3dc3d3548
children 9b09a3a7cf68
files src/macmenu.c
diffstat 1 files changed, 262 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/src/macmenu.c	Wed Dec 21 12:04:26 2005 +0000
+++ b/src/macmenu.c	Wed Dec 21 12:31:02 2005 +0000
@@ -1,4 +1,4 @@
-/* Menu support for GNU Emacs on the for Mac OS.
+/* Menu support for GNU Emacs on Mac OS.
    Copyright (C) 2000, 2001, 2002, 2003, 2004,
                  2005 Free Software Foundation, Inc.
 
@@ -24,6 +24,7 @@
 #include <config.h>
 
 #include <stdio.h>
+
 #include "lisp.h"
 #include "termhooks.h"
 #include "keyboard.h"
@@ -154,7 +155,7 @@
 
 Lisp_Object Qdebug_on_next_call;
 
-extern Lisp_Object Qmenu_bar;
+extern Lisp_Object Qmenu_bar, Qmac_apple_event;
 
 extern Lisp_Object QCtoggle, QCradio;
 
@@ -165,27 +166,28 @@
 
 extern Lisp_Object Qmenu_bar_update_hook;
 
+void set_frame_menubar P_ ((FRAME_PTR, int, int));
+
 #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,
 				Lisp_Object, Lisp_Object, Lisp_Object,
 				Lisp_Object, Lisp_Object));
 #ifdef HAVE_DIALOGS
-static Lisp_Object mac_dialog_show ();
+static Lisp_Object mac_dialog_show P_ ((FRAME_PTR, int, Lisp_Object,
+					Lisp_Object, char **));
 #endif
-static Lisp_Object mac_menu_show ();
-
-static void keymap_panes ();
-static void single_keymap_panes ();
-static void single_menu_item ();
-static void list_of_panes ();
-static void list_of_items ();
+static Lisp_Object mac_menu_show P_ ((struct frame *, int, int, int, int,
+				      Lisp_Object, char **));
+static void keymap_panes P_ ((Lisp_Object *, int, int));
+static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+				     int, int));
+static void list_of_panes P_ ((Lisp_Object));
+static void list_of_items P_ ((Lisp_Object));
 
 static void fill_submenu (MenuHandle, widget_value *);
 static void fill_menubar (widget_value *);
@@ -280,8 +282,7 @@
   menu_items_submenu_depth = 0;
 }
 
-/* Call at the end of generating the data in menu_items.
-   This fills in the number of items in the last pane.  */
+/* Call at the end of generating the data in menu_items.  */
 
 static void
 finish_menu_items ()
@@ -415,11 +416,21 @@
      P is the number of panes we have made so far.  */
   for (mapno = 0; mapno < nmaps; mapno++)
     single_keymap_panes (keymaps[mapno],
-                         Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
+			 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
 
   finish_menu_items ();
 }
 
+/* Args passed between single_keymap_panes and single_menu_item.  */
+struct skp
+  {
+     Lisp_Object pending_maps;
+     int maxdepth, notreal;
+  };
+
+static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+				  void *));
+
 /* This is a recursive subroutine of keymap_panes.
    It handles one keymap, KEYMAP.
    The other arguments are passed along
@@ -437,89 +448,71 @@
      int notreal;
      int maxdepth;
 {
-  Lisp_Object pending_maps = Qnil;
-  Lisp_Object tail, item;
-  struct gcpro gcpro1, gcpro2;
+  struct skp skp;
+  struct gcpro gcpro1;
+
+  skp.pending_maps = Qnil;
+  skp.maxdepth = maxdepth;
+  skp.notreal = notreal;
 
   if (maxdepth <= 0)
     return;
 
   push_menu_pane (pane_name, prefix);
 
-  for (tail = keymap; CONSP (tail); tail = XCDR (tail))
-    {
-      GCPRO2 (keymap, pending_maps);
-      /* Look at each key binding, and if it is a menu item add it
-	 to this menu.  */
-      item = XCAR (tail);
-      if (CONSP (item))
-	single_menu_item (XCAR (item), XCDR (item),
-			  &pending_maps, notreal, maxdepth);
-      else if (VECTORP (item))
-	{
-	  /* Loop over the char values represented in the vector.  */
-	  int len = XVECTOR (item)->size;
-	  int c;
-	  for (c = 0; c < len; c++)
-	    {
-	      Lisp_Object character;
-	      XSETFASTINT (character, c);
-	      single_menu_item (character, XVECTOR (item)->contents[c],
-				&pending_maps, notreal, maxdepth);
-	    }
-	}
-      UNGCPRO;
-    }
+  GCPRO1 (skp.pending_maps);
+  map_keymap (keymap, single_menu_item, Qnil, &skp, 1);
+  UNGCPRO;
 
   /* Process now any submenus which want to be panes at this level.  */
-  while (!NILP (pending_maps))
+  while (CONSP (skp.pending_maps))
     {
       Lisp_Object elt, eltcdr, string;
-      elt = Fcar (pending_maps);
+      elt = XCAR (skp.pending_maps);
       eltcdr = XCDR (elt);
       string = XCAR (eltcdr);
       /* We no longer discard the @ from the beginning of the string here.
 	 Instead, we do this in mac_menu_show.  */
       single_keymap_panes (Fcar (elt), string,
 			   XCDR (eltcdr), notreal, maxdepth - 1);
-      pending_maps = Fcdr (pending_maps);
+      skp.pending_maps = XCDR (skp.pending_maps);
     }
 }
 
 /* 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.
-   PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
+   SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
    separate panes.
-   If NOTREAL is nonzero, only check for equivalent key bindings, don't
+   If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
    evaluate expressions in menu items and don't make any menu.
-   If we encounter submenus deeper than MAXDEPTH levels, ignore them.  */
+   If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them.  */
 
 static void
-single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
-     Lisp_Object key, item;
-     Lisp_Object *pending_maps_ptr;
-     int maxdepth, notreal;
+single_menu_item (key, item, dummy, skp_v)
+     Lisp_Object key, item, dummy;
+     void *skp_v;
 {
   Lisp_Object map, item_string, enabled;
   struct gcpro gcpro1, gcpro2;
   int res;
+  struct skp *skp = skp_v;
 
   /* Parse the menu item and leave the result in item_properties.  */
   GCPRO2 (key, item);
-  res = parse_menu_item (item, notreal, 0);
+  res = parse_menu_item (item, skp->notreal, 0);
   UNGCPRO;
   if (!res)
     return;			/* Not a menu item.  */
 
   map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
 
-  if (notreal)
+  if (skp->notreal)
     {
       /* We don't want to make a menu, just traverse the keymaps to
 	 precompute equivalent key bindings.  */
       if (!NILP (map))
-	single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
+	single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
       return;
     }
 
@@ -530,8 +523,8 @@
     {
       if (!NILP (enabled))
 	/* An enabled separate pane. Remember this to handle it later.  */
-	*pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
-				   *pending_maps_ptr);
+	skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
+				   skp->pending_maps);
       return;
     }
 
@@ -539,14 +532,14 @@
 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
 		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
-                  XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
-                  XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
+		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
+		  XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
 
   /* Display a submenu using the toolkit.  */
   if (! (NILP (map) || NILP (enabled)))
     {
       push_submenu_start ();
-      single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
+      single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
       push_submenu_end ();
     }
 }
@@ -563,13 +556,13 @@
 
   init_menu_items ();
 
-  for (tail = menu; !NILP (tail); tail = Fcdr (tail))
+  for (tail = menu; CONSP (tail); tail = XCDR (tail))
     {
       Lisp_Object elt, pane_name, pane_data;
-      elt = Fcar (tail);
+      elt = XCAR (tail);
       pane_name = Fcar (elt);
       CHECK_STRING (pane_name);
-      push_menu_pane (pane_name, Qnil);
+      push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
       pane_data = Fcdr (elt);
       CHECK_CONS (pane_data);
       list_of_items (pane_data);
@@ -586,20 +579,22 @@
 {
   Lisp_Object tail, item, item1;
 
-  for (tail = pane; !NILP (tail); tail = Fcdr (tail))
+  for (tail = pane; CONSP (tail); tail = XCDR (tail))
     {
-      item = Fcar (tail);
+      item = XCAR (tail);
       if (STRINGP (item))
-	push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
-      else if (NILP (item))
+	push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
+			Qnil, Qnil, Qnil, Qnil);
+      else if (CONSP (item))
+	{
+	  item1 = XCAR (item);
+	  CHECK_STRING (item1);
+	  push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
+			  Qt, Qnil, Qnil, Qnil, Qnil);
+	}
+      else
 	push_left_right_boundary ();
-      else
-	{
-	  CHECK_CONS (item);
-	  item1 = Fcar (item);
-	  CHECK_STRING (item1);
-	  push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
-	}
+
     }
 }
 
@@ -659,15 +654,14 @@
   Lisp_Object keymap, tem;
   int xpos = 0, ypos = 0;
   Lisp_Object title;
-  char *error_name;
+  char *error_name = NULL;
   Lisp_Object selection;
   FRAME_PTR f = NULL;
   Lisp_Object x, y, window;
   int keymaps = 0;
   int for_click = 0;
+  int specpdl_count = SPECPDL_INDEX ();
   struct gcpro gcpro1;
-  int specpdl_count = SPECPDL_INDEX ();
-
 
 #ifdef HAVE_MENUS
   if (! NILP (position))
@@ -677,7 +671,8 @@
       /* Decode the first argument: find the window and the coordinates.  */
       if (EQ (position, Qt)
 	  || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                                   || EQ (XCAR (position), Qtool_bar))))
+				   || EQ (XCAR (position), Qtool_bar)
+				   || EQ (XCAR (position), Qmac_apple_event))))
 	{
 	  /* Use the mouse's current position.  */
 	  FRAME_PTR new_f = SELECTED_FRAME ();
@@ -703,8 +698,8 @@
 	  if (CONSP (tem))
 	    {
 	      window = Fcar (Fcdr (position));
-	      x = Fcar (tem);
-	      y = Fcar (Fcdr (tem));
+	      x = XCAR (tem);
+	      y = Fcar (XCDR (tem));
 	    }
 	  else
 	    {
@@ -788,11 +783,11 @@
 
       /* The first keymap that has a prompt string
 	 supplies the menu title.  */
-      for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
+      for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
 	{
 	  Lisp_Object prompt;
 
-	  maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
+	  maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
 
 	  prompt = Fkeymap_prompt (keymap);
 	  if (NILP (title) && !NILP (prompt))
@@ -879,7 +874,8 @@
   /* Decode the first argument: find the window or frame to use.  */
   if (EQ (position, Qt)
       || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                               || EQ (XCAR (position), Qtool_bar))))
+			       || EQ (XCAR (position), Qtool_bar)
+			       || EQ (XCAR (position), Qmac_apple_event))))
     {
 #if 0 /* Using the frame the mouse is on may not be right.  */
       /* Use the mouse's current position.  */
@@ -947,6 +943,7 @@
     Lisp_Object title;
     char *error_name;
     Lisp_Object selection;
+    int specpdl_count = SPECPDL_INDEX ();
 
     /* Decode the dialog items from what was specified.  */
     title = Fcar (contents);
@@ -955,11 +952,11 @@
     list_of_panes (Fcons (contents, Qnil));
 
     /* Display them in a dialog box.  */
+    record_unwind_protect (cleanup_popup_menu, Qnil);
     BLOCK_INPUT;
     selection = mac_dialog_show (f, 0, title, header, &error_name);
     UNBLOCK_INPUT;
-
-    discard_menu_items ();
+    unbind_to (specpdl_count, Qnil);
 
     if (error_name) error (error_name);
     return selection;
@@ -971,13 +968,14 @@
    This is called from keyboard.c when it gets the
    MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
 
-   To activate the menu bar, we signal to the input thread that it can
-   return from the WM_INITMENU message, allowing the normal Windows
-   processing of the menus.
+   To activate the menu bar, we use the button-press event location
+   that was saved in saved_menu_event_location.
 
    But first we recompute the menu bar contents (the whole tree).
 
-   This way we can safely execute Lisp code.  */
+   The reason for saving the button event until here, instead of
+   passing it to the toolkit right away, is that we can safely
+   execute Lisp code.  */
 
 void
 x_activate_menubar (f)
@@ -1074,14 +1072,12 @@
 	      buf.arg = entry;
 	      kbd_buffer_store_event (&buf);
 
-	      f->output_data.mac->menu_command_in_progress = 0;
 	      f->output_data.mac->menubar_active = 0;
 	      return;
 	    }
 	  i += MENU_ITEMS_ITEM_LENGTH;
 	}
     }
-  f->output_data.mac->menu_command_in_progress = 0;
   f->output_data.mac->menubar_active = 0;
 }
 
@@ -1127,22 +1123,18 @@
   UNBLOCK_INPUT;
 }
 
-/* Return a tree of widget_value structures for a menu bar item
+/* Set up data in menu_items for a menu bar item
    whose event type is ITEM_KEY (with string ITEM_NAME)
    and whose contents come from the list of keymaps MAPS.  */
 
-static widget_value *
-single_submenu (item_key, item_name, maps)
+static int
+parse_single_submenu (item_key, item_name, maps)
      Lisp_Object item_key, item_name, maps;
 {
-  widget_value *wv, *prev_wv, *save_wv, *first_wv;
-  int i;
-  int submenu_depth = 0;
   Lisp_Object length;
   int len;
   Lisp_Object *mapvec;
-  widget_value **submenu_stack;
-  int previous_items = menu_items_used;
+  int i;
   int top_level_items = 0;
 
   length = Flength (maps);
@@ -1156,28 +1148,44 @@
       maps = Fcdr (maps);
     }
 
-  menu_items_n_panes = 0;
-
   /* Loop over the given keymaps, making a pane for each map.
      But don't make a pane that is empty--ignore that map instead.  */
   for (i = 0; i < len; i++)
     {
-      if (SYMBOLP (mapvec[i])
-	  || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
+      if (!KEYMAPP (mapvec[i]))
 	{
 	  /* Here we have a command at top level in the menu bar
 	     as opposed to a submenu.  */
 	  top_level_items = 1;
 	  push_menu_pane (Qnil, Qnil);
 	  push_menu_item (item_name, Qt, item_key, mapvec[i],
-                          Qnil, Qnil, Qnil, Qnil);
+			  Qnil, Qnil, Qnil, Qnil);
 	}
       else
-	single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
+	{
+	  Lisp_Object prompt;
+	  prompt = Fkeymap_prompt (mapvec[i]);
+	  single_keymap_panes (mapvec[i],
+			       !NILP (prompt) ? prompt : item_name,
+			       item_key, 0, 10);
+	}
     }
 
-  /* Create a tree of widget_value objects
-     representing the panes and their items.  */
+  return top_level_items;
+}
+
+/* Create a tree of widget_value objects
+   representing the panes and items
+   in menu_items starting at index START, up to index END.  */
+
+static widget_value *
+digest_single_submenu (start, end, top_level_items)
+     int start, end, top_level_items;
+{
+  widget_value *wv, *prev_wv, *save_wv, *first_wv;
+  int i;
+  int submenu_depth = 0;
+  widget_value **submenu_stack;
 
   submenu_stack
     = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
@@ -1191,12 +1199,12 @@
   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
-     single_submenu, even though those are also in menu_items.  */
-  i = previous_items;
-  while (i < menu_items_used)
+  /* Loop over all panes and items made by the preceding call
+     to parse_single_submenu and construct a tree of widget_value objects.
+     Ignore the panes and items used by previous calls to
+     digest_single_submenu, even though those are also in menu_items.  */
+  i = start;
+  while (i < end)
     {
       if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
 	{
@@ -1230,7 +1238,7 @@
 #ifndef HAVE_MULTILINGUAL_MENU
 	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
 	    {
-	      pane_name = ENCODE_SYSTEM (pane_name);
+	      pane_name = ENCODE_MENU_STRING (pane_name);
 	      AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
 	    }
 #endif
@@ -1266,7 +1274,7 @@
 	{
 	  /* Create a new item within current pane.  */
 	  Lisp_Object item_name, enable, descrip, def, type, selected;
-          Lisp_Object help;
+	  Lisp_Object help;
 
 	  item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
 	  enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
@@ -1277,13 +1285,13 @@
 	  help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
 
 #ifndef HAVE_MULTILINGUAL_MENU
-	  if (STRING_MULTIBYTE (item_name))
+          if (STRING_MULTIBYTE (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))
+          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
 	    {
 	      descrip = ENCODE_MENU_STRING (descrip);
 	      AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
@@ -1315,7 +1323,7 @@
 	    abort ();
 
 	  wv->selected = !NILP (selected);
-	  if (!STRINGP (help))
+	  if (! STRINGP (help))
 	    help = Qnil;
 
 	  wv->help = help;
@@ -1337,6 +1345,7 @@
 
   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
@@ -1418,20 +1427,28 @@
 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),
+      InstallMenuEventHandler (menu, menu_quit_handler,
+			       GetEventTypeCount (typesList),
                                typesList, menu_handle, NULL);
       if (menu_handle) break;
       menu = GetMenuHandle (++i);
     }
-  DisposeEventHandlerUPP (handler);
+
+  i = menu_handle ? MIN_POPUP_SUBMENU_ID : MIN_SUBMENU_ID;  
+  menu = GetMenuHandle (i);
+  while (menu != NULL)
+    {
+      InstallMenuEventHandler (menu, menu_quit_handler,
+			       GetEventTypeCount (typesList),
+                               typesList, menu_handle, NULL);
+      menu = GetMenuHandle (++i);
+    }
 #endif /* HAVE_CANCELMENUTRACKING */
 }
 
@@ -1448,7 +1465,9 @@
   int menubar_widget = f->output_data.mac->menubar_widget;
   Lisp_Object items;
   widget_value *wv, *first_wv, *prev_wv = 0;
-  int i;
+  int i, last_i = 0;
+  int *submenu_start, *submenu_end;
+  int *submenu_top_level_items, *submenu_n_panes;
 
   /* We must not change the menubar when actually in use.  */
   if (f->output_data.mac->menubar_active)
@@ -1461,14 +1480,6 @@
   else if (pending_menu_activation && !deep_p)
     deep_p = 1;
 
-  wv = xmalloc_widget_value ();
-  wv->name = "menubar";
-  wv->value = 0;
-  wv->enabled = 1;
-  wv->button_type = BUTTON_TYPE_NONE;
-  wv->help = Qnil;
-  first_wv = wv;
-
   if (deep_p)
     {
       /* Make a widget-value tree representing the entire menu trees.  */
@@ -1503,6 +1514,7 @@
 
       /* Run the Lucid hook.  */
       safe_run_hooks (Qactivate_menubar_hook);
+
       /* If it has changed current-menubar from previous value,
 	 really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag))
@@ -1517,21 +1529,56 @@
 	bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
 	       previous_menu_items_used * sizeof (Lisp_Object));
 
-      /* Fill in the current menu bar contents.  */
+      /* Fill in menu_items with the current menu bar contents.
+	 This can evaluate Lisp code.  */
       menu_items = f->menu_bar_vector;
       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
+      submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
+      submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
+      submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
+      submenu_top_level_items
+	= (int *) alloca (XVECTOR (items)->size * sizeof (int *));
       init_menu_items ();
       for (i = 0; i < XVECTOR (items)->size; i += 4)
 	{
 	  Lisp_Object key, string, maps;
 
+	  last_i = i;
+
 	  key = XVECTOR (items)->contents[i];
 	  string = XVECTOR (items)->contents[i + 1];
 	  maps = XVECTOR (items)->contents[i + 2];
 	  if (NILP (string))
 	    break;
 
-	  wv = single_submenu (key, string, maps);
+	  submenu_start[i] = menu_items_used;
+
+	  menu_items_n_panes = 0;
+	  submenu_top_level_items[i]
+	    = parse_single_submenu (key, string, maps);
+	  submenu_n_panes[i] = menu_items_n_panes;
+
+	  submenu_end[i] = menu_items_used;
+	}
+
+      finish_menu_items ();
+
+      /* Convert menu_items into widget_value trees
+	 to display the menu.  This cannot evaluate Lisp code.  */
+
+      wv = xmalloc_widget_value ();
+      wv->name = "menubar";
+      wv->value = 0;
+      wv->enabled = 1;
+      wv->button_type = BUTTON_TYPE_NONE;
+      wv->help = Qnil;
+      first_wv = wv;
+
+      for (i = 0; i < last_i; i += 4)
+	{
+	  menu_items_n_panes = submenu_n_panes[i];
+	  wv = digest_single_submenu (submenu_start[i], submenu_end[i],
+				      submenu_top_level_items[i]);
 	  if (prev_wv)
 	    prev_wv->next = wv;
 	  else
@@ -1542,8 +1589,6 @@
 	  prev_wv = wv;
 	}
 
-      finish_menu_items ();
-
       set_buffer_internal_1 (prev);
       unbind_to (specpdl_count, Qnil);
 
@@ -1552,22 +1597,18 @@
 
       for (i = 0; i < previous_menu_items_used; i++)
 	if (menu_items_used == i
-	    || (NILP (Fequal (previous_items[i],
-			      XVECTOR (menu_items)->contents[i]))))
+	    || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
 	  break;
       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
 	{
 	  free_menubar_widget_value_tree (first_wv);
-	  menu_items = Qnil;
+	  discard_menu_items ();
 
 	  return;
 	}
 
       /* Now GC cannot happen during the lifetime of the widget_value,
-	 so it's safe to store data from a Lisp_String, as long as
-	 local copies are made when the actual menu is created.
-	 Windows takes care of this for normal string items, but
-	 not for owner-drawn items or additional item-info.  */
+	 so it's safe to store data from a Lisp_String.  */
       wv = first_wv->contents;
       for (i = 0; i < XVECTOR (items)->size; i += 4)
 	{
@@ -1582,13 +1623,21 @@
 
       f->menu_bar_vector = menu_items;
       f->menu_bar_items_used = menu_items_used;
-      menu_items = Qnil;
+      discard_menu_items ();
     }
   else
     {
       /* Make a widget-value tree containing
 	 just the top level menu bar strings.  */
 
+      wv = xmalloc_widget_value ();
+      wv->name = "menubar";
+      wv->value = 0;
+      wv->enabled = 1;
+      wv->button_type = BUTTON_TYPE_NONE;
+      wv->help = Qnil;
+      first_wv = wv;
+
       items = FRAME_MENU_BAR_ITEMS (f);
       for (i = 0; i < XVECTOR (items)->size; i += 4)
 	{
@@ -1676,6 +1725,7 @@
   set_frame_menubar (f, 1, 1);
 }
 
+
 /* Get rid of the menu bar of frame F, and free its storage.
    This is used when deleting a frame, and when turning off the menu bar.  */
 
@@ -1683,7 +1733,7 @@
 free_frame_menubar (f)
      FRAME_PTR f;
 {
-  f->output_data.mac->menubar_widget = NULL;
+  f->output_data.mac->menubar_widget = 0;
 }
 
 
@@ -1760,6 +1810,7 @@
   Lisp_Object *subprefix_stack
     = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
   int submenu_depth = 0;
+
   int first_pane;
   int specpdl_count = SPECPDL_INDEX ();
 
@@ -1813,12 +1864,14 @@
 	  /* Create a new pane.  */
 	  Lisp_Object pane_name, prefix;
 	  char *pane_string;
+
 	  pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
 	  prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+
 #ifndef HAVE_MULTILINGUAL_MENU
 	  if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
 	    {
-	      pane_name = ENCODE_SYSTEM (pane_name);
+	      pane_name = ENCODE_MENU_STRING (pane_name);
 	      AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
 	    }
 #endif
@@ -1861,14 +1914,13 @@
 	{
 	  /* Create a new item within current pane.  */
 	  Lisp_Object item_name, enable, descrip, def, type, selected, help;
-
 	  item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
 	  enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
 	  descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
 	  def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
 	  type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
 	  selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
-          help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
+	  help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
 
 #ifndef HAVE_MULTILINGUAL_MENU
           if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
@@ -1876,8 +1928,9 @@
 	      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_MENU_STRING (descrip);
 	      AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
 	    }
@@ -1907,7 +1960,8 @@
 	    abort ();
 
 	  wv->selected = !NILP (selected);
-          if (!STRINGP (help))
+
+          if (! STRINGP (help))
 	    help = Qnil;
 
 	  wv->help = help;
@@ -1934,6 +1988,7 @@
       if (STRING_MULTIBYTE (title))
 	title = ENCODE_MENU_STRING (title);
 #endif
+
       wv_title->name = (char *) SDATA (title);
       wv_title->enabled = FALSE;
       wv_title->title = TRUE;
@@ -1957,7 +2012,6 @@
   pos.v = y;
 
   SetPortWindowPort (FRAME_MAC_WINDOW (f));
-
   LocalToGlobal (&pos);
 
   /* No selection has been chosen yet.  */
@@ -2167,11 +2221,11 @@
   "button6", "button7", "button8", "button9", "button10" };
 
 static Lisp_Object
-mac_dialog_show (f, keymaps, title, header, error)
+mac_dialog_show (f, keymaps, title, header, error_name)
      FRAME_PTR f;
      int keymaps;
      Lisp_Object title, header;
-     char **error;
+     char **error_name;
 {
   int i, nb_buttons=0;
   char dialog_name[6];
@@ -2184,11 +2238,11 @@
   /* 1 means we've seen the boundary between left-hand elts and right-hand.  */
   int boundary_seen = 0;
 
-  *error = NULL;
+  *error_name = NULL;
 
   if (menu_items_n_panes > 1)
     {
-      *error = "Multiple panes in dialog box";
+      *error_name = "Multiple panes in dialog box";
       return Qnil;
     }
 
@@ -2216,18 +2270,16 @@
       {
 
 	/* Create a new item within current pane.  */
-	Lisp_Object item_name, enable, descrip, help;
-
+	Lisp_Object item_name, enable, descrip;
 	item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
 	enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
 	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);
-	    *error = "Submenu in dialog items";
+	    *error_name = "Submenu in dialog items";
 	    return Qnil;
 	  }
 	if (EQ (item_name, Qquote))
@@ -2241,7 +2293,7 @@
 	if (nb_buttons >= 9)
 	  {
 	    free_menubar_widget_value_tree (first_wv);
-	    *error = "Too many dialog items";
+	    *error_name = "Too many dialog items";
 	    return Qnil;
 	  }
 
@@ -2304,8 +2356,8 @@
   /* Free the widget_value objects we used to specify the contents.  */
   free_menubar_widget_value_tree (first_wv);
 
-  /* Find the selected item, and its pane, to return the proper
-     value.  */
+  /* Find the selected item, and its pane, to return
+     the proper value.  */
   if (menu_item_selection != 0)
     {
       Lisp_Object prefix;
@@ -2322,6 +2374,12 @@
 		= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
 	      i += MENU_ITEMS_PANE_LENGTH;
 	    }
+	  else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
+	    {
+	      /* This is the boundary between left-side elts and
+		 right-side elts.  */
+	      ++i;
+	    }
 	  else
 	    {
 	      entry
@@ -2340,6 +2398,9 @@
 	    }
 	}
     }
+  else
+    /* Make "Cancel" equivalent to C-g.  */
+    Fsignal (Qquit, Qnil);
 
   return Qnil;
 }
@@ -2365,7 +2426,11 @@
 add_menu_item (MenuHandle menu, widget_value *wv, int submenu,
 	       int force_disable)
 {
+#if TARGET_API_MAC_CARBON
+  CFStringRef item_name;
+#else
   Str255 item_name;
+#endif
   int pos;
 
   if (name_is_separator (wv->name))
@@ -2376,42 +2441,49 @@
 
 #if TARGET_API_MAC_CARBON
       pos = CountMenuItems (menu);
-#else
-      pos = CountMItems (menu);
-#endif
-
-      strcpy (item_name, "");
-      strncat (item_name, wv->name, 255);
+
+      item_name = cfstring_create_with_utf8_cstring (wv->name);
+
       if (wv->key != NULL)
 	{
-	  strncat (item_name, " ", 255);
-	  strncat (item_name, wv->key, 255);
+	  CFStringRef name, key;
+
+	  name = item_name;
+	  key = cfstring_create_with_utf8_cstring (wv->key);
+	  item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
+						name, key);
+	  CFRelease (name);
+	  CFRelease (key);
 	}
-      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
+
+      SetMenuItemTextWithCFString (menu, pos, item_name);
+      CFRelease (item_name);
+
+      if (wv->enabled && !force_disable)
+        EnableMenuItem (menu, pos);
+      else
+        DisableMenuItem (menu, pos);
+#else  /* ! TARGET_API_MAC_CARBON */
+      pos = CountMItems (menu);
+
+      item_name[sizeof (item_name) - 1] = '\0';
+      strncpy (item_name, wv->name, sizeof (item_name) - 1);
+      if (wv->key != NULL)
+	{
+	  int len = strlen (item_name);
+
+	  strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
+	  len = strlen (item_name);
+	  strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
+	}
       c2pstr (item_name);
       SetMenuItemText (menu, pos, item_name);
-#endif
 
       if (wv->enabled && !force_disable)
-#if TARGET_API_MAC_CARBON
-        EnableMenuItem (menu, pos);
-#else
         EnableItem (menu, pos);
-#endif
       else
-#if TARGET_API_MAC_CARBON
-        DisableMenuItem (menu, pos);
-#else
         DisableItem (menu, pos);
-#endif
+#endif  /* ! TARGET_API_MAC_CARBON */
 
       /* Draw radio buttons and tickboxes. */
       {
@@ -2425,7 +2497,7 @@
       SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
     }
 
-  if (submenu != NULL)
+  if (submenu != 0)
     SetMenuItemHierarchicalID (menu, pos, submenu);
 }
 
@@ -2444,7 +2516,7 @@
         add_menu_item (menu, wv, cur_submenu, 0);
       }
     else
-      add_menu_item (menu, wv, NULL, 0);
+      add_menu_item (menu, wv, 0, 0);
 }
 
 
@@ -2463,7 +2535,7 @@
         add_menu_item (menu, wv, cur_submenu, 0);
       }
     else
-      add_menu_item (menu, wv, NULL, 0);
+      add_menu_item (menu, wv, 0, 0);
 }
 
 /* Construct native Mac OS menubar based on widget_value tree.  */
@@ -2493,7 +2565,6 @@
 }
 
 #endif /* HAVE_MENUS */
-
 
 void
 syms_of_macmenu ()