Convert (most) functions in src to standard C.
[bpt/emacs.git] / src / xmenu.c
index 9c0dd18..deb7c09 100644 (file)
@@ -1,13 +1,13 @@
 /* X Communication module for terminals which understand the X protocol.
    Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
-                 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,9 +15,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* X pop-up deck-of-cards menu facility for GNU Emacs.
  *
@@ -39,6 +37,7 @@ Boston, MA 02110-1301, USA.  */
 #endif
 
 #include <stdio.h>
+#include <setjmp.h>
 
 #include "lisp.h"
 #include "keyboard.h"
@@ -82,6 +81,8 @@ Boston, MA 02110-1301, USA.  */
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
 #ifdef USE_LUCID
+#include "xsettings.h"
+#include "../lwlib/xlwmenu.h"
 #ifdef HAVE_XAW3D
 #include <X11/Xaw3d/Paned.h>
 #else /* !HAVE_XAW3D */
@@ -96,6 +97,12 @@ Boston, MA 02110-1301, USA.  */
 #endif /* not USE_X_TOOLKIT */
 #endif /* HAVE_X_WINDOWS */
 
+#ifdef USE_GTK
+#include "gtkutil.h"
+#endif
+
+#include "menu.h"
+
 #ifndef TRUE
 #define TRUE 1
 #define FALSE 0
@@ -103,8 +110,6 @@ Boston, MA 02110-1301, USA.  */
 
 Lisp_Object Qdebug_on_next_call;
 
-extern Lisp_Object Vmenu_updating_frame;
-
 extern Lisp_Object Qmenu_bar;
 
 extern Lisp_Object QCtoggle, QCradio;
@@ -117,117 +122,35 @@ 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 P_ ((FRAME_PTR, int, int));
+extern void set_frame_menubar (FRAME_PTR, int, int);
 extern XtAppContext Xt_app_con;
 
-static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
-                                    char **));
-static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
-                                     LWLIB_ID, int));
-
-/* Define HAVE_BOXES if menus can handle radio and toggle buttons.  */
-
-#define HAVE_BOXES 1
+static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
+                                 char **);
+static void popup_get_selection (XEvent *, struct x_display_info *,
+                                 LWLIB_ID, int);
 #endif /* USE_X_TOOLKIT */
 
 #ifdef USE_GTK
-#include "gtkutil.h"
-#define HAVE_BOXES 1
-extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
-static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
-                                    char **));
-#endif
-
-/* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
-   isn't defined.  The use of HAVE_MULTILINGUAL_MENU could probably be
-   confined to an extended version of this with sections of code below
-   using it unconditionally.  */
-#ifdef USE_GTK
-/* gtk just uses utf-8.  */
-# define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
-#elif defined HAVE_X_I18N
-# define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
-#else
-# define ENCODE_MENU_STRING(str) string_make_unibyte (str)
+extern void set_frame_menubar (FRAME_PTR, int, int);
+static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
+                                 char **);
 #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 list_of_panes P_ ((Lisp_Object));
-static void list_of_items P_ ((Lisp_Object));
-
+static int update_frame_menubar (struct frame *);
 \f
-/* This holds a Lisp vector that holds the results of decoding
-   the keymaps or alist-of-alists that specify a menu.
-
-   It describes the panes and items within the panes.
-
-   Each pane is described by 3 elements in the vector:
-   t, the pane name, the pane's prefix key.
-   Then follow the pane's items, with 5 elements per item:
-   the item string, the enable flag, the item's value,
-   the definition, and the equivalent keyboard key's description string.
-
-   In some cases, multiple levels of menus may be described.
-   A single vector slot containing nil indicates the start of a submenu.
-   A single vector slot containing lambda indicates the end of a submenu.
-   The submenu follows a menu item which is the way to reach the submenu.
-
-   A single vector slot containing quote indicates that the
-   following items should appear on the right of a dialog box.
-
-   Using a Lisp vector to hold this information while we decode it
-   takes care of protecting all the data from GC.  */
-
-#define MENU_ITEMS_PANE_NAME 1
-#define MENU_ITEMS_PANE_PREFIX 2
-#define MENU_ITEMS_PANE_LENGTH 3
-
-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;
-
-/* If non-nil, means that the global vars defined here are already in use.
-   Used to detect cases where we try to re-enter this non-reentrant code.  */
-static Lisp_Object menu_items_inuse;
-
-/* Number of slots currently allocated in menu_items.  */
-static int menu_items_allocated;
-
-/* This is the index in menu_items of the first empty slot.  */
-static int menu_items_used;
-
-/* The number of panes currently recorded in menu_items,
-   excluding those within submenus.  */
-static int menu_items_n_panes;
-
-/* Current depth within submenus.  */
-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.  */
 static int popup_activated_flag;
 
 static int next_menubar_widget_id;
 
+/* For NS and NTGUI, these prototypes are defined in keyboard.h.  */
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+extern widget_value *xmalloc_widget_value (void);
+extern widget_value *digest_single_submenu (int, int, int);
+#endif
+
 /* This is set nonzero after the user activates the menu bar, and set
    to zero again after the menu bars are redisplayed by prepare_menu_bar.
    While it is nonzero, all calls to set_frame_menubar go deep.
@@ -264,463 +187,6 @@ menubar_id_to_frame (id)
 
 #endif
 \f
-/* Initialize the menu_items structure if we haven't already done so.
-   Also mark it as currently empty.  */
-
-static void
-init_menu_items ()
-{
-  if (!NILP (menu_items_inuse))
-    error ("Trying to use a menu from within a menu-entry");
-
-  if (NILP (menu_items))
-    {
-      menu_items_allocated = 60;
-      menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
-    }
-
-  menu_items_inuse = Qt;
-  menu_items_used = 0;
-  menu_items_n_panes = 0;
-  menu_items_submenu_depth = 0;
-}
-
-/* Call at the end of generating the data in menu_items.  */
-
-static void
-finish_menu_items ()
-{
-}
-
-static Lisp_Object
-unuse_menu_items (dummy)
-     Lisp_Object dummy;
-{
-  return menu_items_inuse = Qnil;
-}
-
-/* Call when finished using the data for the current menu
-   in menu_items.  */
-
-static void
-discard_menu_items ()
-{
-  /* Free the structure if it is especially large.
-     Otherwise, hold on to it, to save time.  */
-  if (menu_items_allocated > 200)
-    {
-      menu_items = Qnil;
-      menu_items_allocated = 0;
-    }
-  xassert (NILP (menu_items_inuse));
-}
-
-/* This undoes save_menu_items, and it is called by the specpdl unwind
-   mechanism.  */
-
-static Lisp_Object
-restore_menu_items (saved)
-     Lisp_Object saved;
-{
-  menu_items = XCAR (saved);
-  menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil);
-  menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
-  saved = XCDR (saved);
-  menu_items_used = XINT (XCAR (saved));
-  saved = XCDR (saved);
-  menu_items_n_panes = XINT (XCAR (saved));
-  saved = XCDR (saved);
-  menu_items_submenu_depth = XINT (XCAR (saved));
-  return Qnil;
-}
-
-/* Push the whole state of menu_items processing onto the specpdl.
-   It will be restored when the specpdl is unwound.  */
-
-static void
-save_menu_items ()
-{
-  Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil,
-                            make_number (menu_items_used),
-                            make_number (menu_items_n_panes),
-                            make_number (menu_items_submenu_depth));
-  record_unwind_protect (restore_menu_items, saved);
-  menu_items_inuse = Qnil;
-  menu_items = Qnil;
-}
-\f
-/* Make the menu_items vector twice as large.  */
-
-static void
-grow_menu_items ()
-{
-  menu_items_allocated *= 2;
-  menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
-}
-
-/* Begin a submenu.  */
-
-static void
-push_submenu_start ()
-{
-  if (menu_items_used + 1 > menu_items_allocated)
-    grow_menu_items ();
-
-  XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
-  menu_items_submenu_depth++;
-}
-
-/* End a submenu.  */
-
-static void
-push_submenu_end ()
-{
-  if (menu_items_used + 1 > menu_items_allocated)
-    grow_menu_items ();
-
-  XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
-  menu_items_submenu_depth--;
-}
-
-/* Indicate boundary between left and right.  */
-
-static void
-push_left_right_boundary ()
-{
-  if (menu_items_used + 1 > menu_items_allocated)
-    grow_menu_items ();
-
-  XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
-}
-
-/* Start a new menu pane in menu_items.
-   NAME is the pane name.  PREFIX_VEC is a prefix key for this pane.  */
-
-static void
-push_menu_pane (name, prefix_vec)
-     Lisp_Object name, prefix_vec;
-{
-  if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
-    grow_menu_items ();
-
-  if (menu_items_submenu_depth == 0)
-    menu_items_n_panes++;
-  XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
-  XVECTOR (menu_items)->contents[menu_items_used++] = name;
-  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).  TYPE is the type of this menu
-   item, one of nil, `toggle' or `radio'. */
-
-static void
-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 ();
-
-  XVECTOR (menu_items)->contents[menu_items_used++] = name;
-  XVECTOR (menu_items)->contents[menu_items_used++] = enable;
-  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++] = 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,
-   and generate menu panes for them in menu_items.
-   If NOTREAL is nonzero,
-   don't bother really computing whether an item is enabled.  */
-
-static void
-keymap_panes (keymaps, nmaps, notreal)
-     Lisp_Object *keymaps;
-     int nmaps;
-     int notreal;
-{
-  int mapno;
-
-  init_menu_items ();
-
-  /* Loop over the given keymaps, making a pane for each map.
-     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],
-                        Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
-
-  finish_menu_items ();
-}
-
-/* Args passed between single_keymap_panes and single_menu_item.  */
-struct skp
-  {
-     Lisp_Object pending_maps;
-     int maxdepth, notreal;
-     int notbuttons;
-  };
-
-static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
-                                 void *));
-
-/* This is a recursive subroutine of keymap_panes.
-   It handles one keymap, KEYMAP.
-   The other arguments are passed along
-   or point to local variables of the previous function.
-   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
-single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
-     Lisp_Object keymap;
-     Lisp_Object pane_name;
-     Lisp_Object prefix;
-     int notreal;
-     int maxdepth;
-{
-  struct skp skp;
-  struct gcpro gcpro1;
-
-  skp.pending_maps = Qnil;
-  skp.maxdepth = maxdepth;
-  skp.notreal = notreal;
-  skp.notbuttons = 0;
-
-  if (maxdepth <= 0)
-    return;
-
-  push_menu_pane (pane_name, prefix);
-
-#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.  */
-  skp.notbuttons = menu_items_used;
-#endif
-
-  GCPRO1 (skp.pending_maps);
-  map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
-  UNGCPRO;
-
-  /* Process now any submenus which want to be panes at this level.  */
-  while (CONSP (skp.pending_maps))
-    {
-      Lisp_Object elt, eltcdr, string;
-      elt = XCAR (skp.pending_maps);
-      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,
-                          XCDR (eltcdr), notreal, maxdepth - 1);
-      skp.pending_maps = XCDR (skp.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.
-   SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
-   separate panes.
-   If SKP->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 SKP->MAXDEPTH levels, ignore them.
-   SKP->NOTBUTTONS is only used when simulating toggle boxes and radio
-   buttons.  It keeps track of if we have seen a button in this menu or
-   not.  */
-
-static void
-single_menu_item (key, item, dummy, skp_v)
-     Lisp_Object key, item, dummy;
-     void *skp_v;
-{
-  Lisp_Object map, item_string, enabled;
-  struct gcpro gcpro1, gcpro2;
-  int res;
-  struct skp *skp = skp_v;
-
-  /* Parse the menu item and leave the result in item_properties.  */
-  GCPRO2 (key, item);
-  res = parse_menu_item (item, skp->notreal, 0);
-  UNGCPRO;
-  if (!res)
-    return;                    /* Not a menu item.  */
-
-  map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
-
-  if (skp->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, skp->maxdepth - 1);
-      return;
-    }
-
-  enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
-  item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
-
-  if (!NILP (map) && SREF (item_string, 0) == '@')
-    {
-      if (!NILP (enabled))
-       /* An enabled separate pane. Remember this to handle it later.  */
-       skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
-                                  skp->pending_maps);
-      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 (skp->notbuttons)
-         /* The first button. Line up previous items in this menu.  */
-         {
-           int index = skp->notbuttons; /* 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 && SREF (tem, 0) != '\0'
-                       && SREF (tem, 0) != '-')
-                     XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
-                       = concat2 (build_string ("    "), tem);
-                   index += MENU_ITEMS_ITEM_LENGTH;
-                 }
-             }
-           skp->notbuttons = 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 (!skp->notbuttons && SREF (item_string, 0) != '\0'
-            && SREF (item_string, 0) != '-')
-      prefix = build_string ("    ");
-
-    if (!NILP (prefix))
-      item_string = concat2 (prefix, item_string);
-  }
-#endif /* not HAVE_BOXES */
-
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
-  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]);
-
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
-  /* Display a submenu using the toolkit.  */
-  if (! (NILP (map) || NILP (enabled)))
-    {
-      push_submenu_start ();
-      single_keymap_panes (map, Qnil, key, 0, skp->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.  */
-
-static void
-list_of_panes (menu)
-     Lisp_Object menu;
-{
-  Lisp_Object tail;
-
-  init_menu_items ();
-
-  for (tail = menu; CONSP (tail); tail = XCDR (tail))
-    {
-      Lisp_Object elt, pane_name, pane_data;
-      elt = XCAR (tail);
-      pane_name = Fcar (elt);
-      CHECK_STRING (pane_name);
-      push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
-      pane_data = Fcdr (elt);
-      CHECK_CONS (pane_data);
-      list_of_items (pane_data);
-    }
-
-  finish_menu_items ();
-}
-
-/* Push the items in a single pane defined by the alist PANE.  */
-
-static void
-list_of_items (pane)
-     Lisp_Object pane;
-{
-  Lisp_Object tail, item, item1;
-
-  for (tail = pane; CONSP (tail); tail = XCDR (tail))
-    {
-      item = XCAR (tail);
-      if (STRINGP (item))
-       push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
-                       Qnil, Qnil, Qnil, Qnil);
-      else if (CONSP (item))
-       {
-         item1 = XCAR (item);
-         CHECK_STRING (item1);
-         push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
-                         Qt, Qnil, Qnil, Qnil, Qnil);
-       }
-      else
-       push_left_right_boundary ();
-
-    }
-}
-\f
 #ifdef HAVE_X_WINDOWS
 /* Return the mouse position in *X and *Y.  The coordinates are window
    relative for the edit window in frame F.
@@ -729,11 +195,8 @@ list_of_items (pane)
    for the window where the mouse is in.  This could be the menu bar,
    the scroll bar or the edit window.  Fx_popup_menu needs to be
    sure it is the edit window.  */
-static void
-mouse_position_for_popup (f, x, y)
-     FRAME_PTR f;
-     int *x;
-     int *y;
+void
+mouse_position_for_popup (FRAME_PTR f, int *x, int *y)
 {
   Window root, dummy_window;
   int dummy;
@@ -772,322 +235,53 @@ mouse_position_for_popup (f, x, y)
 
 #endif /* HAVE_X_WINDOWS */
 
-DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
-       doc: /* 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.  (WINDOW may be a window or a frame object.)
-This controls the position of 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 the
-list of events corresponding to the user's choice. Note that
-`x-popup-menu' does not actually execute the command bound to that
-sequence 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.
-
-If the user gets rid of the menu without making a valid choice, for
-instance by clicking the mouse away from a valid choice or by typing
-keyboard input, then this normally results in a quit and
-`x-popup-menu' does not return.  But if POSITION is a mouse button
-event (indicating that the user invoked the menu with the mouse) then
-no quit occurs and `x-popup-menu' returns nil.  */)
-     (position, menu)
-     Lisp_Object position, menu;
-{
-  Lisp_Object keymap, tem;
-  int xpos = 0, ypos = 0;
-  Lisp_Object title;
-  char *error_name = NULL;
-  Lisp_Object selection = Qnil;
-  FRAME_PTR f = NULL;
-  Lisp_Object x, y, window;
-  int keymaps = 0;
-  int for_click = 0;
-  int specpdl_count = SPECPDL_INDEX ();
-  struct gcpro gcpro1;
-
 #ifdef HAVE_MENUS
-  if (! NILP (position))
-    {
-      int get_current_pos_p = 0;
-      check_x ();
 
-      /* Decode the first argument: find the window and the coordinates.  */
-      if (EQ (position, Qt)
-         || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                                  || EQ (XCAR (position), Qtool_bar))))
-       {
-          get_current_pos_p = 1;
-        }
-      else
-       {
-         tem = Fcar (position);
-         if (CONSP (tem))
-           {
-             window = Fcar (Fcdr (position));
-             x = XCAR (tem);
-             y = Fcar (XCDR (tem));
-           }
-         else
-           {
-             for_click = 1;
-             tem = Fcar (Fcdr (position));  /* EVENT_START (position) */
-             window = Fcar (tem);           /* POSN_WINDOW (tem) */
-             tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
-             x = Fcar (tem);
-             y = Fcdr (tem);
-           }
-
-          /* If a click happens in an external tool bar or a detached
-             tool bar, x and y is NIL.  In that case, use the current
-             mouse position.  This happens for the help button in the
-             tool bar.  Ideally popup-menu should pass NIL to
-             this function, but it doesn't.  */
-          if (NILP (x) && NILP (y))
-            get_current_pos_p = 1;
-       }
-
-      if (get_current_pos_p)
-        {
-         /* Use the mouse's current position.  */
-         FRAME_PTR new_f = SELECTED_FRAME ();
-#ifdef HAVE_X_WINDOWS
-          /* Can't use mouse_position_hook for X since it returns
-             coordinates relative to the window the mouse is in,
-             we need coordinates relative to the edit widget always.  */
-          if (new_f != 0)
-            {
-              int cur_x, cur_y;
-
-              mouse_position_for_popup (new_f, &cur_x, &cur_y);
-              /* cur_x/y may be negative, so use make_number.  */
-              x = make_number (cur_x);
-              y = make_number (cur_y);
-            }
-
-#else /* not HAVE_X_WINDOWS */
-         Lisp_Object bar_window;
-         enum scroll_bar_part part;
-         unsigned long time;
-
-         if (mouse_position_hook)
-           (*mouse_position_hook) (&new_f, 1, &bar_window,
-                                   &part, &x, &y, &time);
-#endif /* not HAVE_X_WINDOWS */
-
-         if (new_f != 0)
-           XSETFRAME (window, new_f);
-         else
-           {
-             window = selected_window;
-             XSETFASTINT (x, 0);
-             XSETFASTINT (y, 0);
-           }
-       }
+DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
+       doc: /* 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.
 
-      CHECK_NUMBER (x);
-      CHECK_NUMBER (y);
+CONTENTS specifies the alternatives to display in the dialog box.
+It is a list of the form (DIALOG ITEM1 ITEM2...).
+Each ITEM is a cons cell (STRING . VALUE).
+The return value is VALUE from the chosen item.
 
-      /* Decode where to put the menu.  */
+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.)
 
-      if (FRAMEP (window))
-       {
-         f = XFRAME (window);
-         xpos = 0;
-         ypos = 0;
-       }
-      else if (WINDOWP (window))
-       {
-         CHECK_LIVE_WINDOW (window);
-         f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+If HEADER is non-nil, the frame title for the box is "Information",
+otherwise it is "Question".
 
-         xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
-         ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
-       }
-      else
-       /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
-          but I don't want to make one now.  */
-       CHECK_WINDOW (window);
+If the user gets rid of the dialog box without making a valid choice,
+for instance using the window manager, then this produces a quit and
+`x-popup-dialog' does not return.  */)
+     (position, contents, header)
+     Lisp_Object position, contents, header;
+{
+  FRAME_PTR f = NULL;
+  Lisp_Object window;
 
-      xpos += XINT (x);
-      ypos += XINT (y);
+  check_x ();
 
-      if (! FRAME_X_P (f))
-        error ("Can not put X menu on non-X terminal");
+  /* Decode the first argument: find the window or frame to use.  */
+  if (EQ (position, Qt)
+      || (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.  */
+      FRAME_PTR new_f = SELECTED_FRAME ();
+      Lisp_Object bar_window;
+      enum scroll_bar_part part;
+      unsigned long time;
+      Lisp_Object x, y;
 
-      XSETFRAME (Vmenu_updating_frame, f);
-    }
-  else
-    Vmenu_updating_frame = Qnil;
-#endif /* HAVE_MENUS */
-
-  record_unwind_protect (unuse_menu_items, Qnil);
-  title = Qnil;
-  GCPRO1 (title);
-
-  /* Decode the menu items from what was specified.  */
-
-  keymap = get_keymap (menu, 0, 0);
-  if (CONSP (keymap))
-    {
-      /* We were given a keymap.  Extract menu info from the keymap.  */
-      Lisp_Object prompt;
-
-      /* 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 = 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)
-       XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
-
-      keymaps = 1;
-    }
-  else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
-    {
-      /* We were given a list of keymaps.  */
-      int nmaps = XFASTINT (Flength (menu));
-      Lisp_Object *maps
-       = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
-      int i;
-
-      title = Qnil;
-
-      /* The first keymap that has a prompt string
-        supplies the menu title.  */
-      for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
-       {
-         Lisp_Object prompt;
-
-         maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
-
-         prompt = Fkeymap_prompt (keymap);
-         if (NILP (title) && !NILP (prompt))
-           title = prompt;
-       }
-
-      /* Extract the detailed info to make one pane.  */
-      keymap_panes (maps, nmaps, NILP (position));
-
-      /* Make the title be the pane title of the first pane.  */
-      if (!NILP (title) && menu_items_n_panes >= 0)
-       XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
-
-      keymaps = 1;
-    }
-  else
-    {
-      /* We were given an old-fashioned menu.  */
-      title = Fcar (menu);
-      CHECK_STRING (title);
-
-      list_of_panes (Fcdr (menu));
-
-      keymaps = 0;
-    }
-
-  unbind_to (specpdl_count, Qnil);
-
-  if (NILP (position))
-    {
-      discard_menu_items ();
-      UNGCPRO;
-      return Qnil;
-    }
-
-#ifdef HAVE_MENUS
-  /* Display them in a menu.  */
-  BLOCK_INPUT;
-
-  selection = xmenu_show (f, xpos, ypos, for_click,
-                         keymaps, title, &error_name);
-  UNBLOCK_INPUT;
-
-  discard_menu_items ();
-
-  UNGCPRO;
-#endif /* HAVE_MENUS */
-
-  if (error_name) error (error_name);
-  return selection;
-}
-
-#ifdef HAVE_MENUS
-
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
-       doc: /* 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 (DIALOG 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.)
-
-If HEADER is non-nil, the frame title for the box is "Information",
-otherwise it is "Question".
-
-If the user gets rid of the dialog box without making a valid choice,
-for instance using the window manager, then this produces a quit and
-`x-popup-dialog' does not return.  */)
-     (position, contents, header)
-     Lisp_Object position, contents, header;
-{
-  FRAME_PTR f = NULL;
-  Lisp_Object window;
-
-  check_x ();
-
-  /* Decode the first argument: find the window or frame to use.  */
-  if (EQ (position, Qt)
-      || (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.  */
-      FRAME_PTR new_f = SELECTED_FRAME ();
-      Lisp_Object bar_window;
-      enum scroll_bar_part part;
-      unsigned long time;
-      Lisp_Object x, y;
-
-      (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
+      (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
 
       if (new_f != 0)
        XSETFRAME (window, new_f);
@@ -1127,8 +321,19 @@ for instance using the window manager, then this produces a quit and
        but I don't want to make one now.  */
     CHECK_WINDOW (window);
 
-  if (! FRAME_X_P (f))
-    error ("Can not put X dialog on non-X terminal");
+  if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
+    error ("Can not put X dialog on this terminal");
+
+  /* Force a redisplay before showing the dialog.  If a frame is created
+     just before showing the dialog, its contents may not have been fully
+     drawn, as this depends on timing of events from the X server.  Redisplay
+     is not done when a dialog is shown.  If redisplay could be done in the
+     X event loop (i.e. the X event loop does not run in a signal handler)
+     this would not be needed.
+
+     Do this before creating the widget value that points to Lisp
+     string contents, because Fredisplay may GC and relocate them.  */
+  Fredisplay (Qt);
 
 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
   /* Display a menu with these alternatives
@@ -1183,8 +388,7 @@ for instance using the window manager, then this produces a quit and
 /* Set menu_items_inuse so no other popup menu or dialog is created.  */
 
 void
-x_menu_set_in_use (in_use)
-     int in_use;
+x_menu_set_in_use (int in_use)
 {
   menu_items_inuse = in_use ? Qt : Qnil;
   popup_activated_flag = in_use;
@@ -1199,8 +403,6 @@ x_menu_set_in_use (in_use)
 void
 x_menu_wait_for_event (void *data)
 {
-  extern EMACS_TIME timer_check P_ ((int));
-
   /* Another way to do this is to register a timer callback, that can be
      done in GTK and Xt.  But we have to do it like this when using only X
      anyway, and with callbacks we would have three variants for timer handling
@@ -1216,7 +418,7 @@ x_menu_wait_for_event (void *data)
 #endif
          )
     {
-      EMACS_TIME next_time = timer_check (1);
+      EMACS_TIME next_time = timer_check (1), *ntp;
       long secs = EMACS_SECS (next_time);
       long usecs = EMACS_USECS (next_time);
       SELECT_TYPE read_fds;
@@ -1229,17 +431,15 @@ x_menu_wait_for_event (void *data)
           int fd = ConnectionNumber (dpyinfo->display);
           FD_SET (fd, &read_fds);
           if (fd > n) n = fd;
+          XFlush (dpyinfo->display);
         }
 
-      if (secs < 0 || (secs == 0 && usecs == 0))
-        {
-          /* Sometimes timer_check returns -1 (no timers) even if there are
-             timers.  So do a timeout anyway.  */
-          EMACS_SET_SECS (next_time, 1);
-          EMACS_SET_USECS (next_time, 0);
-        }
+      if (secs < 0 && usecs < 0)
+        ntp = 0;
+      else
+        ntp = &next_time;
 
-      select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
+      select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
     }
 }
 #endif /* ! MSDOS */
@@ -1418,11 +618,12 @@ If FRAME is nil or not given, use the selected frame.  */)
       /* Activate the first menu.  */
       GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
 
-      gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar),
-                                  GTK_WIDGET (children->data));
-
-      popup_activated_flag = 1;
-      g_list_free (children);
+      if (children)
+        {
+          g_signal_emit_by_name (children->data, "activate_item");
+          popup_activated_flag = 1;
+          g_list_free (children);
+        }
     }
   UNBLOCK_INPUT;
 
@@ -1433,9 +634,7 @@ If FRAME is nil or not given, use the selected frame.  */)
    Used for popup menus and dialogs. */
 
 static void
-popup_widget_loop (do_timers, widget)
-     int do_timers;
-     GtkWidget *widget;
+popup_widget_loop (int do_timers, GtkWidget *widget)
 {
   ++popup_activated_flag;
 
@@ -1463,8 +662,7 @@ popup_widget_loop (do_timers, widget)
    execute Lisp code.  */
 
 void
-x_activate_menubar (f)
-     FRAME_PTR f;
+x_activate_menubar (FRAME_PTR f)
 {
   if (! FRAME_X_P (f))
     abort ();
@@ -1517,588 +715,179 @@ popup_activate_callback (widget, id, client_data)
 /* This callback is invoked when a dialog or menu is finished being
    used and has been unposted.  */
 
-#ifdef USE_GTK
-static void
-popup_deactivate_callback (widget, client_data)
-     GtkWidget *widget;
-     gpointer client_data;
-{
-  popup_activated_flag = 0;
-}
-#else
-static void
-popup_deactivate_callback (widget, id, client_data)
-     Widget widget;
-     LWLIB_ID id;
-     XtPointer client_data;
-{
-  popup_activated_flag = 0;
-}
-#endif
-
-
-/* Function that finds the frame for WIDGET and shows the HELP text
-   for that widget.
-   F is the frame if known, or NULL if not known.  */
-static void
-show_help_event (f, widget, help)
-     FRAME_PTR f;
-     xt_or_gtk_widget widget;
-     Lisp_Object help;
-{
-  Lisp_Object frame;
-
-  if (f)
-    {
-      XSETFRAME (frame, f);
-      kbd_buffer_store_help_event (frame, help);
-    }
-  else
-    {
-#if 0  /* This code doesn't do anything useful.  ++kfs */
-      /* WIDGET is the popup menu.  It's parent is the frame's
-        widget.  See which frame that is.  */
-      xt_or_gtk_widget frame_widget = XtParent (widget);
-      Lisp_Object tail;
-
-      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
-       {
-         frame = XCAR (tail);
-         if (FRAMEP (frame)
-             && (f = XFRAME (frame),
-                 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
-           break;
-       }
-#endif
-      show_help_echo (help, Qnil, Qnil, Qnil, 1);
-    }
-}
-
-/* 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 data structure for the menu item, or null in case of
-   unhighlighting.  */
-
-#ifdef USE_GTK
-void
-menu_highlight_callback (widget, call_data)
-     GtkWidget *widget;
-     gpointer call_data;
-{
-  xg_menu_item_cb_data *cb_data;
-  Lisp_Object help;
-
-  cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
-                                                       XG_ITEM_DATA);
-  if (! cb_data) return;
-
-  help = call_data ? cb_data->help : Qnil;
-
-  /* If popup_activated_flag is greater than 1 we are in a popup menu.
-     Don't show help for them, they won't appear before the
-     popup is popped down.  */
-  if (popup_activated_flag <= 1)
-    show_help_event (cb_data->cl_data->f, widget, help);
-}
-#else
-void
-menu_highlight_callback (widget, id, call_data)
-     Widget widget;
-     LWLIB_ID id;
-     void *call_data;
-{
-  struct frame *f;
-  Lisp_Object help;
-
-  widget_value *wv = (widget_value *) call_data;
-
-  help = wv ? wv->help : Qnil;
-
-  /* Determine the frame for the help event.  */
-  f = menubar_id_to_frame (id);
-
-  show_help_event (f, widget, help);
-}
-#endif
-
-/* Find the menu selection and store it in the keyboard buffer.
-   F is the frame the menu is on.
-   MENU_BAR_ITEMS_USED is the length of VECTOR.
-   VECTOR is an array of menu events for the whole menu.  */
-
-static void
-find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
-     FRAME_PTR f;
-     EMACS_INT menu_bar_items_used;
-     Lisp_Object vector;
-     void *client_data;
-{
-  Lisp_Object prefix, entry;
-  Lisp_Object *subprefix_stack;
-  int submenu_depth = 0;
-  int i;
-
-  entry = Qnil;
-  subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
-  prefix = Qnil;
-  i = 0;
-
-  while (i < menu_bar_items_used)
-    {
-      if (EQ (XVECTOR (vector)->contents[i], Qnil))
-       {
-         subprefix_stack[submenu_depth++] = prefix;
-         prefix = entry;
-         i++;
-       }
-      else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
-       {
-         prefix = subprefix_stack[--submenu_depth];
-         i++;
-       }
-      else if (EQ (XVECTOR (vector)->contents[i], Qt))
-       {
-         prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
-         i += MENU_ITEMS_PANE_LENGTH;
-       }
-      else
-       {
-         entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
-         /* The EMACS_INT cast avoids a warning.  There's no problem
-            as long as pointers have enough bits to hold small integers.  */
-         if ((int) (EMACS_INT) client_data == i)
-           {
-             int j;
-             struct input_event buf;
-             Lisp_Object frame;
-             EVENT_INIT (buf);
-
-             XSETFRAME (frame, f);
-             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]))
-                 {
-                   buf.kind = MENU_BAR_EVENT;
-                   buf.frame_or_window = frame;
-                   buf.arg = subprefix_stack[j];
-                   kbd_buffer_store_event (&buf);
-                 }
-
-             if (!NILP (prefix))
-               {
-                 buf.kind = MENU_BAR_EVENT;
-                 buf.frame_or_window = frame;
-                 buf.arg = prefix;
-                 kbd_buffer_store_event (&buf);
-               }
-
-             buf.kind = MENU_BAR_EVENT;
-             buf.frame_or_window = frame;
-             buf.arg = entry;
-             kbd_buffer_store_event (&buf);
-
-             return;
-           }
-         i += MENU_ITEMS_ITEM_LENGTH;
-       }
-    }
-}
-
-
-#ifdef USE_GTK
-/* Gtk calls callbacks just because we tell it what item should be
-   selected in a radio group.  If this variable is set to a non-zero
-   value, we are creating menus and don't want callbacks right now.
-*/
-static int xg_crazy_callback_abort;
-
-/* This callback is called from the menu bar pulldown menu
-   when the user makes a selection.
-   Figure out what the user chose
-   and put the appropriate events into the keyboard buffer.  */
-static void
-menubar_selection_callback (widget, client_data)
-     GtkWidget *widget;
-     gpointer client_data;
-{
-  xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
-
-  if (xg_crazy_callback_abort)
-    return;
-
-  if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
-    return;
-
-  /* For a group of radio buttons, GTK calls the selection callback first
-     for the item that was active before the selection and then for the one that
-     is active after the selection.  For C-h k this means we get the help on
-     the deselected item and then the selected item is executed.  Prevent that
-     by ignoring the non-active item.  */
-  if (GTK_IS_RADIO_MENU_ITEM (widget)
-      && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
-    return;
-
-  /* When a menu is popped down, X generates a focus event (i.e. focus
-     goes back to the frame below the menu).  Since GTK buffers events,
-     we force it out here before the menu selection event.  Otherwise
-     sit-for will exit at once if the focus event follows the menu selection
-     event.  */
-
-  BLOCK_INPUT;
-  while (gtk_events_pending ())
-    gtk_main_iteration ();
-  UNBLOCK_INPUT;
-
-  find_and_call_menu_selection (cb_data->cl_data->f,
-                                cb_data->cl_data->menu_bar_items_used,
-                                cb_data->cl_data->menu_bar_vector,
-                                cb_data->call_data);
-}
-
-#else /* not USE_GTK */
-
-/* This callback is called from the menu bar pulldown menu
-   when the user makes a selection.
-   Figure out what the user chose
-   and put the appropriate events into the keyboard buffer.  */
-static void
-menubar_selection_callback (widget, id, client_data)
-     Widget widget;
-     LWLIB_ID id;
-     XtPointer client_data;
-{
-  FRAME_PTR f;
-
-  f = menubar_id_to_frame (id);
-  if (!f)
-    return;
-  find_and_call_menu_selection (f, f->menu_bar_items_used,
-                                f->menu_bar_vector, client_data);
-}
-#endif /* not USE_GTK */
-
-/* Allocate a widget_value, blocking input.  */
-
-widget_value *
-xmalloc_widget_value ()
-{
-  widget_value *value;
-
-  BLOCK_INPUT;
-  value = malloc_widget_value ();
-  UNBLOCK_INPUT;
-
-  return value;
-}
-
-/* This recursively calls free_widget_value on the tree of widgets.
-   It must free all data that was malloc'ed for these widget_values.
-   In Emacs, many slots are pointers into the data of Lisp_Strings, and
-   must be left alone.  */
-
-void
-free_menubar_widget_value_tree (wv)
-     widget_value *wv;
-{
-  if (! wv) return;
-
-  wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
-
-  if (wv->contents && (wv->contents != (widget_value*)1))
-    {
-      free_menubar_widget_value_tree (wv->contents);
-      wv->contents = (widget_value *) 0xDEADBEEF;
-    }
-  if (wv->next)
-    {
-      free_menubar_widget_value_tree (wv->next);
-      wv->next = (widget_value *) 0xDEADBEEF;
-    }
-  BLOCK_INPUT;
-  free_widget_value (wv);
-  UNBLOCK_INPUT;
-}
-\f
-/* Set up data in menu_items for a menu bar item
-   whose event type is ITEM_KEY (with string ITEM_NAME)
-   and whose contents come from the list of keymaps MAPS.  */
-
-static int
-parse_single_submenu (item_key, item_name, maps)
-     Lisp_Object item_key, item_name, maps;
-{
-  Lisp_Object length;
-  int len;
-  Lisp_Object *mapvec;
-  int i;
-  int top_level_items = 0;
-
-  length = Flength (maps);
-  len = XINT (length);
-
-  /* Convert the list MAPS into a vector MAPVEC.  */
-  mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-  for (i = 0; i < len; i++)
-    {
-      mapvec[i] = Fcar (maps);
-      maps = Fcdr (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++)
-    {
-      if (!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);
-         push_menu_item (item_name, Qt, item_key, mapvec[i],
-                         Qnil, Qnil, Qnil, Qnil);
-       }
-      else
-       {
-         Lisp_Object prompt;
-         prompt = Fkeymap_prompt (mapvec[i]);
-         single_keymap_panes (mapvec[i],
-                              !NILP (prompt) ? prompt : item_name,
-                              item_key, 0, 10);
-       }
-    }
-
-  return top_level_items;
-}
-
-/* Create a tree of widget_value objects
-   representing the panes and items
-   in menu_items starting at index START, up to index END.  */
-
-static widget_value *
-digest_single_submenu (start, end, top_level_items)
-     int start, end, top_level_items;
-{
-  widget_value *wv, *prev_wv, *save_wv, *first_wv;
-  int i;
-  int submenu_depth = 0;
-  widget_value **submenu_stack;
-  int panes_seen = 0;
-
-  submenu_stack
-    = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
-  wv = xmalloc_widget_value ();
-  wv->name = "menu";
-  wv->value = 0;
-  wv->enabled = 1;
-  wv->button_type = BUTTON_TYPE_NONE;
-  wv->help = Qnil;
-  first_wv = wv;
-  save_wv = 0;
-  prev_wv = 0;
-
-  /* Loop over all panes and items made by the preceding call
-     to parse_single_submenu and construct a tree of widget_value objects.
-     Ignore the panes and items used by previous calls to
-     digest_single_submenu, even though those are also in menu_items.  */
-  i = start;
-  while (i < end)
-    {
-      if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
-       {
-         submenu_stack[submenu_depth++] = save_wv;
-         save_wv = prev_wv;
-         prev_wv = 0;
-         i++;
-       }
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
-       {
-         prev_wv = save_wv;
-         save_wv = submenu_stack[--submenu_depth];
-         i++;
-       }
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
-              && submenu_depth != 0)
-       i += MENU_ITEMS_PANE_LENGTH;
-      /* Ignore a nil in the item list.
-        It's meaningful only for dialog boxes.  */
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
-       i += 1;
-      else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
-       {
-         /* Create a new pane.  */
-         Lisp_Object pane_name, prefix;
-         char *pane_string;
-
-         panes_seen++;
-
-         pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
-         prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
-
-#ifndef HAVE_MULTILINGUAL_MENU
-         if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
-           {
-             pane_name = ENCODE_MENU_STRING (pane_name);
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
-           }
-#endif
-         pane_string = (NILP (pane_name)
-                        ? "" : (char *) SDATA (pane_name));
-         /* If there is just one top-level pane, put all its items directly
-            under the top-level menu.  */
-         if (menu_items_n_panes == 1)
-           pane_string = "";
-
-         /* If the pane has a meaningful name,
-            make the pane a top-level menu item
-            with its items as a submenu beneath it.  */
-         if (strcmp (pane_string, ""))
-           {
-             wv = xmalloc_widget_value ();
-             if (save_wv)
-               save_wv->next = wv;
-             else
-               first_wv->contents = wv;
-             wv->lname = pane_name;
-              /* Set value to 1 so update_submenu_strings can handle '@'  */
-             wv->value = (char *)1;
-             wv->enabled = 1;
-             wv->button_type = BUTTON_TYPE_NONE;
-             wv->help = Qnil;
-             save_wv = wv;
-           }
-         else
-           save_wv = first_wv;
-
-         prev_wv = 0;
-         i += MENU_ITEMS_PANE_LENGTH;
-       }
-      else
-       {
-         /* Create a new item within current pane.  */
-         Lisp_Object item_name, enable, descrip, def, type, selected;
-         Lisp_Object help;
+#ifdef USE_GTK
+static void
+popup_deactivate_callback (GtkWidget *widget, gpointer client_data)
+{
+  popup_activated_flag = 0;
+}
+#else
+static void
+popup_deactivate_callback (widget, id, client_data)
+     Widget widget;
+     LWLIB_ID id;
+     XtPointer client_data;
+{
+  popup_activated_flag = 0;
+}
+#endif
 
-         /* All items should be contained in panes.  */
-         if (panes_seen == 0)
-           abort ();
 
-         item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
-         enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
-         descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
-         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);
+/* Function that finds the frame for WIDGET and shows the HELP text
+   for that widget.
+   F is the frame if known, or NULL if not known.  */
+static void
+show_help_event (FRAME_PTR f, xt_or_gtk_widget widget, Lisp_Object help)
+{
+  Lisp_Object frame;
 
-#ifndef HAVE_MULTILINGUAL_MENU
-          if (STRING_MULTIBYTE (item_name))
-           {
-             item_name = ENCODE_MENU_STRING (item_name);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
+  if (f)
+    {
+      XSETFRAME (frame, f);
+      kbd_buffer_store_help_event (frame, help);
+    }
+  else
+    {
+#if 0  /* This code doesn't do anything useful.  ++kfs */
+      /* WIDGET is the popup menu.  It's parent is the frame's
+        widget.  See which frame that is.  */
+      xt_or_gtk_widget frame_widget = XtParent (widget);
+      Lisp_Object tail;
 
-          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-           {
-             descrip = ENCODE_MENU_STRING (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
-#endif /* not HAVE_MULTILINGUAL_MENU */
+      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+       {
+         frame = XCAR (tail);
+         if (FRAMEP (frame)
+             && (f = XFRAME (frame),
+                 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
+           break;
+       }
+#endif
+      show_help_echo (help, Qnil, Qnil, Qnil, 1);
+    }
+}
 
-         wv = xmalloc_widget_value ();
-         if (prev_wv)
-           prev_wv->next = wv;
-         else
-           save_wv->contents = wv;
+/* 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 data structure for the menu item, or null in case of
+   unhighlighting.  */
 
-         wv->lname = item_name;
-         if (!NILP (descrip))
-           wv->lkey = descrip;
-         wv->value = 0;
-         /* The EMACS_INT cast avoids a warning.  There's no problem
-            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);
+#ifdef USE_GTK
+void
+menu_highlight_callback (GtkWidget *widget, gpointer call_data)
+{
+  xg_menu_item_cb_data *cb_data;
+  Lisp_Object help;
 
-         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 ();
+  cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
+                                                       XG_ITEM_DATA);
+  if (! cb_data) return;
 
-         wv->selected = !NILP (selected);
-         if (! STRINGP (help))
-           help = Qnil;
+  help = call_data ? cb_data->help : Qnil;
 
-         wv->help = help;
+  /* If popup_activated_flag is greater than 1 we are in a popup menu.
+     Don't show help for them, they won't appear before the
+     popup is popped down.  */
+  if (popup_activated_flag <= 1)
+    show_help_event (cb_data->cl_data->f, widget, help);
+}
+#else
+void
+menu_highlight_callback (widget, id, call_data)
+     Widget widget;
+     LWLIB_ID id;
+     void *call_data;
+{
+  struct frame *f;
+  Lisp_Object help;
 
-         prev_wv = wv;
+  widget_value *wv = (widget_value *) call_data;
 
-         i += MENU_ITEMS_ITEM_LENGTH;
-       }
-    }
+  help = wv ? wv->help : Qnil;
 
-  /* 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;
-    }
+  /* Determine the frame for the help event.  */
+  f = menubar_id_to_frame (id);
 
-  return first_wv;
+  show_help_event (f, widget, help);
 }
+#endif
+
+#ifdef USE_GTK
+/* Gtk calls callbacks just because we tell it what item should be
+   selected in a radio group.  If this variable is set to a non-zero
+   value, we are creating menus and don't want callbacks right now.
+*/
+static int xg_crazy_callback_abort;
 
-/* Walk through the widget_value tree starting at FIRST_WV and update
-   the char * pointers from the corresponding lisp values.
-   We do this after building the whole tree, since GC may happen while the
-   tree is constructed, and small strings are relocated.  So we must wait
-   until no GC can happen before storing pointers into lisp values.  */
+/* This callback is called from the menu bar pulldown menu
+   when the user makes a selection.
+   Figure out what the user chose
+   and put the appropriate events into the keyboard buffer.  */
 static void
-update_submenu_strings (first_wv)
-     widget_value *first_wv;
+menubar_selection_callback (GtkWidget *widget, gpointer client_data)
 {
-  widget_value *wv;
+  xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
 
-  for (wv = first_wv; wv; wv = wv->next)
-    {
-      if (STRINGP (wv->lname))
-        {
-          wv->name = (char *) SDATA (wv->lname);
+  if (xg_crazy_callback_abort)
+    return;
 
-          /* Ignore the @ that means "separate pane".
-             This is a kludge, but this isn't worth more time.  */
-          if (wv->value == (char *)1)
-            {
-              if (wv->name[0] == '@')
-               wv->name++;
-              wv->value = 0;
-            }
-        }
+  if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
+    return;
 
-      if (STRINGP (wv->lkey))
-        wv->key = (char *) SDATA (wv->lkey);
+  /* For a group of radio buttons, GTK calls the selection callback first
+     for the item that was active before the selection and then for the one that
+     is active after the selection.  For C-h k this means we get the help on
+     the deselected item and then the selected item is executed.  Prevent that
+     by ignoring the non-active item.  */
+  if (GTK_IS_RADIO_MENU_ITEM (widget)
+      && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+    return;
 
-      if (wv->contents)
-        update_submenu_strings (wv->contents);
-    }
+  /* When a menu is popped down, X generates a focus event (i.e. focus
+     goes back to the frame below the menu).  Since GTK buffers events,
+     we force it out here before the menu selection event.  Otherwise
+     sit-for will exit at once if the focus event follows the menu selection
+     event.  */
+
+  BLOCK_INPUT;
+  while (gtk_events_pending ())
+    gtk_main_iteration ();
+  UNBLOCK_INPUT;
+
+  find_and_call_menu_selection (cb_data->cl_data->f,
+                                cb_data->cl_data->menu_bar_items_used,
+                                cb_data->cl_data->menu_bar_vector,
+                                cb_data->call_data);
 }
 
+#else /* not USE_GTK */
+
+/* This callback is called from the menu bar pulldown menu
+   when the user makes a selection.
+   Figure out what the user chose
+   and put the appropriate events into the keyboard buffer.  */
+static void
+menubar_selection_callback (widget, id, client_data)
+     Widget widget;
+     LWLIB_ID id;
+     XtPointer client_data;
+{
+  FRAME_PTR f;
+
+  f = menubar_id_to_frame (id);
+  if (!f)
+    return;
+  find_and_call_menu_selection (f, f->menu_bar_items_used,
+                                f->menu_bar_vector, client_data);
+}
+#endif /* not USE_GTK */
 \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;
+update_frame_menubar (FRAME_PTR f)
 {
 #ifdef USE_GTK
   return xg_update_frame_menubar (f);
@@ -2146,15 +935,50 @@ update_frame_menubar (f)
   return 1;
 }
 
+#ifdef USE_LUCID
+static void
+apply_systemfont_to_dialog (w)
+     Widget w;
+{
+  const char *fn = xsettings_get_system_normal_font ();
+  if (fn) 
+    {
+      XrmDatabase db = XtDatabase (XtDisplay (w));
+      if (db)
+        XrmPutStringResource (&db, "*dialog.faceName", fn);
+    }
+}
+
+static void
+apply_systemfont_to_menu (w)
+     Widget w;
+{
+  const char *fn = xsettings_get_system_normal_font ();
+  int defflt;
+
+  if (!fn) return;
+
+  if (XtIsShell (w)) /* popup menu */
+    {
+      Widget *childs = NULL;
+
+      XtVaGetValues (w, XtNchildren, &childs, NULL);
+      if (*childs) w = *childs;
+    }
+
+  /* Only use system font if the default is used for the menu.  */
+  XtVaGetValues (w, XtNdefaultFace, &defflt, NULL);
+  if (defflt)
+    XtVaSetValues (w, XtNfaceName, fn, NULL);
+}
+#endif
+
 /* 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, deep_p)
-     FRAME_PTR f;
-     int first_time;
-     int deep_p;
+set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
 {
   xt_or_gtk_widget menubar_widget;
 #ifdef USE_X_TOOLKIT
@@ -2332,8 +1156,7 @@ set_frame_menubar (f, first_time, deep_p)
       f->menu_bar_vector = menu_items;
       f->menu_bar_items_used = menu_items_used;
 
-      /* This calls restore_menu_items to restore menu_items, etc.,
-        as they were outside.  */
+      /* This undoes save_menu_items.  */
       unbind_to (specpdl_count, Qnil);
 
       /* Now GC cannot happen during the lifetime of the widget_value,
@@ -2459,6 +1282,7 @@ set_frame_menubar (f, first_time, deep_p)
 
       /* Make menu pop down on C-g.  */
       XtOverrideTranslations (menubar_widget, override);
+      apply_systemfont_to_menu (menubar_widget);
     }
 
   {
@@ -2468,8 +1292,10 @@ set_frame_menubar (f, first_time, deep_p)
            + f->output_data.x->menubar_widget->core.border_width)
         : 0);
 
-#if 0 /* Experimentally, we now get the right results
-        for -geometry -0-0 without this.  24 Aug 96, rms.  */
+#if 1 /* Experimentally, we now get the right results
+        for -geometry -0-0 without this.  24 Aug 96, rms.
+         Maybe so, but the menu bar size is missing the pixels so the
+         WM size hints are off by theses pixel.  Jan D, oct 2009.  */
 #ifdef USE_LUCID
     if (FRAME_EXTERNAL_MENU_BAR (f))
       {
@@ -2479,7 +1305,7 @@ set_frame_menubar (f, first_time, deep_p)
         menubar_size += ibw;
       }
 #endif /* USE_LUCID */
-#endif /* 0 */
+#endif /* 1 */
 
     f->output_data.x->menubar_height = menubar_size;
   }
@@ -2501,8 +1327,7 @@ set_frame_menubar (f, first_time, deep_p)
    is visible.  */
 
 void
-initialize_frame_menubar (f)
-     FRAME_PTR f;
+initialize_frame_menubar (FRAME_PTR 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.  */
@@ -2612,17 +1437,13 @@ struct next_popup_x_y
 
    Here only X and Y are used.  */
 static void
-menu_position_func (menu, x, y, push_in, user_data)
-     GtkMenu *menu;
-     gint *x;
-     gint *y;
-     gboolean *push_in;
-     gpointer user_data;
+menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
 {
   struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
   GtkRequisition req;
-  int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width;
-  int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
+  int disp_width = x_display_pixel_width (dpyinfo);
+  int disp_height = x_display_pixel_height (dpyinfo);
 
   *x = data->x;
   *y = data->y;
@@ -2637,9 +1458,7 @@ menu_position_func (menu, x, y, push_in, user_data)
 }
 
 static void
-popup_selection_callback (widget, client_data)
-     GtkWidget *widget;
-     gpointer client_data;
+popup_selection_callback (GtkWidget *widget, gpointer client_data)
 {
   xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
 
@@ -2648,8 +1467,7 @@ popup_selection_callback (widget, client_data)
 }
 
 static Lisp_Object
-pop_down_menu (arg)
-     Lisp_Object arg;
+pop_down_menu (Lisp_Object arg)
 {
   struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
 
@@ -2664,12 +1482,7 @@ pop_down_menu (arg)
    menu pops down.
    menu_item_selection will be set to the selection.  */
 static void
-create_and_show_popup_menu (f, first_wv, x, y, for_click)
-     FRAME_PTR f;
-     widget_value *first_wv;
-     int x;
-     int y;
-     int for_click;
+create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, int for_click, EMACS_UINT timestamp)
 {
   int i;
   GtkWidget *menu;
@@ -2711,11 +1524,13 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
 
   /* Display the menu.  */
   gtk_widget_show_all (menu);
-  gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
+
+  gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
+                 timestamp > 0 ? timestamp : gtk_get_current_event_time());
 
   record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
 
-  if (GTK_WIDGET_MAPPED (menu))
+  if (gtk_widget_get_mapped (menu))
     {
       /* Set this to one.  popup_widget_loop increases it by one, so it becomes
          two.  show_help_echo uses this to detect popup menus.  */
@@ -2774,12 +1589,13 @@ pop_down_menu (arg)
    menu pops down.
    menu_item_selection will be set to the selection.  */
 static void
-create_and_show_popup_menu (f, first_wv, x, y, for_click)
+create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
      FRAME_PTR f;
      widget_value *first_wv;
      int x;
      int y;
      int for_click;
+     EMACS_UINT timestamp;
 {
   int i;
   Arg av[2];
@@ -2798,6 +1614,8 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
                            popup_deactivate_callback,
                            menu_highlight_callback);
 
+  apply_systemfont_to_menu (menu);
+
   dummy.type = ButtonPress;
   dummy.serial = 0;
   dummy.send_event = 0;
@@ -2847,15 +1665,9 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
 
 #endif /* not USE_GTK */
 
-static Lisp_Object
-xmenu_show (f, x, y, for_click, keymaps, title, error)
-     FRAME_PTR f;
-     int x;
-     int y;
-     int for_click;
-     int keymaps;
-     Lisp_Object title;
-     char **error;
+Lisp_Object
+xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
+           Lisp_Object title, char **error, EMACS_UINT timestamp)
 {
   int i;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
@@ -3053,8 +1865,8 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
       wv_title->name = (char *) SDATA (title);
       wv_title->enabled = TRUE;
       wv_title->button_type = BUTTON_TYPE_NONE;
-      wv_title->next = wv_sep1;
       wv_title->help = Qnil;
+      wv_title->next = wv_sep1;
       first_wv->contents = wv_title;
     }
 
@@ -3062,7 +1874,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   menu_item_selection = 0;
 
   /* Actually create and show the menu until popped down.  */
-  create_and_show_popup_menu (f, first_wv, x, y, for_click);
+  create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
 
   /* Free the widget_value objects we used to specify the contents.  */
   free_menubar_widget_value_tree (first_wv);
@@ -3130,9 +1942,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 \f
 #ifdef USE_GTK
 static void
-dialog_selection_callback (widget, client_data)
-     GtkWidget *widget;
-     gpointer client_data;
+dialog_selection_callback (GtkWidget *widget, gpointer client_data)
 {
   /* The EMACS_INT cast avoids a warning.  There's no problem
      as long as pointers have enough bits to hold small integers.  */
@@ -3146,9 +1956,7 @@ dialog_selection_callback (widget, client_data)
    dialog pops down.
    menu_item_selection will be set to the selection.  */
 static void
-create_and_show_dialog (f, first_wv)
-     FRAME_PTR f;
-     widget_value *first_wv;
+create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
 {
   GtkWidget *menu;
 
@@ -3208,11 +2016,13 @@ create_and_show_dialog (f, first_wv)
     abort();
 
   dialog_id = widget_id_tick++;
+#ifdef HAVE_XFT
+  apply_systemfont_to_dialog (f->output_data.x->widget);
+#endif
   lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
                     f->output_data.x->widget, 1, 0,
                     dialog_selection_callback, 0, 0);
   lw_modify_all_widgets (dialog_id, first_wv->contents, True);
-
   /* Display the dialog box.  */
   lw_pop_up_all_widgets (dialog_id);
   popup_activated_flag = 1;
@@ -3243,11 +2053,7 @@ static char * button_names [] = {
   "button6", "button7", "button8", "button9", "button10" };
 
 static Lisp_Object
-xdialog_show (f, keymaps, title, header, error_name)
-     FRAME_PTR f;
-     int keymaps;
-     Lisp_Object title, header;
-     char **error_name;
+xdialog_show (FRAME_PTR f, int keymaps, Lisp_Object title, Lisp_Object header, char **error_name)
 {
   int i, nb_buttons=0;
   char dialog_name[6];
@@ -3372,14 +2178,6 @@ xdialog_show (f, keymaps, title, header, error_name)
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
-  /* Force a redisplay before showing the dialog.  If a frame is created
-     just before showing the dialog, its contents may not have been fully
-     drawn, as this depends on timing of events from the X server.  Redisplay
-     is not done when a dialog is shown.  If redisplay could be done in the
-     X event loop (i.e. the X event loop does not run in a signal handler)
-     this would not be needed.  */
-  Fredisplay (Qt);
-
   /* Actually create and show the dialog.  */
   create_and_show_dialog (f, first_wv);
 
@@ -3515,14 +2313,15 @@ pop_down_menu (arg)
 }
 
 
-static Lisp_Object
-xmenu_show (f, x, y, for_click, keymaps, title, error)
+Lisp_Object
+xmenu_show (f, x, y, for_click, keymaps, title, error, timestamp)
      FRAME_PTR f;
      int x, y;
      int for_click;
      int keymaps;
      Lisp_Object title;
      char **error;
+     EMACS_UINT timestamp;
 {
   Window root;
   XMenu *menu;
@@ -3537,7 +2336,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
   unsigned int dummy_uint;
   int specpdl_count = SPECPDL_INDEX ();
 
-  if (! FRAME_X_P (f))
+  if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
     abort ();
 
   *error = 0;
@@ -3700,6 +2499,23 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
       y -= (uly + height) - dispheight;
       uly = dispheight - height;
     }
+#ifndef HAVE_X_WINDOWS
+  if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
+    {
+      /* Move the menu away of the echo area, to avoid overwriting the
+        menu with help echo messages or vice versa.  */
+      if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
+       {
+         y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
+         uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
+       }
+      else
+       {
+         y--;
+         uly--;
+       }
+    }
+#endif
   if (ulx < 0) x -= ulx;
   if (uly < 0) y -= uly;
 
@@ -3799,7 +2615,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 /* Detect if a dialog or menu has been posted.  */
 
 int
-popup_activated ()
+popup_activated (void)
 {
   return popup_activated_flag;
 }
@@ -3818,13 +2634,9 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_
 }
 \f
 void
-syms_of_xmenu ()
+syms_of_xmenu (void)
 {
-  staticpro (&menu_items);
-  menu_items = Qnil;
-  menu_items_inuse = Qnil;
-
-  Qdebug_on_next_call = intern ("debug-on-next-call");
+  Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
   staticpro (&Qdebug_on_next_call);
 
 #ifdef USE_X_TOOLKIT
@@ -3832,13 +2644,12 @@ syms_of_xmenu ()
   next_menubar_widget_id = 1;
 #endif
 
-  defsubr (&Sx_popup_menu);
   defsubr (&Smenu_or_popup_active_p);
 
 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
   defsubr (&Sx_menu_bar_open_internal);
-  Ffset (intern ("accelerate-menu"),
-        intern (Sx_menu_bar_open_internal.symbol_name));
+  Ffset (intern_c_string ("accelerate-menu"),
+        intern_c_string (Sx_menu_bar_open_internal.symbol_name));
 #endif
 
 #ifdef HAVE_MENUS