(server-process-filter): Ignore lines that don't start
[bpt/emacs.git] / src / xmenu.c
index 224fc7f..993ae91 100644 (file)
@@ -41,6 +41,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "keyboard.h"
 #include "blockinput.h"
 #include "puresize.h"
+#include "buffer.h"
 
 #ifdef MSDOS
 #include "msdos.h"
@@ -67,6 +68,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <X11/CoreP.h>
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
+#include <X11/Xaw/Paned.h>
 #include "../lwlib/lwlib.h"
 #else /* not USE_X_TOOLKIT */
 #include "../oldXMenu/XMenu.h"
@@ -81,11 +83,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define FALSE 0
 #endif /* no TRUE */
 
+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 Vdefine_key_rebound_commands;
+
+extern Lisp_Object Voverriding_local_map;
+extern Lisp_Object Voverriding_local_map_menu_flag;
+
+extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
+
+extern Lisp_Object Qmenu_bar_update_hook;
+
 #ifdef USE_X_TOOLKIT
+extern void set_frame_menubar ();
 extern void process_expose_from_menu ();
 extern XtAppContext Xt_app_con;
 
@@ -151,47 +165,34 @@ static int menu_items_submenu_depth;
    Xt on behalf of one of the widget sets.  */
 static int popup_activated_flag;
 
-/* This holds a Lisp vector
-   which contains frames that have menu bars.
-   Each frame that has a menu bar is found at some index in this vector
-   and the menu bar widget refers to the frame through that index.  */
-static Lisp_Object frame_vector;
+static int next_menubar_widget_id;
 \f
-/* Return the index of FRAME in frame_vector.
-   If FRAME isn't in frame_vector yet, put it in,
-   lengthening the vector if necessary.  */
-
-static int
-frame_vector_add_frame (f)
-     FRAME_PTR *f;
-{
-  int length = XVECTOR (frame_vector)->size;
-  int i, empty = -1;
-  Lisp_Object new, frame;
+#ifdef USE_X_TOOLKIT
 
-  XSETFRAME (frame, f);
+/* Return the frame whose ->output_data.x->id equals ID, or 0 if none.  */
 
-  for (i = 0; i < length; i++)
-    {
-      if (EQ (frame, XVECTOR (frame_vector)->contents[i]))
-       return i;
-      if (NILP (XVECTOR (frame_vector)->contents[i]))
-       empty = i;
-    }
+static struct frame *
+menubar_id_to_frame (id)
+     LWLIB_ID id;
+{
+  Lisp_Object tail, frame;
+  FRAME_PTR f;
 
-  if (empty >= 0)
+  for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr)
     {
-      XVECTOR (frame_vector)->contents[empty] = frame;
-      return empty;
+      frame = XCONS (tail)->car;
+      if (!GC_FRAMEP (frame))
+        continue;
+      f = XFRAME (frame);
+      if (f->output_data.nothing == 1)
+       continue;
+      if (f->output_data.x->id == id)
+       return f;
     }
-
-  new = Fmake_vector (make_number (length * 2), Qnil);
-  bcopy (XVECTOR (frame_vector)->contents,
-        XVECTOR (new)->contents, sizeof (Lisp_Object) * length);
-  
-  XVECTOR (frame_vector)->contents[length] = frame;
-  return length;
+  return 0;
 }
+
+#endif
 \f
 /* Initialize the menu_items structure if we haven't already done so.
    Also mark it as currently empty.  */
@@ -379,9 +380,13 @@ menu_item_equiv_key (item_string, item1, descrip_ptr)
          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--
-        doing that takes too much time and makes menus too slow.  */
-      && !(!NILP (cachelist) && NILP (savedkey)))
+      /* 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;
@@ -427,6 +432,11 @@ 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;
 }
 
@@ -755,7 +765,6 @@ cached information about equivalent key sequences.")
   FRAME_PTR f;
   Lisp_Object x, y, window;
   int keymaps = 0;
-  int menubarp = 0;
   int for_click = 0;
   struct gcpro gcpro1;
 
@@ -764,7 +773,8 @@ cached information about equivalent key sequences.")
       check_x ();
 
       /* Decode the first argument: find the window and the coordinates.  */
-      if (EQ (position, Qt))
+      if (EQ (position, Qt)
+         || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
        {
          /* Use the mouse's current position.  */
          FRAME_PTR new_f = selected_frame;
@@ -801,11 +811,6 @@ cached information about equivalent key sequences.")
              tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
              x = Fcar (tem);
              y = Fcdr (tem);
-
-             /* Determine whether this menu is handling a menu bar click.  */
-             tem = Fcar (Fcdr (Fcar (Fcdr (position))));
-             if (CONSP (tem) && EQ (Fcar (tem), Qmenu_bar))
-               menubarp = 1;
            }
        }
 
@@ -825,8 +830,8 @@ cached information about equivalent key sequences.")
          CHECK_LIVE_WINDOW (window, 0);
          f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
 
-         xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left);
-         ypos = (f->display.x->line_height * XWINDOW (window)->top);
+         xpos = (FONT_WIDTH (f->output_data.x->font) * XWINDOW (window)->left);
+         ypos = (f->output_data.x->line_height * XWINDOW (window)->top);
        }
       else
        /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
@@ -918,7 +923,7 @@ cached information about equivalent key sequences.")
   /* Display them in a menu.  */
   BLOCK_INPUT;
 
-  selection = xmenu_show (f, xpos, ypos, menubarp, for_click,
+  selection = xmenu_show (f, xpos, ypos, for_click,
                          keymaps, title, &error_name);
   UNBLOCK_INPUT;
 
@@ -954,7 +959,8 @@ on the left of the dialog box and all following items on the right.\n\
   check_x ();
 
   /* Decode the first argument: find the window or frame to use.  */
-  if (EQ (position, Qt))
+  if (EQ (position, Qt)
+      || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
     {
 #if 0 /* Using the frame the mouse is on may not be right.  */
       /* Use the mouse's current position.  */
@@ -971,9 +977,7 @@ on the left of the dialog box and all following items on the right.\n\
       else
        window = selected_window;
 #endif
-      /* Decode the first argument: find the window and the coordinates.  */
-      if (EQ (position, Qt))
-       window = selected_window;
+      window = selected_window;
     }
   else if (CONSP (position))
     {
@@ -1031,7 +1035,7 @@ on the left of the dialog box and all following items on the right.\n\
 
     /* Display them in a dialog box.  */
     BLOCK_INPUT;
-    selection = xdialog_show (f, 0, 0, title, &error_name);
+    selection = xdialog_show (f, 0, title, &error_name);
     UNBLOCK_INPUT;
 
     discard_menu_items ();
@@ -1047,13 +1051,14 @@ on the left of the dialog box and all following items on the right.\n\
 /* Loop in Xt until the menu pulldown or dialog popup has been
    popped down (deactivated).
 
-   NOTE: All calls to popup_get_selection() should be protected
+   NOTE: All calls to popup_get_selection should be protected
    with BLOCK_INPUT, UNBLOCK_INPUT wrappers.  */
 
 void
-popup_get_selection (initial_event, dpyinfo)
+popup_get_selection (initial_event, dpyinfo, id)
      XEvent *initial_event;
      struct x_display_info *dpyinfo;
+     LWLIB_ID id;
 {
   XEvent event;
 
@@ -1082,14 +1087,24 @@ popup_get_selection (initial_event, dpyinfo)
       else if (event.type == ButtonRelease
               && dpyinfo->display == event.xbutton.display)
        dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+      /* 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
+              && dpyinfo->display == event.xbutton.display)
+       {
+         popup_activated_flag = 0;
+         break;
+       }
 
       /* Queue all events not for this popup,
-        except for Expose, which we've already handled.  */
+        except for Expose, which we've already handled.
+        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.xany.display != dpyinfo->display
-             || ! x_any_window_to_frame (dpyinfo, event.xany.window)))
+             || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
        {
-
          queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue));
 
          if (queue_tmp != NULL) 
@@ -1099,8 +1114,8 @@ popup_get_selection (initial_event, dpyinfo)
              queue = queue_tmp;
            }
        }
-
-      XtDispatchEvent (&event);
+      else
+       XtDispatchEvent (&event);
 
       if (!popup_activated ())
        break;
@@ -1119,6 +1134,36 @@ popup_get_selection (initial_event, dpyinfo)
     }
 }
 
+/* Activate the menu bar of frame F.
+   This is called from keyboard.c when it gets the
+   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 makes the toolkit do its thing.
+
+   But first we recompute the menu bar contents (the whole tree).
+
+   The reason for saving the button event until here, instead of
+   passing it to the toolkit right away, is that we can safely
+   execute Lisp code.  */
+   
+x_activate_menubar (f)
+     FRAME_PTR f;
+{
+  if (f->output_data.x->saved_button_event->type != ButtonPress)
+    return;
+
+  set_frame_menubar (f, 0, 1);
+
+  BLOCK_INPUT;
+  XtDispatchEvent ((XEvent *) f->output_data.x->saved_button_event);
+  UNBLOCK_INPUT;
+
+  /* Ignore this if we get it a second time.  */
+  f->output_data.x->saved_button_event->type = 0;
+}
+
 /* Detect if a dialog or menu has been posted.  */
 
 int
@@ -1151,8 +1196,8 @@ menubar_selection_callback (widget, id, client_data)
      LWLIB_ID id;
      XtPointer client_data;
 {
-  Lisp_Object prefix;
-  FRAME_PTR f = XFRAME (XVECTOR (frame_vector)->contents[id]);
+  Lisp_Object prefix, entry;
+  FRAME_PTR f = menubar_id_to_frame (id);
   Lisp_Object vector;
   Lisp_Object *subprefix_stack;
   int submenu_depth = 0;
@@ -1166,8 +1211,6 @@ menubar_selection_callback (widget, id, client_data)
   i = 0;
   while (i < f->menu_bar_items_used)
     {
-      Lisp_Object entry;
-
       if (EQ (XVECTOR (vector)->contents[i], Qnil))
        {
          subprefix_stack[submenu_depth++] = prefix;
@@ -1197,7 +1240,7 @@ menubar_selection_callback (widget, id, client_data)
 
              XSETFRAME (frame, f);
              buf.kind = menu_bar_event;
-             buf.frame_or_window = Fcons (frame, Qmenu_bar);
+             buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
              kbd_buffer_store_event (&buf);
 
              for (j = 0; j < submenu_depth; j++)
@@ -1284,6 +1327,7 @@ single_submenu (item_key, item_name, maps)
   widget_value **submenu_stack;
   int mapno;
   int previous_items = menu_items_used;
+  int top_level_items = 0;
 
   length = Flength (maps);
   len = XINT (length);
@@ -1301,7 +1345,16 @@ single_submenu (item_key, item_name, maps)
   /* Loop over the given keymaps, making a pane for each map.
      But don't make a pane that is empty--ignore that map instead.  */
   for (i = 0; i < len; i++)
-    single_keymap_panes (mapvec[i], item_name, item_key, 0);
+    {
+      if (SYMBOLP (mapvec[i]))
+       {
+         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);
+    }
 
   /* Create a tree of widget_value objects
      representing the panes and their items.  */
@@ -1314,6 +1367,7 @@ single_submenu (item_key, item_name, maps)
   wv->enabled = 1;
   first_wv = wv;
   save_wv = 0;
+  prev_wv = 0;
  
   /* Loop over all panes and items made during this call
      and construct a tree of widget_value objects.
@@ -1367,7 +1421,9 @@ single_submenu (item_key, item_name, maps)
              else
                first_wv->contents = wv;
              wv->name = pane_string;
-             if (!NILP (prefix))
+             /* Ignore the @ that means "separate pane".
+                This is a kludge, but this isn't worth more time.  */
+             if (!NILP (prefix) && wv->name[0] == '@')
                wv->name++;
              wv->value = 0;
              wv->enabled = 1;
@@ -1389,8 +1445,9 @@ single_submenu (item_key, item_name, maps)
          wv = malloc_widget_value ();
          if (prev_wv) 
            prev_wv->next = wv;
-         else 
+         else
            save_wv->contents = wv;
+
          wv->name = (char *) XSTRING (item_name)->data;
          if (!NILP (descrip))
            wv->key = (char *) XSTRING (descrip)->data;
@@ -1405,18 +1462,28 @@ single_submenu (item_key, item_name, maps)
        }
     }
 
+  /* If we have just one "menu item"
+     that was originally a button, return it by itself.  */
+  if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
+    {
+      wv = first_wv->contents;
+      free_widget_value (first_wv);
+      return wv;
+    }
+
   return first_wv;
 }
 \f
 extern void EmacsFrameSetCharSize ();
 
-/* Recompute the menu bar of frame F.  */
+/* Recompute all the widgets of frame F, when the menu bar
+   has been changed.  */
 
 static void
 update_frame_menubar (f)
      FRAME_PTR f;
 {
-  struct x_display *x = f->display.x;
+  struct x_output *x = f->output_data.x;
   int columns, rows;
   int menubar_changed;
   
@@ -1468,104 +1535,215 @@ update_frame_menubar (f)
   UNBLOCK_INPUT;
 }
 
+/* Set the contents of the menubar widgets of frame F.
+   The argument FIRST_TIME is currently ignored;
+   it is set the first time this is called, from initialize_frame_menubar.  */
+
 void
-set_frame_menubar (f, first_time)
+set_frame_menubar (f, first_time, deep_p)
      FRAME_PTR f;
      int first_time;
+     int deep_p;
 {
-  Widget menubar_widget = f->display.x->menubar_widget;
+  Widget menubar_widget = f->output_data.x->menubar_widget;
   Lisp_Object tail, items, frame;
   widget_value *wv, *first_wv, *prev_wv = 0;
   int i;
-  int id;
-  int count;
+  LWLIB_ID id;
 
-  count = inhibit_garbage_collection ();
+  if (f->output_data.x->id == 0)
+    f->output_data.x->id = next_menubar_widget_id++;
+  id = f->output_data.x->id;
 
-  id = frame_vector_add_frame (f);
+  if (! menubar_widget)
+    deep_p = 1;
 
   wv = malloc_widget_value ();
   wv->name = "menubar";
   wv->value = 0;
   wv->enabled = 1;
   first_wv = wv;
-  items = FRAME_MENU_BAR_ITEMS (f);
-  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)
+  if (deep_p)
     {
-      Lisp_Object key, string, maps;
+      /* Make a widget-value tree representing the entire menu trees.  */
+
+      struct buffer *prev = current_buffer;
+      Lisp_Object buffer;
+      int specpdl_count = specpdl_ptr - specpdl;
+      int previous_menu_items_used = f->menu_bar_items_used;
+      Lisp_Object *previous_items
+       = (Lisp_Object *) alloca (previous_menu_items_used
+                                 * sizeof (Lisp_Object));
+
+      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 ());
+      if (NILP (Voverriding_local_map_menu_flag))
+       {
+         specbind (Qoverriding_terminal_local_map, Qnil);
+         specbind (Qoverriding_local_map, Qnil);
+       }
 
-      key = XVECTOR (items)->contents[i];
-      string = XVECTOR (items)->contents[i + 1];
-      maps = XVECTOR (items)->contents[i + 2];
-      if (NILP (string))
-       break;
+      set_buffer_internal_1 (XBUFFER (buffer));
 
-      wv = single_submenu (key, string, maps);
-      if (prev_wv) 
-       prev_wv->next = wv;
-      else
-       first_wv->contents = wv;
-      /* Don't set wv->name here; GC during the loop might relocate it.  */
-      wv->enabled = 1;
-      prev_wv = wv;
-    }
+      /* Run the Lucid hook.  */
+      call1 (Vrun_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))
+       call0 (Qrecompute_lucid_menubar);
+      call1 (Vrun_hooks, Qmenu_bar_update_hook);
+      FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
 
-  /* 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)
-    {
-      Lisp_Object string;
-      string = XVECTOR (items)->contents[i + 1];
-      if (NILP (string))
-       break;
-      wv->name = (char *) XSTRING (string)->data;
-      wv = wv->next;
+      items = FRAME_MENU_BAR_ITEMS (f);
+
+      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));
+
+      /* Fill in the current menu bar contents.  */
+      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)
+       {
+         Lisp_Object key, string, maps;
+
+         key = XVECTOR (items)->contents[i];
+         string = XVECTOR (items)->contents[i + 1];
+         maps = XVECTOR (items)->contents[i + 2];
+         if (NILP (string))
+           break;
+
+         wv = single_submenu (key, string, maps);
+         if (prev_wv) 
+           prev_wv->next = wv;
+         else
+           first_wv->contents = wv;
+         /* Don't set wv->name here; GC during the loop might relocate it.  */
+         wv->enabled = 1;
+         prev_wv = wv;
+       }
+
+      finish_menu_items ();
+
+      set_buffer_internal_1 (prev);
+      unbind_to (specpdl_count, Qnil);
+
+      /* If there has been no change in the Lisp-level contents
+        of the menu bar, skip redisplaying it.  Just exit.  */
+
+      for (i = 0; i < previous_menu_items_used; i++)
+       if (menu_items_used == i
+           || (previous_items[i] != XVECTOR (menu_items)->contents[i]))
+         break;
+      if (i == menu_items_used && i == previous_menu_items_used)
+       {
+         free_menubar_widget_value_tree (first_wv);
+         menu_items = Qnil;
+
+         return;
+       }
+
+      /* 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)
+       {
+         Lisp_Object string;
+         string = XVECTOR (items)->contents[i + 1];
+         if (NILP (string))
+           break;
+         wv->name = (char *) XSTRING (string)->data;
+         wv = wv->next;
+       }
+
+      f->menu_bar_vector = menu_items;
+      f->menu_bar_items_used = menu_items_used;
+      menu_items = Qnil;
     }
+  else
+    {
+      /* Make a widget-value tree containing
+        just the top level menu bar strings.  */
 
-  finish_menu_items ();
+      items = FRAME_MENU_BAR_ITEMS (f);
+      for (i = 0; i < XVECTOR (items)->size; i += 3)
+       {
+         Lisp_Object string;
 
-  f->menu_bar_vector = menu_items;
-  f->menu_bar_items_used = menu_items_used;
-  menu_items = Qnil;
+         string = XVECTOR (items)->contents[i + 1];
+         if (NILP (string))
+           break;
 
-  unbind_to (count, Qnil);
+         wv = malloc_widget_value ();
+         wv->name = (char *) XSTRING (string)->data;
+         wv->value = 0;
+         wv->enabled = 1;
+
+         if (prev_wv) 
+           prev_wv->next = wv;
+         else
+           first_wv->contents = wv;
+         prev_wv = wv;
+       }
+    }
+
+  /* Create or update the menu bar widget.  */
 
   BLOCK_INPUT;
 
   if (menubar_widget)
     {
       /* Disable resizing (done for Motif!) */
-      lw_allow_resizing (f->display.x->widget, False);
+      lw_allow_resizing (f->output_data.x->widget, False);
 
       /* The third arg is DEEP_P, which says to consider the entire
         menu trees we supply, rather than just the menu bar item names.  */
-      lw_modify_all_widgets (id, first_wv, 1);
+      lw_modify_all_widgets (id, first_wv, deep_p);
 
       /* Re-enable the edit widget to resize.  */
-      lw_allow_resizing (f->display.x->widget, True);
+      lw_allow_resizing (f->output_data.x->widget, True);
     }
   else
     {
-      menubar_widget = lw_create_widget ("menubar", "menubar", 
-                                        id, first_wv, 
-                                        f->display.x->column_widget,
+      menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv, 
+                                        f->output_data.x->column_widget,
                                         0,
                                         popup_activate_callback,
                                         menubar_selection_callback,
                                         popup_deactivate_callback);
-      f->display.x->menubar_widget = menubar_widget;
+      f->output_data.x->menubar_widget = menubar_widget;
     }
+
+  {
+    int menubar_size 
+      = (f->output_data.x->menubar_widget
+        ? (f->output_data.x->menubar_widget->core.height
+           + f->output_data.x->menubar_widget->core.border_width)
+        : 0);
+
+    if (FRAME_EXTERNAL_MENU_BAR (f))
+      {
+        Dimension ibw = 0;
+        XtVaGetValues (f->output_data.x->column_widget,
+                      XtNinternalBorderWidth, &ibw, NULL);
+        menubar_size += ibw;
+      }
+
+    f->output_data.x->menubar_height = menubar_size;
+  }
   
   free_menubar_widget_value_tree (first_wv);
 
-  /* Don't update the menubar the first time it is created via x_window.  */
-  if (!first_time)
-    update_frame_menubar (f);
+  update_frame_menubar (f);
 
   UNBLOCK_INPUT;
 }
@@ -1582,7 +1760,7 @@ initialize_frame_menubar (f)
   /* This function is called before the first chance to redisplay
      the frame.  It has to be, so the frame will have the right size.  */
   FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
-  set_frame_menubar (f, 1);
+  set_frame_menubar (f, 1, 1);
 }
 
 /* Get rid of the menu bar of frame F, and free its storage.
@@ -1595,14 +1773,12 @@ free_frame_menubar (f)
   Widget menubar_widget;
   int id;
 
-  menubar_widget = f->display.x->menubar_widget;
+  menubar_widget = f->output_data.x->menubar_widget;
   
   if (menubar_widget)
     {
-      id = frame_vector_add_frame (f);
       BLOCK_INPUT;
-      lw_destroy_all_widgets (id);
-      XVECTOR (frame_vector)->contents[id] = Qnil;
+      lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
       UNBLOCK_INPUT;
     }
 }
@@ -1617,7 +1793,6 @@ 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.
-   MENUBARP is 1 if this menu came from the menu bar.
    FOR_CLICK 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
@@ -1629,8 +1804,13 @@ free_frame_menubar (f)
 #ifdef USE_X_TOOLKIT
 
 /* We need a unique id for each widget handled by the Lucid Widget
-   library.  This includes the frame main windows, popup menu and
-   dialog box.  */
+   library.
+
+   For the main windows, and popup menus, we use this counter,
+   which we increment each time after use.  This starts from 1<<16.
+
+   For menu bars, we use numbers starting at 0, counted in
+   next_menubar_widget_id.  */
 LWLIB_ID widget_id_tick;
 
 #ifdef __STDC__
@@ -1649,20 +1829,19 @@ popup_selection_callback (widget, id, client_data)
 }
 
 static Lisp_Object
-xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error)
      FRAME_PTR f;
      int x;
      int y;
-     int menubarp;             /* This arg is unused in Xt version.  */
      int for_click;
      int keymaps;
      Lisp_Object title;
      char **error;
 {
   int i;
-  int menu_id;
+  LWLIB_ID menu_id;
   Widget menu;
-  Arg av [2];
+  Arg av[2];
   int ac = 0;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
   widget_value **submenu_stack
@@ -1670,8 +1849,7 @@ xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
   Lisp_Object *subprefix_stack
     = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
   int submenu_depth = 0;
-
-  Position root_x, root_y;
+  XButtonPressedEvent dummy;
 
   int first_pane;
   int next_release_must_exit = 0;
@@ -1810,12 +1988,57 @@ xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
     }
 
   /* Actually create the menu.  */
-  menu_id = ++widget_id_tick;
+  menu_id = widget_id_tick++;
   menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
-                          f->display.x->widget, 1, 0,
+                          f->output_data.x->widget, 1, 0,
                           popup_selection_callback,
                           popup_deactivate_callback);
 
+  /* Adjust coordinates to relative to the outer (window manager) window.  */
+  {
+    Window child;
+    int win_x = 0, win_y = 0;
+
+    /* Find the position of the outside upper-left corner of
+       the inner window, with respect to the outer window.  */
+    if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
+      {
+       BLOCK_INPUT;
+       XTranslateCoordinates (FRAME_X_DISPLAY (f),
+
+                              /* From-window, to-window.  */
+                              f->output_data.x->window_desc,
+                              f->output_data.x->parent_desc,
+
+                              /* From-position, to-position.  */
+                              0, 0, &win_x, &win_y,
+
+                              /* Child of window.  */
+                              &child);
+       UNBLOCK_INPUT;
+       x += win_x;
+       y += win_y;
+      }
+  }
+
+  /* Adjust coordinates to be root-window-relative.  */
+  x += f->output_data.x->left_pos;
+  y += f->output_data.x->top_pos;
+
+  dummy.type = ButtonPress;
+  dummy.serial = 0;
+  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;
+  dummy.x_root = x;
+  dummy.y_root = y;
+  dummy.x = x;
+  dummy.y = y;
+
   /* Don't allow any geometry request from the user.  */
   XtSetArg (av[ac], XtNgeometry, 0); ac++;
   XtSetValues (menu, av, ac);
@@ -1827,32 +2050,28 @@ xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
   menu_item_selection = 0;
 
   /* Display the menu.  */
-  lw_popup_menu (menu);
+  lw_popup_menu (menu, &dummy);
   popup_activated_flag = 1;
 
   /* Process events that apply to the menu.  */
-  popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f));
+  popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id);
 
-#if 0
   /* fp turned off the following statement and wrote a comment
      that it is unnecessary--that the menu has already disappeared.
-     I observer that is not so. -- rms.  */
-  /* Make sure the menu disappears.  */
+     Nowadays the menu disappears ok, all right, but
+     we need to delete the widgets or multiple ones will pile up.  */
   lw_destroy_all_widgets (menu_id); 
-#endif
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
   if (menu_item_selection != 0)
     {
-      Lisp_Object prefix;
+      Lisp_Object prefix, entry;
 
       prefix = Qnil;
       i = 0;
       while (i < menu_items_used)
        {
-         Lisp_Object entry;
-
          if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
            {
              subprefix_stack[submenu_depth++] = prefix;
@@ -1910,6 +2129,7 @@ dialog_selection_callback (widget, id, client_data)
   BLOCK_INPUT;
   lw_destroy_all_widgets (id);
   UNBLOCK_INPUT;
+  popup_activated_flag = 0;
 }
 
 static char * button_names [] = {
@@ -1917,15 +2137,14 @@ static char * button_names [] = {
   "button6", "button7", "button8", "button9", "button10" };
 
 static Lisp_Object
-xdialog_show (f, menubarp, keymaps, title, error)
+xdialog_show (f, keymaps, title, error)
      FRAME_PTR f;
-     int menubarp;
      int keymaps;
      Lisp_Object title;
      char **error;
 {
   int i, nb_buttons=0;
-  int dialog_id;
+  LWLIB_ID dialog_id;
   Widget menu;
   char dialog_name[6];
 
@@ -2035,9 +2254,9 @@ xdialog_show (f, menubarp, keymaps, title, error)
   }
 
   /* Actually create the dialog.  */
-  dialog_id = ++widget_id_tick;
+  dialog_id = widget_id_tick++;
   menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
-                          f->display.x->widget, 1, 0,
+                          f->output_data.x->widget, 1, 0,
                           dialog_selection_callback, 0);
   lw_modify_all_widgets (dialog_id, first_wv->contents, True);
   /* Free the widget_value objects we used to specify the contents.  */
@@ -2051,7 +2270,9 @@ xdialog_show (f, menubarp, keymaps, title, error)
   popup_activated_flag = 1;
 
   /* Process events that apply to the menu.  */
-  popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f));
+  popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
+
+  lw_destroy_all_widgets (dialog_id); 
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
@@ -2095,10 +2316,9 @@ xdialog_show (f, menubarp, keymaps, title, error)
 #else /* not USE_X_TOOLKIT */
 
 static Lisp_Object
-xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
+xmenu_show (f, x, y, for_click, keymaps, title, error)
      FRAME_PTR f;
      int x, y;
-     int menubarp;
      int for_click;
      int keymaps;
      Lisp_Object title;
@@ -2147,14 +2367,14 @@ xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
 
     /* Find the position of the outside upper-left corner of
        the inner window, with respect to the outer window.  */
-    if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
+    if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
       {
        BLOCK_INPUT;
        XTranslateCoordinates (FRAME_X_DISPLAY (f),
 
                               /* From-window, to-window.  */
-                              f->display.x->window_desc,
-                              f->display.x->parent_desc,
+                              f->output_data.x->window_desc,
+                              f->output_data.x->parent_desc,
 
                               /* From-position, to-position.  */
                               0, 0, &win_x, &win_y,
@@ -2169,8 +2389,8 @@ xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
 #endif /* HAVE_X_WINDOWS */
 
   /* Adjust coordinates to be root-window-relative.  */
-  x += f->display.x->left_pos;
-  y += f->display.x->top_pos;
+  x += f->output_data.x->left_pos;
+  y += f->output_data.x->top_pos;
  
   /* Create all the necessary panes and their items.  */
   i = 0;
@@ -2306,9 +2526,11 @@ xmenu_show (f, x, y, menubarp, for_click, keymaps, title, error)
                          x, y, ButtonReleaseMask, &datap);
 
 
+#ifdef HAVE_X_WINDOWS
   /* Assume the mouse has moved out of the X window.
      If it has actually moved in, we will get an EnterNotify.  */
-  x_mouse_leave ();
+  x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
+#endif
 
   switch (status)
     {
@@ -2379,13 +2601,14 @@ syms_of_xmenu ()
   staticpro (&menu_items);
   menu_items = Qnil;
 
+  Qdebug_on_next_call = intern ("debug-on-next-call");
+  staticpro (&Qdebug_on_next_call);
+
 #ifdef USE_X_TOOLKIT
   widget_id_tick = (1<<16);    
+  next_menubar_widget_id = 1;
 #endif
 
-  staticpro (&frame_vector);
-  frame_vector = Fmake_vector (make_number (10), Qnil);
-
   defsubr (&Sx_popup_menu);
   defsubr (&Sx_popup_dialog);
 }