summaryrefslogtreecommitdiff
path: root/src/xmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmenu.c')
-rw-r--r--src/xmenu.c698
1 files changed, 538 insertions, 160 deletions
diff --git a/src/xmenu.c b/src/xmenu.c
index e4b039808ec..bc3e22e3e16 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -81,7 +81,9 @@ Boston, MA 02111-1307, USA. */
#endif /* USE_LUCID */
#include "../lwlib/lwlib.h"
#else /* not USE_X_TOOLKIT */
+#ifndef USE_GTK
#include "../oldXMenu/XMenu.h"
+#endif
#endif /* not USE_X_TOOLKIT */
#endif /* HAVE_X_WINDOWS */
@@ -116,6 +118,13 @@ static void popup_get_selection ();
/* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
#define HAVE_BOXES 1
+#endif /* USE_X_TOOLKIT */
+
+#ifdef USE_GTK
+#include "gtkutil.h"
+#define HAVE_BOXES 1
+extern void set_frame_menubar ();
+static Lisp_Object xdialog_show ();
#endif
static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
@@ -194,7 +203,7 @@ static int menu_items_submenu_depth;
/* Flag which when set indicates a dialog or menu has been posted by
Xt on behalf of one of the widget sets. */
-int popup_activated_flag;
+static int popup_activated_flag;
static int next_menubar_widget_id;
@@ -593,7 +602,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
}
#endif /* not HAVE_BOXES */
-#ifndef USE_X_TOOLKIT
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
if (!NILP(map))
/* Indicate visually that this is a submenu. */
item_string = concat2 (item_string, build_string (" >"));
@@ -606,7 +615,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
/* Display a submenu using the toolkit. */
if (! (NILP (map) || NILP (enabled)))
{
@@ -771,6 +780,7 @@ cached information about equivalent key sequences. */)
#ifdef HAVE_MENUS
if (! NILP (position))
{
+ int get_current_pos_p = 0;
check_x ();
/* Decode the first argument: find the window and the coordinates. */
@@ -778,6 +788,38 @@ cached information about equivalent key sequences. */)
|| (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 = Fcar (tem);
+ y = Fcar (Fcdr (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
@@ -813,25 +855,6 @@ cached information about equivalent key sequences. */)
XSETFASTINT (y, 0);
}
}
- else
- {
- tem = Fcar (position);
- if (CONSP (tem))
- {
- window = Fcar (Fcdr (position));
- x = Fcar (tem);
- y = Fcar (Fcdr (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);
- }
- }
CHECK_NUMBER (x);
CHECK_NUMBER (y);
@@ -1040,7 +1063,7 @@ on the left of the dialog box and all following items on the right.
but I don't want to make one now. */
CHECK_WINDOW (window);
-#ifndef USE_X_TOOLKIT
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
/* Display a menu with these alternatives
in the middle of frame F. */
{
@@ -1081,7 +1104,7 @@ on the left of the dialog box and all following items on the right.
#endif
}
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
/* Loop in Xt until the menu pulldown or dialog popup has been
popped down (deactivated). This is used for x-popup-menu
@@ -1092,6 +1115,7 @@ on the left of the dialog box and all following items on the right.
NOTE: All calls to popup_get_selection should be protected
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
+#ifdef USE_X_TOOLKIT
static void
popup_get_selection (initial_event, dpyinfo, id, do_timers)
XEvent *initial_event;
@@ -1148,6 +1172,24 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers)
}
}
+#endif /* USE_X_TOOLKIT */
+
+#ifdef USE_GTK
+/* Loop util popup_activated_flag is set to zero in a callback.
+ Used for popup menus and dialogs. */
+static void
+popup_widget_loop ()
+{
+ ++popup_activated_flag;
+
+ /* Process events in the Gtk event loop until done. */
+ while (popup_activated_flag)
+ {
+ gtk_main_iteration ();
+ }
+}
+#endif
+
/* Activate the menu bar of frame F.
This is called from keyboard.c when it gets the
MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
@@ -1169,9 +1211,20 @@ x_activate_menubar (f)
if (!f->output_data.x->saved_menu_event->type)
return;
+#ifdef USE_GTK
+ if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window))
+ return;
+#endif
+
set_frame_menubar (f, 0, 1);
BLOCK_INPUT;
+#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)
@@ -1193,6 +1246,7 @@ popup_activated ()
/* This callback is invoked when the user selects a menubar cascade
pushbutton, but before the pulldown menu is posted. */
+#ifndef USE_GTK
static void
popup_activate_callback (widget, id, client_data)
Widget widget;
@@ -1201,10 +1255,20 @@ popup_activate_callback (widget, id, client_data)
{
popup_activated_flag = 1;
}
+#endif
/* This callback is invoked when a dialog or menu is finished being
used and has been unposted. */
+#ifdef USE_GTK
+static void
+popup_deactivate_callback (widget, client_data)
+ GtkWidget *widget;
+ gpointer client_data;
+{
+ popup_activated_flag = 0;
+}
+#else
static void
popup_deactivate_callback (widget, id, client_data)
Widget widget;
@@ -1213,27 +1277,20 @@ popup_deactivate_callback (widget, id, client_data)
{
popup_activated_flag = 0;
}
+#endif
-/* Lwlib callback called when menu items are highlighted/unhighlighted
- while moving the mouse over them. WIDGET is the menu bar or menu
- popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
- the widget_value structure for the menu item, or null in case of
- unhighlighting. */
-void
-menu_highlight_callback (widget, id, call_data)
- Widget widget;
- LWLIB_ID id;
- void *call_data;
+/* Function that finds the frame for WIDGET and shows the HELP text
+ 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;
{
- widget_value *wv = (widget_value *) call_data;
- struct frame *f;
- Lisp_Object frame, help;
+ Lisp_Object frame;
- help = wv ? wv->help : Qnil;
-
- /* Determine the frame for the help event. */
- f = menubar_id_to_frame (id);
if (f)
{
XSETFRAME (frame, f);
@@ -1243,7 +1300,7 @@ menu_highlight_callback (widget, id, call_data)
{
/* WIDGET is the popup menu. It's parent is the frame's
widget. See which frame that is. */
- Widget frame_widget = XtParent (widget);
+ xt_or_gtk_widget frame_widget = XtParent (widget);
Lisp_Object tail;
for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
@@ -1259,32 +1316,77 @@ menu_highlight_callback (widget, id, call_data)
}
}
-/* This callback is called from the menu bar pulldown menu
- when the user makes a selection.
- Figure out what the user chose
- and put the appropriate events into the keyboard buffer. */
+/* Callback called when menu items are highlighted/unhighlighted
+ while moving the mouse over them. WIDGET is the menu bar or menu
+ popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
+ the data structure for the menu item, or null in case of
+ unhighlighting. */
-static void
-menubar_selection_callback (widget, id, client_data)
+#ifdef USE_GTK
+void
+menu_highlight_callback (widget, call_data)
+ GtkWidget *widget;
+ gpointer call_data;
+{
+ xg_menu_item_cb_data *cb_data;
+ Lisp_Object help;
+
+ cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
+ XG_ITEM_DATA);
+ if (! cb_data) return;
+
+ 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);
+}
+#else
+void
+menu_highlight_callback (widget, id, call_data)
Widget widget;
LWLIB_ID id;
- XtPointer client_data;
+ void *call_data;
+{
+ struct frame *f;
+ Lisp_Object help;
+
+ widget_value *wv = (widget_value *) call_data;
+
+ help = wv ? wv->help : Qnil;
+
+ /* Determine the frame for the help event. */
+ f = menubar_id_to_frame (id);
+
+ show_help_event (f, widget, help);
+}
+#endif
+
+/* 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
+find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
+ FRAME_PTR f;
+ int menu_bar_items_used;
+ Lisp_Object vector;
+ void *client_data;
{
Lisp_Object prefix, entry;
- FRAME_PTR f = menubar_id_to_frame (id);
- Lisp_Object vector;
Lisp_Object *subprefix_stack;
int submenu_depth = 0;
int i;
- if (!f)
- return;
entry = Qnil;
- subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
- vector = f->menu_bar_vector;
+ subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
prefix = Qnil;
i = 0;
- while (i < f->menu_bar_items_used)
+
+ while (i < menu_bar_items_used)
{
if (EQ (XVECTOR (vector)->contents[i], Qnil))
{
@@ -1348,6 +1450,59 @@ menubar_selection_callback (widget, id, client_data)
}
}
+
+#ifdef USE_GTK
+/* Gtk calls callbacks just because we tell it what item should be
+ selected in a radio group. If this variable is set to a non-zero
+ value, we are creating menus and don't want callbacks right now.
+*/
+static int xg_crazy_callback_abort;
+
+/* This callback is called from the menu bar pulldown menu
+ when the user makes a selection.
+ 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;
+{
+ xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
+
+ if (xg_crazy_callback_abort)
+ return;
+
+ if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
+ return;
+
+ 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,
+ cb_data->call_data);
+}
+
+#else /* not USE_GTK */
+
+/* This callback is called from the menu bar pulldown menu
+ when the user makes a selection.
+ 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;
+{
+ FRAME_PTR f;
+
+ f = menubar_id_to_frame (id);
+ if (!f)
+ return;
+ find_and_call_menu_selection (f, f->menu_bar_items_used,
+ f->menu_bar_vector, client_data);
+}
+#endif /* not USE_GTK */
+
/* Allocate a widget_value, blocking input. */
widget_value *
@@ -1623,9 +1778,12 @@ static int
update_frame_menubar (f)
FRAME_PTR f;
{
+#ifdef USE_GTK
+ return xg_update_frame_menubar (f);
+#else
struct x_output *x = f->output_data.x;
int columns, rows;
-
+
if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
return 0;
@@ -1657,6 +1815,7 @@ update_frame_menubar (f)
/* Force the pane widget to resize itself with the right values. */
EmacsFrameSetCharSize (x->edit_widget, columns, rows);
UNBLOCK_INPUT;
+#endif
return 1;
}
@@ -1670,21 +1829,25 @@ set_frame_menubar (f, first_time, deep_p)
int first_time;
int deep_p;
{
- Widget menubar_widget = f->output_data.x->menubar_widget;
+ xt_or_gtk_widget menubar_widget = f->output_data.x->menubar_widget;
+#ifdef USE_X_TOOLKIT
+ LWLIB_ID id;
+#endif
Lisp_Object items;
widget_value *wv, *first_wv, *prev_wv = 0;
int i, last_i;
int *submenu_start, *submenu_end;
int *submenu_top_level_items, *submenu_n_panes;
- LWLIB_ID id;
XSETFRAME (Vmenu_updating_frame, f);
+#ifdef USE_X_TOOLKIT
if (f->output_data.x->id == 0)
f->output_data.x->id = next_menubar_widget_id++;
id = f->output_data.x->id;
-
+#endif
+
if (! menubar_widget)
deep_p = 1;
else if (pending_menu_activation && !deep_p)
@@ -1893,6 +2056,35 @@ set_frame_menubar (f, first_time, deep_p)
BLOCK_INPUT;
+#ifdef USE_GTK
+ xg_crazy_callback_abort = 1;
+ if (menubar_widget)
+ {
+ /* The third arg is DEEP_P, which says to consider the entire
+ menu trees we supply, rather than just the menu bar item names. */
+ xg_modify_menubar_widgets (menubar_widget,
+ f,
+ first_wv,
+ deep_p,
+ G_CALLBACK (menubar_selection_callback),
+ G_CALLBACK (popup_deactivate_callback),
+ G_CALLBACK (menu_highlight_callback));
+ }
+ else
+ {
+ GtkWidget *wvbox = f->output_data.x->vbox_widget;
+
+ menubar_widget
+ = xg_create_widget ("menubar", "menubar", f, first_wv,
+ G_CALLBACK (menubar_selection_callback),
+ G_CALLBACK (popup_deactivate_callback),
+ G_CALLBACK (menu_highlight_callback));
+
+ f->output_data.x->menubar_widget = menubar_widget;
+ }
+
+
+#else /* not USE_GTK */
if (menubar_widget)
{
/* Disable resizing (done for Motif!) */
@@ -1939,10 +2131,15 @@ set_frame_menubar (f, first_time, deep_p)
f->output_data.x->menubar_height = menubar_size;
}
+#endif /* not USE_GTK */
free_menubar_widget_value_tree (first_wv);
update_frame_menubar (f);
+#ifdef USE_GTK
+ xg_crazy_callback_abort = 0;
+#endif
+
UNBLOCK_INPUT;
}
@@ -1963,8 +2160,10 @@ initialize_frame_menubar (f)
/* Get rid of the menu bar of frame F, and free its storage.
- This is used when deleting a frame, and when turning off the menu bar. */
+ This is used when deleting a frame, and when turning off the menu bar.
+ For GTK this function is in gtkutil.c. */
+#ifndef USE_GTK
void
free_frame_menubar (f)
FRAME_PTR f;
@@ -2011,8 +2210,9 @@ free_frame_menubar (f)
UNBLOCK_INPUT;
}
}
+#endif /* not USE_GTK */
-#endif /* USE_X_TOOLKIT */
+#endif /* USE_X_TOOLKIT || USE_GTK */
/* xmenu_show actually displays a menu using the panes and items in menu_items
and returns the value selected from it.
@@ -2030,7 +2230,116 @@ free_frame_menubar (f)
ERROR is a place to store an error message string in case of failure.
(We return nil on failure, but the value doesn't actually matter.) */
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+
+/* The item selected in the popup menu. */
+static Lisp_Object *volatile menu_item_selection;
+
+#ifdef USE_GTK
+
+/* Used when position a popup menu. See menu_position_func and
+ create_and_show_popup_menu below. */
+struct next_popup_x_y
+{
+ int x;
+ int y;
+};
+
+/* The menu position function to use if we are not putting a popup
+ menu where the pointer is.
+ MENU is the menu to pop up.
+ X and Y shall on exit contain x/y where the menu shall pop up.
+ PUSH_IN is not documented in the GTK manual.
+ USER_DATA is any data passed in when calling gtk_menu_popup.
+ Here it points to a struct next_popup_x_y where the coordinates
+ to store in *X and *Y are.
+
+ 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;
+{
+ *x = ((struct next_popup_x_y*)user_data)->x;
+ *y = ((struct next_popup_x_y*)user_data)->y;
+}
+
+static void
+popup_selection_callback (widget, client_data)
+ GtkWidget *widget;
+ gpointer client_data;
+{
+ xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
+
+ if (xg_crazy_callback_abort) return;
+ if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
+}
+
+/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
+ 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;
+{
+ int i;
+ GtkWidget *menu;
+ GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
+ struct next_popup_x_y popup_x_y;
+
+ xg_crazy_callback_abort = 1;
+ menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
+ G_CALLBACK (popup_selection_callback),
+ G_CALLBACK (popup_deactivate_callback),
+ 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. */
+ pos_func = menu_position_func;
+
+ /* Adjust coordinates to be root-window-relative. */
+ x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
+ y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
+
+ popup_x_y.x = x;
+ popup_x_y.y = y;
+ }
+
+ /* Display the menu. */
+ gtk_widget_show_all (menu);
+ gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
+
+ xg_did_tearoff = 0;
+ /* Set this to one. popup_widget_loop increases it by one, so it becomes
+ two. show_help_echo uses this to detect popup menus. */
+ popup_activated_flag = 1;
+ /* Process events that apply to the menu. */
+ popup_widget_loop ();
+
+ if (xg_did_tearoff)
+ xg_keep_popup (menu, xg_did_tearoff);
+ else
+ gtk_widget_destroy (menu);
+
+ /* Must reset this manually because the button release event is not passed
+ to Emacs event loop. */
+ FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
+}
+
+#else /* not USE_GTK */
/* We need a unique id for each widget handled by the Lucid Widget
library.
@@ -2042,8 +2351,6 @@ free_frame_menubar (f)
next_menubar_widget_id. */
LWLIB_ID widget_id_tick;
-static Lisp_Object *volatile menu_item_selection;
-
static void
popup_selection_callback (widget, id, client_data)
Widget widget;
@@ -2053,6 +2360,76 @@ popup_selection_callback (widget, id, client_data)
menu_item_selection = (Lisp_Object *) client_data;
}
+/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
+ 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;
+{
+ int i;
+ Arg av[2];
+ int ac = 0;
+ XButtonPressedEvent dummy;
+ LWLIB_ID menu_id;
+ Widget menu;
+ Window child;
+
+ menu_id = widget_id_tick++;
+ menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
+ f->output_data.x->widget, 1, 0,
+ popup_selection_callback,
+ popup_deactivate_callback,
+ menu_highlight_callback);
+
+ dummy.type = ButtonPress;
+ dummy.serial = 0;
+ dummy.send_event = 0;
+ dummy.display = FRAME_X_DISPLAY (f);
+ dummy.time = CurrentTime;
+ dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
+ dummy.window = dummy.root;
+ dummy.subwindow = dummy.root;
+ dummy.x = x;
+ dummy.y = y;
+
+ /* Adjust coordinates to be root-window-relative. */
+ x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
+ y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
+
+ dummy.x_root = x;
+ dummy.y_root = y;
+
+ dummy.state = 0;
+ dummy.button = 0;
+ for (i = 0; i < 5; i++)
+ if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
+ dummy.button = i;
+
+ /* Don't allow any geometry request from the user. */
+ XtSetArg (av[ac], XtNgeometry, 0); ac++;
+ XtSetValues (menu, av, ac);
+
+ /* Display the menu. */
+ lw_popup_menu (menu, (XEvent *) &dummy);
+ popup_activated_flag = 1;
+
+ /* Process events that apply to the menu. */
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0);
+
+ /* fp turned off the following statement and wrote a comment
+ that it is unnecessary--that the menu has already disappeared.
+ Nowadays the menu disappears ok, all right, but
+ we need to delete the widgets or multiple ones will pile up. */
+ lw_destroy_all_widgets (menu_id);
+}
+
+#endif /* not USE_GTK */
+
static Lisp_Object
xmenu_show (f, x, y, for_click, keymaps, title, error)
FRAME_PTR f;
@@ -2064,17 +2441,12 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
char **error;
{
int i;
- LWLIB_ID menu_id;
- Widget menu;
- Arg av[2];
- int ac = 0;
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
widget_value **submenu_stack
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
Lisp_Object *subprefix_stack
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
int submenu_depth = 0;
- XButtonPressedEvent dummy;
int first_pane;
@@ -2266,70 +2638,14 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
first_wv->contents = wv_title;
}
- /* Actually create the menu. */
- menu_id = widget_id_tick++;
- menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
- f->output_data.x->widget, 1, 0,
- popup_selection_callback,
- popup_deactivate_callback,
- menu_highlight_callback);
-
- /* See if whe positions are up to date. Temporary code to be removed
- when we are sure positions are always up to date. */
- {
- int real_x, real_y;
- x_real_positions (f, &real_x, &real_y);
-
- if (real_x != f->output_data.x->left_pos ||
- real_y != f->output_data.x->top_pos)
- abort ();
- }
-
- dummy.type = ButtonPress;
- dummy.serial = 0;
- dummy.send_event = 0;
- dummy.display = FRAME_X_DISPLAY (f);
- dummy.time = CurrentTime;
- dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
- dummy.window = dummy.root;
- dummy.subwindow = dummy.root;
- dummy.x = x;
- dummy.y = y;
-
- /* Adjust coordinates to be root-window-relative. */
- x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
- y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
-
- dummy.x_root = x;
- dummy.y_root = y;
- dummy.state = 0;
- dummy.button = 0;
- for (i = 0; i < 5; i++)
- if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
- dummy.button = i;
-
- /* Don't allow any geometry request from the user. */
- XtSetArg (av[ac], XtNgeometry, 0); ac++;
- XtSetValues (menu, av, ac);
-
- /* Free the widget_value objects we used to specify the contents. */
- free_menubar_widget_value_tree (first_wv);
-
/* No selection has been chosen yet. */
menu_item_selection = 0;
- /* Display the menu. */
- lw_popup_menu (menu, (XEvent *) &dummy);
- popup_activated_flag = 1;
+ /* Actually create and show the menu until popped down. */
+ create_and_show_popup_menu (f, first_wv, x, y, for_click);
- /* Process events that apply to the menu. */
- popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0);
-
- /* fp turned off the following statement and wrote a comment
- that it is unnecessary--that the menu has already disappeared.
- Nowadays the menu disappears ok, all right, but
- we need to delete the widgets or multiple ones will pile up. */
- lw_destroy_all_widgets (menu_id);
+ /* Free the widget_value objects we used to specify the contents. */
+ free_menubar_widget_value_tree (first_wv);
/* Find the selected item, and its pane, to return
the proper value. */
@@ -2389,6 +2705,48 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
return Qnil;
}
+#ifdef USE_GTK
+static void
+dialog_selection_callback (widget, client_data)
+ 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. */
+ if ((int) (EMACS_INT) client_data != -1)
+ menu_item_selection = (Lisp_Object *) client_data;
+
+ popup_activated_flag = 0;
+}
+
+/* Pop up the dialog for frame F defined by FIRST_WV and loop until the
+ 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;
+{
+ GtkWidget *menu;
+
+ menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
+ G_CALLBACK (dialog_selection_callback),
+ G_CALLBACK (popup_deactivate_callback),
+ 0);
+
+ if (menu)
+ {
+ /* Display the menu. */
+ gtk_widget_show_all (menu);
+
+ /* Process events that apply to the menu. */
+ popup_widget_loop ();
+
+ gtk_widget_destroy (menu);
+ }
+}
+
+#else /* not USE_GTK */
static void
dialog_selection_callback (widget, id, client_data)
Widget widget;
@@ -2399,12 +2757,14 @@ dialog_selection_callback (widget, id, client_data)
as long as pointers have enough bits to hold small integers. */
if ((int) (EMACS_INT) client_data != -1)
menu_item_selection = (Lisp_Object *) client_data;
+
BLOCK_INPUT;
lw_destroy_all_widgets (id);
UNBLOCK_INPUT;
popup_activated_flag = 0;
}
+
/* ARG is the LWLIB ID of the dialog box, represented
as a Lisp object as (HIGHPART . LOWPART). */
@@ -2421,6 +2781,46 @@ xdialog_show_unwind (arg)
return Qnil;
}
+
+/* Pop up the dialog for frame F defined by FIRST_WV and loop until the
+ 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;
+{
+ LWLIB_ID dialog_id;
+
+ dialog_id = widget_id_tick++;
+ 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;
+
+ /* Process events that apply to the dialog box.
+ Also handle timers. */
+ {
+ int count = SPECPDL_INDEX ();
+ int fact = 4 * sizeof (LWLIB_ID);
+
+ /* xdialog_show_unwind is responsible for popping the dialog box down. */
+ record_unwind_protect (xdialog_show_unwind,
+ Fcons (make_number (dialog_id >> (fact)),
+ make_number (dialog_id & ~(-1 << (fact)))));
+
+ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1);
+
+ unbind_to (count, Qnil);
+ }
+}
+
+#endif /* not USE_GTK */
+
static char * button_names [] = {
"button1", "button2", "button3", "button4", "button5",
"button6", "button7", "button8", "button9", "button10" };
@@ -2433,7 +2833,6 @@ xdialog_show (f, keymaps, title, error)
char **error;
{
int i, nb_buttons=0;
- LWLIB_ID dialog_id;
char dialog_name[6];
widget_value *wv, *first_wv = 0, *prev_wv = 0;
@@ -2543,38 +2942,17 @@ xdialog_show (f, keymaps, title, error)
first_wv = wv;
}
- /* Actually create the dialog. */
- dialog_id = widget_id_tick++;
- 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);
- /* Free the widget_value objects we used to specify the contents. */
- free_menubar_widget_value_tree (first_wv);
-
/* No selection has been chosen yet. */
menu_item_selection = 0;
- /* Display the dialog box. */
- lw_pop_up_all_widgets (dialog_id);
- popup_activated_flag = 1;
-
- /* Process events that apply to the dialog box.
- Also handle timers. */
- {
- int count = SPECPDL_INDEX ();
-
- /* xdialog_show_unwind is responsible for popping the dialog box down. */
- record_unwind_protect (xdialog_show_unwind,
- Fcons (make_number (dialog_id >> (4 * sizeof (LWLIB_ID))),
- make_number (dialog_id & ~(-1 << (4 * sizeof (LWLIB_ID))))));
-
- popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1);
-
- unbind_to (count, Qnil);
- }
+ /* Actually create and show the dialog. */
+ create_and_show_dialog (f, first_wv);
- /* Find the selected item and pane, and return the corresponding value. */
+ /* Free the widget_value objects we used to specify the contents. */
+ free_menubar_widget_value_tree (first_wv);
+
+ /* Find the selected item, and its pane, to return
+ the proper value. */
if (menu_item_selection != 0)
{
Lisp_Object prefix;
@@ -2619,7 +2997,7 @@ xdialog_show (f, keymaps, title, error)
return Qnil;
}
-#else /* not USE_X_TOOLKIT */
+#else /* not USE_X_TOOLKIT && not USE_GTK */
/* The frame of the last activated non-toolkit menu bar.
Used to generate menu help events. */