Promote SSDATA macro from gtkutil.c and xsmfns.c to lisp.h.
[bpt/emacs.git] / src / xmenu.c
index fee66df..93fcf69 100644 (file)
@@ -1,6 +1,6 @@
 /* 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, 2011 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -37,6 +37,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 
 #include <stdio.h>
+#include <setjmp.h>
 
 #include "lisp.h"
 #include "keyboard.h"
@@ -80,13 +81,17 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #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 */
 #include <X11/Xaw/Paned.h>
 #endif /* HAVE_XAW3D */
 #endif /* USE_LUCID */
+#ifdef USE_MOTIF
 #include "../lwlib/lwlib.h"
+#endif
 #else /* not USE_X_TOOLKIT */
 #ifndef USE_GTK
 #include "../oldXMenu/XMenu.h"
@@ -107,38 +112,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 Lisp_Object Qdebug_on_next_call;
 
-extern Lisp_Object Vmenu_updating_frame;
-
-extern Lisp_Object Qmenu_bar;
-
-extern Lisp_Object QCtoggle, QCradio;
-
-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 P_ ((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));
-#endif /* USE_X_TOOLKIT */
-
-#ifdef USE_GTK
-extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
-static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
-                                    char **));
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
+                                 const char **);
 #endif
 
-static int update_frame_menubar P_ ((struct frame *));
-static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
-                                  Lisp_Object, char **));
+static int update_frame_menubar (struct frame *);
 \f
 /* Flag which when set indicates a dialog or menu has been posted by
    Xt on behalf of one of the widget sets.  */
@@ -146,28 +125,13 @@ 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 P_ ((void));
-extern widget_value *digest_single_submenu P_ ((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.
-
-   I don't understand why this is needed, but it does seem to be
-   needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>.  */
-
-int pending_menu_activation;
 \f
 #ifdef USE_X_TOOLKIT
 
 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none.  */
 
 static struct frame *
-menubar_id_to_frame (id)
-     LWLIB_ID id;
+menubar_id_to_frame (LWLIB_ID id)
 {
   Lisp_Object tail, frame;
   FRAME_PTR f;
@@ -196,11 +160,8 @@ menubar_id_to_frame (id)
    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;
@@ -239,282 +200,6 @@ 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;
-         void (*mouse_position_hook) P_ ((struct frame **, int,
-                                          Lisp_Object *,
-                                          enum scroll_bar_part *,
-                                          Lisp_Object *,
-                                          Lisp_Object *,
-                                          unsigned long *)) =
-           new_f->terminal->mouse_position_hook;
-
-         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);
-           }
-       }
-
-      CHECK_NUMBER (x);
-      CHECK_NUMBER (y);
-
-      /* Decode where to put the menu.  */
-
-      if (FRAMEP (window))
-       {
-         f = XFRAME (window);
-         xpos = 0;
-         ypos = 0;
-       }
-      else if (WINDOWP (window))
-       {
-         CHECK_LIVE_WINDOW (window);
-         f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
-
-         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);
-
-      xpos += XINT (x);
-      ypos += XINT (y);
-
-      if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
-        error ("Can not put X menu on this terminal");
-
-      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,
@@ -540,8 +225,7 @@ 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;
+  (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
 {
   FRAME_PTR f = NULL;
   Lisp_Object window;
@@ -604,6 +288,17 @@ for instance using the window manager, then this produces a quit and
   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
      in the middle of frame F.  */
@@ -620,7 +315,7 @@ for instance using the window manager, then this produces a quit and
 #else
   {
     Lisp_Object title;
-    char *error_name;
+    const char *error_name;
     Lisp_Object selection;
     int specpdl_count = SPECPDL_INDEX ();
 
@@ -657,8 +352,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;
@@ -673,8 +367,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
@@ -690,7 +382,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;
@@ -703,17 +395,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 */
@@ -731,11 +421,7 @@ x_menu_wait_for_event (void *data)
    with BLOCK_INPUT, UNBLOCK_INPUT wrappers.  */
 
 static void
-popup_get_selection (initial_event, dpyinfo, id, do_timers)
-     XEvent *initial_event;
-     struct x_display_info *dpyinfo;
-     LWLIB_ID id;
-     int do_timers;
+popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo, LWLIB_ID id, int do_timers)
 {
   XEvent event;
 
@@ -792,8 +478,7 @@ arrow keys, select a menu entry with the return key or cancel with the
 escape key.  If FRAME has no menu bar this function does nothing.
 
 If FRAME is nil or not given, use the selected frame.  */)
-     (frame)
-     Lisp_Object frame;
+  (Lisp_Object frame)
 {
   XEvent ev;
   FRAME_PTR f = check_x_frame (frame);
@@ -871,8 +556,7 @@ arrow keys, select a menu entry with the return key or cancel with the
 escape key.  If FRAME has no menu bar this function does nothing.
 
 If FRAME is nil or not given, use the selected frame.  */)
-     (frame)
-     Lisp_Object frame;
+  (Lisp_Object frame)
 {
   GtkWidget *menubar;
   FRAME_PTR f;
@@ -908,9 +592,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;
 
@@ -938,8 +620,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 ();
@@ -955,18 +636,14 @@ x_activate_menubar (f)
 
   set_frame_menubar (f, 0, 1);
   BLOCK_INPUT;
+  popup_activated_flag = 1;
 #ifdef USE_GTK
   XPutBackEvent (f->output_data.x->display_info->display,
                  f->output_data.x->saved_menu_event);
-  popup_activated_flag = 1;
 #else
   XtDispatchEvent (f->output_data.x->saved_menu_event);
 #endif
   UNBLOCK_INPUT;
-#ifdef USE_MOTIF
-  if (f->output_data.x->saved_menu_event->type == ButtonRelease)
-    pending_menu_activation = 1;
-#endif
 
   /* Ignore this if we get it a second time.  */
   f->output_data.x->saved_menu_event->type = 0;
@@ -977,10 +654,7 @@ x_activate_menubar (f)
 
 #ifndef USE_GTK
 static void
-popup_activate_callback (widget, id, client_data)
-     Widget widget;
-     LWLIB_ID id;
-     XtPointer client_data;
+popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
   popup_activated_flag = 1;
 #ifdef USE_X_TOOLKIT
@@ -994,18 +668,13 @@ popup_activate_callback (widget, id, client_data)
 
 #ifdef USE_GTK
 static void
-popup_deactivate_callback (widget, client_data)
-     GtkWidget *widget;
-     gpointer client_data;
+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_deactivate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
   popup_activated_flag = 0;
 }
@@ -1016,10 +685,7 @@ popup_deactivate_callback (widget, id, client_data)
    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;
+show_help_event (FRAME_PTR f, xt_or_gtk_widget widget, Lisp_Object help)
 {
   Lisp_Object frame;
 
@@ -1057,9 +723,7 @@ show_help_event (f, widget, help)
 
 #ifdef USE_GTK
 void
-menu_highlight_callback (widget, call_data)
-     GtkWidget *widget;
-     gpointer call_data;
+menu_highlight_callback (GtkWidget *widget, gpointer call_data)
 {
   xg_menu_item_cb_data *cb_data;
   Lisp_Object help;
@@ -1078,10 +742,7 @@ menu_highlight_callback (widget, call_data)
 }
 #else
 void
-menu_highlight_callback (widget, id, call_data)
-     Widget widget;
-     LWLIB_ID id;
-     void *call_data;
+menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
 {
   struct frame *f;
   Lisp_Object help;
@@ -1109,9 +770,7 @@ static int xg_crazy_callback_abort;
    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;
+menubar_selection_callback (GtkWidget *widget, gpointer client_data)
 {
   xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
 
@@ -1154,10 +813,7 @@ menubar_selection_callback (widget, client_data)
    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;
+menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
   FRAME_PTR f;
 
@@ -1173,8 +829,7 @@ menubar_selection_callback (widget, id, client_data)
    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);
@@ -1222,15 +877,48 @@ update_frame_menubar (f)
   return 1;
 }
 
+#ifdef USE_LUCID
+static void
+apply_systemfont_to_dialog (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 (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
@@ -1257,8 +945,6 @@ set_frame_menubar (f, first_time, deep_p)
 
   if (! menubar_widget)
     deep_p = 1;
-  else if (pending_menu_activation && !deep_p)
-    deep_p = 1;
   /* Make the first call for any given frame always go deep.  */
   else if (!f->output_data.x->saved_menu_event && !deep_p)
     {
@@ -1319,8 +1005,8 @@ set_frame_menubar (f, first_time, deep_p)
 
       /* Save the frame's previous menu bar contents data.  */
       if (previous_menu_items_used)
-       bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
-              previous_menu_items_used * sizeof (Lisp_Object));
+       memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
+               previous_menu_items_used * sizeof (Lisp_Object));
 
       /* Fill in menu_items with the current menu bar contents.
         This can evaluate Lisp code.  */
@@ -1420,7 +1106,7 @@ set_frame_menubar (f, first_time, deep_p)
          string = XVECTOR (items)->contents[i + 1];
          if (NILP (string))
             break;
-          wv->name = (char *) SDATA (string);
+          wv->name = SSDATA (string);
           update_submenu_strings (wv->contents);
           wv = wv->next;
        }
@@ -1449,7 +1135,7 @@ set_frame_menubar (f, first_time, deep_p)
            break;
 
          wv = xmalloc_widget_value ();
-         wv->name = (char *) SDATA (string);
+         wv->name = SSDATA (string);
          wv->value = 0;
          wv->enabled = 1;
          wv->button_type = BUTTON_TYPE_NONE;
@@ -1534,17 +1220,26 @@ set_frame_menubar (f, first_time, deep_p)
 
       /* Make menu pop down on C-g.  */
       XtOverrideTranslations (menubar_widget, override);
+#ifdef USE_LUCID
+      apply_systemfont_to_menu (menubar_widget);
+#endif
     }
 
   {
-    int menubar_size
+    int menubar_size;
+    if (f->output_data.x->menubar_widget)
+      XtRealizeWidget (f->output_data.x->menubar_widget);
+
+    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 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 these pixels.  Jan D, oct 2009.  */
 #ifdef USE_LUCID
     if (FRAME_EXTERNAL_MENU_BAR (f))
       {
@@ -1554,7 +1249,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;
   }
@@ -1576,8 +1271,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.  */
@@ -1592,8 +1286,7 @@ initialize_frame_menubar (f)
 
 #ifndef USE_GTK
 void
-free_frame_menubar (f)
-     FRAME_PTR f;
+free_frame_menubar (FRAME_PTR f)
 {
   Widget menubar_widget;
 
@@ -1628,15 +1321,15 @@ free_frame_menubar (f)
       lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
       f->output_data.x->menubar_widget = NULL;
 
-#ifdef USE_MOTIF
       if (f->output_data.x->widget)
        {
+#ifdef USE_MOTIF
          XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
          if (x1 == 0 && y1 == 0)
            XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
-       }
 #endif
-
+          x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
+       }
       UNBLOCK_INPUT;
     }
 }
@@ -1687,17 +1380,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;
@@ -1712,9 +1401,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;
 
@@ -1723,8 +1410,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);
 
@@ -1739,12 +1425,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;
@@ -1786,11 +1467,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.  */
@@ -1819,10 +1502,7 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
 LWLIB_ID widget_id_tick;
 
 static void
-popup_selection_callback (widget, id, client_data)
-     Widget widget;
-     LWLIB_ID id;
-     XtPointer client_data;
+popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
   menu_item_selection = (Lisp_Object *) client_data;
 }
@@ -1831,8 +1511,7 @@ popup_selection_callback (widget, id, client_data)
    as a Lisp object as (HIGHPART . LOWPART).  */
 
 static Lisp_Object
-pop_down_menu (arg)
-     Lisp_Object arg;
+pop_down_menu (Lisp_Object arg)
 {
   LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
                  | XINT (XCDR (arg)));
@@ -1849,12 +1528,8 @@ 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;
   Arg av[2];
@@ -1873,6 +1548,10 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
                            popup_deactivate_callback,
                            menu_highlight_callback);
 
+#ifdef USE_LUCID
+  apply_systemfont_to_menu (menu);
+#endif
+
   dummy.type = ButtonPress;
   dummy.serial = 0;
   dummy.send_event = 0;
@@ -1922,15 +1601,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, const char **error, EMACS_UINT timestamp)
 {
   int i;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
@@ -1994,7 +1667,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
        {
          /* Create a new pane.  */
          Lisp_Object pane_name, prefix;
-         char *pane_string;
+         const char *pane_string;
 
          pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
          prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
@@ -2007,7 +1680,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
            }
 #endif
          pane_string = (NILP (pane_name)
-                        ? "" : (char *) SDATA (pane_name));
+                        ? "" : SSDATA (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)
@@ -2072,9 +1745,9 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
            prev_wv->next = wv;
          else
            save_wv->contents = wv;
-         wv->name = (char *) SDATA (item_name);
+         wv->name = SSDATA (item_name);
          if (!NILP (descrip))
-           wv->key = (char *) SDATA (descrip);
+           wv->key = SSDATA (descrip);
          wv->value = 0;
          /* If this item has a null value,
             make the call_data null so that it won't display a box
@@ -2125,7 +1798,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
        title = ENCODE_MENU_STRING (title);
 #endif
 
-      wv_title->name = (char *) SDATA (title);
+      wv_title->name = SSDATA (title);
       wv_title->enabled = TRUE;
       wv_title->button_type = BUTTON_TYPE_NONE;
       wv_title->help = Qnil;
@@ -2137,7 +1810,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);
@@ -2205,9 +1878,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.  */
@@ -2221,9 +1892,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;
 
@@ -2252,10 +1921,7 @@ create_and_show_dialog (f, first_wv)
 
 #else /* not USE_GTK */
 static void
-dialog_selection_callback (widget, id, client_data)
-     Widget widget;
-     LWLIB_ID id;
-     XtPointer client_data;
+dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
   /* The EMACS_INT cast avoids a warning.  There's no problem
      as long as pointers have enough bits to hold small integers.  */
@@ -2273,9 +1939,7 @@ dialog_selection_callback (widget, id, 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)
 {
   LWLIB_ID dialog_id;
 
@@ -2283,11 +1947,13 @@ create_and_show_dialog (f, first_wv)
     abort();
 
   dialog_id = widget_id_tick++;
+#ifdef USE_LUCID
+  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;
@@ -2313,16 +1979,16 @@ create_and_show_dialog (f, first_wv)
 
 #endif /* not USE_GTK */
 
-static char * button_names [] = {
+static const char * button_names [] = {
   "button1", "button2", "button3", "button4", "button5",
   "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,
+              const char **error_name)
 {
   int i, nb_buttons=0;
   char dialog_name[6];
@@ -2349,11 +2015,11 @@ xdialog_show (f, keymaps, title, header, error_name)
      representing the text label and buttons.  */
   {
     Lisp_Object pane_name, prefix;
-    char *pane_string;
+    const char *pane_string;
     pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
     prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
     pane_string = (NILP (pane_name)
-                  ? "" : (char *) SDATA (pane_name));
+                  ? "" : SSDATA (pane_name));
     prev_wv = xmalloc_widget_value ();
     prev_wv->value = pane_string;
     if (keymaps && !NILP (prefix))
@@ -2400,8 +2066,8 @@ xdialog_show (f, keymaps, title, header, error_name)
        prev_wv->next = wv;
        wv->name = (char *) button_names[nb_buttons];
        if (!NILP (descrip))
-         wv->key = (char *) SDATA (descrip);
-       wv->value = (char *) SDATA (item_name);
+         wv->key = SSDATA (descrip);
+       wv->value = SSDATA (item_name);
        wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
        wv->enabled = !NILP (enable);
        wv->help = Qnil;
@@ -2447,14 +2113,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);
 
@@ -2528,11 +2186,8 @@ static struct frame *menu_help_frame;
    keyboard events.  */
 
 static void
-menu_help_callback (help_string, pane, item)
-     char *help_string;
-     int pane, item;
+menu_help_callback (char *help_string, int pane, int item)
 {
-  extern Lisp_Object Qmenu_item;
   Lisp_Object *first_item;
   Lisp_Object pane_name;
   Lisp_Object menu_object;
@@ -2555,8 +2210,7 @@ menu_help_callback (help_string, pane, item)
 }
 
 static Lisp_Object
-pop_down_menu (arg)
-     Lisp_Object arg;
+pop_down_menu (Lisp_Object arg)
 {
   struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
   struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
@@ -2590,14 +2244,9 @@ pop_down_menu (arg)
 }
 
 
-static Lisp_Object
-xmenu_show (f, x, y, for_click, keymaps, title, error)
-     FRAME_PTR f;
-     int x, 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, const char **error, EMACS_UINT timestamp)
 {
   Window root;
   XMenu *menu;
@@ -2668,7 +2317,7 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
          pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
          prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
          pane_string = (NILP (pane_name)
-                        ? "" : (char *) SDATA (pane_name));
+                        ? "" : SSDATA (pane_name));
          if (keymaps && !NILP (prefix))
            pane_string++;
 
@@ -2728,12 +2377,10 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
              item_data
                = (unsigned char *) alloca (maxwidth
                                            + SBYTES (descrip) + 1);
-             bcopy (SDATA (item_name), item_data,
-                    SBYTES (item_name));
+             memcpy (item_data, SDATA (item_name), SBYTES (item_name));
              for (j = SCHARS (item_name); j < maxwidth; j++)
                item_data[j] = ' ';
-             bcopy (SDATA (descrip), item_data + j,
-                    SBYTES (descrip));
+             memcpy (item_data + j, SDATA (descrip), SBYTES (descrip));
              item_data[j + SBYTES (descrip)] = 0;
            }
          else
@@ -2775,6 +2422,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;
 
@@ -2871,19 +2535,22 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
 
 #endif /* HAVE_MENUS */
 
-/* Detect if a dialog or menu has been posted.  */
+#ifndef MSDOS
+/* Detect if a dialog or menu has been posted.  MSDOS has its own
+   implementation on msdos.c.  */
 
 int
-popup_activated ()
+popup_activated (void)
 {
   return popup_activated_flag;
 }
+#endif /* not MSDOS */
 
 /* The following is used by delayed window autoselection.  */
 
 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
        doc: /* Return t if a menu or popup dialog is active.  */)
-     ()
+  (void)
 {
 #ifdef HAVE_MENUS
   return (popup_activated ()) ? Qt : Qnil;
@@ -2893,9 +2560,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)
 {
-  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
@@ -2903,19 +2570,15 @@ 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
   defsubr (&Sx_popup_dialog);
 #endif
 }
-
-/* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
-   (do not change this comment) */