diff src/xmenu.c @ 90385:72dea2ff0142

Revision: emacs@sv.gnu.org/emacs--unicode--0--patch-57 Merge from emacs--devo--0 Patches applied: * emacs--devo--0 (patch 226-238) - Update from CVS - Merge from gnus--rel--5.10 - Update from CVS: lisp/progmodes/python.el (python-mode): Fix typo. * gnus--rel--5.10 (patch 86-90) - Update from CVS - Merge from emacs--devo--0
author Miles Bader <miles@gnu.org>
date Fri, 21 Apr 2006 05:39:14 +0000
parents d1c5430c5bff c12e24e779ab
children 2ecafc6d5db7
line wrap: on
line diff
--- a/src/xmenu.c	Mon Apr 17 08:41:12 2006 +0000
+++ b/src/xmenu.c	Fri Apr 21 05:39:14 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,23 +2176,33 @@
 	}
 
       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.  */
 
+      /* Compare the new menu items with the ones computed last time.  */
       for (i = 0; i < previous_menu_items_used; i++)
 	if (menu_items_used == i
 	    || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
 	  break;
       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
 	{
+	  /* The menu items have not changed.  Don't bother updating
+	     the menus in any form, since it would be a no-op.  */
 	  free_menubar_widget_value_tree (first_wv);
 	  discard_menu_items ();
-
+	  unbind_to (specpdl_count, Qnil);
 	  return;
 	}
 
+      /* The menu items are different, so store them in the frame.  */
+      f->menu_bar_vector = menu_items;
+      f->menu_bar_items_used = menu_items_used;
+
+      /* This calls restore_menu_items to restore menu_items, etc.,
+	 as they were outside.  */
+      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 +2217,6 @@
           wv = wv->next;
 	}
 
-      f->menu_bar_vector = menu_items;
-      f->menu_bar_items_used = menu_items_used;
-      discard_menu_items ();
     }
   else
     {