aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard M. Stallman1994-03-10 17:03:21 +0000
committerRichard M. Stallman1994-03-10 17:03:21 +0000
commit101bb4a5539a543fae012c71b2d23b642c2026e3 (patch)
treeb440510c3f2d65cd2a2c7e76eb5fddf8f39a7336 /src
parent51d5a2c95f507e988922ccd80828a1c73405bdd7 (diff)
downloademacs-101bb4a5539a543fae012c71b2d23b642c2026e3.tar.gz
emacs-101bb4a5539a543fae012c71b2d23b642c2026e3.zip
(Fx_popup_menu): If POSITION is nil,
don't require an open X connection. (single_keymap_panes, keymap_panes, menu_item_enabled_p): New arg NOTREAL. (Fx_popup_menu): Pass new arg (1 if POSITION is nil). (menu_item_enabled_p): If NOTREAL, always return t. (single_keymap_panes) [!USE_X_TOOLKIT]: Append > to item_string if submenu. [USE_X_TOOLKIT]: Display submenus in Xt style. (menu_items): Record where submenus start and end. (menu_items_submenu_depth): New variable. (init_menu_items): Init it. (push_submenu_start, push_submenu_end): New functions. (grow_menu_items): New function. (push_menu_pane, push_menu_item): Use it. (push_menu_pane): Increment menu_items_n_panes only if depth is 0. (single_keymap_panes) [USE_X_TOOLKIT]: Record submenus in menu_items. (xmenu_show) [USE_X_TOOLKIT]: Give submenus to toolkit.
Diffstat (limited to 'src')
-rw-r--r--src/xmenu.c210
1 files changed, 164 insertions, 46 deletions
diff --git a/src/xmenu.c b/src/xmenu.c
index acfb48e2fec..eb9122b2d06 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -113,6 +113,11 @@ static void list_of_items ();
113 the item string, the enable flag, the item's value, 113 the item string, the enable flag, the item's value,
114 and the equivalent keyboard key's description string. 114 and the equivalent keyboard key's description string.
115 115
116 In some cases, multiple levels of menus may be described.
117 A single vector slot containing nil indicates the start of a submenu.
118 A single vector slot containing lambda indicates the end of a submenu.
119 The submenu follows a menu item which is the way to reach the submenu.
120
116 Using a Lisp vector to hold this information while we decode it 121 Using a Lisp vector to hold this information while we decode it
117 takes care of protecting all the data from GC. */ 122 takes care of protecting all the data from GC. */
118 123
@@ -134,9 +139,13 @@ static int menu_items_allocated;
134/* This is the index in menu_items of the first empty slot. */ 139/* This is the index in menu_items of the first empty slot. */
135static int menu_items_used; 140static int menu_items_used;
136 141
137/* The number of panes currently recorded in menu_items. */ 142/* The number of panes currently recorded in menu_items,
143 excluding those within submenus. */
138static int menu_items_n_panes; 144static int menu_items_n_panes;
139 145
146/* Current depth within submenus. */
147static int menu_items_submenu_depth;
148
140/* Initialize the menu_items structure if we haven't already done so. 149/* Initialize the menu_items structure if we haven't already done so.
141 Also mark it as currently empty. */ 150 Also mark it as currently empty. */
142 151
@@ -151,6 +160,7 @@ init_menu_items ()
151 160
152 menu_items_used = 0; 161 menu_items_used = 0;
153 menu_items_n_panes = 0; 162 menu_items_n_panes = 0;
163 menu_items_submenu_depth = 0;
154} 164}
155 165
156/* Call at the end of generating the data in menu_items. 166/* Call at the end of generating the data in menu_items.
@@ -176,6 +186,45 @@ discard_menu_items ()
176 } 186 }
177} 187}
178 188
189/* Make the menu_items vector twice as large. */
190
191static void
192grow_menu_items ()
193{
194 Lisp_Object old;
195 int old_size = menu_items_allocated;
196 old = menu_items;
197
198 menu_items_allocated *= 2;
199 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
200 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
201 old_size * sizeof (Lisp_Object));
202}
203
204/* Begin a submenu. */
205
206static void
207push_submenu_start ()
208{
209 if (menu_items_used + 1 > menu_items_allocated)
210 grow_menu_items ();
211
212 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
213 menu_items_submenu_depth++;
214}
215
216/* End a submenu. */
217
218static void
219push_submenu_end ()
220{
221 if (menu_items_used + 1 > menu_items_allocated)
222 grow_menu_items ();
223
224 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
225 menu_items_submenu_depth--;
226}
227
179/* Start a new menu pane in menu_items.. 228/* Start a new menu pane in menu_items..
180 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */ 229 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
181 230
@@ -184,18 +233,10 @@ push_menu_pane (name, prefix_vec)
184 Lisp_Object name, prefix_vec; 233 Lisp_Object name, prefix_vec;
185{ 234{
186 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated) 235 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
187 { 236 grow_menu_items ();
188 Lisp_Object old;
189 int old_size = menu_items_allocated;
190 old = menu_items;
191 237
192 menu_items_allocated *= 2; 238 if (menu_items_submenu_depth == 0)
193 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); 239 menu_items_n_panes++;
194 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
195 old_size * sizeof (Lisp_Object));
196 }
197
198 menu_items_n_panes++;
199 XVECTOR (menu_items)->contents[menu_items_used++] = Qt; 240 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
200 XVECTOR (menu_items)->contents[menu_items_used++] = name; 241 XVECTOR (menu_items)->contents[menu_items_used++] = name;
201 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec; 242 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
@@ -212,16 +253,7 @@ push_menu_item (name, enable, key, equiv)
212 Lisp_Object name, enable, key, equiv; 253 Lisp_Object name, enable, key, equiv;
213{ 254{
214 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) 255 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
215 { 256 grow_menu_items ();
216 Lisp_Object old;
217 int old_size = menu_items_allocated;
218 old = menu_items;
219
220 menu_items_allocated *= 2;
221 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
222 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
223 old_size * sizeof (Lisp_Object));
224 }
225 257
226 XVECTOR (menu_items)->contents[menu_items_used++] = name; 258 XVECTOR (menu_items)->contents[menu_items_used++] = name;
227 XVECTOR (menu_items)->contents[menu_items_used++] = enable; 259 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
@@ -319,15 +351,18 @@ menu_item_enabled_p_1 (arg)
319} 351}
320 352
321/* Return non-nil if the command DEF is enabled when used as a menu item. 353/* Return non-nil if the command DEF is enabled when used as a menu item.
322 This is based on looking for a menu-enable property. */ 354 This is based on looking for a menu-enable property.
355 If NOTREAL is set, don't bother really computing this. */
323 356
324static Lisp_Object 357static Lisp_Object
325menu_item_enabled_p (def) 358menu_item_enabled_p (def, notreal)
326 Lisp_Object def; 359 Lisp_Object def;
327{ 360{
328 Lisp_Object enabled, tem; 361 Lisp_Object enabled, tem;
329 362
330 enabled = Qt; 363 enabled = Qt;
364 if (notreal)
365 return enabled;
331 if (XTYPE (def) == Lisp_Symbol) 366 if (XTYPE (def) == Lisp_Symbol)
332 { 367 {
333 /* No property, or nil, means enable. 368 /* No property, or nil, means enable.
@@ -343,12 +378,15 @@ menu_item_enabled_p (def)
343} 378}
344 379
345/* Look through KEYMAPS, a vector of keymaps that is NMAPS long, 380/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
346 and generate menu panes for them in menu_items. */ 381 and generate menu panes for them in menu_items.
382 If NOTREAL is nonzero,
383 don't bother really computing whether an item is enabled. */
347 384
348static void 385static void
349keymap_panes (keymaps, nmaps) 386keymap_panes (keymaps, nmaps, notreal)
350 Lisp_Object *keymaps; 387 Lisp_Object *keymaps;
351 int nmaps; 388 int nmaps;
389 int notreal;
352{ 390{
353 int mapno; 391 int mapno;
354 392
@@ -358,7 +396,7 @@ keymap_panes (keymaps, nmaps)
358 But don't make a pane that is empty--ignore that map instead. 396 But don't make a pane that is empty--ignore that map instead.
359 P is the number of panes we have made so far. */ 397 P is the number of panes we have made so far. */
360 for (mapno = 0; mapno < nmaps; mapno++) 398 for (mapno = 0; mapno < nmaps; mapno++)
361 single_keymap_panes (keymaps[mapno], Qnil, Qnil); 399 single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal);
362 400
363 finish_menu_items (); 401 finish_menu_items ();
364} 402}
@@ -366,13 +404,16 @@ keymap_panes (keymaps, nmaps)
366/* This is a recursive subroutine of keymap_panes. 404/* This is a recursive subroutine of keymap_panes.
367 It handles one keymap, KEYMAP. 405 It handles one keymap, KEYMAP.
368 The other arguments are passed along 406 The other arguments are passed along
369 or point to local variables of the previous function. */ 407 or point to local variables of the previous function.
408 If NOTREAL is nonzero,
409 don't bother really computing whether an item is enabled. */
370 410
371static void 411static void
372single_keymap_panes (keymap, pane_name, prefix) 412single_keymap_panes (keymap, pane_name, prefix, notreal)
373 Lisp_Object keymap; 413 Lisp_Object keymap;
374 Lisp_Object pane_name; 414 Lisp_Object pane_name;
375 Lisp_Object prefix; 415 Lisp_Object prefix;
416 int notreal;
376{ 417{
377 Lisp_Object pending_maps; 418 Lisp_Object pending_maps;
378 Lisp_Object tail, item, item1, item_string, table; 419 Lisp_Object tail, item, item1, item_string, table;
@@ -410,7 +451,8 @@ single_keymap_panes (keymap, pane_name, prefix)
410 a string. Since there's no GCPRO5, we refetch 451 a string. Since there's no GCPRO5, we refetch
411 item_string instead of protecting it. */ 452 item_string instead of protecting it. */
412 GCPRO4 (keymap, pending_maps, def, descrip); 453 GCPRO4 (keymap, pending_maps, def, descrip);
413 enabled = menu_item_enabled_p (def); 454 enabled = menu_item_enabled_p (def, notreal);
455
414 UNGCPRO; 456 UNGCPRO;
415 457
416 item_string = XCONS (item1)->car; 458 item_string = XCONS (item1)->car;
@@ -420,8 +462,28 @@ single_keymap_panes (keymap, pane_name, prefix)
420 pending_maps = Fcons (Fcons (def, Fcons (item_string, XCONS (item)->car)), 462 pending_maps = Fcons (Fcons (def, Fcons (item_string, XCONS (item)->car)),
421 pending_maps); 463 pending_maps);
422 else 464 else
423 push_menu_item (item_string, enabled, XCONS (item)->car, 465 {
424 descrip); 466 Lisp_Object submap;
467 submap = get_keymap_1 (def, 0, 1);
468#ifndef USE_X_TOOLKIT
469 /* Indicate visually that this is a submenu. */
470 if (!NILP (submap))
471 item_string = concat2 (item_string,
472 build_string (" >"));
473#endif
474 push_menu_item (item_string, enabled, XCONS (item)->car,
475 descrip);
476#ifdef USE_X_TOOLKIT
477 /* Display a submenu using the toolkit. */
478 if (! NILP (submap))
479 {
480 push_submenu_start ();
481 single_keymap_panes (submap, Qnil,
482 XCONS (item)->car, notreal);
483 push_submenu_end ();
484 }
485#endif
486 }
425 } 487 }
426 } 488 }
427 } 489 }
@@ -455,7 +517,7 @@ single_keymap_panes (keymap, pane_name, prefix)
455 a string. Since there's no GCPRO5, we refetch 517 a string. Since there's no GCPRO5, we refetch
456 item_string instead of protecting it. */ 518 item_string instead of protecting it. */
457 GCPRO4 (keymap, pending_maps, def, descrip); 519 GCPRO4 (keymap, pending_maps, def, descrip);
458 enabled = menu_item_enabled_p (def); 520 enabled = menu_item_enabled_p (def, notreal);
459 UNGCPRO; 521 UNGCPRO;
460 522
461 item_string = XCONS (item1)->car; 523 item_string = XCONS (item1)->car;
@@ -465,8 +527,26 @@ single_keymap_panes (keymap, pane_name, prefix)
465 pending_maps = Fcons (Fcons (def, Fcons (item_string, character)), 527 pending_maps = Fcons (Fcons (def, Fcons (item_string, character)),
466 pending_maps); 528 pending_maps);
467 else 529 else
468 push_menu_item (item_string, enabled, 530 {
469 character, descrip); 531 Lisp_Object submap;
532 submap = get_keymap_1 (def, 0, 1);
533#ifndef USE_X_TOOLKIT
534 if (!NILP (submap))
535 item_string = concat2 (item_string,
536 build_string (" >"));
537#endif
538 push_menu_item (item_string, enabled, character,
539 descrip);
540#ifdef USE_X_TOOLKIT
541 if (! NILP (submap))
542 {
543 push_submenu_start ();
544 single_keymap_panes (submap, Qnil,
545 character, notreal);
546 push_submenu_end ();
547 }
548#endif
549 }
470 } 550 }
471 } 551 }
472 } 552 }
@@ -476,12 +556,14 @@ single_keymap_panes (keymap, pane_name, prefix)
476 /* Process now any submenus which want to be panes at this level. */ 556 /* Process now any submenus which want to be panes at this level. */
477 while (!NILP (pending_maps)) 557 while (!NILP (pending_maps))
478 { 558 {
479 Lisp_Object elt, eltcdr; 559 Lisp_Object elt, eltcdr, string;
480 elt = Fcar (pending_maps); 560 elt = Fcar (pending_maps);
481 eltcdr = XCONS (elt)->cdr; 561 eltcdr = XCONS (elt)->cdr;
482 single_keymap_panes (Fcar (elt), 562 string = XCONS (eltcdr)->car;
483 /* Fails to discard the @. */ 563 /* We no longer discard the @ from the beginning of the string here.
484 XCONS (eltcdr)->car, XCONS (eltcdr)->cdr); 564 Instead, we do this in xmenu_show. */
565 single_keymap_panes (Fcar (elt), string,
566 XCONS (eltcdr)->cdr, notreal);
485 pending_maps = Fcdr (pending_maps); 567 pending_maps = Fcdr (pending_maps);
486 } 568 }
487} 569}
@@ -581,10 +663,10 @@ cached information about equivalent key sequences.")
581 int menubarp = 0; 663 int menubarp = 0;
582 struct gcpro gcpro1; 664 struct gcpro gcpro1;
583 665
584 check_x ();
585
586 if (! NILP (position)) 666 if (! NILP (position))
587 { 667 {
668 check_x ();
669
588 /* Decode the first argument: find the window and the coordinates. */ 670 /* Decode the first argument: find the window and the coordinates. */
589 if (EQ (position, Qt)) 671 if (EQ (position, Qt))
590 { 672 {
@@ -668,7 +750,7 @@ cached information about equivalent key sequences.")
668 keymap = get_keymap (menu); 750 keymap = get_keymap (menu);
669 751
670 /* Extract the detailed info to make one pane. */ 752 /* Extract the detailed info to make one pane. */
671 keymap_panes (&menu, 1); 753 keymap_panes (&menu, 1, NILP (position));
672 754
673 /* Search for a string appearing directly as an element of the keymap. 755 /* Search for a string appearing directly as an element of the keymap.
674 That string is the title of the menu. */ 756 That string is the title of the menu. */
@@ -704,7 +786,7 @@ cached information about equivalent key sequences.")
704 } 786 }
705 787
706 /* Extract the detailed info to make one pane. */ 788 /* Extract the detailed info to make one pane. */
707 keymap_panes (maps, nmaps); 789 keymap_panes (maps, nmaps, NILP (position));
708 790
709 /* Make the title be the pane title of the first pane. */ 791 /* Make the title be the pane title of the first pane. */
710 if (!NILP (title) && menu_items_n_panes >= 0) 792 if (!NILP (title) && menu_items_n_panes >= 0)
@@ -1123,6 +1205,11 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1123 widget_value *menubar_item = 0; 1205 widget_value *menubar_item = 0;
1124 1206
1125 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1207 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1208 widget_value **submenu_stack
1209 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1210 Lisp_Object *subprefix_stack
1211 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1212 int submenu_depth = 0;
1126 1213
1127 /* Define a queue to save up for later unreading 1214 /* Define a queue to save up for later unreading
1128 all X events that don't pertain to the menu. */ 1215 all X events that don't pertain to the menu. */
@@ -1188,7 +1275,23 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1188 i = 0; 1275 i = 0;
1189 while (i < menu_items_used) 1276 while (i < menu_items_used)
1190 { 1277 {
1191 if (EQ (XVECTOR (menu_items)->contents[i], Qt)) 1278 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1279 {
1280 submenu_stack[submenu_depth++] = save_wv;
1281 save_wv = prev_wv;
1282 prev_wv = 0;
1283 i++;
1284 }
1285 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1286 {
1287 prev_wv = save_wv;
1288 save_wv = submenu_stack[--submenu_depth];
1289 i++;
1290 }
1291 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1292 && submenu_depth != 0)
1293 i += MENU_ITEMS_PANE_LENGTH;
1294 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1192 { 1295 {
1193 /* Create a new pane. */ 1296 /* Create a new pane. */
1194 Lisp_Object pane_name, prefix; 1297 Lisp_Object pane_name, prefix;
@@ -1197,7 +1300,7 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1197 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; 1300 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1198 pane_string = (NILP (pane_name) 1301 pane_string = (NILP (pane_name)
1199 ? "" : (char *) XSTRING (pane_name)->data); 1302 ? "" : (char *) XSTRING (pane_name)->data);
1200 /* If there is just one pane, put all its items directly 1303 /* If there is just one top-level pane, put all its items directly
1201 under the top-level menu. */ 1304 under the top-level menu. */
1202 if (menu_items_n_panes == 1) 1305 if (menu_items_n_panes == 1)
1203 pane_string = ""; 1306 pane_string = "";
@@ -1402,7 +1505,18 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1402 { 1505 {
1403 Lisp_Object entry; 1506 Lisp_Object entry;
1404 1507
1405 if (EQ (XVECTOR (menu_items)->contents[i], Qt)) 1508 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1509 {
1510 subprefix_stack[submenu_depth++] = prefix;
1511 prefix = entry;
1512 i++;
1513 }
1514 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1515 {
1516 prefix = subprefix_stack[--submenu_depth];
1517 i++;
1518 }
1519 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1406 { 1520 {
1407 prefix 1521 prefix
1408 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; 1522 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
@@ -1416,9 +1530,13 @@ xmenu_show (f, x, y, menubarp, keymaps, title, error)
1416 { 1530 {
1417 if (keymaps != 0) 1531 if (keymaps != 0)
1418 { 1532 {
1533 int j;
1534
1419 entry = Fcons (entry, Qnil); 1535 entry = Fcons (entry, Qnil);
1420 if (!NILP (prefix)) 1536 if (!NILP (prefix))
1421 entry = Fcons (prefix, entry); 1537 entry = Fcons (prefix, entry);
1538 for (j = submenu_depth - 1; j >= 0; j--)
1539 entry = Fcons (subprefix_stack[j], entry);
1422 } 1540 }
1423 return entry; 1541 return entry;
1424 } 1542 }