diff options
| author | Jan Djärv | 2003-01-19 21:50:03 +0000 |
|---|---|---|
| committer | Jan Djärv | 2003-01-19 21:50:03 +0000 |
| commit | 488dd4c404eba70d48e4ee70141b8abcce2f863b (patch) | |
| tree | 741ec2bb5abe963b292521e3a478e716a4ebb999 /src/xmenu.c | |
| parent | 3c77dc44b8052a9bcb19486a605a861cf120b31e (diff) | |
| download | emacs-488dd4c404eba70d48e4ee70141b8abcce2f863b.tar.gz emacs-488dd4c404eba70d48e4ee70141b8abcce2f863b.zip | |
GTK version
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. */ | |||
| 81 | #endif /* USE_LUCID */ | 81 | #endif /* USE_LUCID */ |
| 82 | #include "../lwlib/lwlib.h" | 82 | #include "../lwlib/lwlib.h" |
| 83 | #else /* not USE_X_TOOLKIT */ | 83 | #else /* not USE_X_TOOLKIT */ |
| 84 | #ifndef USE_GTK | ||
| 84 | #include "../oldXMenu/XMenu.h" | 85 | #include "../oldXMenu/XMenu.h" |
| 86 | #endif | ||
| 85 | #endif /* not USE_X_TOOLKIT */ | 87 | #endif /* not USE_X_TOOLKIT */ |
| 86 | #endif /* HAVE_X_WINDOWS */ | 88 | #endif /* HAVE_X_WINDOWS */ |
| 87 | 89 | ||
| @@ -116,6 +118,13 @@ static void popup_get_selection (); | |||
| 116 | /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ | 118 | /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ |
| 117 | 119 | ||
| 118 | #define HAVE_BOXES 1 | 120 | #define HAVE_BOXES 1 |
| 121 | #endif /* USE_X_TOOLKIT */ | ||
| 122 | |||
| 123 | #ifdef USE_GTK | ||
| 124 | #include "gtkutil.h" | ||
| 125 | #define HAVE_BOXES 1 | ||
| 126 | extern void set_frame_menubar (); | ||
| 127 | static Lisp_Object xdialog_show (); | ||
| 119 | #endif | 128 | #endif |
| 120 | 129 | ||
| 121 | static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | 130 | static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, |
| @@ -194,7 +203,7 @@ static int menu_items_submenu_depth; | |||
| 194 | 203 | ||
| 195 | /* Flag which when set indicates a dialog or menu has been posted by | 204 | /* Flag which when set indicates a dialog or menu has been posted by |
| 196 | Xt on behalf of one of the widget sets. */ | 205 | Xt on behalf of one of the widget sets. */ |
| 197 | int popup_activated_flag; | 206 | static int popup_activated_flag; |
| 198 | 207 | ||
| 199 | static int next_menubar_widget_id; | 208 | static int next_menubar_widget_id; |
| 200 | 209 | ||
| @@ -593,7 +602,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, | |||
| 593 | } | 602 | } |
| 594 | #endif /* not HAVE_BOXES */ | 603 | #endif /* not HAVE_BOXES */ |
| 595 | 604 | ||
| 596 | #ifndef USE_X_TOOLKIT | 605 | #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) |
| 597 | if (!NILP(map)) | 606 | if (!NILP(map)) |
| 598 | /* Indicate visually that this is a submenu. */ | 607 | /* Indicate visually that this is a submenu. */ |
| 599 | item_string = concat2 (item_string, build_string (" >")); | 608 | item_string = concat2 (item_string, build_string (" >")); |
| @@ -606,7 +615,7 @@ single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, | |||
| 606 | XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], | 615 | XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], |
| 607 | XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); | 616 | XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); |
| 608 | 617 | ||
| 609 | #ifdef USE_X_TOOLKIT | 618 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 610 | /* Display a submenu using the toolkit. */ | 619 | /* Display a submenu using the toolkit. */ |
| 611 | if (! (NILP (map) || NILP (enabled))) | 620 | if (! (NILP (map) || NILP (enabled))) |
| 612 | { | 621 | { |
| @@ -771,6 +780,7 @@ cached information about equivalent key sequences. */) | |||
| 771 | #ifdef HAVE_MENUS | 780 | #ifdef HAVE_MENUS |
| 772 | if (! NILP (position)) | 781 | if (! NILP (position)) |
| 773 | { | 782 | { |
| 783 | int get_current_pos_p = 0; | ||
| 774 | check_x (); | 784 | check_x (); |
| 775 | 785 | ||
| 776 | /* Decode the first argument: find the window and the coordinates. */ | 786 | /* Decode the first argument: find the window and the coordinates. */ |
| @@ -778,6 +788,38 @@ cached information about equivalent key sequences. */) | |||
| 778 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) | 788 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) |
| 779 | || EQ (XCAR (position), Qtool_bar)))) | 789 | || EQ (XCAR (position), Qtool_bar)))) |
| 780 | { | 790 | { |
| 791 | get_current_pos_p = 1; | ||
| 792 | } | ||
| 793 | else | ||
| 794 | { | ||
| 795 | tem = Fcar (position); | ||
| 796 | if (CONSP (tem)) | ||
| 797 | { | ||
| 798 | window = Fcar (Fcdr (position)); | ||
| 799 | x = Fcar (tem); | ||
| 800 | y = Fcar (Fcdr (tem)); | ||
| 801 | } | ||
| 802 | else | ||
| 803 | { | ||
| 804 | for_click = 1; | ||
| 805 | tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ | ||
| 806 | window = Fcar (tem); /* POSN_WINDOW (tem) */ | ||
| 807 | tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */ | ||
| 808 | x = Fcar (tem); | ||
| 809 | y = Fcdr (tem); | ||
| 810 | } | ||
| 811 | |||
| 812 | /* If a click happens in an external tool bar or a detached | ||
| 813 | tool bar, x and y is NIL. In that case, use the current | ||
| 814 | mouse position. This happens for the help button in the | ||
| 815 | tool bar. Ideally popup-menu should pass NIL to | ||
| 816 | this function, but it doesn't. */ | ||
| 817 | if (NILP (x) && NILP (y)) | ||
| 818 | get_current_pos_p = 1; | ||
| 819 | } | ||
| 820 | |||
| 821 | if (get_current_pos_p) | ||
| 822 | { | ||
| 781 | /* Use the mouse's current position. */ | 823 | /* Use the mouse's current position. */ |
| 782 | FRAME_PTR new_f = SELECTED_FRAME (); | 824 | FRAME_PTR new_f = SELECTED_FRAME (); |
| 783 | #ifdef HAVE_X_WINDOWS | 825 | #ifdef HAVE_X_WINDOWS |
| @@ -813,25 +855,6 @@ cached information about equivalent key sequences. */) | |||
| 813 | XSETFASTINT (y, 0); | 855 | XSETFASTINT (y, 0); |
| 814 | } | 856 | } |
| 815 | } | 857 | } |
| 816 | else | ||
| 817 | { | ||
| 818 | tem = Fcar (position); | ||
| 819 | if (CONSP (tem)) | ||
| 820 | { | ||
| 821 | window = Fcar (Fcdr (position)); | ||
| 822 | x = Fcar (tem); | ||
| 823 | y = Fcar (Fcdr (tem)); | ||
| 824 | } | ||
| 825 | else | ||
| 826 | { | ||
| 827 | for_click = 1; | ||
| 828 | tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ | ||
| 829 | window = Fcar (tem); /* POSN_WINDOW (tem) */ | ||
| 830 | tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */ | ||
| 831 | x = Fcar (tem); | ||
| 832 | y = Fcdr (tem); | ||
| 833 | } | ||
| 834 | } | ||
| 835 | 858 | ||
| 836 | CHECK_NUMBER (x); | 859 | CHECK_NUMBER (x); |
| 837 | CHECK_NUMBER (y); | 860 | CHECK_NUMBER (y); |
| @@ -1040,7 +1063,7 @@ on the left of the dialog box and all following items on the right. | |||
| 1040 | but I don't want to make one now. */ | 1063 | but I don't want to make one now. */ |
| 1041 | CHECK_WINDOW (window); | 1064 | CHECK_WINDOW (window); |
| 1042 | 1065 | ||
| 1043 | #ifndef USE_X_TOOLKIT | 1066 | #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) |
| 1044 | /* Display a menu with these alternatives | 1067 | /* Display a menu with these alternatives |
| 1045 | in the middle of frame F. */ | 1068 | in the middle of frame F. */ |
| 1046 | { | 1069 | { |
| @@ -1081,7 +1104,7 @@ on the left of the dialog box and all following items on the right. | |||
| 1081 | #endif | 1104 | #endif |
| 1082 | } | 1105 | } |
| 1083 | 1106 | ||
| 1084 | #ifdef USE_X_TOOLKIT | 1107 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 1085 | 1108 | ||
| 1086 | /* Loop in Xt until the menu pulldown or dialog popup has been | 1109 | /* Loop in Xt until the menu pulldown or dialog popup has been |
| 1087 | popped down (deactivated). This is used for x-popup-menu | 1110 | 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. | |||
| 1092 | NOTE: All calls to popup_get_selection should be protected | 1115 | NOTE: All calls to popup_get_selection should be protected |
| 1093 | with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ | 1116 | with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ |
| 1094 | 1117 | ||
| 1118 | #ifdef USE_X_TOOLKIT | ||
| 1095 | static void | 1119 | static void |
| 1096 | popup_get_selection (initial_event, dpyinfo, id, do_timers) | 1120 | popup_get_selection (initial_event, dpyinfo, id, do_timers) |
| 1097 | XEvent *initial_event; | 1121 | XEvent *initial_event; |
| @@ -1148,6 +1172,24 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers) | |||
| 1148 | } | 1172 | } |
| 1149 | } | 1173 | } |
| 1150 | 1174 | ||
| 1175 | #endif /* USE_X_TOOLKIT */ | ||
| 1176 | |||
| 1177 | #ifdef USE_GTK | ||
| 1178 | /* Loop util popup_activated_flag is set to zero in a callback. | ||
| 1179 | Used for popup menus and dialogs. */ | ||
| 1180 | static void | ||
| 1181 | popup_widget_loop () | ||
| 1182 | { | ||
| 1183 | ++popup_activated_flag; | ||
| 1184 | |||
| 1185 | /* Process events in the Gtk event loop until done. */ | ||
| 1186 | while (popup_activated_flag) | ||
| 1187 | { | ||
| 1188 | gtk_main_iteration (); | ||
| 1189 | } | ||
| 1190 | } | ||
| 1191 | #endif | ||
| 1192 | |||
| 1151 | /* Activate the menu bar of frame F. | 1193 | /* Activate the menu bar of frame F. |
| 1152 | This is called from keyboard.c when it gets the | 1194 | This is called from keyboard.c when it gets the |
| 1153 | MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue. | 1195 | MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue. |
| @@ -1169,9 +1211,20 @@ x_activate_menubar (f) | |||
| 1169 | if (!f->output_data.x->saved_menu_event->type) | 1211 | if (!f->output_data.x->saved_menu_event->type) |
| 1170 | return; | 1212 | return; |
| 1171 | 1213 | ||
| 1214 | #ifdef USE_GTK | ||
| 1215 | if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window)) | ||
| 1216 | return; | ||
| 1217 | #endif | ||
| 1218 | |||
| 1172 | set_frame_menubar (f, 0, 1); | 1219 | set_frame_menubar (f, 0, 1); |
| 1173 | BLOCK_INPUT; | 1220 | BLOCK_INPUT; |
| 1221 | #ifdef USE_GTK | ||
| 1222 | XPutBackEvent (f->output_data.x->display_info->display, | ||
| 1223 | f->output_data.x->saved_menu_event); | ||
| 1224 | popup_activated_flag = 1; | ||
| 1225 | #else | ||
| 1174 | XtDispatchEvent (f->output_data.x->saved_menu_event); | 1226 | XtDispatchEvent (f->output_data.x->saved_menu_event); |
| 1227 | #endif | ||
| 1175 | UNBLOCK_INPUT; | 1228 | UNBLOCK_INPUT; |
| 1176 | #ifdef USE_MOTIF | 1229 | #ifdef USE_MOTIF |
| 1177 | if (f->output_data.x->saved_menu_event->type == ButtonRelease) | 1230 | if (f->output_data.x->saved_menu_event->type == ButtonRelease) |
| @@ -1193,6 +1246,7 @@ popup_activated () | |||
| 1193 | /* This callback is invoked when the user selects a menubar cascade | 1246 | /* This callback is invoked when the user selects a menubar cascade |
| 1194 | pushbutton, but before the pulldown menu is posted. */ | 1247 | pushbutton, but before the pulldown menu is posted. */ |
| 1195 | 1248 | ||
| 1249 | #ifndef USE_GTK | ||
| 1196 | static void | 1250 | static void |
| 1197 | popup_activate_callback (widget, id, client_data) | 1251 | popup_activate_callback (widget, id, client_data) |
| 1198 | Widget widget; | 1252 | Widget widget; |
| @@ -1201,10 +1255,20 @@ popup_activate_callback (widget, id, client_data) | |||
| 1201 | { | 1255 | { |
| 1202 | popup_activated_flag = 1; | 1256 | popup_activated_flag = 1; |
| 1203 | } | 1257 | } |
| 1258 | #endif | ||
| 1204 | 1259 | ||
| 1205 | /* This callback is invoked when a dialog or menu is finished being | 1260 | /* This callback is invoked when a dialog or menu is finished being |
| 1206 | used and has been unposted. */ | 1261 | used and has been unposted. */ |
| 1207 | 1262 | ||
| 1263 | #ifdef USE_GTK | ||
| 1264 | static void | ||
| 1265 | popup_deactivate_callback (widget, client_data) | ||
| 1266 | GtkWidget *widget; | ||
| 1267 | gpointer client_data; | ||
| 1268 | { | ||
| 1269 | popup_activated_flag = 0; | ||
| 1270 | } | ||
| 1271 | #else | ||
| 1208 | static void | 1272 | static void |
| 1209 | popup_deactivate_callback (widget, id, client_data) | 1273 | popup_deactivate_callback (widget, id, client_data) |
| 1210 | Widget widget; | 1274 | Widget widget; |
| @@ -1213,27 +1277,20 @@ popup_deactivate_callback (widget, id, client_data) | |||
| 1213 | { | 1277 | { |
| 1214 | popup_activated_flag = 0; | 1278 | popup_activated_flag = 0; |
| 1215 | } | 1279 | } |
| 1280 | #endif | ||
| 1216 | 1281 | ||
| 1217 | /* Lwlib callback called when menu items are highlighted/unhighlighted | ||
| 1218 | while moving the mouse over them. WIDGET is the menu bar or menu | ||
| 1219 | popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to | ||
| 1220 | the widget_value structure for the menu item, or null in case of | ||
| 1221 | unhighlighting. */ | ||
| 1222 | 1282 | ||
| 1223 | void | 1283 | /* Function that finds the frame for WIDGET and shows the HELP text |
| 1224 | menu_highlight_callback (widget, id, call_data) | 1284 | for that widget. |
| 1225 | Widget widget; | 1285 | F is the frame if known, or NULL if not known. */ |
| 1226 | LWLIB_ID id; | 1286 | static void |
| 1227 | void *call_data; | 1287 | show_help_event (f, widget, help) |
| 1288 | FRAME_PTR f; | ||
| 1289 | xt_or_gtk_widget widget; | ||
| 1290 | Lisp_Object help; | ||
| 1228 | { | 1291 | { |
| 1229 | widget_value *wv = (widget_value *) call_data; | 1292 | Lisp_Object frame; |
| 1230 | struct frame *f; | ||
| 1231 | Lisp_Object frame, help; | ||
| 1232 | 1293 | ||
| 1233 | help = wv ? wv->help : Qnil; | ||
| 1234 | |||
| 1235 | /* Determine the frame for the help event. */ | ||
| 1236 | f = menubar_id_to_frame (id); | ||
| 1237 | if (f) | 1294 | if (f) |
| 1238 | { | 1295 | { |
| 1239 | XSETFRAME (frame, f); | 1296 | XSETFRAME (frame, f); |
| @@ -1243,7 +1300,7 @@ menu_highlight_callback (widget, id, call_data) | |||
| 1243 | { | 1300 | { |
| 1244 | /* WIDGET is the popup menu. It's parent is the frame's | 1301 | /* WIDGET is the popup menu. It's parent is the frame's |
| 1245 | widget. See which frame that is. */ | 1302 | widget. See which frame that is. */ |
| 1246 | Widget frame_widget = XtParent (widget); | 1303 | xt_or_gtk_widget frame_widget = XtParent (widget); |
| 1247 | Lisp_Object tail; | 1304 | Lisp_Object tail; |
| 1248 | 1305 | ||
| 1249 | for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) | 1306 | for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) |
| @@ -1259,32 +1316,77 @@ menu_highlight_callback (widget, id, call_data) | |||
| 1259 | } | 1316 | } |
| 1260 | } | 1317 | } |
| 1261 | 1318 | ||
| 1262 | /* This callback is called from the menu bar pulldown menu | 1319 | /* Callback called when menu items are highlighted/unhighlighted |
| 1263 | when the user makes a selection. | 1320 | while moving the mouse over them. WIDGET is the menu bar or menu |
| 1264 | Figure out what the user chose | 1321 | popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to |
| 1265 | and put the appropriate events into the keyboard buffer. */ | 1322 | the data structure for the menu item, or null in case of |
| 1323 | unhighlighting. */ | ||
| 1266 | 1324 | ||
| 1267 | static void | 1325 | #ifdef USE_GTK |
| 1268 | menubar_selection_callback (widget, id, client_data) | 1326 | void |
| 1327 | menu_highlight_callback (widget, call_data) | ||
| 1328 | GtkWidget *widget; | ||
| 1329 | gpointer call_data; | ||
| 1330 | { | ||
| 1331 | xg_menu_item_cb_data *cb_data; | ||
| 1332 | Lisp_Object help; | ||
| 1333 | |||
| 1334 | cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget), | ||
| 1335 | XG_ITEM_DATA); | ||
| 1336 | if (! cb_data) return; | ||
| 1337 | |||
| 1338 | help = call_data ? cb_data->help : Qnil; | ||
| 1339 | |||
| 1340 | /* If popup_activated_flag is greater than 1 we are in a popup menu. | ||
| 1341 | Don't show help for them, they won't appear before the | ||
| 1342 | popup is popped down. */ | ||
| 1343 | if (popup_activated_flag <= 1) | ||
| 1344 | show_help_event (cb_data->cl_data->f, widget, help); | ||
| 1345 | } | ||
| 1346 | #else | ||
| 1347 | void | ||
| 1348 | menu_highlight_callback (widget, id, call_data) | ||
| 1269 | Widget widget; | 1349 | Widget widget; |
| 1270 | LWLIB_ID id; | 1350 | LWLIB_ID id; |
| 1271 | XtPointer client_data; | 1351 | void *call_data; |
| 1352 | { | ||
| 1353 | struct frame *f; | ||
| 1354 | Lisp_Object help; | ||
| 1355 | |||
| 1356 | widget_value *wv = (widget_value *) call_data; | ||
| 1357 | |||
| 1358 | help = wv ? wv->help : Qnil; | ||
| 1359 | |||
| 1360 | /* Determine the frame for the help event. */ | ||
| 1361 | f = menubar_id_to_frame (id); | ||
| 1362 | |||
| 1363 | show_help_event (f, widget, help); | ||
| 1364 | } | ||
| 1365 | #endif | ||
| 1366 | |||
| 1367 | /* Find the menu selection and store it in the keyboard buffer. | ||
| 1368 | F is the frame the menu is on. | ||
| 1369 | MENU_BAR_ITEMS_USED is the length of VECTOR. | ||
| 1370 | VECTOR is an array of menu events for the whole menu. | ||
| 1371 | */ | ||
| 1372 | void | ||
| 1373 | find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) | ||
| 1374 | FRAME_PTR f; | ||
| 1375 | int menu_bar_items_used; | ||
| 1376 | Lisp_Object vector; | ||
| 1377 | void *client_data; | ||
| 1272 | { | 1378 | { |
| 1273 | Lisp_Object prefix, entry; | 1379 | Lisp_Object prefix, entry; |
| 1274 | FRAME_PTR f = menubar_id_to_frame (id); | ||
| 1275 | Lisp_Object vector; | ||
| 1276 | Lisp_Object *subprefix_stack; | 1380 | Lisp_Object *subprefix_stack; |
| 1277 | int submenu_depth = 0; | 1381 | int submenu_depth = 0; |
| 1278 | int i; | 1382 | int i; |
| 1279 | 1383 | ||
| 1280 | if (!f) | ||
| 1281 | return; | ||
| 1282 | entry = Qnil; | 1384 | entry = Qnil; |
| 1283 | subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); | 1385 | subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object)); |
| 1284 | vector = f->menu_bar_vector; | ||
| 1285 | prefix = Qnil; | 1386 | prefix = Qnil; |
| 1286 | i = 0; | 1387 | i = 0; |
| 1287 | while (i < f->menu_bar_items_used) | 1388 | |
| 1389 | while (i < menu_bar_items_used) | ||
| 1288 | { | 1390 | { |
| 1289 | if (EQ (XVECTOR (vector)->contents[i], Qnil)) | 1391 | if (EQ (XVECTOR (vector)->contents[i], Qnil)) |
| 1290 | { | 1392 | { |
| @@ -1348,6 +1450,59 @@ menubar_selection_callback (widget, id, client_data) | |||
| 1348 | } | 1450 | } |
| 1349 | } | 1451 | } |
| 1350 | 1452 | ||
| 1453 | |||
| 1454 | #ifdef USE_GTK | ||
| 1455 | /* Gtk calls callbacks just because we tell it what item should be | ||
| 1456 | selected in a radio group. If this variable is set to a non-zero | ||
| 1457 | value, we are creating menus and don't want callbacks right now. | ||
| 1458 | */ | ||
| 1459 | static int xg_crazy_callback_abort; | ||
| 1460 | |||
| 1461 | /* This callback is called from the menu bar pulldown menu | ||
| 1462 | when the user makes a selection. | ||
| 1463 | Figure out what the user chose | ||
| 1464 | and put the appropriate events into the keyboard buffer. */ | ||
| 1465 | static void | ||
| 1466 | menubar_selection_callback (widget, client_data) | ||
| 1467 | GtkWidget *widget; | ||
| 1468 | gpointer client_data; | ||
| 1469 | { | ||
| 1470 | xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data; | ||
| 1471 | |||
| 1472 | if (xg_crazy_callback_abort) | ||
| 1473 | return; | ||
| 1474 | |||
| 1475 | if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f) | ||
| 1476 | return; | ||
| 1477 | |||
| 1478 | find_and_call_menu_selection (cb_data->cl_data->f, | ||
| 1479 | cb_data->cl_data->menu_bar_items_used, | ||
| 1480 | cb_data->cl_data->menu_bar_vector, | ||
| 1481 | cb_data->call_data); | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | #else /* not USE_GTK */ | ||
| 1485 | |||
| 1486 | /* This callback is called from the menu bar pulldown menu | ||
| 1487 | when the user makes a selection. | ||
| 1488 | Figure out what the user chose | ||
| 1489 | and put the appropriate events into the keyboard buffer. */ | ||
| 1490 | static void | ||
| 1491 | menubar_selection_callback (widget, id, client_data) | ||
| 1492 | Widget widget; | ||
| 1493 | LWLIB_ID id; | ||
| 1494 | XtPointer client_data; | ||
| 1495 | { | ||
| 1496 | FRAME_PTR f; | ||
| 1497 | |||
| 1498 | f = menubar_id_to_frame (id); | ||
| 1499 | if (!f) | ||
| 1500 | return; | ||
| 1501 | find_and_call_menu_selection (f, f->menu_bar_items_used, | ||
| 1502 | f->menu_bar_vector, client_data); | ||
| 1503 | } | ||
| 1504 | #endif /* not USE_GTK */ | ||
| 1505 | |||
| 1351 | /* Allocate a widget_value, blocking input. */ | 1506 | /* Allocate a widget_value, blocking input. */ |
| 1352 | 1507 | ||
| 1353 | widget_value * | 1508 | widget_value * |
| @@ -1623,9 +1778,12 @@ static int | |||
| 1623 | update_frame_menubar (f) | 1778 | update_frame_menubar (f) |
| 1624 | FRAME_PTR f; | 1779 | FRAME_PTR f; |
| 1625 | { | 1780 | { |
| 1781 | #ifdef USE_GTK | ||
| 1782 | return xg_update_frame_menubar (f); | ||
| 1783 | #else | ||
| 1626 | struct x_output *x = f->output_data.x; | 1784 | struct x_output *x = f->output_data.x; |
| 1627 | int columns, rows; | 1785 | int columns, rows; |
| 1628 | 1786 | ||
| 1629 | if (!x->menubar_widget || XtIsManaged (x->menubar_widget)) | 1787 | if (!x->menubar_widget || XtIsManaged (x->menubar_widget)) |
| 1630 | return 0; | 1788 | return 0; |
| 1631 | 1789 | ||
| @@ -1657,6 +1815,7 @@ update_frame_menubar (f) | |||
| 1657 | /* Force the pane widget to resize itself with the right values. */ | 1815 | /* Force the pane widget to resize itself with the right values. */ |
| 1658 | EmacsFrameSetCharSize (x->edit_widget, columns, rows); | 1816 | EmacsFrameSetCharSize (x->edit_widget, columns, rows); |
| 1659 | UNBLOCK_INPUT; | 1817 | UNBLOCK_INPUT; |
| 1818 | #endif | ||
| 1660 | return 1; | 1819 | return 1; |
| 1661 | } | 1820 | } |
| 1662 | 1821 | ||
| @@ -1670,21 +1829,25 @@ set_frame_menubar (f, first_time, deep_p) | |||
| 1670 | int first_time; | 1829 | int first_time; |
| 1671 | int deep_p; | 1830 | int deep_p; |
| 1672 | { | 1831 | { |
| 1673 | Widget menubar_widget = f->output_data.x->menubar_widget; | 1832 | xt_or_gtk_widget menubar_widget = f->output_data.x->menubar_widget; |
| 1833 | #ifdef USE_X_TOOLKIT | ||
| 1834 | LWLIB_ID id; | ||
| 1835 | #endif | ||
| 1674 | Lisp_Object items; | 1836 | Lisp_Object items; |
| 1675 | widget_value *wv, *first_wv, *prev_wv = 0; | 1837 | widget_value *wv, *first_wv, *prev_wv = 0; |
| 1676 | int i, last_i; | 1838 | int i, last_i; |
| 1677 | int *submenu_start, *submenu_end; | 1839 | int *submenu_start, *submenu_end; |
| 1678 | int *submenu_top_level_items, *submenu_n_panes; | 1840 | int *submenu_top_level_items, *submenu_n_panes; |
| 1679 | 1841 | ||
| 1680 | LWLIB_ID id; | ||
| 1681 | 1842 | ||
| 1682 | XSETFRAME (Vmenu_updating_frame, f); | 1843 | XSETFRAME (Vmenu_updating_frame, f); |
| 1683 | 1844 | ||
| 1845 | #ifdef USE_X_TOOLKIT | ||
| 1684 | if (f->output_data.x->id == 0) | 1846 | if (f->output_data.x->id == 0) |
| 1685 | f->output_data.x->id = next_menubar_widget_id++; | 1847 | f->output_data.x->id = next_menubar_widget_id++; |
| 1686 | id = f->output_data.x->id; | 1848 | id = f->output_data.x->id; |
| 1687 | 1849 | #endif | |
| 1850 | |||
| 1688 | if (! menubar_widget) | 1851 | if (! menubar_widget) |
| 1689 | deep_p = 1; | 1852 | deep_p = 1; |
| 1690 | else if (pending_menu_activation && !deep_p) | 1853 | else if (pending_menu_activation && !deep_p) |
| @@ -1893,6 +2056,35 @@ set_frame_menubar (f, first_time, deep_p) | |||
| 1893 | 2056 | ||
| 1894 | BLOCK_INPUT; | 2057 | BLOCK_INPUT; |
| 1895 | 2058 | ||
| 2059 | #ifdef USE_GTK | ||
| 2060 | xg_crazy_callback_abort = 1; | ||
| 2061 | if (menubar_widget) | ||
| 2062 | { | ||
| 2063 | /* The third arg is DEEP_P, which says to consider the entire | ||
| 2064 | menu trees we supply, rather than just the menu bar item names. */ | ||
| 2065 | xg_modify_menubar_widgets (menubar_widget, | ||
| 2066 | f, | ||
| 2067 | first_wv, | ||
| 2068 | deep_p, | ||
| 2069 | G_CALLBACK (menubar_selection_callback), | ||
| 2070 | G_CALLBACK (popup_deactivate_callback), | ||
| 2071 | G_CALLBACK (menu_highlight_callback)); | ||
| 2072 | } | ||
| 2073 | else | ||
| 2074 | { | ||
| 2075 | GtkWidget *wvbox = f->output_data.x->vbox_widget; | ||
| 2076 | |||
| 2077 | menubar_widget | ||
| 2078 | = xg_create_widget ("menubar", "menubar", f, first_wv, | ||
| 2079 | G_CALLBACK (menubar_selection_callback), | ||
| 2080 | G_CALLBACK (popup_deactivate_callback), | ||
| 2081 | G_CALLBACK (menu_highlight_callback)); | ||
| 2082 | |||
| 2083 | f->output_data.x->menubar_widget = menubar_widget; | ||
| 2084 | } | ||
| 2085 | |||
| 2086 | |||
| 2087 | #else /* not USE_GTK */ | ||
| 1896 | if (menubar_widget) | 2088 | if (menubar_widget) |
| 1897 | { | 2089 | { |
| 1898 | /* Disable resizing (done for Motif!) */ | 2090 | /* Disable resizing (done for Motif!) */ |
| @@ -1939,10 +2131,15 @@ set_frame_menubar (f, first_time, deep_p) | |||
| 1939 | 2131 | ||
| 1940 | f->output_data.x->menubar_height = menubar_size; | 2132 | f->output_data.x->menubar_height = menubar_size; |
| 1941 | } | 2133 | } |
| 2134 | #endif /* not USE_GTK */ | ||
| 1942 | 2135 | ||
| 1943 | free_menubar_widget_value_tree (first_wv); | 2136 | free_menubar_widget_value_tree (first_wv); |
| 1944 | update_frame_menubar (f); | 2137 | update_frame_menubar (f); |
| 1945 | 2138 | ||
| 2139 | #ifdef USE_GTK | ||
| 2140 | xg_crazy_callback_abort = 0; | ||
| 2141 | #endif | ||
| 2142 | |||
| 1946 | UNBLOCK_INPUT; | 2143 | UNBLOCK_INPUT; |
| 1947 | } | 2144 | } |
| 1948 | 2145 | ||
| @@ -1963,8 +2160,10 @@ initialize_frame_menubar (f) | |||
| 1963 | 2160 | ||
| 1964 | 2161 | ||
| 1965 | /* Get rid of the menu bar of frame F, and free its storage. | 2162 | /* Get rid of the menu bar of frame F, and free its storage. |
| 1966 | This is used when deleting a frame, and when turning off the menu bar. */ | 2163 | This is used when deleting a frame, and when turning off the menu bar. |
| 2164 | For GTK this function is in gtkutil.c. */ | ||
| 1967 | 2165 | ||
| 2166 | #ifndef USE_GTK | ||
| 1968 | void | 2167 | void |
| 1969 | free_frame_menubar (f) | 2168 | free_frame_menubar (f) |
| 1970 | FRAME_PTR f; | 2169 | FRAME_PTR f; |
| @@ -2011,8 +2210,9 @@ free_frame_menubar (f) | |||
| 2011 | UNBLOCK_INPUT; | 2210 | UNBLOCK_INPUT; |
| 2012 | } | 2211 | } |
| 2013 | } | 2212 | } |
| 2213 | #endif /* not USE_GTK */ | ||
| 2014 | 2214 | ||
| 2015 | #endif /* USE_X_TOOLKIT */ | 2215 | #endif /* USE_X_TOOLKIT || USE_GTK */ |
| 2016 | 2216 | ||
| 2017 | /* xmenu_show actually displays a menu using the panes and items in menu_items | 2217 | /* xmenu_show actually displays a menu using the panes and items in menu_items |
| 2018 | and returns the value selected from it. | 2218 | and returns the value selected from it. |
| @@ -2030,7 +2230,116 @@ free_frame_menubar (f) | |||
| 2030 | ERROR is a place to store an error message string in case of failure. | 2230 | ERROR is a place to store an error message string in case of failure. |
| 2031 | (We return nil on failure, but the value doesn't actually matter.) */ | 2231 | (We return nil on failure, but the value doesn't actually matter.) */ |
| 2032 | 2232 | ||
| 2033 | #ifdef USE_X_TOOLKIT | 2233 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 2234 | |||
| 2235 | /* The item selected in the popup menu. */ | ||
| 2236 | static Lisp_Object *volatile menu_item_selection; | ||
| 2237 | |||
| 2238 | #ifdef USE_GTK | ||
| 2239 | |||
| 2240 | /* Used when position a popup menu. See menu_position_func and | ||
| 2241 | create_and_show_popup_menu below. */ | ||
| 2242 | struct next_popup_x_y | ||
| 2243 | { | ||
| 2244 | int x; | ||
| 2245 | int y; | ||
| 2246 | }; | ||
| 2247 | |||
| 2248 | /* The menu position function to use if we are not putting a popup | ||
| 2249 | menu where the pointer is. | ||
| 2250 | MENU is the menu to pop up. | ||
| 2251 | X and Y shall on exit contain x/y where the menu shall pop up. | ||
| 2252 | PUSH_IN is not documented in the GTK manual. | ||
| 2253 | USER_DATA is any data passed in when calling gtk_menu_popup. | ||
| 2254 | Here it points to a struct next_popup_x_y where the coordinates | ||
| 2255 | to store in *X and *Y are. | ||
| 2256 | |||
| 2257 | Here only X and Y are used. */ | ||
| 2258 | static void | ||
| 2259 | menu_position_func (menu, x, y, push_in, user_data) | ||
| 2260 | GtkMenu *menu; | ||
| 2261 | gint *x; | ||
| 2262 | gint *y; | ||
| 2263 | gboolean *push_in; | ||
| 2264 | gpointer user_data; | ||
| 2265 | { | ||
| 2266 | *x = ((struct next_popup_x_y*)user_data)->x; | ||
| 2267 | *y = ((struct next_popup_x_y*)user_data)->y; | ||
| 2268 | } | ||
| 2269 | |||
| 2270 | static void | ||
| 2271 | popup_selection_callback (widget, client_data) | ||
| 2272 | GtkWidget *widget; | ||
| 2273 | gpointer client_data; | ||
| 2274 | { | ||
| 2275 | xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data; | ||
| 2276 | |||
| 2277 | if (xg_crazy_callback_abort) return; | ||
| 2278 | if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data; | ||
| 2279 | } | ||
| 2280 | |||
| 2281 | /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the | ||
| 2282 | menu pops down. | ||
| 2283 | menu_item_selection will be set to the selection. */ | ||
| 2284 | static void | ||
| 2285 | create_and_show_popup_menu (f, first_wv, x, y, for_click) | ||
| 2286 | FRAME_PTR f; | ||
| 2287 | widget_value *first_wv; | ||
| 2288 | int x; | ||
| 2289 | int y; | ||
| 2290 | int for_click; | ||
| 2291 | { | ||
| 2292 | int i; | ||
| 2293 | GtkWidget *menu; | ||
| 2294 | GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ | ||
| 2295 | struct next_popup_x_y popup_x_y; | ||
| 2296 | |||
| 2297 | xg_crazy_callback_abort = 1; | ||
| 2298 | menu = xg_create_widget ("popup", first_wv->name, f, first_wv, | ||
| 2299 | G_CALLBACK (popup_selection_callback), | ||
| 2300 | G_CALLBACK (popup_deactivate_callback), | ||
| 2301 | G_CALLBACK (menu_highlight_callback)); | ||
| 2302 | xg_crazy_callback_abort = 0; | ||
| 2303 | |||
| 2304 | for (i = 0; i < 5; i++) | ||
| 2305 | if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) | ||
| 2306 | break; | ||
| 2307 | |||
| 2308 | if (! for_click) | ||
| 2309 | { | ||
| 2310 | /* Not invoked by a click. pop up at x/y. */ | ||
| 2311 | pos_func = menu_position_func; | ||
| 2312 | |||
| 2313 | /* Adjust coordinates to be root-window-relative. */ | ||
| 2314 | x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | ||
| 2315 | y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | ||
| 2316 | |||
| 2317 | popup_x_y.x = x; | ||
| 2318 | popup_x_y.y = y; | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | /* Display the menu. */ | ||
| 2322 | gtk_widget_show_all (menu); | ||
| 2323 | gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); | ||
| 2324 | |||
| 2325 | xg_did_tearoff = 0; | ||
| 2326 | /* Set this to one. popup_widget_loop increases it by one, so it becomes | ||
| 2327 | two. show_help_echo uses this to detect popup menus. */ | ||
| 2328 | popup_activated_flag = 1; | ||
| 2329 | /* Process events that apply to the menu. */ | ||
| 2330 | popup_widget_loop (); | ||
| 2331 | |||
| 2332 | if (xg_did_tearoff) | ||
| 2333 | xg_keep_popup (menu, xg_did_tearoff); | ||
| 2334 | else | ||
| 2335 | gtk_widget_destroy (menu); | ||
| 2336 | |||
| 2337 | /* Must reset this manually because the button release event is not passed | ||
| 2338 | to Emacs event loop. */ | ||
| 2339 | FRAME_X_DISPLAY_INFO (f)->grabbed = 0; | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | #else /* not USE_GTK */ | ||
| 2034 | 2343 | ||
| 2035 | /* We need a unique id for each widget handled by the Lucid Widget | 2344 | /* We need a unique id for each widget handled by the Lucid Widget |
| 2036 | library. | 2345 | library. |
| @@ -2042,8 +2351,6 @@ free_frame_menubar (f) | |||
| 2042 | next_menubar_widget_id. */ | 2351 | next_menubar_widget_id. */ |
| 2043 | LWLIB_ID widget_id_tick; | 2352 | LWLIB_ID widget_id_tick; |
| 2044 | 2353 | ||
| 2045 | static Lisp_Object *volatile menu_item_selection; | ||
| 2046 | |||
| 2047 | static void | 2354 | static void |
| 2048 | popup_selection_callback (widget, id, client_data) | 2355 | popup_selection_callback (widget, id, client_data) |
| 2049 | Widget widget; | 2356 | Widget widget; |
| @@ -2053,6 +2360,76 @@ popup_selection_callback (widget, id, client_data) | |||
| 2053 | menu_item_selection = (Lisp_Object *) client_data; | 2360 | menu_item_selection = (Lisp_Object *) client_data; |
| 2054 | } | 2361 | } |
| 2055 | 2362 | ||
| 2363 | /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the | ||
| 2364 | menu pops down. | ||
| 2365 | menu_item_selection will be set to the selection. */ | ||
| 2366 | static void | ||
| 2367 | create_and_show_popup_menu (f, first_wv, x, y, for_click) | ||
| 2368 | FRAME_PTR f; | ||
| 2369 | widget_value *first_wv; | ||
| 2370 | int x; | ||
| 2371 | int y; | ||
| 2372 | int for_click; | ||
| 2373 | { | ||
| 2374 | int i; | ||
| 2375 | Arg av[2]; | ||
| 2376 | int ac = 0; | ||
| 2377 | XButtonPressedEvent dummy; | ||
| 2378 | LWLIB_ID menu_id; | ||
| 2379 | Widget menu; | ||
| 2380 | Window child; | ||
| 2381 | |||
| 2382 | menu_id = widget_id_tick++; | ||
| 2383 | menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, | ||
| 2384 | f->output_data.x->widget, 1, 0, | ||
| 2385 | popup_selection_callback, | ||
| 2386 | popup_deactivate_callback, | ||
| 2387 | menu_highlight_callback); | ||
| 2388 | |||
| 2389 | dummy.type = ButtonPress; | ||
| 2390 | dummy.serial = 0; | ||
| 2391 | dummy.send_event = 0; | ||
| 2392 | dummy.display = FRAME_X_DISPLAY (f); | ||
| 2393 | dummy.time = CurrentTime; | ||
| 2394 | dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window; | ||
| 2395 | dummy.window = dummy.root; | ||
| 2396 | dummy.subwindow = dummy.root; | ||
| 2397 | dummy.x = x; | ||
| 2398 | dummy.y = y; | ||
| 2399 | |||
| 2400 | /* Adjust coordinates to be root-window-relative. */ | ||
| 2401 | x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | ||
| 2402 | y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | ||
| 2403 | |||
| 2404 | dummy.x_root = x; | ||
| 2405 | dummy.y_root = y; | ||
| 2406 | |||
| 2407 | dummy.state = 0; | ||
| 2408 | dummy.button = 0; | ||
| 2409 | for (i = 0; i < 5; i++) | ||
| 2410 | if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) | ||
| 2411 | dummy.button = i; | ||
| 2412 | |||
| 2413 | /* Don't allow any geometry request from the user. */ | ||
| 2414 | XtSetArg (av[ac], XtNgeometry, 0); ac++; | ||
| 2415 | XtSetValues (menu, av, ac); | ||
| 2416 | |||
| 2417 | /* Display the menu. */ | ||
| 2418 | lw_popup_menu (menu, (XEvent *) &dummy); | ||
| 2419 | popup_activated_flag = 1; | ||
| 2420 | |||
| 2421 | /* Process events that apply to the menu. */ | ||
| 2422 | popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0); | ||
| 2423 | |||
| 2424 | /* fp turned off the following statement and wrote a comment | ||
| 2425 | that it is unnecessary--that the menu has already disappeared. | ||
| 2426 | Nowadays the menu disappears ok, all right, but | ||
| 2427 | we need to delete the widgets or multiple ones will pile up. */ | ||
| 2428 | lw_destroy_all_widgets (menu_id); | ||
| 2429 | } | ||
| 2430 | |||
| 2431 | #endif /* not USE_GTK */ | ||
| 2432 | |||
| 2056 | static Lisp_Object | 2433 | static Lisp_Object |
| 2057 | xmenu_show (f, x, y, for_click, keymaps, title, error) | 2434 | xmenu_show (f, x, y, for_click, keymaps, title, error) |
| 2058 | FRAME_PTR f; | 2435 | FRAME_PTR f; |
| @@ -2064,17 +2441,12 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) | |||
| 2064 | char **error; | 2441 | char **error; |
| 2065 | { | 2442 | { |
| 2066 | int i; | 2443 | int i; |
| 2067 | LWLIB_ID menu_id; | ||
| 2068 | Widget menu; | ||
| 2069 | Arg av[2]; | ||
| 2070 | int ac = 0; | ||
| 2071 | widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; | 2444 | widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; |
| 2072 | widget_value **submenu_stack | 2445 | widget_value **submenu_stack |
| 2073 | = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); | 2446 | = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); |
| 2074 | Lisp_Object *subprefix_stack | 2447 | Lisp_Object *subprefix_stack |
| 2075 | = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); | 2448 | = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); |
| 2076 | int submenu_depth = 0; | 2449 | int submenu_depth = 0; |
| 2077 | XButtonPressedEvent dummy; | ||
| 2078 | 2450 | ||
| 2079 | int first_pane; | 2451 | int first_pane; |
| 2080 | 2452 | ||
| @@ -2266,70 +2638,14 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) | |||
| 2266 | first_wv->contents = wv_title; | 2638 | first_wv->contents = wv_title; |
| 2267 | } | 2639 | } |
| 2268 | 2640 | ||
| 2269 | /* Actually create the menu. */ | ||
| 2270 | menu_id = widget_id_tick++; | ||
| 2271 | menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, | ||
| 2272 | f->output_data.x->widget, 1, 0, | ||
| 2273 | popup_selection_callback, | ||
| 2274 | popup_deactivate_callback, | ||
| 2275 | menu_highlight_callback); | ||
| 2276 | |||
| 2277 | /* See if whe positions are up to date. Temporary code to be removed | ||
| 2278 | when we are sure positions are always up to date. */ | ||
| 2279 | { | ||
| 2280 | int real_x, real_y; | ||
| 2281 | x_real_positions (f, &real_x, &real_y); | ||
| 2282 | |||
| 2283 | if (real_x != f->output_data.x->left_pos || | ||
| 2284 | real_y != f->output_data.x->top_pos) | ||
| 2285 | abort (); | ||
| 2286 | } | ||
| 2287 | |||
| 2288 | dummy.type = ButtonPress; | ||
| 2289 | dummy.serial = 0; | ||
| 2290 | dummy.send_event = 0; | ||
| 2291 | dummy.display = FRAME_X_DISPLAY (f); | ||
| 2292 | dummy.time = CurrentTime; | ||
| 2293 | dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window; | ||
| 2294 | dummy.window = dummy.root; | ||
| 2295 | dummy.subwindow = dummy.root; | ||
| 2296 | dummy.x = x; | ||
| 2297 | dummy.y = y; | ||
| 2298 | |||
| 2299 | /* Adjust coordinates to be root-window-relative. */ | ||
| 2300 | x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | ||
| 2301 | y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | ||
| 2302 | |||
| 2303 | dummy.x_root = x; | ||
| 2304 | dummy.y_root = y; | ||
| 2305 | dummy.state = 0; | ||
| 2306 | dummy.button = 0; | ||
| 2307 | for (i = 0; i < 5; i++) | ||
| 2308 | if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) | ||
| 2309 | dummy.button = i; | ||
| 2310 | |||
| 2311 | /* Don't allow any geometry request from the user. */ | ||
| 2312 | XtSetArg (av[ac], XtNgeometry, 0); ac++; | ||
| 2313 | XtSetValues (menu, av, ac); | ||
| 2314 | |||
| 2315 | /* Free the widget_value objects we used to specify the contents. */ | ||
| 2316 | free_menubar_widget_value_tree (first_wv); | ||
| 2317 | |||
| 2318 | /* No selection has been chosen yet. */ | 2641 | /* No selection has been chosen yet. */ |
| 2319 | menu_item_selection = 0; | 2642 | menu_item_selection = 0; |
| 2320 | 2643 | ||
| 2321 | /* Display the menu. */ | 2644 | /* Actually create and show the menu until popped down. */ |
| 2322 | lw_popup_menu (menu, (XEvent *) &dummy); | 2645 | create_and_show_popup_menu (f, first_wv, x, y, for_click); |
| 2323 | popup_activated_flag = 1; | ||
| 2324 | 2646 | ||
| 2325 | /* Process events that apply to the menu. */ | 2647 | /* Free the widget_value objects we used to specify the contents. */ |
| 2326 | popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0); | 2648 | free_menubar_widget_value_tree (first_wv); |
| 2327 | |||
| 2328 | /* fp turned off the following statement and wrote a comment | ||
| 2329 | that it is unnecessary--that the menu has already disappeared. | ||
| 2330 | Nowadays the menu disappears ok, all right, but | ||
| 2331 | we need to delete the widgets or multiple ones will pile up. */ | ||
| 2332 | lw_destroy_all_widgets (menu_id); | ||
| 2333 | 2649 | ||
| 2334 | /* Find the selected item, and its pane, to return | 2650 | /* Find the selected item, and its pane, to return |
| 2335 | the proper value. */ | 2651 | the proper value. */ |
| @@ -2389,6 +2705,48 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) | |||
| 2389 | return Qnil; | 2705 | return Qnil; |
| 2390 | } | 2706 | } |
| 2391 | 2707 | ||
| 2708 | #ifdef USE_GTK | ||
| 2709 | static void | ||
| 2710 | dialog_selection_callback (widget, client_data) | ||
| 2711 | GtkWidget *widget; | ||
| 2712 | gpointer client_data; | ||
| 2713 | { | ||
| 2714 | /* The EMACS_INT cast avoids a warning. There's no problem | ||
| 2715 | as long as pointers have enough bits to hold small integers. */ | ||
| 2716 | if ((int) (EMACS_INT) client_data != -1) | ||
| 2717 | menu_item_selection = (Lisp_Object *) client_data; | ||
| 2718 | |||
| 2719 | popup_activated_flag = 0; | ||
| 2720 | } | ||
| 2721 | |||
| 2722 | /* Pop up the dialog for frame F defined by FIRST_WV and loop until the | ||
| 2723 | dialog pops down. | ||
| 2724 | menu_item_selection will be set to the selection. */ | ||
| 2725 | static void | ||
| 2726 | create_and_show_dialog (f, first_wv) | ||
| 2727 | FRAME_PTR f; | ||
| 2728 | widget_value *first_wv; | ||
| 2729 | { | ||
| 2730 | GtkWidget *menu; | ||
| 2731 | |||
| 2732 | menu = xg_create_widget ("dialog", first_wv->name, f, first_wv, | ||
| 2733 | G_CALLBACK (dialog_selection_callback), | ||
| 2734 | G_CALLBACK (popup_deactivate_callback), | ||
| 2735 | 0); | ||
| 2736 | |||
| 2737 | if (menu) | ||
| 2738 | { | ||
| 2739 | /* Display the menu. */ | ||
| 2740 | gtk_widget_show_all (menu); | ||
| 2741 | |||
| 2742 | /* Process events that apply to the menu. */ | ||
| 2743 | popup_widget_loop (); | ||
| 2744 | |||
| 2745 | gtk_widget_destroy (menu); | ||
| 2746 | } | ||
| 2747 | } | ||
| 2748 | |||
| 2749 | #else /* not USE_GTK */ | ||
| 2392 | static void | 2750 | static void |
| 2393 | dialog_selection_callback (widget, id, client_data) | 2751 | dialog_selection_callback (widget, id, client_data) |
| 2394 | Widget widget; | 2752 | Widget widget; |
| @@ -2399,12 +2757,14 @@ dialog_selection_callback (widget, id, client_data) | |||
| 2399 | as long as pointers have enough bits to hold small integers. */ | 2757 | as long as pointers have enough bits to hold small integers. */ |
| 2400 | if ((int) (EMACS_INT) client_data != -1) | 2758 | if ((int) (EMACS_INT) client_data != -1) |
| 2401 | menu_item_selection = (Lisp_Object *) client_data; | 2759 | menu_item_selection = (Lisp_Object *) client_data; |
| 2760 | |||
| 2402 | BLOCK_INPUT; | 2761 | BLOCK_INPUT; |
| 2403 | lw_destroy_all_widgets (id); | 2762 | lw_destroy_all_widgets (id); |
| 2404 | UNBLOCK_INPUT; | 2763 | UNBLOCK_INPUT; |
| 2405 | popup_activated_flag = 0; | 2764 | popup_activated_flag = 0; |
| 2406 | } | 2765 | } |
| 2407 | 2766 | ||
| 2767 | |||
| 2408 | /* ARG is the LWLIB ID of the dialog box, represented | 2768 | /* ARG is the LWLIB ID of the dialog box, represented |
| 2409 | as a Lisp object as (HIGHPART . LOWPART). */ | 2769 | as a Lisp object as (HIGHPART . LOWPART). */ |
| 2410 | 2770 | ||
| @@ -2421,6 +2781,46 @@ xdialog_show_unwind (arg) | |||
| 2421 | return Qnil; | 2781 | return Qnil; |
| 2422 | } | 2782 | } |
| 2423 | 2783 | ||
| 2784 | |||
| 2785 | /* Pop up the dialog for frame F defined by FIRST_WV and loop until the | ||
| 2786 | dialog pops down. | ||
| 2787 | menu_item_selection will be set to the selection. */ | ||
| 2788 | static void | ||
| 2789 | create_and_show_dialog (f, first_wv) | ||
| 2790 | FRAME_PTR f; | ||
| 2791 | widget_value *first_wv; | ||
| 2792 | { | ||
| 2793 | LWLIB_ID dialog_id; | ||
| 2794 | |||
| 2795 | dialog_id = widget_id_tick++; | ||
| 2796 | lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, | ||
| 2797 | f->output_data.x->widget, 1, 0, | ||
| 2798 | dialog_selection_callback, 0, 0); | ||
| 2799 | lw_modify_all_widgets (dialog_id, first_wv->contents, True); | ||
| 2800 | |||
| 2801 | /* Display the dialog box. */ | ||
| 2802 | lw_pop_up_all_widgets (dialog_id); | ||
| 2803 | popup_activated_flag = 1; | ||
| 2804 | |||
| 2805 | /* Process events that apply to the dialog box. | ||
| 2806 | Also handle timers. */ | ||
| 2807 | { | ||
| 2808 | int count = SPECPDL_INDEX (); | ||
| 2809 | int fact = 4 * sizeof (LWLIB_ID); | ||
| 2810 | |||
| 2811 | /* xdialog_show_unwind is responsible for popping the dialog box down. */ | ||
| 2812 | record_unwind_protect (xdialog_show_unwind, | ||
| 2813 | Fcons (make_number (dialog_id >> (fact)), | ||
| 2814 | make_number (dialog_id & ~(-1 << (fact))))); | ||
| 2815 | |||
| 2816 | popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1); | ||
| 2817 | |||
| 2818 | unbind_to (count, Qnil); | ||
| 2819 | } | ||
| 2820 | } | ||
| 2821 | |||
| 2822 | #endif /* not USE_GTK */ | ||
| 2823 | |||
| 2424 | static char * button_names [] = { | 2824 | static char * button_names [] = { |
| 2425 | "button1", "button2", "button3", "button4", "button5", | 2825 | "button1", "button2", "button3", "button4", "button5", |
| 2426 | "button6", "button7", "button8", "button9", "button10" }; | 2826 | "button6", "button7", "button8", "button9", "button10" }; |
| @@ -2433,7 +2833,6 @@ xdialog_show (f, keymaps, title, error) | |||
| 2433 | char **error; | 2833 | char **error; |
| 2434 | { | 2834 | { |
| 2435 | int i, nb_buttons=0; | 2835 | int i, nb_buttons=0; |
| 2436 | LWLIB_ID dialog_id; | ||
| 2437 | char dialog_name[6]; | 2836 | char dialog_name[6]; |
| 2438 | 2837 | ||
| 2439 | widget_value *wv, *first_wv = 0, *prev_wv = 0; | 2838 | widget_value *wv, *first_wv = 0, *prev_wv = 0; |
| @@ -2543,38 +2942,17 @@ xdialog_show (f, keymaps, title, error) | |||
| 2543 | first_wv = wv; | 2942 | first_wv = wv; |
| 2544 | } | 2943 | } |
| 2545 | 2944 | ||
| 2546 | /* Actually create the dialog. */ | ||
| 2547 | dialog_id = widget_id_tick++; | ||
| 2548 | lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, | ||
| 2549 | f->output_data.x->widget, 1, 0, | ||
| 2550 | dialog_selection_callback, 0, 0); | ||
| 2551 | lw_modify_all_widgets (dialog_id, first_wv->contents, True); | ||
| 2552 | /* Free the widget_value objects we used to specify the contents. */ | ||
| 2553 | free_menubar_widget_value_tree (first_wv); | ||
| 2554 | |||
| 2555 | /* No selection has been chosen yet. */ | 2945 | /* No selection has been chosen yet. */ |
| 2556 | menu_item_selection = 0; | 2946 | menu_item_selection = 0; |
| 2557 | 2947 | ||
| 2558 | /* Display the dialog box. */ | 2948 | /* Actually create and show the dialog. */ |
| 2559 | lw_pop_up_all_widgets (dialog_id); | 2949 | create_and_show_dialog (f, first_wv); |
| 2560 | popup_activated_flag = 1; | ||
| 2561 | |||
| 2562 | /* Process events that apply to the dialog box. | ||
| 2563 | Also handle timers. */ | ||
| 2564 | { | ||
| 2565 | int count = SPECPDL_INDEX (); | ||
| 2566 | |||
| 2567 | /* xdialog_show_unwind is responsible for popping the dialog box down. */ | ||
| 2568 | record_unwind_protect (xdialog_show_unwind, | ||
| 2569 | Fcons (make_number (dialog_id >> (4 * sizeof (LWLIB_ID))), | ||
| 2570 | make_number (dialog_id & ~(-1 << (4 * sizeof (LWLIB_ID)))))); | ||
| 2571 | |||
| 2572 | popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1); | ||
| 2573 | |||
| 2574 | unbind_to (count, Qnil); | ||
| 2575 | } | ||
| 2576 | 2950 | ||
| 2577 | /* Find the selected item and pane, and return the corresponding value. */ | 2951 | /* Free the widget_value objects we used to specify the contents. */ |
| 2952 | free_menubar_widget_value_tree (first_wv); | ||
| 2953 | |||
| 2954 | /* Find the selected item, and its pane, to return | ||
| 2955 | the proper value. */ | ||
| 2578 | if (menu_item_selection != 0) | 2956 | if (menu_item_selection != 0) |
| 2579 | { | 2957 | { |
| 2580 | Lisp_Object prefix; | 2958 | Lisp_Object prefix; |
| @@ -2619,7 +2997,7 @@ xdialog_show (f, keymaps, title, error) | |||
| 2619 | return Qnil; | 2997 | return Qnil; |
| 2620 | } | 2998 | } |
| 2621 | 2999 | ||
| 2622 | #else /* not USE_X_TOOLKIT */ | 3000 | #else /* not USE_X_TOOLKIT && not USE_GTK */ |
| 2623 | 3001 | ||
| 2624 | /* The frame of the last activated non-toolkit menu bar. | 3002 | /* The frame of the last activated non-toolkit menu bar. |
| 2625 | Used to generate menu help events. */ | 3003 | Used to generate menu help events. */ |