(compile_pattern_1): If representation of STRING
[bpt/emacs.git] / src / xmenu.c
index 36d15e5..77a367a 100644 (file)
@@ -1,5 +1,5 @@
 /* X Communication module for terminals which understand the X protocol.
-   Copyright (C) 1986, 1988, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1986, 1988, 1993, 1994, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -86,8 +86,12 @@ Boston, MA 02111-1307, USA.  */
 #define FALSE 0
 #endif /* no TRUE */
 
+Lisp_Object Vmenu_updating_frame;
+
 Lisp_Object Qdebug_on_next_call;
 
+Lisp_Object Qmenu_alias;
+
 extern Lisp_Object Qmenu_enable;
 extern Lisp_Object Qmenu_bar;
 extern Lisp_Object Qmouse_click, Qevent_kind;
@@ -169,6 +173,15 @@ static int menu_items_submenu_depth;
 static int popup_activated_flag;
 
 static int next_menubar_widget_id;
+
+/* This is set nonzero after the user activates the menu bar, and set
+   to zero again after the menu bars are redisplayed by prepare_menu_bar.
+   While it is nonzero, all calls to set_frame_menubar go deep.
+
+   I don't understand why this is needed, but it does seem to be
+   needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>.  */
+
+int pending_menu_activation;
 \f
 #ifdef USE_X_TOOLKIT
 
@@ -396,7 +409,8 @@ menu_item_equiv_key (item_string, item1, descrip_ptr)
       /* If the command is an alias for another
         (such as easymenu.el and lmenu.el set it up),
         see if the original command name has equivalent keys.  */
-      if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function))
+      if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
+         && ! NILP (Fget (def, Qmenu_alias)))
        savedkey = Fwhere_is_internal (XSYMBOL (def)->function,
                                       Qnil, Qt, Qnil);
       else
@@ -490,7 +504,7 @@ keymap_panes (keymaps, nmaps, notreal)
      But don't make a pane that is empty--ignore that map instead.
      P is the number of panes we have made so far.  */
   for (mapno = 0; mapno < nmaps; mapno++)
-    single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal);
+    single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
 
   finish_menu_items ();
 }
@@ -500,19 +514,25 @@ keymap_panes (keymaps, nmaps, notreal)
    The other arguments are passed along
    or point to local variables of the previous function.
    If NOTREAL is nonzero,
-   don't bother really computing whether an item is enabled.  */
+   don't bother really computing whether an item is enabled.
+
+   If we encounter submenus deeper than MAXDEPTH levels, ignore them.  */
 
 static void
-single_keymap_panes (keymap, pane_name, prefix, notreal)
+single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
      Lisp_Object keymap;
      Lisp_Object pane_name;
      Lisp_Object prefix;
      int notreal;
+     int maxdepth;
 {
   Lisp_Object pending_maps;
   Lisp_Object tail, item, item1, item_string, table;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
+  if (maxdepth <= 0)
+    return;
+
   pending_maps = Qnil;
 
   push_menu_pane (pane_name, prefix);
@@ -579,7 +599,8 @@ single_keymap_panes (keymap, pane_name, prefix, notreal)
                        {
                          push_submenu_start ();
                          single_keymap_panes (submap, Qnil,
-                                              XCONS (item)->car, notreal);
+                                              XCONS (item)->car, notreal,
+                                              maxdepth - 1);
                          push_submenu_end ();
                        }
 #endif
@@ -648,7 +669,8 @@ single_keymap_panes (keymap, pane_name, prefix, notreal)
                            {
                              push_submenu_start ();
                              single_keymap_panes (submap, Qnil,
-                                                  character, notreal);
+                                                  character, notreal,
+                                                  maxdepth - 1);
                              push_submenu_end ();
                            }
 #endif
@@ -669,7 +691,7 @@ single_keymap_panes (keymap, pane_name, prefix, notreal)
       /* We no longer discard the @ from the beginning of the string here.
         Instead, we do this in xmenu_show.  */
       single_keymap_panes (Fcar (elt), string,
-                          XCONS (eltcdr)->cdr, notreal);
+                          XCONS (eltcdr)->cdr, notreal, maxdepth - 1);
       pending_maps = Fcdr (pending_maps);
     }
 }
@@ -741,10 +763,14 @@ The menu items come from key bindings that have a menu string as well as\n\
 a definition; actually, the \"definition\" in such a key binding looks like\n\
 \(STRING . REAL-DEFINITION).  To give the menu a title, put a string into\n\
 the keymap as a top-level element.\n\n\
+If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.\n\
+Otherwise, REAL-DEFINITION should be a valid key binding definition.\n\
+\n\
 You can also use a list of keymaps as MENU.\n\
   Then each keymap makes a separate pane.\n\
 When MENU is a keymap or a list of keymaps, the return value\n\
 is a list of events.\n\n\
+\n\
 Alternatively, you can specify a menu of multiple panes\n\
   with a list of the form (TITLE PANE1 PANE2...),\n\
 where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
@@ -771,6 +797,7 @@ cached information about equivalent key sequences.")
   int for_click = 0;
   struct gcpro gcpro1;
 
+#ifdef HAVE_MENUS
   if (! NILP (position))
     {
       check_x ();
@@ -833,8 +860,10 @@ cached information about equivalent key sequences.")
          CHECK_LIVE_WINDOW (window, 0);
          f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
 
-         xpos = (FONT_WIDTH (f->output_data.x->font) * XWINDOW (window)->left);
-         ypos = (f->output_data.x->line_height * XWINDOW (window)->top);
+         xpos = (FONT_WIDTH (f->output_data.x->font)
+                 * XFASTINT (XWINDOW (window)->left));
+         ypos = (f->output_data.x->line_height
+                 * XFASTINT (XWINDOW (window)->top));
        }
       else
        /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
@@ -843,7 +872,11 @@ cached information about equivalent key sequences.")
 
       xpos += XINT (x);
       ypos += XINT (y);
+
+      XSETFRAME (Vmenu_updating_frame, f);
     }
+  Vmenu_updating_frame = Qnil;
+#endif /* HAVE_MENUS */
 
   title = Qnil;
   GCPRO1 (title);
@@ -866,6 +899,8 @@ cached information about equivalent key sequences.")
       /* Search for a string appearing directly as an element of the keymap.
         That string is the title of the menu.  */
       prompt = map_prompt (keymap);
+      if (NILP (title) && !NILP (prompt))
+       title = prompt;
 
       /* Make that be the pane title of the first pane.  */
       if (!NILP (prompt) && menu_items_n_panes >= 0)
@@ -923,6 +958,7 @@ cached information about equivalent key sequences.")
       return Qnil;
     }
 
+#ifdef HAVE_MENUS
   /* Display them in a menu.  */
   BLOCK_INPUT;
 
@@ -933,11 +969,14 @@ cached information about equivalent key sequences.")
   discard_menu_items ();
 
   UNGCPRO;
+#endif /* HAVE_MENUS */
 
   if (error_name) error (error_name);
   return selection;
 }
 
+#ifdef HAVE_MENUS
+
 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
   "Pop up a dialog box and return user's selection.\n\
 POSITION specifies which frame to use.\n\
@@ -996,6 +1035,8 @@ on the left of the dialog box and all following items on the right.\n\
     }
   else if (WINDOWP (position) || FRAMEP (position))
     window = position;
+  else
+    window = Qnil;
 
   /* Decode where to put the menu.  */
 
@@ -1087,10 +1128,21 @@ popup_get_selection (initial_event, dpyinfo, id)
       /* Handle expose events for editor frames right away.  */
       if (event.type == Expose)
        process_expose_from_menu (event);
-      /* Make sure we don't consider buttons grabbed after menu goes.  */
+      /* Make sure we don't consider buttons grabbed after menu goes.
+        And make sure to deactivate for any ButtonRelease,
+        even if XtDispatchEvent doesn't do that.  */
       else if (event.type == ButtonRelease
               && dpyinfo->display == event.xbutton.display)
-       dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+        {
+          dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+          popup_activated_flag = 0;
+#ifdef USE_MOTIF /* Pretending that the event came from a 
+                   Btn1Down seems the only way to convince Motif to
+                   activate its callbacks; setting the XmNmenuPost
+                   isn't working. --marcus@sysc.pdx.edu.  */
+         event.xbutton.button = 1;
+#endif
+        }
       /* If the user presses a key, deactivate the menu.
         The user is likely to do that if we get wedged.  */
       else if (event.type == KeyPress
@@ -1109,11 +1161,13 @@ popup_get_selection (initial_event, dpyinfo, id)
        }
 
       /* Queue all events not for this popup,
-        except for Expose, which we've already handled.
+        except for Expose, which we've already handled, and ButtonRelease.
         Note that the X window is associated with the frame if this
         is a menu bar popup, but not if it's a dialog box.  So we use
         x_non_menubar_window_to_frame, not x_any_window_to_frame.  */
       if (event.type != Expose
+          && !(event.type == ButtonRelease
+               && dpyinfo->display == event.xbutton.display)
          && (event.xany.display != dpyinfo->display
              || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
        {
@@ -1151,7 +1205,7 @@ popup_get_selection (initial_event, dpyinfo, id)
    menu_bar_activate_event out of the Emacs event queue.
 
    To activate the menu bar, we use the X button-press event
-   that was saved in saved_button_event.
+   that was saved in saved_menu_event.
    That makes the toolkit do its thing.
 
    But first we recompute the menu bar contents (the whole tree).
@@ -1163,17 +1217,20 @@ popup_get_selection (initial_event, dpyinfo, id)
 x_activate_menubar (f)
      FRAME_PTR f;
 {
-  if (f->output_data.x->saved_button_event->type != ButtonPress)
+  if (!f->output_data.x->saved_menu_event->type)
     return;
 
   set_frame_menubar (f, 0, 1);
-
   BLOCK_INPUT;
-  XtDispatchEvent ((XEvent *) f->output_data.x->saved_button_event);
+  XtDispatchEvent ((XEvent *) f->output_data.x->saved_menu_event);
   UNBLOCK_INPUT;
-
+#ifdef USE_MOTIF
+  if (f->output_data.x->saved_menu_event->type == ButtonRelease)
+    pending_menu_activation = 1;
+#endif
+  
   /* Ignore this if we get it a second time.  */
-  f->output_data.x->saved_button_event->type = 0;
+  f->output_data.x->saved_menu_event->type = 0;
 }
 
 /* Detect if a dialog or menu has been posted.  */
@@ -1293,6 +1350,19 @@ popup_deactivate_callback (widget, id, client_data)
   popup_activated_flag = 0;
 }
 
+/* Allocate a widget_value, blocking input.  */
+
+widget_value *
+xmalloc_widget_value ()
+{
+  widget_value *value;
+
+  BLOCK_INPUT;
+  value = malloc_widget_value ();
+  UNBLOCK_INPUT;
+
+  return value;
+}
 
 /* This recursively calls free_widget_value on the tree of widgets.
    It must free all data that was malloc'ed for these widget_values.
@@ -1358,14 +1428,18 @@ single_submenu (item_key, item_name, maps)
      But don't make a pane that is empty--ignore that map instead.  */
   for (i = 0; i < len; i++)
     {
-      if (SYMBOLP (mapvec[i]))
+      if (SYMBOLP (mapvec[i])
+         || (CONSP (mapvec[i])
+             && NILP (Fkeymapp (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);
        }
       else
-       single_keymap_panes (mapvec[i], item_name, item_key, 0);
+       single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
     }
 
   /* Create a tree of widget_value objects
@@ -1373,7 +1447,7 @@ single_submenu (item_key, item_name, maps)
 
   submenu_stack
     = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
-  wv = malloc_widget_value ();
+  wv = xmalloc_widget_value ();
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
@@ -1427,7 +1501,7 @@ single_submenu (item_key, item_name, maps)
             with its items as a submenu beneath it.  */
          if (strcmp (pane_string, ""))
            {
-             wv = malloc_widget_value ();
+             wv = xmalloc_widget_value ();
              if (save_wv)
                save_wv->next = wv;
              else
@@ -1454,7 +1528,7 @@ single_submenu (item_key, item_name, maps)
            = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
          def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
 
-         wv = malloc_widget_value ();
+         wv = xmalloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
          else
@@ -1563,14 +1637,25 @@ set_frame_menubar (f, first_time, deep_p)
   int i;
   LWLIB_ID id;
 
+  XSETFRAME (Vmenu_updating_frame, f);
+
   if (f->output_data.x->id == 0)
     f->output_data.x->id = next_menubar_widget_id++;
   id = f->output_data.x->id;
 
   if (! menubar_widget)
     deep_p = 1;
+  else if (pending_menu_activation && !deep_p)
+    deep_p = 1;
+  /* Make the first call for any given frame always go deep.  */
+  else if (!f->output_data.x->saved_menu_event && !deep_p)
+    {
+      deep_p = 1;
+      f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
+      f->output_data.x->saved_menu_event->type = 0;
+    }
 
-  wv = malloc_widget_value ();
+  wv = xmalloc_widget_value ();
   wv->name = "menubar";
   wv->value = 0;
   wv->enabled = 1;
@@ -1588,13 +1673,18 @@ set_frame_menubar (f, first_time, deep_p)
        = (Lisp_Object *) alloca (previous_menu_items_used
                                  * sizeof (Lisp_Object));
 
+      /* If we are making a new widget, its contents are empty,
+        do always reinitialize them.  */
+      if (! menubar_widget)
+       previous_menu_items_used = 0;
+
       buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
       specbind (Qinhibit_quit, Qt);
       /* Don't let the debugger step into this code
         because it is not reentrant.  */
       specbind (Qdebug_on_next_call, Qnil);
 
-      record_unwind_protect (Fstore_match_data, Fmatch_data ());
+      record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
       if (NILP (Voverriding_local_map_menu_flag))
        {
          specbind (Qoverriding_terminal_local_map, Qnil);
@@ -1624,7 +1714,7 @@ set_frame_menubar (f, first_time, deep_p)
       menu_items = f->menu_bar_vector;
       menu_items_allocated = XVECTOR (menu_items)->size;
       init_menu_items ();
-      for (i = 0; i < XVECTOR (items)->size; i += 3)
+      for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object key, string, maps;
 
@@ -1654,7 +1744,7 @@ set_frame_menubar (f, first_time, deep_p)
 
       for (i = 0; i < previous_menu_items_used; i++)
        if (menu_items_used == i
-           || (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)
        {
@@ -1667,7 +1757,7 @@ set_frame_menubar (f, first_time, deep_p)
       /* 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;
-      for (i = 0; i < XVECTOR (items)->size; i += 3)
+      for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object string;
          string = XVECTOR (items)->contents[i + 1];
@@ -1687,7 +1777,7 @@ set_frame_menubar (f, first_time, deep_p)
         just the top level menu bar strings.  */
 
       items = FRAME_MENU_BAR_ITEMS (f);
-      for (i = 0; i < XVECTOR (items)->size; i += 3)
+      for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
          Lisp_Object string;
 
@@ -1695,10 +1785,15 @@ set_frame_menubar (f, first_time, deep_p)
          if (NILP (string))
            break;
 
-         wv = malloc_widget_value ();
+         wv = xmalloc_widget_value ();
          wv->name = (char *) XSTRING (string)->data;
          wv->value = 0;
          wv->enabled = 1;
+         /* This prevents lwlib from assuming this
+            menu item is really supposed to be empty.  */
+         /* The EMACS_INT cast avoids a warning.
+            This value just has to be different from small integers.  */
+         wv->call_data = (void *) (EMACS_INT) (-1);
 
          if (prev_wv) 
            prev_wv->next = wv;
@@ -1747,6 +1842,8 @@ set_frame_menubar (f, first_time, deep_p)
            + f->output_data.x->menubar_widget->core.border_width)
         : 0);
 
+#if 0 /* Experimentally, we now get the right results
+        for -geometry -0-0 without this.  24 Aug 96, rms.  */
 #ifdef USE_LUCID
     if (FRAME_EXTERNAL_MENU_BAR (f))
       {
@@ -1756,6 +1853,7 @@ set_frame_menubar (f, first_time, deep_p)
         menubar_size += ibw;
       }
 #endif /* USE_LUCID */
+#endif /* 0 */
 
     f->output_data.x->menubar_height = menubar_size;
   }
@@ -1793,6 +1891,8 @@ free_frame_menubar (f)
   int id;
 
   menubar_widget = f->output_data.x->menubar_widget;
+
+  f->output_data.x->menubar_height = 0;
   
   if (menubar_widget)
     {
@@ -1812,7 +1912,7 @@ free_frame_menubar (f)
 /* F is the frame the menu is for.
    X and Y are the frame-relative specified position,
    relative to the inside upper left corner of the frame F.
-   FOR_CLICK if this menu was invoked for a mouse click.
+   FOR_CLICK is nonzero if this menu was invoked for a mouse click.
    KEYMAPS is 1 if this menu was specified with keymaps;
     in that case, we return a list containing the chosen item's value
     and perhaps also the pane's prefix.
@@ -1883,7 +1983,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 
   /* Create a tree of widget_value objects
      representing the panes and their items.  */
-  wv = malloc_widget_value ();
+  wv = xmalloc_widget_value ();
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
@@ -1935,7 +2035,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
             with its items as a submenu beneath it.  */
          if (!keymaps && strcmp (pane_string, ""))
            {
-             wv = malloc_widget_value ();
+             wv = xmalloc_widget_value ();
              if (save_wv)
                save_wv->next = wv;
              else
@@ -1966,7 +2066,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
            = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
          def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
 
-         wv = malloc_widget_value ();
+         wv = xmalloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
          else 
@@ -1990,9 +2090,9 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   /* Deal with the title, if it is non-nil.  */
   if (!NILP (title))
     {
-      widget_value *wv_title = malloc_widget_value ();
-      widget_value *wv_sep1 = malloc_widget_value ();
-      widget_value *wv_sep2 = malloc_widget_value ();
+      widget_value *wv_title = xmalloc_widget_value ();
+      widget_value *wv_sep1 = xmalloc_widget_value ();
+      widget_value *wv_sep2 = xmalloc_widget_value ();
 
       wv_sep2->name = "--";
       wv_sep2->next = first_wv->contents;
@@ -2049,7 +2149,6 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   dummy.send_event = 0;
   dummy.display = FRAME_X_DISPLAY (f);
   dummy.time = CurrentTime;
-  dummy.button = 0;
   dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
   dummy.window = dummy.root;
   dummy.subwindow = dummy.root;
@@ -2057,6 +2156,11 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   dummy.y_root = y;
   dummy.x = x;
   dummy.y = y;
+  dummy.state = (FRAME_X_DISPLAY_INFO (f)->grabbed >> 1) * Button1Mask;
+  dummy.button = 0;
+  for (i = 0; i < 5; i++)
+    if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
+      dummy.button = i;
 
   /* Don't allow any geometry request from the user.  */
   XtSetArg (av[ac], XtNgeometry, 0); ac++;
@@ -2195,7 +2299,7 @@ xdialog_show (f, keymaps, title, error)
     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
     pane_string = (NILP (pane_name)
                   ? "" : (char *) XSTRING (pane_name)->data);  
-    prev_wv = malloc_widget_value ();
+    prev_wv = xmalloc_widget_value ();
     prev_wv->value = pane_string;
     if (keymaps && !NILP (prefix))
       prev_wv->name++;
@@ -2229,14 +2333,14 @@ xdialog_show (f, keymaps, title, error)
            i++;
            continue;
          }
-       if (nb_buttons >= 10)
+       if (nb_buttons >= 9)
          {
            free_menubar_widget_value_tree (first_wv);
            *error = "Too many dialog items";
            return Qnil;
          }
 
-       wv = malloc_widget_value ();
+       wv = xmalloc_widget_value ();
        prev_wv->next = wv;
        wv->name = (char *) button_names[nb_buttons];
        if (!NILP (descrip))
@@ -2258,7 +2362,7 @@ xdialog_show (f, keymaps, title, error)
     if (! boundary_seen)
       left_count = nb_buttons - nb_buttons / 2;
 
-    wv = malloc_widget_value ();
+    wv = xmalloc_widget_value ();
     wv->name = dialog_name;
 
     /* Dialog boxes use a really stupid name encoding
@@ -2455,7 +2559,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
                  j++;
                  continue;
                }
-             width = XSTRING (item)->size;
+             width = XSTRING (item)->size_byte;
              if (width > maxwidth)
                maxwidth = width;
 
@@ -2478,7 +2582,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
            = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
          if (!NILP (descrip))
            {
-             int gap = maxwidth - XSTRING (item_name)->size;
+             int gap = maxwidth - XSTRING (item_name)->size_byte;
 #ifdef C_ALLOCA
              Lisp_Object spacer;
              spacer = Fmake_string (make_number (gap), make_number (' '));
@@ -2490,14 +2594,14 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
                 to reduce gc needs.  */
              item_data
                = (unsigned char *) alloca (maxwidth
-                                           + XSTRING (descrip)->size + 1);
+                                           + XSTRING (descrip)->size_byte + 1);
              bcopy (XSTRING (item_name)->data, item_data,
-                    XSTRING (item_name)->size);
+                    XSTRING (item_name)->size_byte);
              for (j = XSTRING (item_name)->size; j < maxwidth; j++)
                item_data[j] = ' ';
              bcopy (XSTRING (descrip)->data, item_data + j,
-                    XSTRING (descrip)->size);
-             item_data[j + XSTRING (descrip)->size] = 0;
+                    XSTRING (descrip)->size_byte);
+             item_data[j + XSTRING (descrip)->size_byte] = 0;
 #endif
            }
          else
@@ -2618,20 +2722,32 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 }
 
 #endif /* not USE_X_TOOLKIT */
+
+#endif /* HAVE_MENUS */
 \f
 syms_of_xmenu ()
 {
   staticpro (&menu_items);
   menu_items = Qnil;
 
+  Qmenu_alias = intern ("menu-alias");
+  staticpro (&Qmenu_alias);
+
   Qdebug_on_next_call = intern ("debug-on-next-call");
   staticpro (&Qdebug_on_next_call);
 
+  DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
+    "Frame for which we are updating a menu.\n\
+The enable predicate for a menu command should check this variable.");
+  Vmenu_updating_frame = Qnil;
+
 #ifdef USE_X_TOOLKIT
   widget_id_tick = (1<<16);    
   next_menubar_widget_id = 1;
 #endif
 
   defsubr (&Sx_popup_menu);
+#ifdef HAVE_MENUS
   defsubr (&Sx_popup_dialog);
+#endif
 }