/* 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.
\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. */
}
#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
/* 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)
{
xg_update_frame_menubar (f);
#else
struct x_output *x;
- int columns, rows;
eassert (FRAME_X_P (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." */
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
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
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);
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. */
#endif /* USE_LUCID */
#endif /* 1 */
- f->output_data.x->menubar_height = menubar_size;
+ FRAME_MENUBAR_HEIGHT (f) = menubar_size;
}
#endif /* not USE_GTK */
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)
{
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 ();
}
}
#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.
/* 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. */
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;
}
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);
}
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;
/* 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;
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);
= 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;
}
}
}
- else if (!for_click)
+ else if (!(menuflags & MENU_FOR_CLICK))
{
unblock_input ();
/* Make "Cancel" equivalent to C-g. */
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);
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];
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;
return Qnil;
}
+ USE_SAFE_ALLOCA;
block_input ();
/* Figure out which root window F is on. */
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,
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);
{
XMenuDestroy (FRAME_X_DISPLAY (f), menu);
*error_name = "Can't create pane";
- unblock_input ();
- return Qnil;
+ goto return_entry;
}
i += MENU_ITEMS_PANE_LENGTH;
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] = ' ';
{
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++;
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
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)
{
{
entry
= AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
- if (keymaps)
+ if (menuflags & MENU_KEYMAPS)
{
entry = list1 (entry);
if (!NILP (pane_prefix))
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);
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 */
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)