changeset 6135:bfe9f873bd64

(menu_bar_items): Accept old vector as arg. Return a vector. (menu_bar_one_keymap, menu_bar_item): Associated changes. (make_lispy_event): Use FRAME_MENU_BAR_LINES as vector.
author Richard M. Stallman <rms@gnu.org>
date Wed, 02 Mar 1994 04:11:11 +0000
parents c656768172d2
children 74f4a8947d57
files src/keyboard.c
diffstat 1 files changed, 135 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/src/keyboard.c	Wed Mar 02 04:04:54 1994 +0000
+++ b/src/keyboard.c	Wed Mar 02 04:11:11 1994 +0000
@@ -985,35 +985,6 @@
 	  && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
 	call0 (Qrecompute_lucid_menubar);
 
-#if 0 /* This is done in xdisp.c now.  */
-#ifdef MULTI_FRAME
-      for (tem = Vframe_list; CONSP (tem); tem = XCONS (tem)->cdr)
-	{
-	  struct frame *f = XFRAME (XCONS (tem)->car);
-	  struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
-
-	  /* If the user has switched buffers or windows, we need to
-	     recompute to reflect the new bindings.  But we'll
-	     recompute when update_mode_lines is set too; that means
-	     that people can use force-mode-line-update to request
-	     that the menu bar be recomputed.  The adverse effect on
-	     the rest of the redisplay algorithm is about the same as
-	     windows_or_buffers_changed anyway.  */
-	  if (windows_or_buffers_changed
-	      || update_mode_lines
-	      || (XFASTINT (w->last_modified) < MODIFF
-		  && (XFASTINT (w->last_modified)
-		      <= XBUFFER (w->buffer)->save_modified)))
-	    {
-	      struct buffer *prev = current_buffer;
-	      current_buffer = XBUFFER (w->buffer);
-	      FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
-	      current_buffer = prev;
-	    }
-	}
-#endif /* MULTI_FRAME */
-#endif /* 0 */
-
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), Qnil);
 
@@ -2509,26 +2480,32 @@
 	    if (row < FRAME_MENU_BAR_LINES (f))
 #endif
 	      {
-		Lisp_Object items;
+		Lisp_Object items, item;
 
 #ifdef USE_X_TOOLKIT
 		/* The click happened in the menubar.
 		   Look for the menu item selected.  */
-		items = map_event_to_object (event, f);
+		item = map_event_to_object (event, f);
 
 		XFASTINT (event->y) = 1;
 #else /* not USE_X_TOOLKIT  */
 		int hpos;
+		int i;
 
 		items = FRAME_MENU_BAR_ITEMS (f);
-		for (; CONSP (items); items = XCONS (items)->cdr)
+		for (i = 0; i < XVECTOR (items)->size; i += 3)
 		  {
 		    Lisp_Object pos, string;
-		    pos = Fcdr (Fcdr (Fcar (items)));
-		    string = Fcar (Fcdr (Fcar (items)));
+		    string = XVECTOR (items)->contents[i + 1];
+		    pos = XVECTOR (items)->contents[i + 2];
+		    if (NILP (string))
+		      break;
 		    if (column >= XINT (pos)
 			&& column < XINT (pos) + XSTRING (string)->size)
-		      break;
+		      {
+			item = XVECTOR (items)->contents[i];
+			break;
+		      }
 		  }
 #endif /* not USE_X_TOOLKIT  */
 
@@ -2539,11 +2516,7 @@
 					 Fcons (make_number (event->timestamp),
 						Qnil))));
 
-		if (CONSP (items))
-		  return Fcons (Fcar (Fcar (items)),
-				Fcons (position, Qnil));
-		else
-		  return Fcons (Qnil, Fcons (position, Qnil));
+		return Fcons (item, Fcons (position, Qnil));
 	      }
 
 	    window = window_from_coordinates (f, column, row, &part);
@@ -3476,15 +3449,24 @@
   return Qnil;
 }
 
-static Lisp_Object menu_bar_item ();
-static Lisp_Object menu_bar_one_keymap ();
-
-/* Return a list of menu items for a menu bar, appropriate
-   to the current buffer.
-   The elements have the form (KEY STRING . nil).  */
+static void menu_bar_item ();
+static void menu_bar_one_keymap ();
+
+/* These variables hold the vector under construction within
+   menu_bar_items and its subroutines, and the current index
+   for storing into that vector.  */
+static Lisp_Object menu_bar_items_vector;
+static Lisp_Object menu_bar_items_index;
+
+/* Return a vector of menu items for a menu bar, appropriate
+   to the current buffer.  Each item has three elements in the vector:
+   KEY STRING nil.
+
+   OLD is an old vector we can optionally reuse, or nil.  */
 
 Lisp_Object
-menu_bar_items ()
+menu_bar_items (old)
+     Lisp_Object old;
 {
   /* The number of keymaps we're scanning right now, and the number of
      keymaps we have allocated space for.  */
@@ -3501,6 +3483,10 @@
   int mapno;
   Lisp_Object oquit;
 
+  int i;
+
+  struct gcpro gcpro1;
+
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -3510,6 +3496,14 @@
   oquit = Vinhibit_quit;
   Vinhibit_quit = Qt; 
 
+  if (!NILP (old))
+    menu_bar_items_vector = old;
+  else
+    menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
+  menu_bar_items_index = 0;
+
+  GCPRO1 (menu_bar_items_vector);
+
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
      keybuf with its symbol, or if the sequence starts with a mouse
@@ -3551,29 +3545,63 @@
 
       tem = Fkeymapp (def);
       if (!NILP (tem))
-	result = menu_bar_one_keymap (def, result);
+	menu_bar_one_keymap (def);
     }
 
+  /* Move to the end those items that should be at the end.  */
+
   for (tail = Vmenu_bar_final_items; CONSP (tail); tail = XCONS (tail)->cdr)
     {
-      Lisp_Object elt;
-
-      elt = Fassq (XCONS (tail)->car, result);
-      if (!NILP (elt))
-	result = Fcons (elt, Fdelq (elt, result));
+      int i;
+      int end = menu_bar_items_index;
+
+      for (i = 0; i < end; i += 3)
+	if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
+	  {
+	    Lisp_Object tem;
+	    end -= 3;
+#define EXCH(a, b) tem = a, a = b, b = tem
+	    EXCH (XVECTOR (menu_bar_items_vector)->contents[i],
+		  XVECTOR (menu_bar_items_vector)->contents[end]);
+	    EXCH (XVECTOR (menu_bar_items_vector)->contents[i + 1],
+		  XVECTOR (menu_bar_items_vector)->contents[end + 1]);
+	    EXCH (XVECTOR (menu_bar_items_vector)->contents[i + 2],
+		  XVECTOR (menu_bar_items_vector)->contents[end + 2]);
+#undef EXCH
+	    i -= 3;
+	  }
     }
 
-  result = Fnreverse (result);
+  /* Add nil, nil, nil at the end.  */
+  i = menu_bar_items_index;
+  if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+    {
+      Lisp_Object tem;
+      int newsize = 2 * i;
+      tem = Fmake_vector (make_number (2 * i), Qnil);
+      bcopy (XVECTOR (menu_bar_items_vector)->contents,
+	     XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+      menu_bar_items_vector = tem;
+    }
+  /* Add this item.  */
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  menu_bar_items_index = i;
+
   Vinhibit_quit = oquit;
-  return result;
+  UNGCPRO;
+  return menu_bar_items_vector;
 }
 
 /* Scan one map KEYMAP, accumulating any menu items it defines
-   that have not yet been seen in RESULT.  Return the updated RESULT.  */
-
-static Lisp_Object
-menu_bar_one_keymap (keymap, result)
-     Lisp_Object keymap, result;
+   that have not yet been seen in RESULT.  Return the updated RESULT.
+   *OLD is the frame's old menu bar list; we swipe elts from that
+   to avoid consing.  */
+
+static void
+menu_bar_one_keymap (keymap)
+     Lisp_Object keymap;
 {
   Lisp_Object tail, item, key, binding, item_string, table;
 
@@ -3589,12 +3617,10 @@
 	    {
 	      item_string = XCONS (binding)->car;
 	      if (XTYPE (item_string) == Lisp_String)
-		result = menu_bar_item (key, item_string,
-					Fcdr (binding), result);
+		menu_bar_item (key, item_string, Fcdr (binding));
 	    }
 	  else if (EQ (binding, Qundefined))
-	    result = menu_bar_item (key, item_string,
-				    binding, result);
+	    menu_bar_item (key, item_string, binding);
 	}
       else if (XTYPE (item) == Lisp_Vector)
 	{
@@ -3610,17 +3636,13 @@
 		{
 		  item_string = XCONS (binding)->car;
 		  if (XTYPE (item_string) == Lisp_String)
-		    result = menu_bar_item (key, item_string,
-					    Fcdr (binding), result);
+		    menu_bar_item (key, item_string, Fcdr (binding));
 		}
 	      else if (EQ (binding, Qundefined))
-		result = menu_bar_item (key, item_string,
-					binding, result);
+		menu_bar_item (key, item_string, binding);
 	    }
 	}
     }
-
-  return result;
 }
 
 /* This is used as the handler when calling internal_condition_case_1.  */
@@ -3632,19 +3654,29 @@
   return Qnil;
 }
 
-static Lisp_Object
-menu_bar_item (key, item_string, def, result)
-     Lisp_Object key, item_string, def, result;
+static void
+menu_bar_item (key, item_string, def)
+     Lisp_Object key, item_string, def;
 {
   Lisp_Object tem;
   Lisp_Object enabled;
+  int i;
 
   if (EQ (def, Qundefined))
     {
       /* If a map has an explicit nil as definition,
 	 discard any previously made menu bar item.  */
-      tem = Fassq (key, result);
-      return Fdelq (tem, result);
+
+      for (i = 0; i < menu_bar_items_index; i += 3)
+	if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+	  {
+	    if (menu_bar_items_index > i + 3)
+	      bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+		     &XVECTOR (menu_bar_items_vector)->contents[i],
+		     (menu_bar_items_index - i - 3) * sizeof (Lisp_Object));
+	    menu_bar_items_index -= 3;
+	    return;
+	  }
     }
 
   /* See if this entry is enabled.  */
@@ -3662,13 +3694,34 @@
 					     menu_bar_item_1);
     }
 
-  /* Add an entry for this key and string
-     if there is none yet.  */
-  tem = Fassq (key, result);
-  if (!NILP (enabled) && NILP (tem))
-    result = Fcons (Fcons (key, Fcons (item_string, Qnil)), result);
-
-  return result;
+  /* Ignore this item if it's not enabled.  */
+  if (NILP (enabled))
+    return;
+
+  /* If there's already such an item, don't make another.  */
+  for (i = 0; i < menu_bar_items_index; i += 3)
+    if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+      break;
+
+  /* If we did not find this item, add it at the end.  */
+  if (i == menu_bar_items_index)
+    {
+      /* If vector is too small, get a bigger one.  */
+      if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+	{
+	  Lisp_Object tem;
+	  int newsize = 2 * i;
+	  tem = Fmake_vector (make_number (2 * i), Qnil);
+	  bcopy (XVECTOR (menu_bar_items_vector)->contents,
+		 XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+	  menu_bar_items_vector = tem;
+	}
+      /* Add this item.  */
+      XVECTOR (menu_bar_items_vector)->contents[i++] = key;
+      XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
+      XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+      menu_bar_items_index = i;
+    }
 }
 
 /* Read a character using menus based on maps in the array MAPS.