diff options
Diffstat (limited to 'src/xmenu.c')
| -rw-r--r-- | src/xmenu.c | 124 |
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, | |||
| 157 | static void list_of_panes P_ ((Lisp_Object)); | 158 | static void list_of_panes P_ ((Lisp_Object)); |
| 158 | static void list_of_items P_ ((Lisp_Object)); | 159 | static void list_of_items P_ ((Lisp_Object)); |
| 159 | 160 | ||
| 160 | extern 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 | |||
| 1123 | static void | ||
| 1124 | x_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 | |||
| 1176 | static Lisp_Object | ||
| 1177 | pop_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 | ||
| 1131 | static void | 1193 | static void |
| 1132 | popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress) | 1194 | popup_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. */ |
| 1264 | static GtkWidget *current_menu; | ||
| 1265 | |||
| 1266 | static Lisp_Object | ||
| 1267 | pop_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 | |||
| 1198 | static void | 1279 | static void |
| 1199 | popup_widget_loop () | 1280 | popup_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; |