diff src/xmenu.c @ 70085:93e99c27012e

(restore_menu_items, save_menu_items): New fns. (set_frame_menubar): Use save_menu_items. Save updated vector in the frame before unwinding it. Don't use unuse_menu_items. Don't use discard_menu_items. (digest_single_submenu): Abort if an item is not in a pane. (init_menu_items): Put the error check at the top.
author Richard M. Stallman <rms@gnu.org>
date Tue, 18 Apr 2006 21:01:16 +0000
parents 3293c81b59b1
children c12e24e779ab
line wrap: on
line diff
--- a/src/xmenu.c	Tue Apr 18 21:00:44 2006 +0000
+++ b/src/xmenu.c	Tue Apr 18 21:01:16 2006 +0000
@@ -266,14 +266,15 @@
 static void
 init_menu_items ()
 {
+  if (!NILP (menu_items_inuse))
+    error ("Trying to use a menu from within a menu-entry");
+
   if (NILP (menu_items))
     {
       menu_items_allocated = 60;
       menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
     }
 
-  if (!NILP (menu_items_inuse))
-    error ("Trying to use a menu from within a menu-entry");
   menu_items_inuse = Qt;
   menu_items_used = 0;
   menu_items_n_panes = 0;
@@ -310,6 +311,39 @@
   xassert (NILP (menu_items_inuse));
 }
 
+/* This undoes save_menu_items, and it is called by the specpdl unwind
+   mechanism.  */
+
+static Lisp_Object
+restore_menu_items (saved)
+     Lisp_Object saved;
+{
+  menu_items = XCAR (saved);
+  menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil);
+  menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
+  saved = XCDR (saved);
+  menu_items_used = XINT (XCAR (saved));
+  saved = XCDR (saved);
+  menu_items_n_panes = XINT (XCAR (saved));
+  saved = XCDR (saved);  
+  menu_items_submenu_depth = XINT (XCAR (saved));
+}
+
+/* Push the whole state of menu_items processing onto the specpdl.
+   It will be restored when the specpdl is unwound.  */
+
+static void
+save_menu_items ()
+{
+  Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil,
+			     make_number (menu_items_used),
+			     make_number (menu_items_n_panes),
+			     make_number (menu_items_submenu_depth));
+  record_unwind_protect (restore_menu_items, saved);
+  menu_items_inuse = Qnil;
+  menu_items = Qnil;
+}
+
 /* Make the menu_items vector twice as large.  */
 
 static void
@@ -320,6 +354,7 @@
   old = menu_items;
 
   menu_items_allocated *= 2;
+
   menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
   bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
 	 old_size * sizeof (Lisp_Object));
@@ -1728,6 +1763,7 @@
   int i;
   int submenu_depth = 0;
   widget_value **submenu_stack;
+  int panes_seen = 0;
 
   submenu_stack
     = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
@@ -1774,6 +1810,8 @@
 	  Lisp_Object pane_name, prefix;
 	  char *pane_string;
 
+	  panes_seen++;
+
 	  pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
 	  prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
 
@@ -1821,6 +1859,10 @@
 	  Lisp_Object item_name, enable, descrip, def, type, selected;
 	  Lisp_Object help;
 
+	  /* All items should be contained in panes.  */
+	  if (panes_seen == 0)
+	    abort ();
+
 	  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);
@@ -2046,7 +2088,6 @@
       specbind (Qdebug_on_next_call, Qnil);
 
       record_unwind_save_match_data ();
-      record_unwind_protect (unuse_menu_items, Qnil);
       if (NILP (Voverriding_local_map_menu_flag))
 	{
 	  specbind (Qoverriding_terminal_local_map, Qnil);
@@ -2074,6 +2115,8 @@
 
       /* Fill in menu_items with the current menu bar contents.
 	 This can evaluate Lisp code.  */
+      save_menu_items ();
+
       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 *));
@@ -2133,7 +2176,6 @@
 	}
 
       set_buffer_internal_1 (prev);
-      unbind_to (specpdl_count, Qnil);
 
       /* If there has been no change in the Lisp-level contents
 	 of the menu bar, skip redisplaying it.  Just exit.  */
@@ -2146,10 +2188,15 @@
 	{
 	  free_menubar_widget_value_tree (first_wv);
 	  discard_menu_items ();
-
+	  unbind_to (specpdl_count, Qnil);
 	  return;
 	}
 
+      f->menu_bar_vector = menu_items;
+      f->menu_bar_items_used = menu_items_used;
+
+      unbind_to (specpdl_count, Qnil);
+
       /* Now GC cannot happen during the lifetime of the widget_value,
 	 so it's safe to store data from a Lisp_String.  */
       wv = first_wv->contents;
@@ -2164,9 +2211,6 @@
           wv = wv->next;
 	}
 
-      f->menu_bar_vector = menu_items;
-      f->menu_bar_items_used = menu_items_used;
-      discard_menu_items ();
     }
   else
     {