aboutsummaryrefslogtreecommitdiffstats
path: root/src/xmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmenu.c')
-rw-r--r--src/xmenu.c124
1 files changed, 109 insertions, 15 deletions
diff --git a/src/xmenu.c b/src/xmenu.c
index a08f4610101..0a83266a482 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA. */
48#include "buffer.h" 48#include "buffer.h"
49#include "charset.h" 49#include "charset.h"
50#include "coding.h" 50#include "coding.h"
51#include "sysselect.h"
51 52
52#ifdef MSDOS 53#ifdef MSDOS
53#include "msdos.h" 54#include "msdos.h"
@@ -157,8 +158,6 @@ static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
157static void list_of_panes P_ ((Lisp_Object)); 158static void list_of_panes P_ ((Lisp_Object));
158static void list_of_items P_ ((Lisp_Object)); 159static void list_of_items P_ ((Lisp_Object));
159 160
160extern EMACS_TIME timer_check P_ ((int));
161
162 161
163/* This holds a Lisp vector that holds the results of decoding 162/* This holds a Lisp vector that holds the results of decoding
164 the keymaps or alist-of-alists that specify a menu. 163 the keymaps or alist-of-alists that specify a menu.
@@ -525,7 +524,7 @@ single_menu_item (key, item, dummy, skp_v)
525 return; /* Not a menu item. */ 524 return; /* Not a menu item. */
526 525
527 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; 526 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
528 527
529 if (skp->notreal) 528 if (skp->notreal)
530 { 529 {
531 /* We don't want to make a menu, just traverse the keymaps to 530 /* We don't want to make a menu, just traverse the keymaps to
@@ -1099,7 +1098,7 @@ on the left of the dialog box and all following items on the right.
1099 the dialog. Also, the lesstif/motif version crashes if there are 1098 the dialog. Also, the lesstif/motif version crashes if there are
1100 no buttons. */ 1099 no buttons. */
1101 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil)); 1100 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
1102 1101
1103 list_of_panes (Fcons (contents, Qnil)); 1102 list_of_panes (Fcons (contents, Qnil));
1104 1103
1105 /* Display them in a dialog box. */ 1104 /* Display them in a dialog box. */
@@ -1115,9 +1114,73 @@ on the left of the dialog box and all following items on the right.
1115 } 1114 }
1116#endif 1115#endif
1117} 1116}
1117
1118
1119#ifndef MSDOS
1120
1121/* Wait for an X event to arrive or for a timer to expire. */
1122
1123static void
1124x_menu_wait_for_event (void *data)
1125{
1126 extern EMACS_TIME timer_check P_ ((int));
1127
1128 /* Another way to do this is to register a timer callback, that can be
1129 done in GTK and Xt. But we have to do it like this when using only X
1130 anyway, and with callbacks we would have three variants for timer handling
1131 instead of the small ifdefs below. */
1132
1133 while (
1134#ifdef USE_X_TOOLKIT
1135 ! XtAppPending (Xt_app_con)
1136#elif defined USE_GTK
1137 ! gtk_events_pending ()
1138#else
1139 ! XPending ((Display*) data)
1140#endif
1141 )
1142 {
1143 EMACS_TIME next_time = timer_check (1);
1144 long secs = EMACS_SECS (next_time);
1145 long usecs = EMACS_USECS (next_time);
1146 SELECT_TYPE read_fds;
1147 struct x_display_info *dpyinfo;
1148 int n = 0;
1149
1150 FD_ZERO (&read_fds);
1151 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
1152 {
1153 int fd = ConnectionNumber (dpyinfo->display);
1154 FD_SET (fd, &read_fds);
1155 if (fd > n) n = fd;
1156 }
1157
1158 if (secs < 0 || (secs == 0 && usecs == 0))
1159 {
1160 /* Sometimes timer_check returns -1 (no timers) even if there are
1161 timers. So do a timeout anyway. */
1162 EMACS_SET_SECS (next_time, 1);
1163 EMACS_SET_USECS (next_time, 0);
1164 }
1165
1166 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
1167 }
1168}
1169#endif /* ! MSDOS */
1170
1118 1171
1119#if defined (USE_X_TOOLKIT) || defined (USE_GTK) 1172#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1120 1173
1174#ifdef USE_X_TOOLKIT
1175
1176static Lisp_Object
1177pop_down_menu (dummy)
1178 int dummy;
1179{
1180 popup_activated_flag = 0;
1181 return Qnil;
1182}
1183
1121/* Loop in Xt until the menu pulldown or dialog popup has been 1184/* Loop in Xt until the menu pulldown or dialog popup has been
1122 popped down (deactivated). This is used for x-popup-menu 1185 popped down (deactivated). This is used for x-popup-menu
1123 and x-popup-dialog; it is not used for the menu bar. 1186 and x-popup-dialog; it is not used for the menu bar.
@@ -1127,7 +1190,6 @@ on the left of the dialog box and all following items on the right.
1127 NOTE: All calls to popup_get_selection should be protected 1190 NOTE: All calls to popup_get_selection should be protected
1128 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ 1191 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
1129 1192
1130#ifdef USE_X_TOOLKIT
1131static void 1193static void
1132popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress) 1194popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress)
1133 XEvent *initial_event; 1195 XEvent *initial_event;
@@ -1138,19 +1200,21 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress)
1138{ 1200{
1139 XEvent event; 1201 XEvent event;
1140 1202
1203 int specpdl_count = SPECPDL_INDEX ();
1204 record_unwind_protect (pop_down_menu, Qnil);
1205
1141 while (popup_activated_flag) 1206 while (popup_activated_flag)
1142 { 1207 {
1143 /* If we have no events to run, consider timers. */
1144 if (do_timers && !XtAppPending (Xt_app_con))
1145 timer_check (1);
1146
1147 if (initial_event) 1208 if (initial_event)
1148 { 1209 {
1149 event = *initial_event; 1210 event = *initial_event;
1150 initial_event = 0; 1211 initial_event = 0;
1151 } 1212 }
1152 else 1213 else
1153 XtAppNextEvent (Xt_app_con, &event); 1214 {
1215 if (do_timers) x_menu_wait_for_event (0);
1216 XtAppNextEvent (Xt_app_con, &event);
1217 }
1154 1218
1155 /* Make sure we don't consider buttons grabbed after menu goes. 1219 /* Make sure we don't consider buttons grabbed after menu goes.
1156 And make sure to deactivate for any ButtonRelease, 1220 And make sure to deactivate for any ButtonRelease,
@@ -1188,6 +1252,8 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress)
1188 1252
1189 x_dispatch_event (&event, event.xany.display); 1253 x_dispatch_event (&event, event.xany.display);
1190 } 1254 }
1255
1256 unbind_to (specpdl_count, Qnil);
1191} 1257}
1192 1258
1193#endif /* USE_X_TOOLKIT */ 1259#endif /* USE_X_TOOLKIT */
@@ -1195,16 +1261,40 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress)
1195#ifdef USE_GTK 1261#ifdef USE_GTK
1196/* Loop util popup_activated_flag is set to zero in a callback. 1262/* Loop util popup_activated_flag is set to zero in a callback.
1197 Used for popup menus and dialogs. */ 1263 Used for popup menus and dialogs. */
1264static GtkWidget *current_menu;
1265
1266static Lisp_Object
1267pop_down_menu (dummy)
1268 int dummy;
1269{
1270 if (current_menu)
1271 {
1272 gtk_widget_unmap (current_menu);
1273 current_menu = 0;
1274 popup_activated_flag = 0;
1275 }
1276 return Qnil;
1277}
1278
1198static void 1279static void
1199popup_widget_loop () 1280popup_widget_loop (do_timers, widget)
1281 int do_timers;
1282 GtkWidget *widget;
1200{ 1283{
1284 int specpdl_count = SPECPDL_INDEX ();
1285 current_menu = widget;
1286 record_unwind_protect (pop_down_menu, Qnil);
1287
1201 ++popup_activated_flag; 1288 ++popup_activated_flag;
1202 1289
1203 /* Process events in the Gtk event loop until done. */ 1290 /* Process events in the Gtk event loop until done. */
1204 while (popup_activated_flag) 1291 while (popup_activated_flag)
1205 { 1292 {
1293 if (do_timers) x_menu_wait_for_event (0);
1206 gtk_main_iteration (); 1294 gtk_main_iteration ();
1207 } 1295 }
1296
1297 unbind_to (specpdl_count, Qnil);
1208} 1298}
1209#endif 1299#endif
1210 1300
@@ -2329,7 +2419,7 @@ menu_position_func (menu, x, y, push_in, user_data)
2329 GtkRequisition req; 2419 GtkRequisition req;
2330 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width; 2420 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width;
2331 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height; 2421 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height;
2332 2422
2333 *x = data->x; 2423 *x = data->x;
2334 *y = data->y; 2424 *y = data->y;
2335 2425
@@ -2402,7 +2492,7 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
2402 two. show_help_echo uses this to detect popup menus. */ 2492 two. show_help_echo uses this to detect popup menus. */
2403 popup_activated_flag = 1; 2493 popup_activated_flag = 1;
2404 /* Process events that apply to the menu. */ 2494 /* Process events that apply to the menu. */
2405 popup_widget_loop (); 2495 popup_widget_loop (1, 0);
2406 2496
2407 gtk_widget_destroy (menu); 2497 gtk_widget_destroy (menu);
2408 2498
@@ -2490,7 +2580,7 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click)
2490 popup_activated_flag = 1; 2580 popup_activated_flag = 1;
2491 2581
2492 /* Process events that apply to the menu. */ 2582 /* Process events that apply to the menu. */
2493 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0, 0); 2583 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1, 0);
2494 2584
2495 /* fp turned off the following statement and wrote a comment 2585 /* fp turned off the following statement and wrote a comment
2496 that it is unnecessary--that the menu has already disappeared. 2586 that it is unnecessary--that the menu has already disappeared.
@@ -2811,7 +2901,7 @@ create_and_show_dialog (f, first_wv)
2811 gtk_widget_show_all (menu); 2901 gtk_widget_show_all (menu);
2812 2902
2813 /* Process events that apply to the menu. */ 2903 /* Process events that apply to the menu. */
2814 popup_widget_loop (); 2904 popup_widget_loop (1, menu);
2815 2905
2816 gtk_widget_destroy (menu); 2906 gtk_widget_destroy (menu);
2817 } 2907 }
@@ -3323,6 +3413,10 @@ xmenu_show (f, x, y, for_click, keymaps, title, error)
3323 XMenuSetFreeze (menu, TRUE); 3413 XMenuSetFreeze (menu, TRUE);
3324 pane = selidx = 0; 3414 pane = selidx = 0;
3325 3415
3416#ifndef MSDOS
3417 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
3418#endif
3419
3326 /* Help display under X won't work because XMenuActivate contains 3420 /* Help display under X won't work because XMenuActivate contains
3327 a loop that doesn't give Emacs a chance to process it. */ 3421 a loop that doesn't give Emacs a chance to process it. */
3328 menu_help_frame = f; 3422 menu_help_frame = f;