diff options
Diffstat (limited to 'src/xmenu.c')
-rw-r--r-- | src/xmenu.c | 698 |
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. */ |