]> code.delx.au - gnu-emacs/blobdiff - src/xmenu.c
Put doc strings in comments.
[gnu-emacs] / src / xmenu.c
index cc8e0faa35eb267ccabdfad5a4556e0d5fd42ad1..bf7bdbfd34e50f80e238ec346aa6029d5befa971 100644 (file)
@@ -1,5 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
 /* X Communication module for terminals which understand the X protocol.
-   Copyright (C) 1986, 1988, 1993, 1994, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1986, 88, 93, 94, 96, 99, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 
 This file is part of GNU Emacs.
 
@@ -30,18 +31,20 @@ Boston, MA 02111-1307, USA.  */
 
 /* Rewritten for clarity and GC protection by rms in Feb 94.  */
 
 
 /* Rewritten for clarity and GC protection by rms in Feb 94.  */
 
+#include <config.h>
+
 /* On 4.3 this loses if it comes after xterm.h.  */
 #include <signal.h>
 /* On 4.3 this loses if it comes after xterm.h.  */
 #include <signal.h>
-#include <config.h>
 
 #include <stdio.h>
 
 #include <stdio.h>
+#define DOC_STRINGS_IN_COMMENTS
 #include "lisp.h"
 #include "termhooks.h"
 #include "lisp.h"
 #include "termhooks.h"
+#include "keyboard.h"
+#include "keymap.h"
 #include "frame.h"
 #include "window.h"
 #include "frame.h"
 #include "window.h"
-#include "keyboard.h"
 #include "blockinput.h"
 #include "blockinput.h"
-#include "puresize.h"
 #include "buffer.h"
 
 #ifdef MSDOS
 #include "buffer.h"
 
 #ifdef MSDOS
@@ -63,7 +66,9 @@ Boston, MA 02111-1307, USA.  */
 #include "dispextern.h"
 
 #ifdef HAVE_X_WINDOWS
 #include "dispextern.h"
 
 #ifdef HAVE_X_WINDOWS
+#undef HAVE_MULTILINGUAL_MENU
 #ifdef USE_X_TOOLKIT
 #ifdef USE_X_TOOLKIT
+#include "widget.h"
 #include <X11/Xlib.h>
 #include <X11/IntrinsicP.h>
 #include <X11/CoreP.h>
 #include <X11/Xlib.h>
 #include <X11/IntrinsicP.h>
 #include <X11/CoreP.h>
@@ -78,23 +83,19 @@ Boston, MA 02111-1307, USA.  */
 #endif /* not USE_X_TOOLKIT */
 #endif /* HAVE_X_WINDOWS */
 
 #endif /* not USE_X_TOOLKIT */
 #endif /* HAVE_X_WINDOWS */
 
-#define min(x,y) (((x) < (y)) ? (x) : (y))
-#define max(x,y) (((x) > (y)) ? (x) : (y))
-
 #ifndef TRUE
 #define TRUE 1
 #define FALSE 0
 #endif /* no TRUE */
 
 #ifndef TRUE
 #define TRUE 1
 #define FALSE 0
 #endif /* no TRUE */
 
-Lisp_Object Qdebug_on_next_call;
+Lisp_Object Vmenu_updating_frame;
 
 
-Lisp_Object Qmenu_alias;
+Lisp_Object Qdebug_on_next_call;
 
 
-extern Lisp_Object Qmenu_enable;
 extern Lisp_Object Qmenu_bar;
 extern Lisp_Object Qmouse_click, Qevent_kind;
 
 extern Lisp_Object Qmenu_bar;
 extern Lisp_Object Qmouse_click, Qevent_kind;
 
-extern Lisp_Object Vdefine_key_rebound_commands;
+extern Lisp_Object QCtoggle, QCradio;
 
 extern Lisp_Object Voverriding_local_map;
 extern Lisp_Object Voverriding_local_map_menu_flag;
 
 extern Lisp_Object Voverriding_local_map;
 extern Lisp_Object Voverriding_local_map_menu_flag;
@@ -112,11 +113,26 @@ static Lisp_Object xdialog_show ();
 void popup_get_selection ();
 #endif
 
 void popup_get_selection ();
 #endif
 
-static Lisp_Object xmenu_show ();
-static void keymap_panes ();
-static void single_keymap_panes ();
-static void list_of_panes ();
-static void list_of_items ();
+#ifdef USE_X_TOOLKIT
+
+/* Define HAVE_BOXES if meus can handle radio and toggle buttons.  */
+
+#define HAVE_BOXES 1
+#endif
+
+static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+                               Lisp_Object, Lisp_Object, Lisp_Object,
+                               Lisp_Object, Lisp_Object));
+static int update_frame_menubar P_ ((struct frame *));
+static Lisp_Object xmenu_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 single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object *,
+                                 int, int, int *));
+static void list_of_panes P_ ((Lisp_Object));
+static void list_of_items P_ ((Lisp_Object));
 \f
 /* This holds a Lisp vector that holds the results of decoding
    the keymaps or alist-of-alists that specify a menu.
 \f
 /* This holds a Lisp vector that holds the results of decoding
    the keymaps or alist-of-alists that specify a menu.
@@ -144,12 +160,18 @@ static void list_of_items ();
 #define MENU_ITEMS_PANE_PREFIX 2
 #define MENU_ITEMS_PANE_LENGTH 3
 
 #define MENU_ITEMS_PANE_PREFIX 2
 #define MENU_ITEMS_PANE_LENGTH 3
 
-#define MENU_ITEMS_ITEM_NAME 0
-#define MENU_ITEMS_ITEM_ENABLE 1
-#define MENU_ITEMS_ITEM_VALUE 2
-#define MENU_ITEMS_ITEM_EQUIV_KEY 3
-#define MENU_ITEMS_ITEM_DEFINITION 4
-#define MENU_ITEMS_ITEM_LENGTH 5
+enum menu_item_idx
+{
+  MENU_ITEMS_ITEM_NAME = 0,
+  MENU_ITEMS_ITEM_ENABLE,
+  MENU_ITEMS_ITEM_VALUE,
+  MENU_ITEMS_ITEM_EQUIV_KEY,
+  MENU_ITEMS_ITEM_DEFINITION,
+  MENU_ITEMS_ITEM_TYPE,
+  MENU_ITEMS_ITEM_SELECTED,
+  MENU_ITEMS_ITEM_HELP,
+  MENU_ITEMS_ITEM_LENGTH
+};
 
 static Lisp_Object menu_items;
 
 
 static Lisp_Object menu_items;
 
@@ -168,7 +190,7 @@ static int menu_items_submenu_depth;
 
 /* Flag which when set indicates a dialog or menu has been posted by
    Xt on behalf of one of the widget sets.  */
 
 /* Flag which when set indicates a dialog or menu has been posted by
    Xt on behalf of one of the widget sets.  */
-static int popup_activated_flag;
+int popup_activated_flag;
 
 static int next_menubar_widget_id;
 
 
 static int next_menubar_widget_id;
 
@@ -192,13 +214,13 @@ menubar_id_to_frame (id)
   Lisp_Object tail, frame;
   FRAME_PTR f;
 
   Lisp_Object tail, frame;
   FRAME_PTR f;
 
-  for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr)
+  for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
     {
     {
-      frame = XCONS (tail)->car;
+      frame = XCAR (tail);
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
-      if (f->output_data.nothing == 1)
+      if (!FRAME_WINDOW_P (f))
        continue;
       if (f->output_data.x->id == id)
        return f;
        continue;
       if (f->output_data.x->id == id)
        return f;
@@ -315,17 +337,17 @@ push_menu_pane (name, prefix_vec)
   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
 }
 
   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
 }
 
-/* Push one menu item into the current pane.
-   NAME is the string to display.  ENABLE if non-nil means
-   this item can be selected.  KEY is the key generated by
-   choosing this item, or nil if this item doesn't really have a definition.
-   DEF is the definition of this item.
-   EQUIV is the textual description of the keyboard equivalent for
-   this item (or nil if none).  */
+/* Push one menu item into the current pane.  NAME is the string to
+   display.  ENABLE if non-nil means this item can be selected.  KEY
+   is the key generated by choosing this item, or nil if this item
+   doesn't really have a definition.  DEF is the definition of this
+   item.  EQUIV is the textual description of the keyboard equivalent
+   for this item (or nil if none).  TYPE is the type of this menu
+   item, one of nil, `toggle' or `radio'. */
 
 static void
 
 static void
-push_menu_item (name, enable, key, def, equiv)
-     Lisp_Object name, enable, key, def, equiv;
+push_menu_item (name, enable, key, def, equiv, type, selected, help)
+     Lisp_Object name, enable, key, def, equiv, type, selected, help;
 {
   if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
     grow_menu_items ();
 {
   if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
     grow_menu_items ();
@@ -335,152 +357,9 @@ push_menu_item (name, enable, key, def, equiv)
   XVECTOR (menu_items)->contents[menu_items_used++] = key;
   XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
   XVECTOR (menu_items)->contents[menu_items_used++] = def;
   XVECTOR (menu_items)->contents[menu_items_used++] = key;
   XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
   XVECTOR (menu_items)->contents[menu_items_used++] = def;
-}
-\f
-/* Figure out the current keyboard equivalent of a menu item ITEM1.
-   The item string for menu display should be ITEM_STRING.
-   Store the equivalent keyboard key sequence's
-   textual description into *DESCRIP_PTR.
-   Also cache them in the item itself.
-   Return the real definition to execute.  */
-
-static Lisp_Object
-menu_item_equiv_key (item_string, item1, descrip_ptr)
-     Lisp_Object item_string;
-     Lisp_Object item1;
-     Lisp_Object *descrip_ptr;
-{
-  /* This is the real definition--the function to run.  */
-  Lisp_Object def;
-  /* This is the sublist that records cached equiv key data
-     so we can save time.  */
-  Lisp_Object cachelist;
-  /* These are the saved equivalent keyboard key sequence
-     and its key-description.  */
-  Lisp_Object savedkey, descrip;
-  Lisp_Object def1;
-  int changed = 0;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-
-  /* If a help string follows the item string, skip it.  */
-  if (CONSP (XCONS (item1)->cdr)
-      && STRINGP (XCONS (XCONS (item1)->cdr)->car))
-    item1 = XCONS (item1)->cdr;
-
-  def = Fcdr (item1);
-
-  /* Get out the saved equivalent-keyboard-key info.  */
-  cachelist = savedkey = descrip = Qnil;
-  if (CONSP (def) && CONSP (XCONS (def)->car)
-      && (NILP (XCONS (XCONS (def)->car)->car)
-         || VECTORP (XCONS (XCONS (def)->car)->car)))
-    {
-      cachelist = XCONS (def)->car;
-      def = XCONS (def)->cdr;
-      savedkey = XCONS (cachelist)->car;
-      descrip = XCONS (cachelist)->cdr;
-    }
-
-  GCPRO4 (def, def1, savedkey, descrip);
-
-  /* Is it still valid?  */
-  def1 = Qnil;
-  if (!NILP (savedkey))
-    def1 = Fkey_binding (savedkey, Qnil);
-  /* If not, update it.  */
-  if (! EQ (def1, def)
-      /* If the command is an alias for another
-         (such as easymenu.el and lmenu.el set it up),
-         check if the original command matches the cached command.  */
-      && !(SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
-           && EQ (def1, XSYMBOL (def)->function))
-      /* If something had no key binding before, don't recheck it
-        because that is too slow--except if we have a list of rebound
-        commands in Vdefine_key_rebound_commands, do recheck any command
-        that appears in that list.  */
-      && (NILP (cachelist) || !NILP (savedkey)
-         || (! EQ (Qt, Vdefine_key_rebound_commands)
-             && !NILP (Fmemq (def, Vdefine_key_rebound_commands)))))
-    {
-      changed = 1;
-      descrip = Qnil;
-      /* 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)
-         && ! NILP (Fget (def, Qmenu_alias)))
-       savedkey = Fwhere_is_internal (XSYMBOL (def)->function,
-                                      Qnil, Qt, Qnil);
-      else
-       /* Otherwise look up the specified command itself.
-          We don't try both, because that makes easymenu menus slow.  */
-       savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
-
-      if (!NILP (savedkey))
-       {
-         descrip = Fkey_description (savedkey);
-         descrip = concat2 (make_string ("  (", 3), descrip);
-         descrip = concat2 (descrip, make_string (")", 1));
-       }
-    }
-
-  /* Cache the data we just got in a sublist of the menu binding.  */
-  if (NILP (cachelist))
-    {
-      CHECK_IMPURE (item1);
-      XCONS (item1)->cdr = Fcons (Fcons (savedkey, descrip), def);
-    }
-  else if (changed)
-    {
-      XCONS (cachelist)->car = savedkey;
-      XCONS (cachelist)->cdr = descrip;
-    }
-
-  UNGCPRO;
-  *descrip_ptr = descrip;
-  return def;
-}
-
-/* This is used as the handler when calling internal_condition_case_1.  */
-
-static Lisp_Object
-menu_item_enabled_p_1 (arg)
-     Lisp_Object arg;
-{
-  /* If we got a quit from within the menu computation,
-     quit all the way out of it.  This takes care of C-] in the debugger.  */
-  if (CONSP (arg) && EQ (XCONS (arg)->car, Qquit))
-    Fsignal (Qquit, Qnil);
-
-  return Qnil;
-}
-
-/* Return non-nil if the command DEF is enabled when used as a menu item.
-   This is based on looking for a menu-enable property.
-   If NOTREAL is set, don't bother really computing this.  */
-
-static Lisp_Object
-menu_item_enabled_p (def, notreal)
-     Lisp_Object def;
-     int notreal;
-{
-  Lisp_Object enabled, tem;
-
-  enabled = Qt;
-  if (notreal)
-    return enabled;
-  if (SYMBOLP (def))
-    {
-      /* No property, or nil, means enable.
-        Otherwise, enable if value is not nil.  */
-      tem = Fget (def, Qmenu_enable);
-      if (!NILP (tem))
-       /* (condition-case nil (eval tem)
-          (error nil))  */
-       enabled = internal_condition_case_1 (Feval, tem, Qerror,
-                                            menu_item_enabled_p_1);
-    }
-  return enabled;
+  XVECTOR (menu_items)->contents[menu_items_used++] = type;
+  XVECTOR (menu_items)->contents[menu_items_used++] = selected;
+  XVECTOR (menu_items)->contents[menu_items_used++] = help;
 }
 \f
 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
 }
 \f
 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
@@ -502,7 +381,8 @@ 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++)
      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],
+                        Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
 
   finish_menu_items ();
 }
 
   finish_menu_items ();
 }
@@ -511,94 +391,46 @@ keymap_panes (keymaps, nmaps, notreal)
    It handles one keymap, KEYMAP.
    The other arguments are passed along
    or point to local variables of the previous function.
    It handles one keymap, KEYMAP.
    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.  */
+   If 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.  */
 
 static void
 
 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;
      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;
+  Lisp_Object pending_maps = Qnil;
+  Lisp_Object tail, item;
+  struct gcpro gcpro1, gcpro2;
+  int notbuttons = 0;
 
 
-  pending_maps = Qnil;
+  if (maxdepth <= 0)
+    return;
 
   push_menu_pane (pane_name, prefix);
 
 
   push_menu_pane (pane_name, prefix);
 
-  for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
+#ifndef HAVE_BOXES
+  /* Remember index for first item in this pane so we can go back and
+     add a prefix when (if) we see the first button.  After that, notbuttons
+     is set to 0, to mark that we have seen a button and all non button
+     items need a prefix.  */
+  notbuttons = menu_items_used;
+#endif
+
+  for (tail = keymap; CONSP (tail); tail = XCDR (tail))
     {
     {
-      /* Look at each key binding, and if it has a menu string,
-        make a menu item from it.  */
-      item = XCONS (tail)->car;
+      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))
       if (CONSP (item))
-       {
-         item1 = XCONS (item)->cdr;
-         if (CONSP (item1))
-           {
-             item_string = XCONS (item1)->car;
-             if (STRINGP (item_string))
-               {
-                 /* This is the real definition--the function to run.  */
-                 Lisp_Object def;
-                 /* These are the saved equivalent keyboard key sequence
-                    and its key-description.  */
-                 Lisp_Object descrip;
-                 Lisp_Object tem, enabled;
-
-                 /* GCPRO because ...enabled_p will call eval
-                    and ..._equiv_key may autoload something.
-                    Protecting KEYMAP preserves everything we use;
-                    aside from that, must protect whatever might be
-                    a string.  Since there's no GCPRO5, we refetch
-                    item_string instead of protecting it.  */
-                 descrip = def = Qnil;
-                 GCPRO4 (keymap, pending_maps, def, descrip);
-
-                 def = menu_item_equiv_key (item_string, item1, &descrip);
-                 enabled = menu_item_enabled_p (def, notreal);
-
-                 UNGCPRO;
-
-                 item_string = XCONS (item1)->car;
-
-                 tem = Fkeymapp (def);
-                 if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
-                   pending_maps = Fcons (Fcons (def, Fcons (item_string, XCONS (item)->car)),
-                                         pending_maps);
-                 else
-                   {
-                     Lisp_Object submap;
-                     GCPRO4 (keymap, pending_maps, descrip, item_string);
-                     submap = get_keymap_1 (def, 0, 1);
-                     UNGCPRO;
-#ifndef USE_X_TOOLKIT
-                     /* Indicate visually that this is a submenu.  */
-                     if (!NILP (submap))
-                       item_string = concat2 (item_string,
-                                              build_string (" >"));
-#endif
-                     /* If definition is nil, pass nil as the key.  */
-                     push_menu_item (item_string, enabled,
-                                     XCONS (item)->car, def,
-                                     descrip);
-#ifdef USE_X_TOOLKIT
-                     /* Display a submenu using the toolkit.  */
-                     if (! NILP (submap))
-                       {
-                         push_submenu_start ();
-                         single_keymap_panes (submap, Qnil,
-                                              XCONS (item)->car, notreal);
-                         push_submenu_end ();
-                       }
-#endif
-                   }
-               }
-           }
-       }
+       single_menu_item (XCAR (item), XCDR (item),
+                         &pending_maps, notreal, maxdepth, &notbuttons);
       else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
       else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
@@ -608,67 +440,11 @@ single_keymap_panes (keymap, pane_name, prefix, notreal)
            {
              Lisp_Object character;
              XSETFASTINT (character, c);
            {
              Lisp_Object character;
              XSETFASTINT (character, c);
-             item1 = XVECTOR (item)->contents[c];
-             if (CONSP (item1))
-               {
-                 item_string = XCONS (item1)->car;
-                 if (STRINGP (item_string))
-                   {
-                     Lisp_Object def;
-
-                     /* These are the saved equivalent keyboard key sequence
-                        and its key-description.  */
-                     Lisp_Object descrip;
-                     Lisp_Object tem, enabled;
-
-                     /* GCPRO because ...enabled_p will call eval
-                        and ..._equiv_key may autoload something.
-                        Protecting KEYMAP preserves everything we use;
-                        aside from that, must protect whatever might be
-                        a string.  Since there's no GCPRO5, we refetch
-                        item_string instead of protecting it.  */
-                     GCPRO4 (keymap, pending_maps, def, descrip);
-                     descrip = def = Qnil;
-
-                     def = menu_item_equiv_key (item_string, item1, &descrip);
-                     enabled = menu_item_enabled_p (def, notreal);
-
-                     UNGCPRO;
-
-                     item_string = XCONS (item1)->car;
-
-                     tem = Fkeymapp (def);
-                     if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
-                       pending_maps = Fcons (Fcons (def, Fcons (item_string, character)),
-                                             pending_maps);
-                     else
-                       {
-                         Lisp_Object submap;
-                         GCPRO4 (keymap, pending_maps, descrip, item_string);
-                         submap = get_keymap_1 (def, 0, 1);
-                         UNGCPRO;
-#ifndef USE_X_TOOLKIT
-                         if (!NILP (submap))
-                           item_string = concat2 (item_string,
-                                                  build_string (" >"));
-#endif
-                         /* If definition is nil, pass nil as the key.  */
-                         push_menu_item (item_string, enabled, character,
-                                         def, descrip);
-#ifdef USE_X_TOOLKIT
-                         if (! NILP (submap))
-                           {
-                             push_submenu_start ();
-                             single_keymap_panes (submap, Qnil,
-                                                  character, notreal);
-                             push_submenu_end ();
-                           }
-#endif
-                       }
-                   }
-               }
+             single_menu_item (character, XVECTOR (item)->contents[c],
+                               &pending_maps, notreal, maxdepth, &notbuttons);
            }
        }
            }
        }
+      UNGCPRO;
     }
 
   /* Process now any submenus which want to be panes at this level.  */
     }
 
   /* Process now any submenus which want to be panes at this level.  */
@@ -676,16 +452,157 @@ single_keymap_panes (keymap, pane_name, prefix, notreal)
     {
       Lisp_Object elt, eltcdr, string;
       elt = Fcar (pending_maps);
     {
       Lisp_Object elt, eltcdr, string;
       elt = Fcar (pending_maps);
-      eltcdr = XCONS (elt)->cdr;
-      string = XCONS (eltcdr)->car;
+      eltcdr = XCDR (elt);
+      string = XCAR (eltcdr);
       /* 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,
       /* 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);
+                          XCDR (eltcdr), notreal, maxdepth - 1);
       pending_maps = Fcdr (pending_maps);
     }
 }
 \f
       pending_maps = Fcdr (pending_maps);
     }
 }
 \f
+/* 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
+   separate panes.
+   If 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.
+   NOTBUTTONS_PTR is only used when simulating toggle boxes and radio
+   buttons.  It points to variable notbuttons in single_keymap_panes,
+   which keeps track of if we have seen a button in this menu or not.  */
+
+static void
+single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
+                 notbuttons_ptr)
+     Lisp_Object key, item;
+     Lisp_Object *pending_maps_ptr;
+     int maxdepth, notreal;
+     int *notbuttons_ptr;
+{
+  Lisp_Object map, item_string, enabled;
+  struct gcpro gcpro1, gcpro2;
+  int res;
+  
+  /* Parse the menu item and leave the result in item_properties.  */
+  GCPRO2 (key, item);
+  res = parse_menu_item (item, notreal, 0);
+  UNGCPRO;
+  if (!res)
+    return;                    /* Not a menu item.  */
+
+  map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
+  
+  if (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);
+      return;
+    }
+
+  enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
+  item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; 
+
+  if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
+    {
+      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);
+      return;
+    }
+
+#ifndef HAVE_BOXES
+  /* Simulate radio buttons and toggle boxes by putting a prefix in
+     front of them.  */
+  {
+    Lisp_Object prefix = Qnil;
+    Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
+    if (!NILP (type))
+      {
+       Lisp_Object selected
+         = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+
+       if (*notbuttons_ptr)
+         /* The first button. Line up previous items in this menu.  */
+         {
+           int index = *notbuttons_ptr; /* Index for first item this menu.  */
+           int submenu = 0;
+           Lisp_Object tem;
+           while (index < menu_items_used)
+             {
+               tem
+                 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
+               if (NILP (tem))
+                 {
+                   index++;
+                   submenu++;          /* Skip sub menu.  */
+                 }
+               else if (EQ (tem, Qlambda))
+                 {
+                   index++;
+                   submenu--;          /* End sub menu.  */
+                 }
+               else if (EQ (tem, Qt))
+                 index += 3;           /* Skip new pane marker. */
+               else if (EQ (tem, Qquote))
+                 index++;              /* Skip a left, right divider. */
+               else
+                 {
+                   if (!submenu && XSTRING (tem)->data[0] != '\0'
+                       && XSTRING (tem)->data[0] != '-')
+                     XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
+                       = concat2 (build_string ("    "), tem);
+                   index += MENU_ITEMS_ITEM_LENGTH;
+                 }
+             }
+           *notbuttons_ptr = 0;
+         }
+
+       /* Calculate prefix, if any, for this item.  */
+       if (EQ (type, QCtoggle))
+         prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
+       else if (EQ (type, QCradio))
+         prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
+      }
+    /* Not a button. If we have earlier buttons, then we need a prefix.  */
+    else if (!*notbuttons_ptr && XSTRING (item_string)->data[0] != '\0'
+            && XSTRING (item_string)->data[0] != '-')
+      prefix = build_string ("    ");
+
+    if (!NILP (prefix))
+      item_string = concat2 (prefix, item_string);
+  }
+#endif /* not HAVE_BOXES */
+#ifndef USE_X_TOOLKIT
+  if (!NILP(map))
+    /* Indicate visually that this is a submenu.  */
+    item_string = concat2 (item_string, build_string (" >"));
+#endif
+
+  push_menu_item (item_string, enabled, key,
+                 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]);
+
+#ifdef USE_X_TOOLKIT
+  /* Display a submenu using the toolkit.  */
+  if (! (NILP (map) || NILP (enabled)))
+    {
+      push_submenu_start ();
+      single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
+      push_submenu_end ();
+    }
+#endif
+}
+\f
 /* Push all the panes and items of a menu described by the
    alist-of-alists MENU.
    This handles old-fashioned calls to x-popup-menu.  */
 /* Push all the panes and items of a menu described by the
    alist-of-alists MENU.
    This handles old-fashioned calls to x-popup-menu.  */
@@ -725,7 +642,7 @@ list_of_items (pane)
     {
       item = Fcar (tail);
       if (STRINGP (item))
     {
       item = Fcar (tail);
       if (STRINGP (item))
-       push_menu_item (item, Qnil, Qnil, Qt, Qnil);
+       push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
       else if (NILP (item))
        push_left_right_boundary ();
       else
       else if (NILP (item))
        push_left_right_boundary ();
       else
@@ -733,51 +650,54 @@ list_of_items (pane)
          CHECK_CONS (item, 0);
          item1 = Fcar (item);
          CHECK_STRING (item1, 1);
          CHECK_CONS (item, 0);
          item1 = Fcar (item);
          CHECK_STRING (item1, 1);
-         push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil);
+         push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
        }
     }
 }
 \f
 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
        }
     }
 }
 \f
 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
-  "Pop up a deck-of-cards menu and return user's selection.\n\
-POSITION is a position specification.  This is either a mouse button event\n\
-or a list ((XOFFSET YOFFSET) WINDOW)\n\
-where XOFFSET and YOFFSET are positions in pixels from the top left\n\
-corner of WINDOW's frame.  (WINDOW may be a frame object instead of a window.)\n\
-This controls the position of the center of the first line\n\
-in the first pane of the menu, not the top left of the menu as a whole.\n\
-If POSITION is t, it means to use the current mouse position.\n\
-\n\
-MENU is a specifier for a menu.  For the simplest case, MENU is a keymap.\n\
-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\
-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\
-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\
-Each ITEM is normally a cons cell (STRING . VALUE);\n\
-but a string can appear as an item--that makes a nonselectable line\n\
-in the menu.\n\
-With this form of menu, the return value is VALUE from the chosen item.\n\
-\n\
-If POSITION is nil, don't display the menu at all, just precalculate the\n\
-cached information about equivalent key sequences.")
-  (position, menu)
+  /* Pop up a deck-of-cards menu and return user's selection.
+POSITION is a position specification.  This is either a mouse button event
+or a list ((XOFFSET YOFFSET) WINDOW)
+where XOFFSET and YOFFSET are positions in pixels from the top left
+corner of WINDOW's frame.  (WINDOW may be a frame object instead of a window.)
+This controls the position of the center of the first line
+in the first pane of the menu, not the top left of the menu as a whole.
+If POSITION is t, it means to use the current mouse position.
+
+MENU is a specifier for a menu.  For the simplest case, MENU is a keymap.
+The menu items come from key bindings that have a menu string as well as
+a definition; actually, the "definition" in such a key binding looks like
+\(STRING . REAL-DEFINITION).  To give the menu a title, put a string into
+the keymap as a top-level element.
+
+If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
+Otherwise, REAL-DEFINITION should be a valid key binding definition.
+
+You can also use a list of keymaps as MENU.
+  Then each keymap makes a separate pane.
+When MENU is a keymap or a list of keymaps, the return value
+is a list of events.
+
+Alternatively, you can specify a menu of multiple panes
+  with a list of the form (TITLE PANE1 PANE2...),
+where each pane is a list of form (TITLE ITEM1 ITEM2...).
+Each ITEM is normally a cons cell (STRING . VALUE);
+but a string can appear as an item--that makes a nonselectable line
+in the menu.
+With this form of menu, the return value is VALUE from the chosen item.
+
+If POSITION is nil, don't display the menu at all, just precalculate the
+cached information about equivalent key sequences.  */
+       (position, menu))
      Lisp_Object position, menu;
 {
      Lisp_Object position, menu;
 {
-  int number_of_panes, panes;
   Lisp_Object keymap, tem;
   Lisp_Object keymap, tem;
-  int xpos, ypos;
+  int xpos = 0, ypos = 0;
   Lisp_Object title;
   char *error_name;
   Lisp_Object selection;
   Lisp_Object title;
   char *error_name;
   Lisp_Object selection;
-  int i, j;
-  FRAME_PTR f;
+  struct frame *f = NULL;
   Lisp_Object x, y, window;
   int keymaps = 0;
   int for_click = 0;
   Lisp_Object x, y, window;
   int keymaps = 0;
   int for_click = 0;
@@ -790,12 +710,13 @@ cached information about equivalent key sequences.")
 
       /* Decode the first argument: find the window and the coordinates.  */
       if (EQ (position, Qt)
 
       /* Decode the first argument: find the window and the coordinates.  */
       if (EQ (position, Qt)
-         || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
+         || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+                                  || EQ (XCAR (position), Qtool_bar))))
        {
          /* Use the mouse's current position.  */
        {
          /* Use the mouse's current position.  */
-         FRAME_PTR new_f = selected_frame;
+         FRAME_PTR new_f = SELECTED_FRAME ();
          Lisp_Object bar_window;
          Lisp_Object bar_window;
-         int part;
+         enum scroll_bar_part part;
          unsigned long time;
 
          if (mouse_position_hook)
          unsigned long time;
 
          if (mouse_position_hook)
@@ -846,8 +767,10 @@ cached information about equivalent key sequences.")
          CHECK_LIVE_WINDOW (window, 0);
          f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
 
          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,
        }
       else
        /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
@@ -856,7 +779,10 @@ cached information about equivalent key sequences.")
 
       xpos += XINT (x);
       ypos += XINT (y);
 
       xpos += XINT (x);
       ypos += XINT (y);
+
+      XSETFRAME (Vmenu_updating_frame, f);
     }
     }
+  Vmenu_updating_frame = Qnil;
 #endif /* HAVE_MENUS */
 
   title = Qnil;
 #endif /* HAVE_MENUS */
 
   title = Qnil;
@@ -864,22 +790,20 @@ cached information about equivalent key sequences.")
 
   /* Decode the menu items from what was specified.  */
 
 
   /* Decode the menu items from what was specified.  */
 
-  keymap = Fkeymapp (menu);
-  tem = Qnil;
-  if (CONSP (menu))
-    tem = Fkeymapp (Fcar (menu));
-  if (!NILP (keymap))
+  keymap = get_keymap (menu, 0, 0);
+  if (CONSP (keymap))
     {
       /* We were given a keymap.  Extract menu info from the keymap.  */
       Lisp_Object prompt;
     {
       /* We were given a keymap.  Extract menu info from the keymap.  */
       Lisp_Object prompt;
-      keymap = get_keymap (menu);
 
       /* Extract the detailed info to make one pane.  */
       keymap_panes (&menu, 1, NILP (position));
 
       /* Search for a string appearing directly as an element of the keymap.
         That string is the title of the menu.  */
 
       /* Extract the detailed info to make one pane.  */
       keymap_panes (&menu, 1, NILP (position));
 
       /* Search for a string appearing directly as an element of the keymap.
         That string is the title of the menu.  */
-      prompt = map_prompt (keymap);
+      prompt = Fkeymap_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)
 
       /* Make that be the pane title of the first pane.  */
       if (!NILP (prompt) && menu_items_n_panes >= 0)
@@ -887,7 +811,7 @@ cached information about equivalent key sequences.")
 
       keymaps = 1;
     }
 
       keymaps = 1;
     }
-  else if (!NILP (tem))
+  else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
     {
       /* We were given a list of keymaps.  */
       int nmaps = XFASTINT (Flength (menu));
     {
       /* We were given a list of keymaps.  */
       int nmaps = XFASTINT (Flength (menu));
@@ -903,9 +827,9 @@ cached information about equivalent key sequences.")
        {
          Lisp_Object prompt;
 
        {
          Lisp_Object prompt;
 
-         maps[i++] = keymap = get_keymap (Fcar (tem));
+         maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
 
 
-         prompt = map_prompt (keymap);
+         prompt = Fkeymap_prompt (keymap);
          if (NILP (title) && !NILP (prompt))
            title = prompt;
        }
          if (NILP (title) && !NILP (prompt))
            title = prompt;
        }
@@ -957,35 +881,37 @@ cached information about equivalent key sequences.")
 #ifdef HAVE_MENUS
 
 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
 #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\
-This is normally a mouse button event or a window or frame.\n\
-If POSITION is t, it means to use the frame the mouse is on.\n\
-The dialog box appears in the middle of the specified frame.\n\
-\n\
-CONTENTS specifies the alternatives to display in the dialog box.\n\
-It is a list of the form (TITLE ITEM1 ITEM2...).\n\
-Each ITEM is a cons cell (STRING . VALUE).\n\
-The return value is VALUE from the chosen item.\n\n\
-An ITEM may also be just a string--that makes a nonselectable item.\n\
-An ITEM may also be nil--that means to put all preceding items\n\
-on the left of the dialog box and all following items on the right.\n\
-\(By default, approximately half appear on each side.)")
-  (position, contents)
+  /* Pop up a dialog box and return user's selection.
+POSITION specifies which frame to use.
+This is normally a mouse button event or a window or frame.
+If POSITION is t, it means to use the frame the mouse is on.
+The dialog box appears in the middle of the specified frame.
+
+CONTENTS specifies the alternatives to display in the dialog box.
+It is a list of the form (TITLE ITEM1 ITEM2...).
+Each ITEM is a cons cell (STRING . VALUE).
+The return value is VALUE from the chosen item.
+
+An ITEM may also be just a string--that makes a nonselectable item.
+An ITEM may also be nil--that means to put all preceding items
+on the left of the dialog box and all following items on the right.
+\(By default, approximately half appear on each side.)  */
+       (position, contents))
      Lisp_Object position, contents;
 {
      Lisp_Object position, contents;
 {
-  FRAME_PTR f;
+  struct frame * f = NULL;
   Lisp_Object window;
 
   check_x ();
 
   /* Decode the first argument: find the window or frame to use.  */
   if (EQ (position, Qt)
   Lisp_Object window;
 
   check_x ();
 
   /* Decode the first argument: find the window or frame to use.  */
   if (EQ (position, Qt)
-      || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
+      || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+                              || EQ (XCAR (position), Qtool_bar))))
     {
 #if 0 /* Using the frame the mouse is on may not be right.  */
       /* Use the mouse's current position.  */
     {
 #if 0 /* Using the frame the mouse is on may not be right.  */
       /* Use the mouse's current position.  */
-      FRAME_PTR new_f = selected_frame;
+      FRAME_PTR new_f = SELECTED_FRAME ();
       Lisp_Object bar_window;
       int part;
       unsigned long time;
       Lisp_Object bar_window;
       int part;
       unsigned long time;
@@ -1127,8 +1053,12 @@ popup_get_selection (initial_event, dpyinfo, id)
       else if (event.type == KeyPress
               && dpyinfo->display == event.xbutton.display)
        {
       else if (event.type == KeyPress
               && dpyinfo->display == event.xbutton.display)
        {
-         popup_activated_flag = 0;
-         break;
+         KeySym keysym = XLookupKeysym (&event.xkey, 0);
+         if (!IsModifierKey (keysym))
+           {
+             popup_activated_flag = 0;
+             break;
+           }
        }
       /* Button presses outside the menu also pop it down.  */
       else if (event.type == ButtonPress
        }
       /* Button presses outside the menu also pop it down.  */
       else if (event.type == ButtonPress
@@ -1150,14 +1080,10 @@ popup_get_selection (initial_event, dpyinfo, id)
          && (event.xany.display != dpyinfo->display
              || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
        {
          && (event.xany.display != dpyinfo->display
              || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
        {
-         queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue));
-
-         if (queue_tmp != NULL) 
-           {
-             queue_tmp->event = event;
-             queue_tmp->next = queue;
-             queue = queue_tmp;
-           }
+         queue_tmp = (struct event_queue *) xmalloc (sizeof *queue_tmp);
+         queue_tmp->event = event;
+         queue_tmp->next = queue;
+         queue = queue_tmp;
        }
       else
        XtDispatchEvent (&event);
        }
       else
        XtDispatchEvent (&event);
@@ -1173,7 +1099,7 @@ popup_get_selection (initial_event, dpyinfo, id)
       queue_tmp = queue;
       XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event);
       queue = queue_tmp->next;
       queue_tmp = queue;
       XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event);
       queue = queue_tmp->next;
-      free ((char *)queue_tmp);
+      xfree ((char *)queue_tmp);
       /* Cause these events to get read as soon as we UNBLOCK_INPUT.  */
       interrupt_input_pending = 1;
     }
       /* Cause these events to get read as soon as we UNBLOCK_INPUT.  */
       interrupt_input_pending = 1;
     }
@@ -1193,6 +1119,7 @@ popup_get_selection (initial_event, dpyinfo, id)
    passing it to the toolkit right away, is that we can safely
    execute Lisp code.  */
    
    passing it to the toolkit right away, is that we can safely
    execute Lisp code.  */
    
+void
 x_activate_menubar (f)
      FRAME_PTR f;
 {
 x_activate_menubar (f)
      FRAME_PTR f;
 {
@@ -1220,7 +1147,6 @@ popup_activated ()
   return popup_activated_flag;
 }
 
   return popup_activated_flag;
 }
 
-
 /* This callback is invoked when the user selects a menubar cascade
    pushbutton, but before the pulldown menu is posted.  */
 
 /* This callback is invoked when the user selects a menubar cascade
    pushbutton, but before the pulldown menu is posted.  */
 
@@ -1233,6 +1159,63 @@ popup_activate_callback (widget, id, client_data)
   popup_activated_flag = 1;
 }
 
   popup_activated_flag = 1;
 }
 
+/* This callback is invoked when a dialog or menu is finished being
+   used and has been unposted.  */
+
+static void
+popup_deactivate_callback (widget, id, client_data)
+     Widget widget;
+     LWLIB_ID id;
+     XtPointer client_data;
+{
+  popup_activated_flag = 0;
+}
+
+/* Lwlib callback called when menu items are highlighted/unhighlighted
+   while moving the mouse over them.  WIDGET is the menu bar or menu
+   popup widget.  ID is its LWLIB_ID.  CALL_DATA contains a pointer to
+   the widget_value structure for the menu item, or null in case of
+   unhighlighting.  */
+
+void
+menu_highlight_callback (widget, id, call_data)
+     Widget widget;
+     LWLIB_ID id;
+     void *call_data;
+{
+  widget_value *wv = (widget_value *) call_data;
+  struct frame *f;
+  Lisp_Object frame, help;
+
+  help = wv && wv->help ? build_string (wv->help) : Qnil;
+  
+  /* Determine the frame for the help event.  */
+  f = menubar_id_to_frame (id);
+  if (f)
+    {
+      XSETFRAME (frame, f);
+      kbd_buffer_store_help_event (frame, help);
+    }
+  else
+    {
+      /* WIDGET is the popup menu.  It's parent is the frame's 
+        widget.  See which frame that is.  */
+      Widget frame_widget = XtParent (widget);
+      Lisp_Object tail;
+
+      for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+       {
+         frame = XCAR (tail);
+         if (GC_FRAMEP (frame)
+             && (f = XFRAME (frame),
+                 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
+           break;
+       }
+
+      show_help_echo (help, Qnil, Qnil, Qnil, 1);
+    }
+}
+
 /* This callback is called from the menu bar pulldown menu
    when the user makes a selection.
    Figure out what the user chose
 /* This callback is called from the menu bar pulldown menu
    when the user makes a selection.
    Figure out what the user chose
@@ -1253,6 +1236,7 @@ menubar_selection_callback (widget, id, client_data)
 
   if (!f)
     return;
 
   if (!f)
     return;
+  entry = Qnil;
   subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
   vector = f->menu_bar_vector;
   prefix = Qnil;
   subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
   vector = f->menu_bar_vector;
   prefix = Qnil;
@@ -1287,27 +1271,31 @@ menubar_selection_callback (widget, id, client_data)
              Lisp_Object frame;
 
              XSETFRAME (frame, f);
              Lisp_Object frame;
 
              XSETFRAME (frame, f);
-             buf.kind = menu_bar_event;
-             buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
+             buf.kind = MENU_BAR_EVENT;
+             buf.frame_or_window = frame;
+             buf.arg = frame;
              kbd_buffer_store_event (&buf);
 
              for (j = 0; j < submenu_depth; j++)
                if (!NILP (subprefix_stack[j]))
                  {
              kbd_buffer_store_event (&buf);
 
              for (j = 0; j < submenu_depth; j++)
                if (!NILP (subprefix_stack[j]))
                  {
-                   buf.kind = menu_bar_event;
-                   buf.frame_or_window = Fcons (frame, subprefix_stack[j]);
+                   buf.kind = MENU_BAR_EVENT;
+                   buf.frame_or_window = frame;
+                   buf.arg = subprefix_stack[j];
                    kbd_buffer_store_event (&buf);
                  }
 
              if (!NILP (prefix))
                {
                    kbd_buffer_store_event (&buf);
                  }
 
              if (!NILP (prefix))
                {
-                 buf.kind = menu_bar_event;
-                 buf.frame_or_window = Fcons (frame, prefix);
+                 buf.kind = MENU_BAR_EVENT;
+                 buf.frame_or_window = frame;
+                 buf.arg = prefix;
                  kbd_buffer_store_event (&buf);
                }
 
                  kbd_buffer_store_event (&buf);
                }
 
-             buf.kind = menu_bar_event;
-             buf.frame_or_window = Fcons (frame, entry);
+             buf.kind = MENU_BAR_EVENT;
+             buf.frame_or_window = frame;
+             buf.arg = entry;
              kbd_buffer_store_event (&buf);
 
              return;
              kbd_buffer_store_event (&buf);
 
              return;
@@ -1317,18 +1305,6 @@ menubar_selection_callback (widget, id, client_data)
     }
 }
 
     }
 }
 
-/* This callback is invoked when a dialog or menu is finished being
-   used and has been unposted.  */
-
-static void
-popup_deactivate_callback (widget, id, client_data)
-     Widget widget;
-     LWLIB_ID id;
-     XtPointer client_data;
-{
-  popup_activated_flag = 0;
-}
-
 /* Allocate a widget_value, blocking input.  */
 
 widget_value *
 /* Allocate a widget_value, blocking input.  */
 
 widget_value *
@@ -1386,7 +1362,6 @@ single_submenu (item_key, item_name, maps)
   int len;
   Lisp_Object *mapvec;
   widget_value **submenu_stack;
   int len;
   Lisp_Object *mapvec;
   widget_value **submenu_stack;
-  int mapno;
   int previous_items = menu_items_used;
   int top_level_items = 0;
 
   int previous_items = menu_items_used;
   int top_level_items = 0;
 
@@ -1408,17 +1383,17 @@ single_submenu (item_key, item_name, maps)
   for (i = 0; i < len; i++)
     {
       if (SYMBOLP (mapvec[i])
   for (i = 0; i < len; i++)
     {
       if (SYMBOLP (mapvec[i])
-         || (CONSP (mapvec[i])
-             && NILP (Fkeymapp (mapvec[i]))))
+         || (CONSP (mapvec[i]) && !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);
        {
          /* 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);
+         push_menu_item (item_name, Qt, item_key, mapvec[i],
+                         Qnil, Qnil, Qnil, Qnil);
        }
       else
        }
       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
     }
 
   /* Create a tree of widget_value objects
@@ -1430,6 +1405,7 @@ single_submenu (item_key, item_name, maps)
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
+  wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
   save_wv = 0;
   prev_wv = 0;
   first_wv = wv;
   save_wv = 0;
   prev_wv = 0;
@@ -1466,8 +1442,17 @@ single_submenu (item_key, item_name, maps)
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
          char *pane_string;
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
          char *pane_string;
+         
          pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
          prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
          pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
          prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+         
+#ifndef HAVE_MULTILINGUAL_MENU
+         if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+           {
+             pane_name = string_make_unibyte (pane_name);
+             AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
+           }
+#endif
          pane_string = (NILP (pane_name)
                         ? "" : (char *) XSTRING (pane_name)->data);
          /* If there is just one top-level pane, put all its items directly
          pane_string = (NILP (pane_name)
                         ? "" : (char *) XSTRING (pane_name)->data);
          /* If there is just one top-level pane, put all its items directly
@@ -1492,6 +1477,7 @@ single_submenu (item_key, item_name, maps)
                wv->name++;
              wv->value = 0;
              wv->enabled = 1;
                wv->name++;
              wv->value = 0;
              wv->enabled = 1;
+             wv->button_type = BUTTON_TYPE_NONE;
            }
          save_wv = wv;
          prev_wv = 0;
            }
          save_wv = wv;
          prev_wv = 0;
@@ -1500,12 +1486,30 @@ single_submenu (item_key, item_name, maps)
       else
        {
          /* Create a new item within current pane.  */
       else
        {
          /* Create a new item within current pane.  */
-         Lisp_Object item_name, enable, descrip, def;
-         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];
-         def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
+         Lisp_Object item_name, enable, descrip, def, type, selected;
+         Lisp_Object 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);
+
+#ifndef HAVE_MULTILINGUAL_MENU
+          if (STRING_MULTIBYTE (item_name))
+           {
+             item_name = string_make_unibyte (item_name);
+             AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
+           }
+         
+          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+           {
+             descrip = string_make_unibyte (descrip);
+             AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
+           }
+#endif /* not HAVE_MULTILINGUAL_MENU */
 
          wv = xmalloc_widget_value ();
          if (prev_wv) 
 
          wv = xmalloc_widget_value ();
          if (prev_wv) 
@@ -1521,6 +1525,20 @@ single_submenu (item_key, item_name, maps)
             as long as pointers have enough bits to hold small integers.  */
          wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
          wv->enabled = !NILP (enable);
             as long as pointers have enough bits to hold small integers.  */
          wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
          wv->enabled = !NILP (enable);
+         
+         if (NILP (type))
+           wv->button_type = BUTTON_TYPE_NONE;
+         else if (EQ (type, QCradio))
+           wv->button_type = BUTTON_TYPE_RADIO;
+         else if (EQ (type, QCtoggle))
+           wv->button_type = BUTTON_TYPE_TOGGLE;
+         else
+           abort ();
+
+         wv->selected = !NILP (selected);
+         if (STRINGP (help))
+           wv->help = XSTRING (help)->data;
+                  
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
@@ -1538,57 +1556,42 @@ single_submenu (item_key, item_name, maps)
 
   return first_wv;
 }
 
   return first_wv;
 }
-\f
-extern void EmacsFrameSetCharSize ();
 
 
-/* Recompute all the widgets of frame F, when the menu bar
-   has been changed.  */
 
 
-static void
+\f
+/* Recompute all the widgets of frame F, when the menu bar has been
+   changed.  Value is non-zero if widgets were updated.  */
+
+static int
 update_frame_menubar (f)
      FRAME_PTR f;
 {
   struct x_output *x = f->output_data.x;
   int columns, rows;
 update_frame_menubar (f)
      FRAME_PTR f;
 {
   struct x_output *x = f->output_data.x;
   int columns, rows;
-  int menubar_changed;
   
   
-  Dimension shell_height;
-
-  /* We assume the menubar contents has changed if the global flag is set,
-     or if the current buffer has changed, or if the menubar has never
-     been updated before.
-   */
-  menubar_changed = (x->menubar_widget
-                    && !XtIsManaged (x->menubar_widget));
-
-  if (! (menubar_changed))
-    return;
+  if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
+    return 0;
 
   BLOCK_INPUT;
 
   BLOCK_INPUT;
-  /* Save the size of the frame because the pane widget doesn't accept to
-     resize itself. So force it.  */
+  /* Save the size of the frame because the pane widget doesn't accept
+     to resize itself. So force it.  */
   columns = f->width;
   rows = f->height;
 
   columns = f->width;
   rows = f->height;
 
-  /* Do the voodoo which means "I'm changing lots of things, don't try to
-     refigure sizes until I'm done." */
+  /* Do the voodoo which means "I'm changing lots of things, don't try
+     to refigure sizes until I'm done."  */
   lw_refigure_widget (x->column_widget, False);
 
   lw_refigure_widget (x->column_widget, False);
 
-  /* the order in which children are managed is the top to
-     bottom order in which they are displayed in the paned window.
-     First, remove the text-area widget.
-   */
+  /* The order in which children are managed is the top to bottom
+     order in which they are displayed in the paned window.  First,
+     remove the text-area widget.  */
   XtUnmanageChild (x->edit_widget);
 
   XtUnmanageChild (x->edit_widget);
 
-  /* remove the menubar that is there now, and put up the menubar that
-     should be there.
-   */
-  if (menubar_changed)
-    {
-      XtManageChild (x->menubar_widget);
-      XtMapWidget (x->menubar_widget);
-      XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0);
-    }
+  /* Remove the menubar that is there now, and put up the menubar that
+     should be there.  */
+  XtManageChild (x->menubar_widget);
+  XtMapWidget (x->menubar_widget);
+  XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
 
   /* Re-manage the text-area widget, and then thrash the sizes.  */
   XtManageChild (x->edit_widget);
 
   /* Re-manage the text-area widget, and then thrash the sizes.  */
   XtManageChild (x->edit_widget);
@@ -1596,8 +1599,8 @@ update_frame_menubar (f)
 
   /* Force the pane widget to resize itself with the right values.  */
   EmacsFrameSetCharSize (x->edit_widget, columns, rows);
 
   /* Force the pane widget to resize itself with the right values.  */
   EmacsFrameSetCharSize (x->edit_widget, columns, rows);
-
   UNBLOCK_INPUT;
   UNBLOCK_INPUT;
+  return 1;
 }
 
 /* Set the contents of the menubar widgets of frame F.
 }
 
 /* Set the contents of the menubar widgets of frame F.
@@ -1611,11 +1614,13 @@ set_frame_menubar (f, first_time, deep_p)
      int deep_p;
 {
   Widget menubar_widget = f->output_data.x->menubar_widget;
      int deep_p;
 {
   Widget menubar_widget = f->output_data.x->menubar_widget;
-  Lisp_Object tail, items, frame;
+  Lisp_Object items;
   widget_value *wv, *first_wv, *prev_wv = 0;
   int i;
   LWLIB_ID id;
 
   widget_value *wv, *first_wv, *prev_wv = 0;
   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 (f->output_data.x->id == 0)
     f->output_data.x->id = next_menubar_widget_id++;
   id = f->output_data.x->id;
@@ -1636,6 +1641,7 @@ set_frame_menubar (f, first_time, deep_p)
   wv->name = "menubar";
   wv->value = 0;
   wv->enabled = 1;
   wv->name = "menubar";
   wv->value = 0;
   wv->enabled = 1;
+  wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
 
   if (deep_p)
   first_wv = wv;
 
   if (deep_p)
@@ -1650,13 +1656,18 @@ set_frame_menubar (f, first_time, deep_p)
        = (Lisp_Object *) alloca (previous_menu_items_used
                                  * sizeof (Lisp_Object));
 
        = (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);
 
       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 (Fset_match_data, Fmatch_data (Qnil, Qnil));
       if (NILP (Voverriding_local_map_menu_flag))
        {
          specbind (Qoverriding_terminal_local_map, Qnil);
       if (NILP (Voverriding_local_map_menu_flag))
        {
          specbind (Qoverriding_terminal_local_map, Qnil);
@@ -1666,7 +1677,8 @@ set_frame_menubar (f, first_time, deep_p)
       set_buffer_internal_1 (XBUFFER (buffer));
 
       /* Run the Lucid hook.  */
       set_buffer_internal_1 (XBUFFER (buffer));
 
       /* Run the Lucid hook.  */
-      call1 (Vrun_hooks, Qactivate_menubar_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))
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag))
@@ -1679,12 +1691,13 @@ set_frame_menubar (f, first_time, deep_p)
       inhibit_garbage_collection ();
 
       /* Save the frame's previous menu bar contents data.  */
       inhibit_garbage_collection ();
 
       /* Save the frame's previous menu bar contents data.  */
-      bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
-            previous_menu_items_used * sizeof (Lisp_Object));
+      if (previous_menu_items_used)
+       bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
+              previous_menu_items_used * sizeof (Lisp_Object));
 
       /* Fill in the current menu bar contents.  */
       menu_items = f->menu_bar_vector;
 
       /* Fill in the current menu bar contents.  */
       menu_items = f->menu_bar_vector;
-      menu_items_allocated = XVECTOR (menu_items)->size;
+      menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
       init_menu_items ();
       for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
       init_menu_items ();
       for (i = 0; i < XVECTOR (items)->size; i += 4)
        {
@@ -1703,6 +1716,7 @@ set_frame_menubar (f, first_time, deep_p)
            first_wv->contents = wv;
          /* Don't set wv->name here; GC during the loop might relocate it.  */
          wv->enabled = 1;
            first_wv->contents = wv;
          /* Don't set wv->name here; GC during the loop might relocate it.  */
          wv->enabled = 1;
+         wv->button_type = BUTTON_TYPE_NONE;
          prev_wv = wv;
        }
 
          prev_wv = wv;
        }
 
@@ -1716,7 +1730,7 @@ set_frame_menubar (f, first_time, deep_p)
 
       for (i = 0; i < previous_menu_items_used; i++)
        if (menu_items_used == i
 
       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)
        {
          break;
       if (i == menu_items_used && i == previous_menu_items_used && i != 0)
        {
@@ -1761,6 +1775,7 @@ set_frame_menubar (f, first_time, deep_p)
          wv->name = (char *) XSTRING (string)->data;
          wv->value = 0;
          wv->enabled = 1;
          wv->name = (char *) XSTRING (string)->data;
          wv->value = 0;
          wv->enabled = 1;
+         wv->button_type = BUTTON_TYPE_NONE;
          /* This prevents lwlib from assuming this
             menu item is really supposed to be empty.  */
          /* The EMACS_INT cast avoids a warning.
          /* This prevents lwlib from assuming this
             menu item is really supposed to be empty.  */
          /* The EMACS_INT cast avoids a warning.
@@ -1803,7 +1818,8 @@ set_frame_menubar (f, first_time, deep_p)
                                         0,
                                         popup_activate_callback,
                                         menubar_selection_callback,
                                         0,
                                         popup_activate_callback,
                                         menubar_selection_callback,
-                                        popup_deactivate_callback);
+                                        popup_deactivate_callback,
+                                        menu_highlight_callback);
       f->output_data.x->menubar_widget = menubar_widget;
     }
 
       f->output_data.x->menubar_widget = menubar_widget;
     }
 
@@ -1814,6 +1830,8 @@ set_frame_menubar (f, first_time, deep_p)
            + f->output_data.x->menubar_widget->core.border_width)
         : 0);
 
            + 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))
       {
 #ifdef USE_LUCID
     if (FRAME_EXTERNAL_MENU_BAR (f))
       {
@@ -1823,12 +1841,12 @@ set_frame_menubar (f, first_time, deep_p)
         menubar_size += ibw;
       }
 #endif /* USE_LUCID */
         menubar_size += ibw;
       }
 #endif /* USE_LUCID */
+#endif /* 0 */
 
     f->output_data.x->menubar_height = menubar_size;
   }
   
   free_menubar_widget_value_tree (first_wv);
 
     f->output_data.x->menubar_height = menubar_size;
   }
   
   free_menubar_widget_value_tree (first_wv);
-
   update_frame_menubar (f);
 
   UNBLOCK_INPUT;
   update_frame_menubar (f);
 
   UNBLOCK_INPUT;
@@ -1849,6 +1867,7 @@ initialize_frame_menubar (f)
   set_frame_menubar (f, 1, 1);
 }
 
   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.  */
 
 /* 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.  */
 
@@ -1857,14 +1876,44 @@ free_frame_menubar (f)
      FRAME_PTR f;
 {
   Widget menubar_widget;
      FRAME_PTR f;
 {
   Widget menubar_widget;
-  int id;
 
   menubar_widget = f->output_data.x->menubar_widget;
 
   menubar_widget = f->output_data.x->menubar_widget;
+
+  f->output_data.x->menubar_height = 0;
   
   if (menubar_widget)
     {
   
   if (menubar_widget)
     {
+#ifdef USE_MOTIF
+      /* Removing the menu bar magically changes the shell widget's x
+        and y position of (0, 0) which, when the menu bar is turned
+        on again, leads to pull-down menuss appearing in strange
+        positions near the upper-left corner of the display.  This
+        happens only with some window managers like twm and ctwm,
+        but not with other like Motif's mwm or kwm, because the
+        latter generate ConfigureNotify events when the menu bar
+        is switched off, which fixes the shell position.  */
+      Position x0, y0, x1, y1;
+#endif
+      
       BLOCK_INPUT;
       BLOCK_INPUT;
+
+#ifdef USE_MOTIF
+      if (f->output_data.x->widget)
+       XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
+#endif
+      
       lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
       lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
+      f->output_data.x->menubar_widget = NULL;
+
+#ifdef USE_MOTIF
+      if (f->output_data.x->widget)
+       {
+         XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
+         if (x1 == 0 && y1 == 0)
+           XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
+       }
+#endif
+      
       UNBLOCK_INPUT;
     }
 }
       UNBLOCK_INPUT;
     }
 }
@@ -1899,11 +1948,7 @@ free_frame_menubar (f)
    next_menubar_widget_id.  */
 LWLIB_ID widget_id_tick;
 
    next_menubar_widget_id.  */
 LWLIB_ID widget_id_tick;
 
-#ifdef __STDC__
 static Lisp_Object *volatile menu_item_selection;
 static Lisp_Object *volatile menu_item_selection;
-#else
-static Lisp_Object *menu_item_selection;
-#endif
 
 static void
 popup_selection_callback (widget, id, client_data)
 
 static void
 popup_selection_callback (widget, id, client_data)
@@ -1938,7 +1983,6 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   XButtonPressedEvent dummy;
 
   int first_pane;
   XButtonPressedEvent dummy;
 
   int first_pane;
-  int next_release_must_exit = 0;
 
   *error = NULL;
 
 
   *error = NULL;
 
@@ -1954,6 +1998,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
   wv->name = "menu";
   wv->value = 0;
   wv->enabled = 1;
+  wv->button_type = BUTTON_TYPE_NONE;
   first_wv = wv;
   first_pane = 1;
  
   first_wv = wv;
   first_pane = 1;
  
@@ -1988,8 +2033,17 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
          char *pane_string;
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
          char *pane_string;
-         pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
-         prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+         
+         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 = string_make_unibyte (pane_name);
+             AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
+           }
+#endif
          pane_string = (NILP (pane_name)
                         ? "" : (char *) XSTRING (pane_name)->data);
          /* If there is just one top-level pane, put all its items directly
          pane_string = (NILP (pane_name)
                         ? "" : (char *) XSTRING (pane_name)->data);
          /* If there is just one top-level pane, put all its items directly
@@ -2012,6 +2066,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
                wv->name++;
              wv->value = 0;
              wv->enabled = 1;
                wv->name++;
              wv->value = 0;
              wv->enabled = 1;
+             wv->button_type = BUTTON_TYPE_NONE;
              save_wv = wv;
              prev_wv = 0;
            }
              save_wv = wv;
              prev_wv = 0;
            }
@@ -2026,13 +2081,29 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
       else
        {
          /* Create a new item within current pane.  */
       else
        {
          /* Create a new item within current pane.  */
-         Lisp_Object item_name, enable, descrip, def;
-         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];
-         def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
-
+         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);
+
+#ifndef HAVE_MULTILINGUAL_MENU
+          if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
+           {
+             item_name = string_make_unibyte (item_name);
+             AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
+           }
+         
+          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+           {
+             descrip = string_make_unibyte (descrip);
+             AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
+           }
+#endif /* not HAVE_MULTILINGUAL_MENU */
          wv = xmalloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
          wv = xmalloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
@@ -2048,6 +2119,20 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
          wv->call_data
            = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
          wv->enabled = !NILP (enable);
          wv->call_data
            = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
          wv->enabled = !NILP (enable);
+
+         if (NILP (type))
+           wv->button_type = BUTTON_TYPE_NONE;
+         else if (EQ (type, QCtoggle))
+           wv->button_type = BUTTON_TYPE_TOGGLE;
+         else if (EQ (type, QCradio))
+           wv->button_type = BUTTON_TYPE_RADIO;
+         else
+           abort ();
+
+         wv->selected = !NILP (selected);
+         if (STRINGP (help))
+           wv->help = XSTRING (help)->data;
+         
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
          prev_wv = wv;
 
          i += MENU_ITEMS_ITEM_LENGTH;
@@ -2067,8 +2152,14 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
       wv_sep1->name = "--";
       wv_sep1->next = wv_sep2;
 
       wv_sep1->name = "--";
       wv_sep1->next = wv_sep2;
 
+#ifndef HAVE_MULTILINGUAL_MENU
+      if (STRING_MULTIBYTE (title))
+       title = string_make_unibyte (title);
+#endif
+      
       wv_title->name = (char *) XSTRING (title)->data;
       wv_title->enabled = True;
       wv_title->name = (char *) XSTRING (title)->data;
       wv_title->enabled = True;
+      wv_title->button_type = BUTTON_TYPE_NONE;
       wv_title->next = wv_sep1;
       first_wv->contents = wv_title;
     }
       wv_title->next = wv_sep1;
       first_wv->contents = wv_title;
     }
@@ -2078,7 +2169,8 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
                           f->output_data.x->widget, 1, 0,
                           popup_selection_callback,
   menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
                           f->output_data.x->widget, 1, 0,
                           popup_selection_callback,
-                          popup_deactivate_callback);
+                          popup_deactivate_callback,
+                          menu_highlight_callback);
 
   /* Adjust coordinates to relative to the outer (window manager) window.  */
   {
 
   /* Adjust coordinates to relative to the outer (window manager) window.  */
   {
@@ -2140,7 +2232,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   menu_item_selection = 0;
 
   /* Display the menu.  */
   menu_item_selection = 0;
 
   /* Display the menu.  */
-  lw_popup_menu (menu, &dummy);
+  lw_popup_menu (menu, (XEvent *) &dummy);
   popup_activated_flag = 1;
 
   /* Process events that apply to the menu.  */
   popup_activated_flag = 1;
 
   /* Process events that apply to the menu.  */
@@ -2158,7 +2250,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
     {
       Lisp_Object prefix, entry;
 
     {
       Lisp_Object prefix, entry;
 
-      prefix = Qnil;
+      prefix = entry = Qnil;
       i = 0;
       while (i < menu_items_used)
        {
       i = 0;
       while (i < menu_items_used)
        {
@@ -2242,7 +2334,7 @@ xdialog_show (f, keymaps, title, error)
   Widget menu;
   char dialog_name[6];
 
   Widget menu;
   char dialog_name[6];
 
-  widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
+  widget_value *wv, *first_wv = 0, *prev_wv = 0;
 
   /* Number of elements seen so far, before boundary.  */
   int left_count = 0;
 
   /* Number of elements seen so far, before boundary.  */
   int left_count = 0;
@@ -2300,7 +2392,7 @@ xdialog_show (f, keymaps, title, error)
            i++;
            continue;
          }
            i++;
            continue;
          }
-       if (nb_buttons >= 10)
+       if (nb_buttons >= 9)
          {
            free_menubar_widget_value_tree (first_wv);
            *error = "Too many dialog items";
          {
            free_menubar_widget_value_tree (first_wv);
            *error = "Too many dialog items";
@@ -2351,7 +2443,7 @@ xdialog_show (f, keymaps, title, error)
   dialog_id = widget_id_tick++;
   menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
                           f->output_data.x->widget, 1, 0,
   dialog_id = widget_id_tick++;
   menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
                           f->output_data.x->widget, 1, 0,
-                          dialog_selection_callback, 0);
+                          dialog_selection_callback, 0, 0);
   lw_modify_all_widgets (dialog_id, first_wv->contents, True);
   /* Free the widget_value objects we used to specify the contents.  */
   free_menubar_widget_value_tree (first_wv);
   lw_modify_all_widgets (dialog_id, first_wv->contents, True);
   /* Free the widget_value objects we used to specify the contents.  */
   free_menubar_widget_value_tree (first_wv);
@@ -2386,6 +2478,12 @@ xdialog_show (f, keymaps, title, error)
                = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
              i += MENU_ITEMS_PANE_LENGTH;
            }
                = 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
          else
            {
              entry
@@ -2407,8 +2505,52 @@ xdialog_show (f, keymaps, title, error)
 
   return Qnil;
 }
 
   return Qnil;
 }
+
 #else /* not USE_X_TOOLKIT */
 
 #else /* not USE_X_TOOLKIT */
 
+/* The frame of the last activated non-toolkit menu bar.
+   Used to generate menu help events.  */
+
+static struct frame *menu_help_frame;
+
+
+/* Show help HELP_STRING, or clear help if HELP_STRING is null.
+
+   PANE is the pane number, and ITEM is the menu item number in
+   the menu (currently not used).
+   
+   This cannot be done with generating a HELP_EVENT because
+   XMenuActivate contains a loop that doesn't let Emacs process
+   keyboard events.  */
+
+static void
+menu_help_callback (help_string, pane, item)
+     char *help_string;
+     int pane, item;
+{
+  extern Lisp_Object Qmenu_item;
+  Lisp_Object *first_item;
+  Lisp_Object pane_name;
+  Lisp_Object menu_object;
+  first_item = XVECTOR (menu_items)->contents;
+  if (EQ (first_item[0], Qt))
+    pane_name = first_item[MENU_ITEMS_PANE_NAME];
+  else if (EQ (first_item[0], Qquote))
+    /* This shouldn't happen, see xmenu_show.  */
+    pane_name = build_string ("");
+  else
+    pane_name = first_item[MENU_ITEMS_ITEM_NAME];
+  /* (menu-item MENU-NAME PANE-NUMBER)  */
+  menu_object = Fcons (Qmenu_item,
+                      Fcons (pane_name,
+                             Fcons (make_number (pane), Qnil)));
+  show_help_echo (help_string ? build_string (help_string) : Qnil,
+                 Qnil, menu_object, make_number (item), 1);
+}
+  
+
 static Lisp_Object
 xmenu_show (f, x, y, for_click, keymaps, title, error)
      FRAME_PTR f;
 static Lisp_Object
 xmenu_show (f, x, y, for_click, keymaps, title, error)
      FRAME_PTR f;
@@ -2526,7 +2668,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
                  j++;
                  continue;
                }
                  j++;
                  continue;
                }
-             width = XSTRING (item)->size;
+             width = STRING_BYTES (XSTRING (item));
              if (width > maxwidth)
                maxwidth = width;
 
              if (width > maxwidth)
                maxwidth = width;
 
@@ -2540,16 +2682,20 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
       else
        {
          /* Create a new item within current pane.  */
       else
        {
          /* Create a new item within current pane.  */
-         Lisp_Object item_name, enable, descrip;
+         Lisp_Object item_name, enable, descrip, help;
          unsigned char *item_data;
          unsigned char *item_data;
+         char *help_string;
 
          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];
 
          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];
+         help_string = STRINGP (help) ? XSTRING (help)->data : NULL;
+         
          if (!NILP (descrip))
            {
          if (!NILP (descrip))
            {
-             int gap = maxwidth - XSTRING (item_name)->size;
+             int gap = maxwidth - STRING_BYTES (XSTRING (item_name));
 #ifdef C_ALLOCA
              Lisp_Object spacer;
              spacer = Fmake_string (make_number (gap), make_number (' '));
 #ifdef C_ALLOCA
              Lisp_Object spacer;
              spacer = Fmake_string (make_number (gap), make_number (' '));
@@ -2561,14 +2707,14 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
                 to reduce gc needs.  */
              item_data
                = (unsigned char *) alloca (maxwidth
                 to reduce gc needs.  */
              item_data
                = (unsigned char *) alloca (maxwidth
-                                           + XSTRING (descrip)->size + 1);
+                                           + STRING_BYTES (XSTRING (descrip)) + 1);
              bcopy (XSTRING (item_name)->data, item_data,
              bcopy (XSTRING (item_name)->data, item_data,
-                    XSTRING (item_name)->size);
+                    STRING_BYTES (XSTRING (item_name)));
              for (j = XSTRING (item_name)->size; j < maxwidth; j++)
                item_data[j] = ' ';
              bcopy (XSTRING (descrip)->data, item_data + j,
              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;
+                    STRING_BYTES (XSTRING (descrip)));
+             item_data[j + STRING_BYTES (XSTRING (descrip))] = 0;
 #endif
            }
          else
 #endif
            }
          else
@@ -2576,7 +2722,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 
          if (XMenuAddSelection (FRAME_X_DISPLAY (f),
                                 menu, lpane, 0, item_data,
 
          if (XMenuAddSelection (FRAME_X_DISPLAY (f),
                                 menu, lpane, 0, item_data,
-                                !NILP (enable))
+                                !NILP (enable), help_string)
              == XM_FAILURE)
            {
              XMenuDestroy (FRAME_X_DISPLAY (f), menu);
              == XM_FAILURE)
            {
              XMenuDestroy (FRAME_X_DISPLAY (f), menu);
@@ -2589,10 +2735,8 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 
   /* All set and ready to fly.  */
   XMenuRecompute (FRAME_X_DISPLAY (f), menu);
 
   /* All set and ready to fly.  */
   XMenuRecompute (FRAME_X_DISPLAY (f), menu);
-  dispwidth = DisplayWidth (FRAME_X_DISPLAY (f),
-                           XScreenNumberOfScreen (FRAME_X_SCREEN (f)));
-  dispheight = DisplayHeight (FRAME_X_DISPLAY (f),
-                             XScreenNumberOfScreen (FRAME_X_SCREEN (f)));
+  dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
+  dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
   x = min (x, dispwidth);
   y = min (y, dispheight);
   x = max (x, 1);
   x = min (x, dispwidth);
   y = min (y, dispheight);
   x = max (x, 1);
@@ -2615,9 +2759,13 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   XMenuSetAEQ (menu, TRUE);
   XMenuSetFreeze (menu, TRUE);
   pane = selidx = 0;
   XMenuSetAEQ (menu, TRUE);
   XMenuSetFreeze (menu, TRUE);
   pane = selidx = 0;
-  
+
+  /* Help display under X won't work because XMenuActivate contains
+     a loop that doesn't give Emacs a chance to process it.  */
+  menu_help_frame = f;
   status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
   status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
-                         x, y, ButtonReleaseMask, &datap);
+                         x, y, ButtonReleaseMask, &datap,
+                         menu_help_callback);
 
 
 #ifdef HAVE_X_WINDOWS
 
 
 #ifdef HAVE_X_WINDOWS
@@ -2692,17 +2840,20 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 
 #endif /* HAVE_MENUS */
 \f
 
 #endif /* HAVE_MENUS */
 \f
+void
 syms_of_xmenu ()
 {
   staticpro (&menu_items);
   menu_items = Qnil;
 
 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);
 
   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.
+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;
 #ifdef USE_X_TOOLKIT
   widget_id_tick = (1<<16);    
   next_menubar_widget_id = 1;