]> code.delx.au - gnu-emacs/blobdiff - src/xmenu.c
Update copyright year to 2015
[gnu-emacs] / src / xmenu.c
index c167eaa8159b17a10f4ccaf9d9c611d1a581dc8c..c6bb9faee6678bc09fc6784ae8cd4cc7dff1c96c 100644 (file)
@@ -1,6 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
 
-Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2014 Free Software
+Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 Free Software
 Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -117,7 +117,7 @@ static int popup_activated_flag;
 \f
 #ifdef USE_X_TOOLKIT
 
-static int next_menubar_widget_id;
+static LWLIB_ID next_menubar_widget_id;
 
 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none.  */
 
@@ -139,53 +139,6 @@ menubar_id_to_frame (LWLIB_ID id)
 }
 
 #endif
-\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.
-   This is for Fx_popup_menu.  The mouse_position_hook can not
-   be used for X, as it returns window relative coordinates
-   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.  */
-void
-mouse_position_for_popup (struct frame *f, int *x, int *y)
-{
-  Window root, dummy_window;
-  int dummy;
-
-  eassert (FRAME_X_P (f));
-
-  block_input ();
-
-  XQueryPointer (FRAME_X_DISPLAY (f),
-                 DefaultRootWindow (FRAME_X_DISPLAY (f)),
-
-                 /* The root window which contains the pointer.  */
-                 &root,
-
-                 /* Window pointer is on, not used  */
-                 &dummy_window,
-
-                 /* The position on that root window.  */
-                 x, y,
-
-                 /* x/y in dummy_window coordinates, not used.  */
-                 &dummy, &dummy,
-
-                 /* Modifier keys and pointer buttons, about which
-                    we don't care.  */
-                 (unsigned int *) &dummy);
-
-  unblock_input ();
-
-  /* xmenu_show expects window coordinates, not root window
-     coordinates.  Translate.  */
-  *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
-  *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
-}
-
-#endif /* HAVE_X_WINDOWS */
 
 #ifndef MSDOS
 
@@ -208,9 +161,6 @@ x_menu_set_in_use (int in_use)
 
 /* Wait for an X event to arrive or for a timer to expire.  */
 
-#ifndef USE_MOTIF
-static
-#endif
 void
 x_menu_wait_for_event (void *data)
 {
@@ -677,7 +627,6 @@ update_frame_menubar (struct frame *f)
   xg_update_frame_menubar (f);
 #else
   struct x_output *x;
-  int columns, rows;
 
   eassert (FRAME_X_P (f));
 
@@ -687,10 +636,6 @@ update_frame_menubar (struct frame *f)
     return;
 
   block_input ();
-  /* Save the size of the frame because the pane widget doesn't accept
-     to resize itself. So force it.  */
-  columns = FRAME_COLS (f);
-  rows = FRAME_LINES (f);
 
   /* Do the voodoo which means "I'm changing lots of things, don't try
      to refigure sizes until I'm done."  */
@@ -711,10 +656,16 @@ update_frame_menubar (struct frame *f)
   XtManageChild (x->edit_widget);
   lw_refigure_widget (x->column_widget, True);
 
-  /* Force the pane widget to resize itself with the right values.  */
-  EmacsFrameSetCharSize (x->edit_widget, columns, rows);
+  /* Force the pane widget to resize itself.  */
+#ifdef USE_LUCID
+  /* For reasons I don't know Lucid wants to add one pixel to the frame
+     height when adding the menu bar.  Compensate that here.  */
+  adjust_frame_size (f, -1, FRAME_TEXT_HEIGHT (f) - 1, 2, 0, Qmenu_bar_lines);
+#else
+  adjust_frame_size (f, -1, -1, 2, 0, Qmenu_bar_lines);
+#endif /* USE_LUCID */
   unblock_input ();
-#endif
+#endif /* USE_GTK */
 }
 
 #ifdef USE_LUCID
@@ -755,7 +706,7 @@ apply_systemfont_to_menu (struct frame *f, Widget w)
 void
 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
 {
-  xt_or_gtk_widget menubar_widget;
+  xt_or_gtk_widget menubar_widget, old_widget;
 #ifdef USE_X_TOOLKIT
   LWLIB_ID id;
 #endif
@@ -768,7 +719,7 @@ set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
 
   eassert (FRAME_X_P (f));
 
-  menubar_widget = f->output_data.x->menubar_widget;
+  menubar_widget = old_widget = f->output_data.x->menubar_widget;
 
   XSETFRAME (Vmenu_updating_frame, f);
 
@@ -788,12 +739,6 @@ set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
       f->output_data.x->saved_menu_event->type = 0;
     }
 
-#ifdef USE_GTK
-  /* If we have detached menus, we must update deep so detached menus
-     also gets updated.  */
-  deep_p = deep_p || xg_have_tear_offs (f);
-#endif
-
   if (deep_p)
     {
       /* Make a widget-value tree representing the entire menu trees.  */
@@ -1073,7 +1018,7 @@ set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
 #endif /* USE_LUCID */
 #endif /* 1 */
 
-    f->output_data.x->menubar_height = menubar_size;
+    FRAME_MENUBAR_HEIGHT (f) = menubar_size;
   }
 #endif /* not USE_GTK */
 
@@ -1111,12 +1056,18 @@ void
 free_frame_menubar (struct frame *f)
 {
   Widget menubar_widget;
+#ifdef USE_MOTIF
+  /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
+     If we want to preserve the old height, calculate it now so we can
+     restore it below.  */
+  int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
+#endif
 
   eassert (FRAME_X_P (f));
 
   menubar_widget = f->output_data.x->menubar_widget;
 
-  f->output_data.x->menubar_height = 0;
+  FRAME_MENUBAR_HEIGHT (f) = 0;
 
   if (menubar_widget)
     {
@@ -1148,9 +1099,20 @@ free_frame_menubar (struct frame *f)
          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);
+         if (frame_inhibit_resize (f, 0, Qmenu_bar_lines))
+           adjust_frame_size (f, -1, old_height, 1, 0, Qmenu_bar_lines);
+         else
+#endif /* USE_MOTIF */
+           adjust_frame_size (f, -1, -1, 2, 0, Qmenu_bar_lines);
+       }
+      else
+       {
+#ifdef USE_MOTIF
+         if (frame_inhibit_resize (f, 0, Qmenu_bar_lines))
+           adjust_frame_size (f, -1, old_height, 1, 0, Qmenu_bar_lines);
 #endif
-         x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
        }
+
       unblock_input ();
     }
 }
@@ -1158,16 +1120,17 @@ free_frame_menubar (struct frame *f)
 
 #endif /* USE_X_TOOLKIT || USE_GTK */
 \f
-/* xmenu_show actually displays a menu using the panes and items in menu_items
+/* x_menu_show actually displays a menu using the panes and items in menu_items
    and returns the value selected from it.
-   There are two versions of xmenu_show, one for Xt and one for Xlib.
+   There are two versions of x_menu_show, one for Xt and one for Xlib.
    Both assume input is blocked by the caller.  */
 
 /* F is the frame the menu is for.
    X and Y are the frame-relative specified position,
    relative to the inside upper left corner of the frame F.
-   FOR_CLICK is true if this menu was invoked for a mouse click.
-   KEYMAPS is true if this menu was specified with keymaps;
+   Bitfield MENUFLAGS bits are:
+   MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
+   MENU_KEYMAPS is set if this menu was specified with keymaps;
     in that case, we return a list containing the chosen item's value
     and perhaps also the pane's prefix.
    TITLE is the specified menu title.
@@ -1322,8 +1285,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
 /* We need a unique id for each widget handled by the Lucid Widget
    library.
 
-   For the main windows, and popup menus, we use this counter,
-   which we increment each time after use.  This starts from 1<<16.
+   For the main windows, and popup menus, we use this counter, which we
+   increment each time after use.  This starts from WIDGET_ID_TICK_START.
 
    For menu bars, we use numbers starting at 0, counted in
    next_menubar_widget_id.  */
@@ -1335,17 +1298,13 @@ popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
   menu_item_selection = client_data;
 }
 
-/* ARG is the LWLIB ID of the dialog box, represented
-   as a Lisp object as (HIGHPART . LOWPART).  */
+/* ID is the LWLIB ID of the dialog box.  */
 
 static void
-pop_down_menu (Lisp_Object arg)
+pop_down_menu (int id)
 {
-  LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
-                 | XINT (XCDR (arg)));
-
   block_input ();
-  lw_destroy_all_widgets (id);
+  lw_destroy_all_widgets ((LWLIB_ID) id);
   unblock_input ();
   popup_activated_flag = 0;
 }
@@ -1411,11 +1370,9 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
   x_activate_timeout_atimer ();
 
   {
-    int fact = 4 * sizeof (LWLIB_ID);
     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
-    record_unwind_protect (pop_down_menu,
-                           Fcons (make_number (menu_id >> (fact)),
-                                  make_number (menu_id & ~(-1 << (fact)))));
+
+    record_unwind_protect_int (pop_down_menu, (int) menu_id);
 
     /* Process events that apply to the menu.  */
     popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, 1);
@@ -1433,8 +1390,8 @@ cleanup_widget_value_tree (void *arg)
 }
 
 Lisp_Object
-xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
-           Lisp_Object title, const char **error_name)
+x_menu_show (struct frame *f, int x, int y, int menuflags,
+            Lisp_Object title, const char **error_name)
 {
   int i;
   widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
@@ -1519,14 +1476,14 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
          /* If the pane has a meaningful name,
             make the pane a top-level menu item
             with its items as a submenu beneath it.  */
-         if (!keymaps && strcmp (pane_string, ""))
+         if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
            {
              wv = make_widget_value (pane_string, NULL, true, Qnil);
              if (save_wv)
                save_wv->next = wv;
              else
                first_wv->contents = wv;
-             if (keymaps && !NILP (prefix))
+             if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
                wv->name++;
              wv->button_type = BUTTON_TYPE_NONE;
              save_wv = wv;
@@ -1625,7 +1582,8 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
   record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
 
   /* 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,
+                             menuflags & MENU_FOR_CLICK);
 
   unbind_to (specpdl_count, Qnil);
 
@@ -1666,7 +1624,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
                = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
              if (menu_item_selection == aref_addr (menu_items, i))
                {
-                 if (keymaps)
+                 if (menuflags & MENU_KEYMAPS)
                    {
                      int j;
 
@@ -1684,7 +1642,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
            }
        }
     }
-  else if (!for_click)
+  else if (!(menuflags & MENU_FOR_CLICK))
     {
       unblock_input ();
       /* Make "Cancel" equivalent to C-g.  */
@@ -1780,12 +1738,10 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
      Also handle timers.  */
   {
     ptrdiff_t count = SPECPDL_INDEX ();
-    int fact = 4 * sizeof (LWLIB_ID);
 
     /* xdialog_show_unwind is responsible for popping the dialog box down.  */
-    record_unwind_protect (pop_down_menu,
-                           Fcons (make_number (dialog_id >> (fact)),
-                                  make_number (dialog_id & ~(-1 << (fact)))));
+
+    record_unwind_protect_int (pop_down_menu, (int) dialog_id);
 
     popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, 1);
 
@@ -2022,7 +1978,7 @@ menu_help_callback (char const *help_string, int pane, int item)
   if (EQ (first_item[0], Qt))
     pane_name = first_item[MENU_ITEMS_PANE_NAME];
   else if (EQ (first_item[0], Qquote))
-    /* This shouldn't happen, see xmenu_show.  */
+    /* This shouldn't happen, see x_menu_show.  */
     pane_name = empty_unibyte_string;
   else
     pane_name = first_item[MENU_ITEMS_ITEM_NAME];
@@ -2064,13 +2020,14 @@ pop_down_menu (Lisp_Object arg)
 
 
 Lisp_Object
-xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
-           Lisp_Object title, const char **error_name)
+x_menu_show (struct frame *f, int x, int y, int menuflags,
+            Lisp_Object title, const char **error_name)
 {
   Window root;
   XMenu *menu;
   int pane, selidx, lpane, status;
-  Lisp_Object entry, pane_prefix;
+  Lisp_Object entry = Qnil;
+  Lisp_Object pane_prefix;
   char *datap;
   int ulx, uly, width, height;
   int dispwidth, dispheight;
@@ -2092,6 +2049,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
       return Qnil;
     }
 
+  USE_SAFE_ALLOCA;
   block_input ();
 
   /* Figure out which root window F is on.  */
@@ -2104,8 +2062,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
   if (menu == NULL)
     {
       *error_name = "Can't create menu";
-      unblock_input ();
-      return Qnil;
+      goto return_entry;
     }
 
   /* Don't GC while we prepare and show the menu,
@@ -2140,7 +2097,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
          prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
          pane_string = (NILP (pane_name)
                         ? "" : SSDATA (pane_name));
-         if (keymaps && !NILP (prefix))
+         if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
            pane_string++;
 
          lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
@@ -2148,8 +2105,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
            {
              XMenuDestroy (FRAME_X_DISPLAY (f), menu);
              *error_name = "Can't create pane";
-             unblock_input ();
-             return Qnil;
+             goto return_entry;
            }
          i += MENU_ITEMS_PANE_LENGTH;
 
@@ -2193,9 +2149,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
 
          if (!NILP (descrip))
            {
-             /* if alloca is fast, use that to make the space,
-                to reduce gc needs.  */
-             item_data = alloca (maxwidth + SBYTES (descrip) + 1);
+             item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
              memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
              for (j = SCHARS (item_name); j < maxwidth; j++)
                item_data[j] = ' ';
@@ -2213,8 +2167,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
            {
              XMenuDestroy (FRAME_X_DISPLAY (f), menu);
              *error_name = "Can't add selection to menu";
-             unblock_input ();
-             return Qnil;
+             goto return_entry;
            }
          i += MENU_ITEMS_ITEM_LENGTH;
           lines++;
@@ -2263,7 +2216,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
   if (ulx < 0) x -= ulx;
   if (uly < 0) y -= uly;
 
-  if (! for_click)
+  if (!(menuflags & MENU_FOR_CLICK))
     {
       /* If position was not given by a mouse click, adjust so upper left
          corner of the menu as a whole ends up at given coordinates.  This
@@ -2288,7 +2241,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
   status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
                           x, y, ButtonReleaseMask, &datap,
                           menu_help_callback);
-  entry = pane_prefix = Qnil;
+  pane_prefix = Qnil;
 
   switch (status)
     {
@@ -2317,7 +2270,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
                    {
                      entry
                        = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
-                     if (keymaps)
+                     if (menuflags & MENU_KEYMAPS)
                        {
                          entry = list1 (entry);
                          if (!NILP (pane_prefix))
@@ -2339,7 +2292,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
     case XM_NO_SELECT:
       /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
         the menu was invoked with a mouse event as POSITION).  */
-      if (! for_click)
+      if (!(menuflags & MENU_FOR_CLICK))
        {
          unblock_input ();
          Fsignal (Qquit, Qnil);
@@ -2347,10 +2300,10 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
       break;
     }
 
+ return_entry:
   unblock_input ();
-  unbind_to (specpdl_count, Qnil);
-
-  return entry;
+  SAFE_FREE ();
+  return unbind_to (specpdl_count, entry);
 }
 
 #endif /* not USE_X_TOOLKIT */
@@ -2378,13 +2331,13 @@ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_
 void
 syms_of_xmenu (void)
 {
-  DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
-
 #ifdef USE_X_TOOLKIT
-  widget_id_tick = (1<<16);
+  enum { WIDGET_ID_TICK_START = 1 << 16 };
+  widget_id_tick = WIDGET_ID_TICK_START;
   next_menubar_widget_id = 1;
 #endif
 
+  DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
   defsubr (&Smenu_or_popup_active_p);
 
 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)