aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Reilly1994-10-02 15:51:13 +0000
committerPaul Reilly1994-10-02 15:51:13 +0000
commit4dedbfe0bf00decbc4c6f42970cde37af21198ff (patch)
treef108eca4a025571ec0815fadfe63e1066338e5a2 /src
parenta263cd2dd908102c57283919ab6a22235e544b58 (diff)
downloademacs-4dedbfe0bf00decbc4c6f42970cde37af21198ff.tar.gz
emacs-4dedbfe0bf00decbc4c6f42970cde37af21198ff.zip
(widget_id_tick): Renamed from popup_id_tick.
(popup_get_selection, popup_activated, popup_activate_callback, menubar_selection_callback, popup_deactivate_callback, single_submenu): New or replaced functions. (popup_activated_flag): New variable. (dispatch_dummy_expose, event_is_in_menu_item, map_event_to_object): Removed. (update_frame_menubar): Use lw_refigure_widget to provide widget set independence. (set_frame_menubar): Use lw_allow_resizing to control unsightly Motif menubar resizing in a widget set independent fashion. (xmenu_show): Removed menubar handling code, since that is now done in lwlib. Display a popup menu title centered and followed by two separators. Use lw_popup_menu() to display the menu. Use popup_get_selection() to deal with X11 event handling while the menu is posted.
Diffstat (limited to 'src')
-rw-r--r--src/xmenu.c726
1 files changed, 380 insertions, 346 deletions
diff --git a/src/xmenu.c b/src/xmenu.c
index c78f8f59aff..096ff34559c 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -66,9 +66,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
66#include <X11/CoreP.h> 66#include <X11/CoreP.h>
67#include <X11/StringDefs.h> 67#include <X11/StringDefs.h>
68#include <X11/Shell.h> 68#include <X11/Shell.h>
69#include <X11/Xaw/Paned.h>
70#include "../lwlib/lwlib.h" 69#include "../lwlib/lwlib.h"
71#include "../lwlib/xlwmenuP.h"
72#endif /* USE_X_TOOLKIT */ 70#endif /* USE_X_TOOLKIT */
73 71
74#define min(x,y) (((x) < (y)) ? (x) : (y)) 72#define min(x,y) (((x) < (y)) ? (x) : (y))
@@ -85,8 +83,10 @@ extern Display *x_current_display;
85#define ButtonReleaseMask ButtonReleased 83#define ButtonReleaseMask ButtonReleased
86#endif /* not HAVE_X11 */ 84#endif /* not HAVE_X11 */
87 85
88/* We need a unique id for each popup menu and dialog box. */ 86/* We need a unique id for each widget handled by the Lucid Widget
89static unsigned int popup_id_tick; 87 library. This includes the frame main windows, popup menu and
88 dialog box. */
89LWLIB_ID widget_id_tick;
90 90
91extern Lisp_Object Qmenu_enable; 91extern Lisp_Object Qmenu_enable;
92extern Lisp_Object Qmenu_bar; 92extern Lisp_Object Qmenu_bar;
@@ -96,6 +96,7 @@ extern void process_expose_from_menu ();
96extern XtAppContext Xt_app_con; 96extern XtAppContext Xt_app_con;
97 97
98static Lisp_Object xdialog_show (); 98static Lisp_Object xdialog_show ();
99void popup_get_selection ();
99#endif 100#endif
100 101
101static Lisp_Object xmenu_show (); 102static Lisp_Object xmenu_show ();
@@ -151,6 +152,11 @@ static int menu_items_n_panes;
151/* Current depth within submenus. */ 152/* Current depth within submenus. */
152static int menu_items_submenu_depth; 153static int menu_items_submenu_depth;
153 154
155/* Flag which when set indicates a dialog or menu has been posted by
156 Xt on behalf of one of the widget sets. */
157static int popup_activated_flag;
158
159
154/* Initialize the menu_items structure if we haven't already done so. 160/* Initialize the menu_items structure if we haven't already done so.
155 Also mark it as currently empty. */ 161 Also mark it as currently empty. */
156 162
@@ -994,122 +1000,148 @@ on the left of the dialog box and all following items on the right.\n\
994 1000
995#ifdef USE_X_TOOLKIT 1001#ifdef USE_X_TOOLKIT
996 1002
997static void 1003/* Loop in Xt until the menu pulldown or dialog popup has been
998dispatch_dummy_expose (w, x, y) 1004 popped down (deactivated). */
999 Widget w; 1005void
1000 int x; 1006popup_get_selection (initial_event)
1001 int y; 1007 XEvent *initial_event;
1002{
1003 XExposeEvent dummy;
1004
1005 dummy.type = Expose;
1006 dummy.window = XtWindow (w);
1007 dummy.count = 0;
1008 dummy.serial = 0;
1009 dummy.send_event = 0;
1010 dummy.display = XtDisplay (w);
1011 dummy.x = x;
1012 dummy.y = y;
1013
1014 XtDispatchEvent ((XEvent *) &dummy);
1015}
1016
1017static int
1018event_is_in_menu_item (mw, event, name, string_w)
1019 XlwMenuWidget mw;
1020 struct input_event *event;
1021 char *name;
1022 int *string_w;
1023{
1024 *string_w += (string_width (mw, name)
1025 + 2 * (mw->menu.horizontal_spacing
1026 + mw->menu.shadow_thickness));
1027 return XINT (event->x) < *string_w;
1028}
1029
1030
1031/* Return the menu bar key which corresponds to event EVENT in frame F. */
1032
1033Lisp_Object
1034map_event_to_object (event, f)
1035 struct input_event *event;
1036 FRAME_PTR f;
1037{ 1008{
1038 int i,j, string_w; 1009 XEvent event;
1039 window_state* ws;
1040 XlwMenuWidget mw = (XlwMenuWidget) f->display.x->menubar_widget;
1041 widget_value *val;
1042 1010
1011 if (initial_event)
1012 event = *initial_event;
1013 else
1014 XtAppNextEvent (Xt_app_con, &event);
1043 1015
1044 string_w = 0; 1016 while (1)
1045 /* Find the window */
1046 for (val = mw->menu.old_stack [0]->contents; val; val = val->next)
1047 { 1017 {
1048 ws = &mw->menu.windows [0]; 1018 BLOCK_INPUT;
1049 if (ws && event_is_in_menu_item (mw, event, val->name, &string_w)) 1019 XtDispatchEvent (&event);
1050 { 1020 UNBLOCK_INPUT;
1051 Lisp_Object items; 1021 if (!popup_activated())
1052 int i; 1022 break;
1053 1023 XtAppNextEvent (Xt_app_con, &event);
1054 items = FRAME_MENU_BAR_ITEMS (f);
1055
1056 for (i = 0; i < XVECTOR (items)->size; i += 3)
1057 {
1058 Lisp_Object pos, string, item;
1059 item = XVECTOR (items)->contents[i];
1060 string = XVECTOR (items)->contents[i + 1];
1061 pos = XVECTOR (items)->contents[i + 2];
1062 if (NILP (string))
1063 break;
1064
1065 if (!strcmp (val->name, XSTRING (string)->data))
1066 return item;
1067 }
1068 }
1069 } 1024 }
1070 return Qnil;
1071} 1025}
1072 1026
1073#ifdef __STDC__ 1027/* Detect if a dialog or menu has been posted. */
1074static Lisp_Object *volatile menu_item_selection; 1028int
1075#else 1029popup_activated ()
1076static Lisp_Object *menu_item_selection; 1030{
1077#endif 1031 return popup_activated_flag;
1032}
1033
1034
1035/* This callback is invoked when the user selects a menubar cascade
1036 pushbutton, but before the pulldown menu is posted. */
1078 1037
1079static void 1038static void
1080popup_selection_callback (widget, id, client_data) 1039popup_activate_callback (widget, id, client_data)
1081 Widget widget; 1040 Widget widget;
1082 LWLIB_ID id; 1041 LWLIB_ID id;
1083 XtPointer client_data; 1042 XtPointer client_data;
1084{ 1043{
1085 menu_item_selection = (Lisp_Object *) client_data; 1044 popup_activated_flag = 1;
1086} 1045}
1087 1046
1047/* This callback is called from the menu bar pulldown menu
1048 when the user makes a selection.
1049 Figure out what the user chose
1050 and put the appropriate events into the keyboard buffer. */
1051
1088static void 1052static void
1089popup_down_callback (widget, id, client_data) 1053menubar_selection_callback (widget, id, client_data)
1090 Widget widget; 1054 Widget widget;
1091 LWLIB_ID id; 1055 LWLIB_ID id;
1092 XtPointer client_data; 1056 XtPointer client_data;
1093{ 1057{
1094 BLOCK_INPUT; 1058 Lisp_Object prefix;
1095 lw_destroy_all_widgets (id); 1059 FRAME_PTR f = (FRAME_PTR) id;
1096 UNBLOCK_INPUT; 1060 Lisp_Object vector;
1061 Lisp_Object *subprefix_stack;
1062 int submenu_depth = 0;
1063 int i;
1064
1065 if (!f)
1066 return;
1067 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
1068 vector = f->menu_bar_vector;
1069 prefix = Qnil;
1070 i = 0;
1071 while (i < f->menu_bar_items_used)
1072 {
1073 Lisp_Object entry;
1074
1075 if (EQ (XVECTOR (vector)->contents[i], Qnil))
1076 {
1077 subprefix_stack[submenu_depth++] = prefix;
1078 prefix = entry;
1079 i++;
1080 }
1081 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
1082 {
1083 prefix = subprefix_stack[--submenu_depth];
1084 i++;
1085 }
1086 else if (EQ (XVECTOR (vector)->contents[i], Qt))
1087 {
1088 prefix
1089 = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
1090 i += MENU_ITEMS_PANE_LENGTH;
1091 }
1092 else
1093 {
1094 entry
1095 = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1096 if ((int) client_data == i)
1097 {
1098 int j;
1099 struct input_event buf;
1100
1101 buf.kind = menu_bar_event;
1102 buf.frame_or_window = Qmenu_bar;
1103 kbd_buffer_store_event (&buf);
1104
1105 for (j = 0; j < submenu_depth; j++)
1106 if (!NILP (subprefix_stack[j]))
1107 {
1108 buf.kind = menu_bar_event;
1109 buf.frame_or_window = subprefix_stack[j];
1110 kbd_buffer_store_event (&buf);
1111 }
1112
1113 if (!NILP (prefix))
1114 {
1115 buf.kind = menu_bar_event;
1116 buf.frame_or_window = prefix;
1117 kbd_buffer_store_event (&buf);
1118 }
1119
1120 buf.kind = menu_bar_event;
1121 buf.frame_or_window = entry;
1122 kbd_buffer_store_event (&buf);
1123
1124 return;
1125 }
1126 i += MENU_ITEMS_ITEM_LENGTH;
1127 }
1128 }
1097} 1129}
1098 1130
1131/* This callback is invoked when a dialog or menu is finished being
1132 used and has been unposted. */
1133
1099static void 1134static void
1100dialog_selection_callback (widget, id, client_data) 1135popup_deactivate_callback (widget, id, client_data)
1101 Widget widget; 1136 Widget widget;
1102 LWLIB_ID id; 1137 LWLIB_ID id;
1103 XtPointer client_data; 1138 XtPointer client_data;
1104{ 1139{
1105 if ((int)client_data != -1) 1140 popup_activated_flag = 0;
1106 menu_item_selection = (Lisp_Object *) client_data;
1107 BLOCK_INPUT;
1108 lw_destroy_all_widgets (id);
1109 UNBLOCK_INPUT;
1110} 1141}
1111 1142
1112/* This recursively calls free_widget_value() on the tree of widgets. 1143
1144/* This recursively calls free_widget_value on the tree of widgets.
1113 It must free all data that was malloc'ed for these widget_values. 1145 It must free all data that was malloc'ed for these widget_values.
1114 In Emacs, many slots are pointers into the data of Lisp_Strings, and 1146 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1115 must be left alone. */ 1147 must be left alone. */
@@ -1136,9 +1168,149 @@ free_menubar_widget_value_tree (wv)
1136 free_widget_value (wv); 1168 free_widget_value (wv);
1137 UNBLOCK_INPUT; 1169 UNBLOCK_INPUT;
1138} 1170}
1171
1172/* Return a tree of widget_value structures for a menu bar item
1173 whose event type is ITEM_KEY (with string ITEM_NAME)
1174 and whose contents come from the list of keymaps MAPS. */
1175
1176static widget_value *
1177single_submenu (item_key, item_name, maps)
1178 Lisp_Object item_key, item_name, maps;
1179{
1180 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1181 int i;
1182 int submenu_depth = 0;
1183 Lisp_Object length;
1184 int len;
1185 Lisp_Object *mapvec;
1186 widget_value **submenu_stack;
1187 int mapno;
1188 int previous_items = menu_items_used;
1189
1190 length = Flength (maps);
1191 len = XINT (length);
1192
1193 /* Convert the list MAPS into a vector MAPVEC. */
1194 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1195 for (i = 0; i < len; i++)
1196 {
1197 mapvec[i] = Fcar (maps);
1198 maps = Fcdr (maps);
1199 }
1200
1201 menu_items_n_panes = 0;
1202
1203 /* Loop over the given keymaps, making a pane for each map.
1204 But don't make a pane that is empty--ignore that map instead. */
1205 for (i = 0; i < len; i++)
1206 single_keymap_panes (mapvec[i], item_name, item_key, 0);
1207
1208 /* Create a tree of widget_value objects
1209 representing the panes and their items. */
1210
1211 submenu_stack
1212 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1213 wv = malloc_widget_value ();
1214 wv->name = "menu";
1215 wv->value = 0;
1216 wv->enabled = 1;
1217 first_wv = wv;
1218 save_wv = 0;
1219
1220 /* Loop over all panes and items made during this call
1221 and construct a tree of widget_value objects.
1222 Ignore the panes and items made by previous calls to
1223 single_submenu, even though those are also in menu_items. */
1224 i = previous_items;
1225 while (i < menu_items_used)
1226 {
1227 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1228 {
1229 submenu_stack[submenu_depth++] = save_wv;
1230 save_wv = prev_wv;
1231 prev_wv = 0;
1232 i++;
1233 }
1234 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1235 {
1236 prev_wv = save_wv;
1237 save_wv = submenu_stack[--submenu_depth];
1238 i++;
1239 }
1240 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1241 && submenu_depth != 0)
1242 i += MENU_ITEMS_PANE_LENGTH;
1243 /* Ignore a nil in the item list.
1244 It's meaningful only for dialog boxes. */
1245 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1246 i += 1;
1247 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1248 {
1249 /* Create a new pane. */
1250 Lisp_Object pane_name, prefix;
1251 char *pane_string;
1252 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1253 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1254 pane_string = (NILP (pane_name)
1255 ? "" : (char *) XSTRING (pane_name)->data);
1256 /* If there is just one top-level pane, put all its items directly
1257 under the top-level menu. */
1258 if (menu_items_n_panes == 1)
1259 pane_string = "";
1260
1261 /* If the pane has a meaningful name,
1262 make the pane a top-level menu item
1263 with its items as a submenu beneath it. */
1264 if (strcmp (pane_string, ""))
1265 {
1266 wv = malloc_widget_value ();
1267 if (save_wv)
1268 save_wv->next = wv;
1269 else
1270 first_wv->contents = wv;
1271 wv->name = pane_string;
1272 if (!NILP (prefix))
1273 wv->name++;
1274 wv->value = 0;
1275 wv->enabled = 1;
1276 }
1277 save_wv = wv;
1278 prev_wv = 0;
1279 i += MENU_ITEMS_PANE_LENGTH;
1280 }
1281 else
1282 {
1283 /* Create a new item within current pane. */
1284 Lisp_Object item_name, enable, descrip;
1285 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1286 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1287 descrip
1288 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1139 1289
1290 wv = malloc_widget_value ();
1291 if (prev_wv)
1292 prev_wv->next = wv;
1293 else
1294 save_wv->contents = wv;
1295 wv->name = (char *) XSTRING (item_name)->data;
1296 if (!NILP (descrip))
1297 wv->key = (char *) XSTRING (descrip)->data;
1298 wv->value = 0;
1299 wv->call_data = (void *) i;
1300 wv->enabled = !NILP (enable);
1301 prev_wv = wv;
1302
1303 i += MENU_ITEMS_ITEM_LENGTH;
1304 }
1305 }
1306
1307 return first_wv;
1308}
1309
1140extern void EmacsFrameSetCharSize (); 1310extern void EmacsFrameSetCharSize ();
1141 1311
1312/* Recompute the menu bar of frame F. */
1313
1142static void 1314static void
1143update_frame_menubar (f) 1315update_frame_menubar (f)
1144 FRAME_PTR f; 1316 FRAME_PTR f;
@@ -1147,6 +1319,12 @@ update_frame_menubar (f)
1147 int columns, rows; 1319 int columns, rows;
1148 int menubar_changed; 1320 int menubar_changed;
1149 1321
1322 Dimension shell_height;
1323
1324 /* We assume the menubar contents has changed if the global flag is set,
1325 or if the current buffer has changed, or if the menubar has never
1326 been updated before.
1327 */
1150 menubar_changed = (x->menubar_widget 1328 menubar_changed = (x->menubar_widget
1151 && !XtIsManaged (x->menubar_widget)); 1329 && !XtIsManaged (x->menubar_widget));
1152 1330
@@ -1159,9 +1337,10 @@ update_frame_menubar (f)
1159 columns = f->width; 1337 columns = f->width;
1160 rows = f->height; 1338 rows = f->height;
1161 1339
1340 /* Do the voodoo which means "I'm changing lots of things, don't try to
1341 refigure sizes until I'm done." */
1342 lw_refigure_widget (x->column_widget, False);
1162 1343
1163 XawPanedSetRefigureMode (x->column_widget, 0);
1164
1165 /* the order in which children are managed is the top to 1344 /* the order in which children are managed is the top to
1166 bottom order in which they are displayed in the paned window. 1345 bottom order in which they are displayed in the paned window.
1167 First, remove the text-area widget. 1346 First, remove the text-area widget.
@@ -1178,12 +1357,9 @@ update_frame_menubar (f)
1178 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0); 1357 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0);
1179 } 1358 }
1180 1359
1181 1360 /* Re-manage the text-area widget, and then thrash the sizes. */
1182 /* Re-manage the text-area widget */
1183 XtManageChild (x->edit_widget); 1361 XtManageChild (x->edit_widget);
1184 1362 lw_refigure_widget (x->column_widget, True);
1185 /* and now thrash the sizes */
1186 XawPanedSetRefigureMode (x->column_widget, 1);
1187 1363
1188 /* Force the pane widget to resize itself with the right values. */ 1364 /* Force the pane widget to resize itself with the right values. */
1189 EmacsFrameSetCharSize (x->edit_widget, columns, rows); 1365 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
@@ -1209,44 +1385,59 @@ set_frame_menubar (f, first_time)
1209 wv->value = 0; 1385 wv->value = 0;
1210 wv->enabled = 1; 1386 wv->enabled = 1;
1211 save_wv = first_wv = wv; 1387 save_wv = first_wv = wv;
1212 1388 items = FRAME_MENU_BAR_ITEMS (f);
1213 if (NILP (items = FRAME_MENU_BAR_ITEMS (f))) 1389 menu_items = f->menu_bar_vector;
1214 items = FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); 1390 menu_items_allocated = XVECTOR (menu_items)->size;
1391 init_menu_items ();
1215 1392
1216 for (i = 0; i < XVECTOR (items)->size; i += 3) 1393 for (i = 0; i < XVECTOR (items)->size; i += 3)
1217 { 1394 {
1218 Lisp_Object string; 1395 Lisp_Object key, string, maps;
1219 1396
1397 key = XVECTOR (items)->contents[i];
1220 string = XVECTOR (items)->contents[i + 1]; 1398 string = XVECTOR (items)->contents[i + 1];
1399 maps = XVECTOR (items)->contents[i + 2];
1221 if (NILP (string)) 1400 if (NILP (string))
1222 break; 1401 break;
1223 1402
1224 wv = malloc_widget_value (); 1403 wv = single_submenu (key, string, maps);
1225 if (prev_wv) 1404 if (prev_wv)
1226 prev_wv->next = wv; 1405 prev_wv->next = wv;
1227 else 1406 else
1228 save_wv->contents = wv; 1407 save_wv->contents = wv;
1229 wv->name = (char *) XSTRING (string)->data; 1408 wv->name = (char *) XSTRING (string)->data;
1230 wv->value = 0;
1231 wv->enabled = 1; 1409 wv->enabled = 1;
1232 prev_wv = wv; 1410 prev_wv = wv;
1233 } 1411 }
1234 1412
1413 finish_menu_items ();
1414
1415 f->menu_bar_vector = menu_items;
1416 f->menu_bar_items_used = menu_items_used;
1417 menu_items = Qnil;
1418
1235 if (menubar_widget) 1419 if (menubar_widget)
1236 lw_modify_all_widgets (id, first_wv, False); 1420 {
1421 /* Disable resizing (done for Motif!) */
1422 lw_allow_resizing (f->display.x->widget, False);
1423
1424 /* The third arg is DEEP_P, which says to consider the entire
1425 menu trees we supply, rather than just the menu bar item names. */
1426 lw_modify_all_widgets (id, first_wv, 1);
1427
1428 /* Re-enable the edit widget to resize. */
1429 lw_allow_resizing (f->display.x->widget, True);
1430 }
1237 else 1431 else
1238 { 1432 {
1239 menubar_widget = lw_create_widget ("menubar", "menubar", 1433 menubar_widget = lw_create_widget ("menubar", "menubar",
1240 id, first_wv, 1434 id, first_wv,
1241 f->display.x->column_widget, 1435 f->display.x->column_widget,
1242 0, 0, 1436 0,
1243 0, 0); 1437 popup_activate_callback,
1438 menubar_selection_callback,
1439 popup_deactivate_callback);
1244 f->display.x->menubar_widget = menubar_widget; 1440 f->display.x->menubar_widget = menubar_widget;
1245 XtVaSetValues (menubar_widget,
1246 XtNshowGrip, 0,
1247 XtNresizeToPreferred, 1,
1248 XtNallowResize, 1,
1249 0);
1250 } 1441 }
1251 1442
1252 free_menubar_widget_value_tree (first_wv); 1443 free_menubar_widget_value_tree (first_wv);
@@ -1258,6 +1449,24 @@ set_frame_menubar (f, first_time)
1258 UNBLOCK_INPUT; 1449 UNBLOCK_INPUT;
1259} 1450}
1260 1451
1452/* Called from Fx_create_frame to create the inital menubar of a frame
1453 before it is mapped, so that the window is mapped with the menubar already
1454 there instead of us tacking it on later and thrashing the window after it
1455 is visible. */
1456
1457void
1458initialize_frame_menubar (f)
1459 FRAME_PTR f;
1460{
1461 /* This function is called before the first chance to redisplay
1462 the frame. It has to be, so the frame will have the right size. */
1463 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1464 set_frame_menubar (f, 1);
1465}
1466
1467/* Get rid of the menu bar of frame F, and free its storage.
1468 This is used when deleting a frame, and when turning off the menu bar. */
1469
1261void 1470void
1262free_frame_menubar (f) 1471free_frame_menubar (f)
1263 FRAME_PTR f; 1472 FRAME_PTR f;
@@ -1275,16 +1484,6 @@ free_frame_menubar (f)
1275 UNBLOCK_INPUT; 1484 UNBLOCK_INPUT;
1276 } 1485 }
1277} 1486}
1278/* Called from Fx_create_frame to create the inital menubar of a frame
1279 before it is mapped, so that the window is mapped with the menubar already
1280 there instead of us tacking it on later and thrashing the window after it
1281 is visible. */
1282void
1283initialize_frame_menubar (f)
1284 FRAME_PTR f;
1285{
1286 set_frame_menubar (f, 1);
1287}
1288 1487
1289/* Horizontal bounds of the current menu bar item. */ 1488/* Horizontal bounds of the current menu bar item. */
1290 1489
@@ -1383,12 +1582,28 @@ extern Lisp_Object Vdouble_click_time;
1383extern unsigned int x_mouse_grabbed; 1582extern unsigned int x_mouse_grabbed;
1384extern Lisp_Object Vmouse_depressed; 1583extern Lisp_Object Vmouse_depressed;
1385 1584
1585#ifdef __STDC__
1586static Lisp_Object *volatile menu_item_selection;
1587#else
1588static Lisp_Object *menu_item_selection;
1589#endif
1590
1591static void
1592popup_selection_callback (widget, id, client_data)
1593 Widget widget;
1594 LWLIB_ID id;
1595 XtPointer client_data;
1596{
1597 menu_item_selection = (Lisp_Object *) client_data;
1598}
1599
1386static Lisp_Object 1600static Lisp_Object
1387xmenu_show (f, x, y, menubarp, keymaps, title, error) 1601xmenu_show (f, x, y, menubarp, keymaps, title, error)
1388 FRAME_PTR f; 1602 FRAME_PTR f;
1389 int x; 1603 int x;
1390 int y; 1604 int y;
1391 int menubarp; 1605 int menubarp; /* Dummy parameter for Xt version of
1606 xmenu_show() */
1392 int keymaps; 1607 int keymaps;
1393 Lisp_Object title; 1608 Lisp_Object title;
1394 char **error; 1609 char **error;
@@ -1396,13 +1611,8 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1396 int i; 1611 int i;
1397 int menu_id; 1612 int menu_id;
1398 Widget menu; 1613 Widget menu;
1399 XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
1400 Arg av [2]; 1614 Arg av [2];
1401 int ac = 0; 1615 int ac = 0;
1402
1403 /* This is the menu bar item (if any) that led to this menu. */
1404 widget_value *menubar_item = 0;
1405
1406 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1616 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1407 widget_value **submenu_stack 1617 widget_value **submenu_stack
1408 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); 1618 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
@@ -1433,48 +1643,6 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1433 *error = "Empty menu"; 1643 *error = "Empty menu";
1434 return Qnil; 1644 return Qnil;
1435 } 1645 }
1436 this_menu_bar_item_beg = -1;
1437 this_menu_bar_item_end = -1;
1438 last_menu_bar_item_end = -1;
1439
1440 /* Figure out which menu bar item, if any, this menu is for. */
1441 if (menubarp)
1442 {
1443 int xbeg;
1444 int xend = 0;
1445 widget_value *mb_item = 0;
1446
1447 for (mb_item = menubar->menu.old_stack[0]->contents;
1448 mb_item;
1449 mb_item = mb_item->next)
1450 {
1451 xbeg = xend;
1452 xend += (string_width (menubar, mb_item->name)
1453 + 2 * (menubar->menu.horizontal_spacing
1454 + menubar->menu.shadow_thickness));
1455 if (x >= xbeg && x < xend)
1456 {
1457 x = xbeg + 4;
1458 y = 0;
1459 menubar_item = mb_item;
1460 /* Arrange to show a different menu if we move in the menu bar
1461 to a different item. */
1462 this_menu_bar_item_beg = xbeg;
1463 this_menu_bar_item_end = xend;
1464 }
1465 }
1466 last_menu_bar_item_end = xend;
1467 }
1468 if (menubar_item == 0)
1469 menubarp = 0;
1470
1471 /* Offset the coordinates to root-relative. */
1472 if (f->display.x->menubar_widget != 0)
1473 y += f->display.x->menubar_widget->core.height;
1474 XtTranslateCoords (f->display.x->widget,
1475 x, y, &root_x, &root_y);
1476 x = root_x;
1477 y = root_y;
1478 1646
1479 /* Create a tree of widget_value objects 1647 /* Create a tree of widget_value objects
1480 representing the panes and their items. */ 1648 representing the panes and their items. */
@@ -1577,11 +1745,31 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1577 } 1745 }
1578 } 1746 }
1579 1747
1748 /* Deal with the title, if it is non-nil. */
1749 if (!NILP (title))
1750 {
1751 widget_value *wv_title = malloc_widget_value ();
1752 widget_value *wv_sep1 = malloc_widget_value ();
1753 widget_value *wv_sep2 = malloc_widget_value ();
1754
1755 wv_sep2->name = "--";
1756 wv_sep2->next = first_wv->contents;
1757
1758 wv_sep1->name = "--";
1759 wv_sep1->next = wv_sep2;
1760
1761 wv_title->name = (char *) XSTRING (title)->data;
1762 wv_title->enabled = True;
1763 wv_title->next = wv_sep1;
1764 first_wv->contents = wv_title;
1765 }
1766
1580 /* Actually create the menu. */ 1767 /* Actually create the menu. */
1581 menu_id = ++popup_id_tick; 1768 menu_id = ++widget_id_tick;
1582 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, 1769 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1583 f->display.x->widget, 1, 0, 1770 f->display.x->widget, 1, 0,
1584 popup_selection_callback, popup_down_callback); 1771 popup_selection_callback,
1772 popup_deactivate_callback);
1585 1773
1586 /* Don't allow any geometry request from the user. */ 1774 /* Don't allow any geometry request from the user. */
1587 XtSetArg (av[ac], XtNgeometry, 0); ac++; 1775 XtSetArg (av[ac], XtNgeometry, 0); ac++;
@@ -1593,42 +1781,9 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1593 /* No selection has been chosen yet. */ 1781 /* No selection has been chosen yet. */
1594 menu_item_selection = 0; 1782 menu_item_selection = 0;
1595 1783
1596 /* If the mouse moves out of the menu before we show the menu,
1597 don't show it at all. */
1598 if (check_mouse_other_menu_bar (f))
1599 {
1600 lw_destroy_all_widgets (menu_id);
1601 return Qnil;
1602 }
1603
1604
1605 /* Highlight the menu bar item (if any) that led to this menu. */
1606 if (menubarp)
1607 {
1608 menubar_item->call_data = (XtPointer) 1;
1609 dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
1610 }
1611
1612 /* Display the menu. */ 1784 /* Display the menu. */
1613 { 1785 lw_popup_menu (menu);
1614 XButtonPressedEvent dummy; 1786 popup_activated_flag = 1;
1615 XlwMenuWidget mw;
1616
1617 mw = (XlwMenuWidget) ((CompositeWidget)menu)->composite.children[0];
1618
1619 dummy.type = ButtonPress;
1620 dummy.serial = 0;
1621 dummy.send_event = 0;
1622 dummy.display = XtDisplay (menu);
1623 dummy.window = XtWindow (XtParent (menu));
1624 dummy.time = CurrentTime;
1625 dummy.button = 0;
1626 dummy.x_root = x;
1627 dummy.y_root = y;
1628
1629 /* We activate directly the lucid implementation. */
1630 pop_up_menu (mw, &dummy);
1631 }
1632 1787
1633 /* No need to check a second time since this is done in the XEvent loop. 1788 /* No need to check a second time since this is done in the XEvent loop.
1634 This slows done the execution. */ 1789 This slows done the execution. */
@@ -1639,143 +1794,15 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1639 /* The mouse moved into a different menu bar item. 1794 /* The mouse moved into a different menu bar item.
1640 We should bring up that item's menu instead. 1795 We should bring up that item's menu instead.
1641 First pop down this menu. */ 1796 First pop down this menu. */
1642#if 0 /* xlwmenu.c now does this. */
1643 XtUngrabPointer ((Widget)
1644 ((XlwMenuWidget)
1645 ((CompositeWidget)menu)->composite.children[0]),
1646 CurrentTime);
1647#endif
1648 lw_destroy_all_widgets (menu_id); 1797 lw_destroy_all_widgets (menu_id);
1649 goto pop_down; 1798 goto pop_down;
1650 } 1799 }
1651#endif 1800#endif
1652 1801
1653 /* Process events that apply to the menu. */ 1802 /* Process events that apply to the menu. */
1654 while (1) 1803 popup_get_selection ((XEvent *) 0);
1655 {
1656 XEvent event;
1657 int queue_and_exit = 0;
1658 int in_this_menu = 0, in_menu_bar = 0;
1659 Widget widget;
1660
1661 XtAppNextEvent (Xt_app_con, &event);
1662
1663 /* Check whether the event happened in the menu
1664 or any child of it. */
1665 widget = XtWindowToWidget (XDISPLAY event.xany.window);
1666
1667 while (widget)
1668 {
1669 if (widget == menu)
1670 {
1671 in_this_menu = 1;
1672 break;
1673 }
1674 if (widget == f->display.x->menubar_widget)
1675 {
1676 in_menu_bar = 1;
1677 break;
1678 }
1679 widget = XtParent (widget);
1680 }
1681
1682 if (event.type == ButtonRelease)
1683 {
1684 /* Do the work of construct_mouse_click since it can't
1685 be called. Initially, the popup menu has been called
1686 from a ButtonPress in the edit_widget. Then the mouse
1687 has been set to grabbed. Reset it now. */
1688 x_mouse_grabbed &= ~(1 << event.xbutton.button);
1689 if (!x_mouse_grabbed)
1690 Vmouse_depressed = Qnil;
1691
1692 /* If we release the button soon without selecting anything,
1693 stay in the loop--that is, leave the menu posted.
1694 Otherwise, exit this loop and thus pop down the menu. */
1695 if (! in_this_menu
1696 && (next_release_must_exit
1697 || !(((XButtonEvent *) (&event))->time - last_event_timestamp
1698 < XINT (Vdouble_click_time))))
1699 break;
1700 }
1701 /* A button press outside the menu => pop it down. */
1702 else if (event.type == ButtonPress && !in_this_menu)
1703 break;
1704 else if (event.type == ButtonPress)
1705 next_release_must_exit = 1;
1706 else if (event.type == KeyPress)
1707 {
1708 /* Exit the loop, but first queue this event for reuse. */
1709 queue_and_exit = 1;
1710 }
1711 else if (event.type == Expose)
1712 process_expose_from_menu (event);
1713 /* If the mouse moves to a different menu bar item, switch to
1714 that item's menu. But only if the button is still held down. */
1715 else if (event.type == MotionNotify
1716 && x_mouse_grabbed)
1717 {
1718 int event_x = (event.xmotion.x_root
1719 - (f->display.x->widget->core.x
1720 + f->display.x->widget->core.border_width));
1721 int event_y = (event.xmotion.y_root
1722 - (f->display.x->widget->core.y
1723 + f->display.x->widget->core.border_width));
1724
1725 if (other_menu_bar_item_p (f, event_x, event_y))
1726 {
1727 /* The mouse moved into a different menu bar item.
1728 We should bring up that item's menu instead.
1729 First pop down this menu. */
1730#if 0 /* xlwmenu.c now does this. */
1731 XtUngrabPointer ((Widget)
1732 ((XlwMenuWidget)
1733 ((CompositeWidget)menu)->composite.children[0]),
1734 event.xbutton.time);
1735#endif
1736 lw_destroy_all_widgets (menu_id);
1737
1738 /* Put back an event that will bring up the other item's menu. */
1739 unread_menu_bar_button (f, event_x);
1740 /* Don't let us select anything in this case. */
1741 menu_item_selection = 0;
1742 break;
1743 }
1744 }
1745 else if (event.type == UnmapNotify)
1746 {
1747 /* If the menu disappears, there is no need to stay in the
1748 loop. */
1749 if (event.xunmap.window == menu->core.window)
1750 break;
1751 }
1752
1753 XtDispatchEvent (&event);
1754
1755 if (queue_and_exit || (!in_this_menu && !in_menu_bar))
1756 {
1757 queue_tmp
1758 = (struct event_queue *) malloc (sizeof (struct event_queue));
1759
1760 if (queue_tmp != NULL)
1761 {
1762 queue_tmp->event = event;
1763 queue_tmp->next = queue;
1764 queue = queue_tmp;
1765 }
1766 }
1767 if (queue_and_exit)
1768 break;
1769 }
1770 1804
1771 pop_down: 1805 pop_down:
1772 /* Unhighlight the menu bar item (if any) that led to this menu. */
1773 if (menubarp)
1774 {
1775 menubar_item->call_data = (XtPointer) 0;
1776 dispatch_dummy_expose (f->display.x->menubar_widget, x, y);
1777 }
1778
1779 /* fp turned off the following statement and wrote a comment 1806 /* fp turned off the following statement and wrote a comment
1780 that it is unnecessary--that the menu has already disappeared. 1807 that it is unnecessary--that the menu has already disappeared.
1781 I observer that is not so. -- rms. */ 1808 I observer that is not so. -- rms. */
@@ -1848,6 +1875,19 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1848 1875
1849 return Qnil; 1876 return Qnil;
1850} 1877}
1878
1879static void
1880dialog_selection_callback (widget, id, client_data)
1881 Widget widget;
1882 LWLIB_ID id;
1883 XtPointer client_data;
1884{
1885 if ((int)client_data != -1)
1886 menu_item_selection = (Lisp_Object *) client_data;
1887 BLOCK_INPUT;
1888 lw_destroy_all_widgets (id);
1889 UNBLOCK_INPUT;
1890}
1851 1891
1852static char * button_names [] = { 1892static char * button_names [] = {
1853 "button1", "button2", "button3", "button4", "button5", 1893 "button1", "button2", "button3", "button4", "button5",
@@ -1864,12 +1904,8 @@ xdialog_show (f, menubarp, keymaps, title, error)
1864 int i, nb_buttons=0; 1904 int i, nb_buttons=0;
1865 int dialog_id; 1905 int dialog_id;
1866 Widget menu; 1906 Widget menu;
1867 XlwMenuWidget menubar = (XlwMenuWidget) f->display.x->menubar_widget;
1868 char dialog_name[6]; 1907 char dialog_name[6];
1869 1908
1870 /* This is the menu bar item (if any) that led to this menu. */
1871 widget_value *menubar_item = 0;
1872
1873 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1909 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1874 1910
1875 /* Define a queue to save up for later unreading 1911 /* Define a queue to save up for later unreading
@@ -1987,13 +2023,10 @@ xdialog_show (f, menubarp, keymaps, title, error)
1987 } 2023 }
1988 2024
1989 /* Actually create the dialog. */ 2025 /* Actually create the dialog. */
1990 dialog_id = ++popup_id_tick; 2026 dialog_id = ++widget_id_tick;
1991 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, 2027 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1992 f->display.x->widget, 1, 0, 2028 f->display.x->widget, 1, 0,
1993 dialog_selection_callback, 0); 2029 dialog_selection_callback, 0);
1994#if 0 /* This causes crashes, and seems to be redundant -- rms. */
1995 lw_modify_all_widgets (dialog_id, first_wv, True);
1996#endif
1997 lw_modify_all_widgets (dialog_id, first_wv->contents, True); 2030 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1998 /* Free the widget_value objects we used to specify the contents. */ 2031 /* Free the widget_value objects we used to specify the contents. */
1999 free_menubar_widget_value_tree (first_wv); 2032 free_menubar_widget_value_tree (first_wv);
@@ -2355,6 +2388,7 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
2355 2388
2356 return entry; 2389 return entry;
2357} 2390}
2391
2358#endif /* not USE_X_TOOLKIT */ 2392#endif /* not USE_X_TOOLKIT */
2359 2393
2360syms_of_xmenu () 2394syms_of_xmenu ()
@@ -2362,7 +2396,7 @@ syms_of_xmenu ()
2362 staticpro (&menu_items); 2396 staticpro (&menu_items);
2363 menu_items = Qnil; 2397 menu_items = Qnil;
2364 2398
2365 popup_id_tick = (1<<16); 2399 widget_id_tick = (1<<16);
2366 defsubr (&Sx_popup_menu); 2400 defsubr (&Sx_popup_menu);
2367 defsubr (&Sx_popup_dialog); 2401 defsubr (&Sx_popup_dialog);
2368} 2402}