/* X Communication module for terminals which understand the X protocol.
- Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2003, 2004,
+ 2005 Free Software Foundation, Inc.
This file is part of GNU Emacs.
static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, char **));
static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
- LWLIB_ID, int, int));
+ LWLIB_ID, int));
/* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
/* gtk just uses utf-8. */
# define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
#else
-/* I'm not convinced ENCODE_SYSTEM is defined correctly, or maybe
- something else should be used here. Except under MS-Windows it
- just converts to unibyte, but encoding with `locale-coding-system'
- seems better -- X may actually display the result correctly, and
- it's not necessarily equivalent to the unibyte text. -- fx */
-# define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
+# define ENCODE_MENU_STRING(str) string_make_unibyte (str)
#endif
static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
init_menu_items ();
- for (tail = menu; !NILP (tail); tail = Fcdr (tail))
+ for (tail = menu; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object elt, pane_name, pane_data;
- elt = Fcar (tail);
+ elt = XCAR (tail);
pane_name = Fcar (elt);
CHECK_STRING (pane_name);
push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
{
Lisp_Object tail, item, item1;
- for (tail = pane; !NILP (tail); tail = Fcdr (tail))
+ for (tail = pane; CONSP (tail); tail = XCDR (tail))
{
- item = Fcar (tail);
+ item = XCAR (tail);
if (STRINGP (item))
push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
Qnil, Qnil, Qnil, Qnil);
- else if (NILP (item))
- push_left_right_boundary ();
- else
+ else if (CONSP (item))
{
- CHECK_CONS (item);
- item1 = Fcar (item);
+ item1 = XCAR (item);
CHECK_STRING (item1);
- push_menu_item (ENCODE_MENU_STRING (item1), Qt, Fcdr (item),
+ push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
Qt, Qnil, Qnil, Qnil, Qnil);
}
+ else
+ push_left_right_boundary ();
+
}
}
\f
or a list ((XOFFSET YOFFSET) WINDOW)
where XOFFSET and YOFFSET are positions in pixels from the top left
corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)
-This controls the position of the center of the first line
-in the first pane of the menu, not the top left of the menu as a whole.
+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.
if (CONSP (tem))
{
window = Fcar (Fcdr (position));
- x = Fcar (tem);
- y = Fcar (Fcdr (tem));
+ x = XCAR (tem);
+ y = Fcar (XCDR (tem));
}
else
{
/* The first keymap that has a prompt string
supplies the menu title. */
- for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
+ for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
{
Lisp_Object prompt;
- maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
+ maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
prompt = Fkeymap_prompt (keymap);
if (NILP (title) && !NILP (prompt))
#ifndef MSDOS
-/* Return non-zero if a dialog or popup menu is already popped up. */
-
-int
-x_menu_in_use ()
-{
- return ! NILP (menu_items_inuse);
-}
-
/* Set menu_items_inuse so no other popup menu or dialog is created. */
void
int in_use;
{
menu_items_inuse = in_use ? Qt : Qnil;
+ popup_activated_flag = in_use;
}
/* Wait for an X event to arrive or for a timer to expire. */
popped down (deactivated). This is used for x-popup-menu
and x-popup-dialog; it is not used for the menu bar.
- If DOWN_ON_KEYPRESS is nonzero, pop down if a key is pressed.
-
NOTE: All calls to popup_get_selection should be protected
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
static void
-popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress)
+popup_get_selection (initial_event, dpyinfo, id, do_timers)
XEvent *initial_event;
struct x_display_info *dpyinfo;
LWLIB_ID id;
int do_timers;
- int down_on_keypress;
{
XEvent event;
while (popup_activated_flag)
{
- if (initial_event)
+ if (initial_event)
{
event = *initial_event;
initial_event = 0;
event.xbutton.state = 0;
#endif
}
- /* If the user presses a key that doesn't go to the menu,
- deactivate the menu.
- The user is likely to do that if we get wedged.
- All toolkits now pop down menus on ESC.
- For dialogs however, the focus may not be on the dialog, so
- in that case, we pop down. */
+ /* Pop down on C-g and Escape. */
else if (event.type == KeyPress
- && down_on_keypress
&& dpyinfo->display == event.xbutton.display)
{
KeySym keysym = XLookupKeysym (&event.xkey, 0);
- if (!IsModifierKey (keysym)
- && x_any_window_to_frame (dpyinfo, event.xany.window) != NULL)
- popup_activated_flag = 0;
+
+ if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
+ || keysym == XK_Escape) /* Any escape, ignore modifiers. */
+ popup_activated_flag = 0;
}
x_dispatch_event (&event, event.xany.display);
/* 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.
- */
-void
+ 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;
- int menu_bar_items_used;
+ EMACS_INT menu_bar_items_used;
Lisp_Object vector;
void *client_data;
{
if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
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,
#ifndef HAVE_MULTILINGUAL_MENU
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
{
- pane_name = ENCODE_SYSTEM (pane_name);
+ pane_name = ENCODE_MENU_STRING (pane_name);
AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
}
#endif
}
else
{
+ char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
+ XtTranslations override = XtParseTranslationTable (menuOverride);
+
menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
f->output_data.x->column_widget,
0,
popup_deactivate_callback,
menu_highlight_callback);
f->output_data.x->menubar_widget = menubar_widget;
+
+ /* Make menu pop down on C-g. */
+ XtOverrideTranslations (menubar_widget, override);
}
{
G_CALLBACK (menu_highlight_callback));
xg_crazy_callback_abort = 0;
- for (i = 0; i < 5; i++)
- if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
- break;
-
if (! for_click)
{
/* Not invoked by a click. pop up at x/y. */
popup_x_y.x = x;
popup_x_y.y = y;
popup_x_y.f = f;
- }
+ i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
+ }
+ else
+ {
+ for (i = 0; i < 5; i++)
+ if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
+ break;
+ }
+
/* Display the menu. */
gtk_widget_show_all (menu);
gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
- fprintf (stderr, "Unwind: %p\n", menu);
record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
/* Set this to one. popup_widget_loop increases it by one, so it becomes
make_number (menu_id & ~(-1 << (fact)))));
/* Process events that apply to the menu. */
- popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1, 0);
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
unbind_to (specpdl_count, Qnil);
}
#ifndef HAVE_MULTILINGUAL_MENU
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
{
- pane_name = ENCODE_SYSTEM (pane_name);
+ pane_name = ENCODE_MENU_STRING (pane_name);
AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
}
#endif
make_number (dialog_id & ~(-1 << (fact)))));
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
- dialog_id, 1, 1);
+ dialog_id, 1);
unbind_to (count, Qnil);
}
}
}
}
+ else
+ /* Make "Cancel" equivalent to C-g. */
+ Fsignal (Qquit, Qnil);
return Qnil;
}
char *datap;
int ulx, uly, width, height;
int dispwidth, dispheight;
- int i, j;
+ int i, j, lines, maxlines;
int maxwidth;
int dummy_int;
unsigned int dummy_uint;
#ifdef HAVE_X_WINDOWS
/* Adjust coordinates to relative to the outer (window manager) window. */
- {
- Window child;
- int win_x = 0, win_y = 0;
-
- /* Find the position of the outside upper-left corner of
- the inner window, with respect to the outer window. */
- if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
- {
- BLOCK_INPUT;
- XTranslateCoordinates (FRAME_X_DISPLAY (f),
-
- /* From-window, to-window. */
- f->output_data.x->window_desc,
- f->output_data.x->parent_desc,
-
- /* From-position, to-position. */
- 0, 0, &win_x, &win_y,
-
- /* Child of window. */
- &child);
- UNBLOCK_INPUT;
- x += win_x;
- y += win_y;
- }
- }
+ x += FRAME_OUTER_TO_INNER_DIFF_X (f);
+ y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
#endif /* HAVE_X_WINDOWS */
/* Adjust coordinates to be root-window-relative. */
y += f->top_pos;
/* Create all the necessary panes and their items. */
- i = 0;
+ maxlines = lines = i = 0;
while (i < menu_items_used)
{
if (EQ (XVECTOR (menu_items)->contents[i], Qt))
Lisp_Object pane_name, prefix;
char *pane_string;
+ maxlines = max (maxlines, lines);
+ lines = 0;
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)
return Qnil;
}
i += MENU_ITEMS_ITEM_LENGTH;
+ lines++;
}
}
+ maxlines = max (maxlines, lines);
+
/* All set and ready to fly. */
XMenuRecompute (FRAME_X_DISPLAY (f), menu);
dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
if (ulx < 0) x -= ulx;
if (uly < 0) y -= uly;
+ if (! 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
+ is what x-popup-menu says in its documentation. */
+ x += width/2;
+ y += 1.5*height/(maxlines+2);
+ }
+
XMenuSetAEQ (menu, TRUE);
XMenuSetFreeze (menu, TRUE);
pane = selidx = 0;
case XM_FAILURE:
*error = "Can't activate menu";
case XM_IA_SELECT:
+ entry = Qnil;
+ break;
case XM_NO_SELECT:
+ /* Make "Cancel" equivalent to C-g unless this menu was popped up by
+ a mouse press. */
+ if (! for_click)
+ Fsignal (Qquit, Qnil);
entry = Qnil;
break;
}