* etc/NEWS: Update for renamed variable.
[bpt/emacs.git] / src / xmenu.c
index 7d7515a..79ead5f 100644 (file)
@@ -1,6 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
 
-Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2011
+Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2012
   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -102,6 +102,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef USE_GTK
 #include "gtkutil.h"
+#ifdef HAVE_GTK3
+#include "xgselect.h"
+#endif
 #endif
 
 #include "menu.h"
@@ -315,7 +318,7 @@ for instance using the window manager, then this produces a quit and
     Lisp_Object title;
     const char *error_name;
     Lisp_Object selection;
-    int specpdl_count = SPECPDL_INDEX ();
+    ptrdiff_t specpdl_count = SPECPDL_INDEX ();
 
     /* Decode the dialog items from what was specified.  */
     title = Fcar (contents);
@@ -347,6 +350,8 @@ for instance using the window manager, then this produces a quit and
 
 #ifndef MSDOS
 
+#if defined USE_GTK || defined USE_MOTIF
+
 /* Set menu_items_inuse so no other popup menu or dialog is created.  */
 
 void
@@ -360,6 +365,8 @@ x_menu_set_in_use (int in_use)
 #endif
 }
 
+#endif
+
 /* Wait for an X event to arrive or for a timer to expire.  */
 
 #ifndef USE_MOTIF
@@ -404,7 +411,15 @@ x_menu_wait_for_event (void *data)
       else
         ntp = &next_time;
 
+#ifdef HAVE_GTK3
+      /* Gtk3 have arrows on menus when they don't fit.  When the pointer is
+         over an arrow, a timeout scrolls it a bit.  Use xg_select so that
+         timeout gets triggered.  */
+
+      xg_select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
+#else
       select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
+#endif
     }
 }
 #endif /* ! MSDOS */
@@ -736,10 +751,13 @@ menu_highlight_callback (GtkWidget *widget, gpointer call_data)
   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);
+     Don't pass the frame to show_help_event for those.
+     Passing frame creates an Emacs event.  As we are looping in
+     popup_widget_loop, it won't be handled.  Passing NULL shows the tip
+     directly without using an Emacs event.  This is what the Lucid code
+     does below.  */
+  show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
+                   widget, help);
 }
 #else
 static void
@@ -961,7 +979,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
 
       struct buffer *prev = current_buffer;
       Lisp_Object buffer;
-      int specpdl_count = SPECPDL_INDEX ();
+      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
       int previous_menu_items_used = f->menu_bar_items_used;
       Lisp_Object *previous_items
        = (Lisp_Object *) alloca (previous_menu_items_used
@@ -1297,7 +1315,7 @@ free_frame_menubar (FRAME_PTR f)
 #ifdef USE_MOTIF
       /* Removing the menu bar magically changes the shell widget's x
         and y position of (0, 0) which, when the menu bar is turned
-        on again, leads to pull-down menuss appearing in strange
+        on again, leads to pull-down menus appearing in strange
         positions near the upper-left corner of the display.  This
         happens only with some window managers like twm and ctwm,
         but not with other like Motif's mwm or kwm, because the
@@ -1427,7 +1445,14 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y,
   GtkWidget *menu;
   GtkMenuPositionFunc pos_func = 0;  /* Pop up at pointer.  */
   struct next_popup_x_y popup_x_y;
-  int specpdl_count = SPECPDL_INDEX ();
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+  int use_pos_func = ! for_click;
+
+#ifdef HAVE_GTK3
+  /* Always use position function for Gtk3.  Otherwise menus may become
+     too small to show anything.  */
+  use_pos_func = 1;
+#endif
 
   if (! FRAME_X_P (f))
     abort ();
@@ -1439,7 +1464,7 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y,
                            G_CALLBACK (menu_highlight_callback));
   xg_crazy_callback_abort = 0;
 
-  if (! for_click)
+  if (use_pos_func)
     {
       /* Not invoked by a click.  pop up at x/y.  */
       pos_func = menu_position_func;
@@ -1454,7 +1479,8 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y,
 
       i = 0;  /* gtk_menu_popup needs this to be 0 for a non-button popup.  */
     }
-  else
+
+  if (for_click)
     {
       for (i = 0; i < 5; i++)
         if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
@@ -1583,7 +1609,7 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv,
 
   {
     int fact = 4 * sizeof (LWLIB_ID);
-    int specpdl_count = SPECPDL_INDEX ();
+    ptrdiff_t specpdl_count = SPECPDL_INDEX ();
     record_unwind_protect (pop_down_menu,
                            Fcons (make_number (menu_id >> (fact)),
                                   make_number (menu_id & ~(-1 << (fact)))));
@@ -1597,6 +1623,17 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv,
 
 #endif /* not USE_GTK */
 
+static Lisp_Object
+cleanup_widget_value_tree (Lisp_Object arg)
+{
+  struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
+  widget_value *wv = p->pointer;
+
+  free_menubar_widget_value_tree (wv);
+
+  return Qnil;
+}
+
 Lisp_Object
 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
            Lisp_Object title, const char **error_name, Time timestamp)
@@ -1611,6 +1648,8 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
 
   int first_pane;
 
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
   if (! FRAME_X_P (f))
     abort ();
 
@@ -1805,11 +1844,15 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
+  /* Make sure to free the widget_value objects we used to specify the
+     contents even with longjmp.  */
+  record_unwind_protect (cleanup_widget_value_tree,
+                        make_save_value (first_wv, 0));
+
   /* Actually create and show the menu until popped down.  */
   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);
+  unbind_to (specpdl_count, Qnil);
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
@@ -1902,7 +1945,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
 
   if (menu)
     {
-      int specpdl_count = SPECPDL_INDEX ();
+      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
       record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
 
       /* Display the menu.  */
@@ -1919,9 +1962,9 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
 static void
 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
 {
-  /* The EMACS_INT cast avoids a warning.  There's no problem
+  /* Treat the pointer as an integer.  There's no problem
      as long as pointers have enough bits to hold small integers.  */
-  if ((int) (EMACS_INT) client_data != -1)
+  if ((intptr_t) client_data != -1)
     menu_item_selection = (Lisp_Object *) client_data;
 
   BLOCK_INPUT;
@@ -1940,7 +1983,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
   LWLIB_ID dialog_id;
 
   if (!FRAME_X_P (f))
-    abort();
+    abort ();
 
   dialog_id = widget_id_tick++;
 #ifdef USE_LUCID
@@ -1958,7 +2001,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
   /* Process events that apply to the dialog box.
      Also handle timers.  */
   {
-    int count = SPECPDL_INDEX ();
+    ptrdiff_t count = SPECPDL_INDEX ();
     int fact = 4 * sizeof (LWLIB_ID);
 
     /* xdialog_show_unwind is responsible for popping the dialog box down.  */
@@ -1996,6 +2039,8 @@ xdialog_show (FRAME_PTR f,
   /* 1 means we've seen the boundary between left-hand elts and right-hand.  */
   int boundary_seen = 0;
 
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
   if (! FRAME_X_P (f))
     abort ();
 
@@ -2088,7 +2133,7 @@ xdialog_show (FRAME_PTR f,
     /*  Frame title: 'Q' = Question, 'I' = Information.
         Can also have 'E' = Error if, one day, we want
         a popup for errors. */
-    if (NILP(header))
+    if (NILP (header))
       dialog_name[0] = 'Q';
     else
       dialog_name[0] = 'I';
@@ -2109,11 +2154,15 @@ xdialog_show (FRAME_PTR f,
   /* No selection has been chosen yet.  */
   menu_item_selection = 0;
 
+  /* Make sure to free the widget_value objects we used to specify the
+     contents even with longjmp.  */
+  record_unwind_protect (cleanup_widget_value_tree,
+                        make_save_value (first_wv, 0));
+
   /* Actually create and show the dialog.  */
   create_and_show_dialog (f, first_wv);
 
-  /* Free the widget_value objects we used to specify the contents.  */
-  free_menubar_widget_value_tree (first_wv);
+  unbind_to (specpdl_count, Qnil);
 
   /* Find the selected item, and its pane, to return
      the proper value.  */
@@ -2255,7 +2304,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
   int maxwidth;
   int dummy_int;
   unsigned int dummy_uint;
-  int specpdl_count = SPECPDL_INDEX ();
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
 
   if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
     abort ();
@@ -2555,8 +2604,7 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_
 void
 syms_of_xmenu (void)
 {
-  Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
-  staticpro (&Qdebug_on_next_call);
+  DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
 
 #ifdef USE_X_TOOLKIT
   widget_id_tick = (1<<16);