Mercurial > emacs
comparison src/xmenu.c @ 95647:0f6a0e86ee24
Remove platform-independent menu definitions.
(menu_items menu_items_inuse, menu_items_allocated)
(menu_items_used, menu_items_n_panes)
(menu_items_submenu_depth): Move to keyboard.h.
(init_menu_items, finish_menu_items, unuse_menu_items)
(discard_menu_items, restore_menu_items, save_menu_items)
(grow_menu_items, push_submenu_start, push_submenu_end)
(push_left_right_boundary, push_menu_pane, push_menu_item)
(keymap_panes, single_keymap_panes, single_menu_item)
(list_of_panes, list_of_items, find_and_call_menu_selection)
(xmalloc_widget_value, free_menubar_widget_value_tree)
(parse_single_submenu, digest_single_submenu)
(update_submenu_strings): Move to menu.c.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Sun, 08 Jun 2008 04:36:46 +0000 |
parents | 8971ddf55736 |
children | c3a24b1a8412 |
comparison
equal
deleted
inserted
replaced
95646:816ec0114c3c | 95647:0f6a0e86ee24 |
---|---|
120 | 120 |
121 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, | 121 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, |
122 char **)); | 122 char **)); |
123 static void popup_get_selection P_ ((XEvent *, struct x_display_info *, | 123 static void popup_get_selection P_ ((XEvent *, struct x_display_info *, |
124 LWLIB_ID, int)); | 124 LWLIB_ID, int)); |
125 | |
126 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ | |
127 | |
128 #define HAVE_BOXES 1 | |
129 #endif /* USE_X_TOOLKIT */ | 125 #endif /* USE_X_TOOLKIT */ |
130 | 126 |
131 #ifdef USE_GTK | 127 #ifdef USE_GTK |
132 #include "gtkutil.h" | 128 #include "gtkutil.h" |
133 #define HAVE_BOXES 1 | |
134 extern void set_frame_menubar P_ ((FRAME_PTR, int, int)); | 129 extern void set_frame_menubar P_ ((FRAME_PTR, int, int)); |
135 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, | 130 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, |
136 char **)); | 131 char **)); |
137 #endif | 132 #endif |
138 | 133 |
139 /* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU | |
140 isn't defined. The use of HAVE_MULTILINGUAL_MENU could probably be | |
141 confined to an extended version of this with sections of code below | |
142 using it unconditionally. */ | |
143 #ifdef USE_GTK | |
144 /* gtk just uses utf-8. */ | |
145 # define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str) | |
146 #elif defined HAVE_X_I18N | |
147 # define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str) | |
148 #else | |
149 # define ENCODE_MENU_STRING(str) string_make_unibyte (str) | |
150 #endif | |
151 | |
152 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | |
153 Lisp_Object, Lisp_Object, Lisp_Object, | |
154 Lisp_Object, Lisp_Object)); | |
155 static int update_frame_menubar P_ ((struct frame *)); | 134 static int update_frame_menubar P_ ((struct frame *)); |
156 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int, | 135 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int, |
157 Lisp_Object, char **)); | 136 Lisp_Object, char **)); |
158 static void keymap_panes P_ ((Lisp_Object *, int, int)); | |
159 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | |
160 int, int)); | |
161 static void list_of_panes P_ ((Lisp_Object)); | |
162 static void list_of_items P_ ((Lisp_Object)); | |
163 | |
164 | 137 |
165 /* This holds a Lisp vector that holds the results of decoding | |
166 the keymaps or alist-of-alists that specify a menu. | |
167 | |
168 It describes the panes and items within the panes. | |
169 | |
170 Each pane is described by 3 elements in the vector: | |
171 t, the pane name, the pane's prefix key. | |
172 Then follow the pane's items, with 5 elements per item: | |
173 the item string, the enable flag, the item's value, | |
174 the definition, and the equivalent keyboard key's description string. | |
175 | |
176 In some cases, multiple levels of menus may be described. | |
177 A single vector slot containing nil indicates the start of a submenu. | |
178 A single vector slot containing lambda indicates the end of a submenu. | |
179 The submenu follows a menu item which is the way to reach the submenu. | |
180 | |
181 A single vector slot containing quote indicates that the | |
182 following items should appear on the right of a dialog box. | |
183 | |
184 Using a Lisp vector to hold this information while we decode it | |
185 takes care of protecting all the data from GC. */ | |
186 | |
187 #define MENU_ITEMS_PANE_NAME 1 | |
188 #define MENU_ITEMS_PANE_PREFIX 2 | |
189 #define MENU_ITEMS_PANE_LENGTH 3 | |
190 | |
191 enum menu_item_idx | |
192 { | |
193 MENU_ITEMS_ITEM_NAME = 0, | |
194 MENU_ITEMS_ITEM_ENABLE, | |
195 MENU_ITEMS_ITEM_VALUE, | |
196 MENU_ITEMS_ITEM_EQUIV_KEY, | |
197 MENU_ITEMS_ITEM_DEFINITION, | |
198 MENU_ITEMS_ITEM_TYPE, | |
199 MENU_ITEMS_ITEM_SELECTED, | |
200 MENU_ITEMS_ITEM_HELP, | |
201 MENU_ITEMS_ITEM_LENGTH | |
202 }; | |
203 | |
204 static Lisp_Object menu_items; | |
205 | |
206 /* If non-nil, means that the global vars defined here are already in use. | |
207 Used to detect cases where we try to re-enter this non-reentrant code. */ | |
208 static Lisp_Object menu_items_inuse; | |
209 | |
210 /* Number of slots currently allocated in menu_items. */ | |
211 static int menu_items_allocated; | |
212 | |
213 /* This is the index in menu_items of the first empty slot. */ | |
214 static int menu_items_used; | |
215 | |
216 /* The number of panes currently recorded in menu_items, | |
217 excluding those within submenus. */ | |
218 static int menu_items_n_panes; | |
219 | |
220 /* Current depth within submenus. */ | |
221 static int menu_items_submenu_depth; | |
222 | |
223 /* Flag which when set indicates a dialog or menu has been posted by | 138 /* Flag which when set indicates a dialog or menu has been posted by |
224 Xt on behalf of one of the widget sets. */ | 139 Xt on behalf of one of the widget sets. */ |
225 static int popup_activated_flag; | 140 static int popup_activated_flag; |
226 | 141 |
227 static int next_menubar_widget_id; | 142 static int next_menubar_widget_id; |
143 | |
144 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | |
145 extern widget_value *xmalloc_widget_value P_ ((void)); | |
146 extern widget_value *digest_single_submenu P_ ((int, int, int)); | |
147 #endif | |
228 | 148 |
229 /* This is set nonzero after the user activates the menu bar, and set | 149 /* This is set nonzero after the user activates the menu bar, and set |
230 to zero again after the menu bars are redisplayed by prepare_menu_bar. | 150 to zero again after the menu bars are redisplayed by prepare_menu_bar. |
231 While it is nonzero, all calls to set_frame_menubar go deep. | 151 While it is nonzero, all calls to set_frame_menubar go deep. |
232 | 152 |
259 } | 179 } |
260 return 0; | 180 return 0; |
261 } | 181 } |
262 | 182 |
263 #endif | 183 #endif |
264 | |
265 /* Initialize the menu_items structure if we haven't already done so. | |
266 Also mark it as currently empty. */ | |
267 | |
268 static void | |
269 init_menu_items () | |
270 { | |
271 if (!NILP (menu_items_inuse)) | |
272 error ("Trying to use a menu from within a menu-entry"); | |
273 | |
274 if (NILP (menu_items)) | |
275 { | |
276 menu_items_allocated = 60; | |
277 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); | |
278 } | |
279 | |
280 menu_items_inuse = Qt; | |
281 menu_items_used = 0; | |
282 menu_items_n_panes = 0; | |
283 menu_items_submenu_depth = 0; | |
284 } | |
285 | |
286 /* Call at the end of generating the data in menu_items. */ | |
287 | |
288 static void | |
289 finish_menu_items () | |
290 { | |
291 } | |
292 | |
293 static Lisp_Object | |
294 unuse_menu_items (dummy) | |
295 Lisp_Object dummy; | |
296 { | |
297 return menu_items_inuse = Qnil; | |
298 } | |
299 | |
300 /* Call when finished using the data for the current menu | |
301 in menu_items. */ | |
302 | |
303 static void | |
304 discard_menu_items () | |
305 { | |
306 /* Free the structure if it is especially large. | |
307 Otherwise, hold on to it, to save time. */ | |
308 if (menu_items_allocated > 200) | |
309 { | |
310 menu_items = Qnil; | |
311 menu_items_allocated = 0; | |
312 } | |
313 xassert (NILP (menu_items_inuse)); | |
314 } | |
315 | |
316 /* This undoes save_menu_items, and it is called by the specpdl unwind | |
317 mechanism. */ | |
318 | |
319 static Lisp_Object | |
320 restore_menu_items (saved) | |
321 Lisp_Object saved; | |
322 { | |
323 menu_items = XCAR (saved); | |
324 menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil); | |
325 menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0); | |
326 saved = XCDR (saved); | |
327 menu_items_used = XINT (XCAR (saved)); | |
328 saved = XCDR (saved); | |
329 menu_items_n_panes = XINT (XCAR (saved)); | |
330 saved = XCDR (saved); | |
331 menu_items_submenu_depth = XINT (XCAR (saved)); | |
332 return Qnil; | |
333 } | |
334 | |
335 /* Push the whole state of menu_items processing onto the specpdl. | |
336 It will be restored when the specpdl is unwound. */ | |
337 | |
338 static void | |
339 save_menu_items () | |
340 { | |
341 Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil, | |
342 make_number (menu_items_used), | |
343 make_number (menu_items_n_panes), | |
344 make_number (menu_items_submenu_depth)); | |
345 record_unwind_protect (restore_menu_items, saved); | |
346 menu_items_inuse = Qnil; | |
347 menu_items = Qnil; | |
348 } | |
349 | |
350 /* Make the menu_items vector twice as large. */ | |
351 | |
352 static void | |
353 grow_menu_items () | |
354 { | |
355 menu_items_allocated *= 2; | |
356 menu_items = larger_vector (menu_items, menu_items_allocated, Qnil); | |
357 } | |
358 | |
359 /* Begin a submenu. */ | |
360 | |
361 static void | |
362 push_submenu_start () | |
363 { | |
364 if (menu_items_used + 1 > menu_items_allocated) | |
365 grow_menu_items (); | |
366 | |
367 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil; | |
368 menu_items_submenu_depth++; | |
369 } | |
370 | |
371 /* End a submenu. */ | |
372 | |
373 static void | |
374 push_submenu_end () | |
375 { | |
376 if (menu_items_used + 1 > menu_items_allocated) | |
377 grow_menu_items (); | |
378 | |
379 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda; | |
380 menu_items_submenu_depth--; | |
381 } | |
382 | |
383 /* Indicate boundary between left and right. */ | |
384 | |
385 static void | |
386 push_left_right_boundary () | |
387 { | |
388 if (menu_items_used + 1 > menu_items_allocated) | |
389 grow_menu_items (); | |
390 | |
391 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote; | |
392 } | |
393 | |
394 /* Start a new menu pane in menu_items. | |
395 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */ | |
396 | |
397 static void | |
398 push_menu_pane (name, prefix_vec) | |
399 Lisp_Object name, prefix_vec; | |
400 { | |
401 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated) | |
402 grow_menu_items (); | |
403 | |
404 if (menu_items_submenu_depth == 0) | |
405 menu_items_n_panes++; | |
406 XVECTOR (menu_items)->contents[menu_items_used++] = Qt; | |
407 XVECTOR (menu_items)->contents[menu_items_used++] = name; | |
408 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec; | |
409 } | |
410 | |
411 /* Push one menu item into the current pane. NAME is the string to | |
412 display. ENABLE if non-nil means this item can be selected. KEY | |
413 is the key generated by choosing this item, or nil if this item | |
414 doesn't really have a definition. DEF is the definition of this | |
415 item. EQUIV is the textual description of the keyboard equivalent | |
416 for this item (or nil if none). TYPE is the type of this menu | |
417 item, one of nil, `toggle' or `radio'. */ | |
418 | |
419 static void | |
420 push_menu_item (name, enable, key, def, equiv, type, selected, help) | |
421 Lisp_Object name, enable, key, def, equiv, type, selected, help; | |
422 { | |
423 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated) | |
424 grow_menu_items (); | |
425 | |
426 XVECTOR (menu_items)->contents[menu_items_used++] = name; | |
427 XVECTOR (menu_items)->contents[menu_items_used++] = enable; | |
428 XVECTOR (menu_items)->contents[menu_items_used++] = key; | |
429 XVECTOR (menu_items)->contents[menu_items_used++] = equiv; | |
430 XVECTOR (menu_items)->contents[menu_items_used++] = def; | |
431 XVECTOR (menu_items)->contents[menu_items_used++] = type; | |
432 XVECTOR (menu_items)->contents[menu_items_used++] = selected; | |
433 XVECTOR (menu_items)->contents[menu_items_used++] = help; | |
434 } | |
435 | |
436 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long, | |
437 and generate menu panes for them in menu_items. | |
438 If NOTREAL is nonzero, | |
439 don't bother really computing whether an item is enabled. */ | |
440 | |
441 static void | |
442 keymap_panes (keymaps, nmaps, notreal) | |
443 Lisp_Object *keymaps; | |
444 int nmaps; | |
445 int notreal; | |
446 { | |
447 int mapno; | |
448 | |
449 init_menu_items (); | |
450 | |
451 /* Loop over the given keymaps, making a pane for each map. | |
452 But don't make a pane that is empty--ignore that map instead. | |
453 P is the number of panes we have made so far. */ | |
454 for (mapno = 0; mapno < nmaps; mapno++) | |
455 single_keymap_panes (keymaps[mapno], | |
456 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10); | |
457 | |
458 finish_menu_items (); | |
459 } | |
460 | |
461 /* Args passed between single_keymap_panes and single_menu_item. */ | |
462 struct skp | |
463 { | |
464 Lisp_Object pending_maps; | |
465 int maxdepth, notreal; | |
466 int notbuttons; | |
467 }; | |
468 | |
469 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | |
470 void *)); | |
471 | |
472 /* This is a recursive subroutine of keymap_panes. | |
473 It handles one keymap, KEYMAP. | |
474 The other arguments are passed along | |
475 or point to local variables of the previous function. | |
476 If NOTREAL is nonzero, only check for equivalent key bindings, don't | |
477 evaluate expressions in menu items and don't make any menu. | |
478 | |
479 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */ | |
480 | |
481 static void | |
482 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth) | |
483 Lisp_Object keymap; | |
484 Lisp_Object pane_name; | |
485 Lisp_Object prefix; | |
486 int notreal; | |
487 int maxdepth; | |
488 { | |
489 struct skp skp; | |
490 struct gcpro gcpro1; | |
491 | |
492 skp.pending_maps = Qnil; | |
493 skp.maxdepth = maxdepth; | |
494 skp.notreal = notreal; | |
495 skp.notbuttons = 0; | |
496 | |
497 if (maxdepth <= 0) | |
498 return; | |
499 | |
500 push_menu_pane (pane_name, prefix); | |
501 | |
502 #ifndef HAVE_BOXES | |
503 /* Remember index for first item in this pane so we can go back and | |
504 add a prefix when (if) we see the first button. After that, notbuttons | |
505 is set to 0, to mark that we have seen a button and all non button | |
506 items need a prefix. */ | |
507 skp.notbuttons = menu_items_used; | |
508 #endif | |
509 | |
510 GCPRO1 (skp.pending_maps); | |
511 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp); | |
512 UNGCPRO; | |
513 | |
514 /* Process now any submenus which want to be panes at this level. */ | |
515 while (CONSP (skp.pending_maps)) | |
516 { | |
517 Lisp_Object elt, eltcdr, string; | |
518 elt = XCAR (skp.pending_maps); | |
519 eltcdr = XCDR (elt); | |
520 string = XCAR (eltcdr); | |
521 /* We no longer discard the @ from the beginning of the string here. | |
522 Instead, we do this in xmenu_show. */ | |
523 single_keymap_panes (Fcar (elt), string, | |
524 XCDR (eltcdr), notreal, maxdepth - 1); | |
525 skp.pending_maps = XCDR (skp.pending_maps); | |
526 } | |
527 } | |
528 | |
529 /* This is a subroutine of single_keymap_panes that handles one | |
530 keymap entry. | |
531 KEY is a key in a keymap and ITEM is its binding. | |
532 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into | |
533 separate panes. | |
534 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't | |
535 evaluate expressions in menu items and don't make any menu. | |
536 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. | |
537 SKP->NOTBUTTONS is only used when simulating toggle boxes and radio | |
538 buttons. It keeps track of if we have seen a button in this menu or | |
539 not. */ | |
540 | |
541 static void | |
542 single_menu_item (key, item, dummy, skp_v) | |
543 Lisp_Object key, item, dummy; | |
544 void *skp_v; | |
545 { | |
546 Lisp_Object map, item_string, enabled; | |
547 struct gcpro gcpro1, gcpro2; | |
548 int res; | |
549 struct skp *skp = skp_v; | |
550 | |
551 /* Parse the menu item and leave the result in item_properties. */ | |
552 GCPRO2 (key, item); | |
553 res = parse_menu_item (item, skp->notreal, 0); | |
554 UNGCPRO; | |
555 if (!res) | |
556 return; /* Not a menu item. */ | |
557 | |
558 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; | |
559 | |
560 if (skp->notreal) | |
561 { | |
562 /* We don't want to make a menu, just traverse the keymaps to | |
563 precompute equivalent key bindings. */ | |
564 if (!NILP (map)) | |
565 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1); | |
566 return; | |
567 } | |
568 | |
569 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; | |
570 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; | |
571 | |
572 if (!NILP (map) && SREF (item_string, 0) == '@') | |
573 { | |
574 if (!NILP (enabled)) | |
575 /* An enabled separate pane. Remember this to handle it later. */ | |
576 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)), | |
577 skp->pending_maps); | |
578 return; | |
579 } | |
580 | |
581 #ifndef HAVE_BOXES | |
582 /* Simulate radio buttons and toggle boxes by putting a prefix in | |
583 front of them. */ | |
584 { | |
585 Lisp_Object prefix = Qnil; | |
586 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]; | |
587 if (!NILP (type)) | |
588 { | |
589 Lisp_Object selected | |
590 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; | |
591 | |
592 if (skp->notbuttons) | |
593 /* The first button. Line up previous items in this menu. */ | |
594 { | |
595 int index = skp->notbuttons; /* Index for first item this menu. */ | |
596 int submenu = 0; | |
597 Lisp_Object tem; | |
598 while (index < menu_items_used) | |
599 { | |
600 tem | |
601 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]; | |
602 if (NILP (tem)) | |
603 { | |
604 index++; | |
605 submenu++; /* Skip sub menu. */ | |
606 } | |
607 else if (EQ (tem, Qlambda)) | |
608 { | |
609 index++; | |
610 submenu--; /* End sub menu. */ | |
611 } | |
612 else if (EQ (tem, Qt)) | |
613 index += 3; /* Skip new pane marker. */ | |
614 else if (EQ (tem, Qquote)) | |
615 index++; /* Skip a left, right divider. */ | |
616 else | |
617 { | |
618 if (!submenu && SREF (tem, 0) != '\0' | |
619 && SREF (tem, 0) != '-') | |
620 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] | |
621 = concat2 (build_string (" "), tem); | |
622 index += MENU_ITEMS_ITEM_LENGTH; | |
623 } | |
624 } | |
625 skp->notbuttons = 0; | |
626 } | |
627 | |
628 /* Calculate prefix, if any, for this item. */ | |
629 if (EQ (type, QCtoggle)) | |
630 prefix = build_string (NILP (selected) ? "[ ] " : "[X] "); | |
631 else if (EQ (type, QCradio)) | |
632 prefix = build_string (NILP (selected) ? "( ) " : "(*) "); | |
633 } | |
634 /* Not a button. If we have earlier buttons, then we need a prefix. */ | |
635 else if (!skp->notbuttons && SREF (item_string, 0) != '\0' | |
636 && SREF (item_string, 0) != '-') | |
637 prefix = build_string (" "); | |
638 | |
639 if (!NILP (prefix)) | |
640 item_string = concat2 (prefix, item_string); | |
641 } | |
642 #endif /* not HAVE_BOXES */ | |
643 | |
644 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | |
645 if (!NILP (map)) | |
646 /* Indicate visually that this is a submenu. */ | |
647 item_string = concat2 (item_string, build_string (" >")); | |
648 #endif | |
649 | |
650 push_menu_item (item_string, enabled, key, | |
651 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF], | |
652 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ], | |
653 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE], | |
654 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], | |
655 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); | |
656 | |
657 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | |
658 /* Display a submenu using the toolkit. */ | |
659 if (! (NILP (map) || NILP (enabled))) | |
660 { | |
661 push_submenu_start (); | |
662 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1); | |
663 push_submenu_end (); | |
664 } | |
665 #endif | |
666 } | |
667 | |
668 /* Push all the panes and items of a menu described by the | |
669 alist-of-alists MENU. | |
670 This handles old-fashioned calls to x-popup-menu. */ | |
671 | |
672 static void | |
673 list_of_panes (menu) | |
674 Lisp_Object menu; | |
675 { | |
676 Lisp_Object tail; | |
677 | |
678 init_menu_items (); | |
679 | |
680 for (tail = menu; CONSP (tail); tail = XCDR (tail)) | |
681 { | |
682 Lisp_Object elt, pane_name, pane_data; | |
683 elt = XCAR (tail); | |
684 pane_name = Fcar (elt); | |
685 CHECK_STRING (pane_name); | |
686 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil); | |
687 pane_data = Fcdr (elt); | |
688 CHECK_CONS (pane_data); | |
689 list_of_items (pane_data); | |
690 } | |
691 | |
692 finish_menu_items (); | |
693 } | |
694 | |
695 /* Push the items in a single pane defined by the alist PANE. */ | |
696 | |
697 static void | |
698 list_of_items (pane) | |
699 Lisp_Object pane; | |
700 { | |
701 Lisp_Object tail, item, item1; | |
702 | |
703 for (tail = pane; CONSP (tail); tail = XCDR (tail)) | |
704 { | |
705 item = XCAR (tail); | |
706 if (STRINGP (item)) | |
707 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt, | |
708 Qnil, Qnil, Qnil, Qnil); | |
709 else if (CONSP (item)) | |
710 { | |
711 item1 = XCAR (item); | |
712 CHECK_STRING (item1); | |
713 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item), | |
714 Qt, Qnil, Qnil, Qnil, Qnil); | |
715 } | |
716 else | |
717 push_left_right_boundary (); | |
718 | |
719 } | |
720 } | |
721 | 184 |
722 #ifdef HAVE_X_WINDOWS | 185 #ifdef HAVE_X_WINDOWS |
723 /* Return the mouse position in *X and *Y. The coordinates are window | 186 /* Return the mouse position in *X and *Y. The coordinates are window |
724 relative for the edit window in frame F. | 187 relative for the edit window in frame F. |
725 This is for Fx_popup_menu. The mouse_position_hook can not | 188 This is for Fx_popup_menu. The mouse_position_hook can not |
1618 | 1081 |
1619 show_help_event (f, widget, help); | 1082 show_help_event (f, widget, help); |
1620 } | 1083 } |
1621 #endif | 1084 #endif |
1622 | 1085 |
1623 /* Find the menu selection and store it in the keyboard buffer. | |
1624 F is the frame the menu is on. | |
1625 MENU_BAR_ITEMS_USED is the length of VECTOR. | |
1626 VECTOR is an array of menu events for the whole menu. */ | |
1627 | |
1628 static void | |
1629 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) | |
1630 FRAME_PTR f; | |
1631 EMACS_INT menu_bar_items_used; | |
1632 Lisp_Object vector; | |
1633 void *client_data; | |
1634 { | |
1635 Lisp_Object prefix, entry; | |
1636 Lisp_Object *subprefix_stack; | |
1637 int submenu_depth = 0; | |
1638 int i; | |
1639 | |
1640 entry = Qnil; | |
1641 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object)); | |
1642 prefix = Qnil; | |
1643 i = 0; | |
1644 | |
1645 while (i < menu_bar_items_used) | |
1646 { | |
1647 if (EQ (XVECTOR (vector)->contents[i], Qnil)) | |
1648 { | |
1649 subprefix_stack[submenu_depth++] = prefix; | |
1650 prefix = entry; | |
1651 i++; | |
1652 } | |
1653 else if (EQ (XVECTOR (vector)->contents[i], Qlambda)) | |
1654 { | |
1655 prefix = subprefix_stack[--submenu_depth]; | |
1656 i++; | |
1657 } | |
1658 else if (EQ (XVECTOR (vector)->contents[i], Qt)) | |
1659 { | |
1660 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX]; | |
1661 i += MENU_ITEMS_PANE_LENGTH; | |
1662 } | |
1663 else | |
1664 { | |
1665 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE]; | |
1666 /* The EMACS_INT cast avoids a warning. There's no problem | |
1667 as long as pointers have enough bits to hold small integers. */ | |
1668 if ((int) (EMACS_INT) client_data == i) | |
1669 { | |
1670 int j; | |
1671 struct input_event buf; | |
1672 Lisp_Object frame; | |
1673 EVENT_INIT (buf); | |
1674 | |
1675 XSETFRAME (frame, f); | |
1676 buf.kind = MENU_BAR_EVENT; | |
1677 buf.frame_or_window = frame; | |
1678 buf.arg = frame; | |
1679 kbd_buffer_store_event (&buf); | |
1680 | |
1681 for (j = 0; j < submenu_depth; j++) | |
1682 if (!NILP (subprefix_stack[j])) | |
1683 { | |
1684 buf.kind = MENU_BAR_EVENT; | |
1685 buf.frame_or_window = frame; | |
1686 buf.arg = subprefix_stack[j]; | |
1687 kbd_buffer_store_event (&buf); | |
1688 } | |
1689 | |
1690 if (!NILP (prefix)) | |
1691 { | |
1692 buf.kind = MENU_BAR_EVENT; | |
1693 buf.frame_or_window = frame; | |
1694 buf.arg = prefix; | |
1695 kbd_buffer_store_event (&buf); | |
1696 } | |
1697 | |
1698 buf.kind = MENU_BAR_EVENT; | |
1699 buf.frame_or_window = frame; | |
1700 buf.arg = entry; | |
1701 kbd_buffer_store_event (&buf); | |
1702 | |
1703 return; | |
1704 } | |
1705 i += MENU_ITEMS_ITEM_LENGTH; | |
1706 } | |
1707 } | |
1708 } | |
1709 | |
1710 | |
1711 #ifdef USE_GTK | 1086 #ifdef USE_GTK |
1712 /* Gtk calls callbacks just because we tell it what item should be | 1087 /* Gtk calls callbacks just because we tell it what item should be |
1713 selected in a radio group. If this variable is set to a non-zero | 1088 selected in a radio group. If this variable is set to a non-zero |
1714 value, we are creating menus and don't want callbacks right now. | 1089 value, we are creating menus and don't want callbacks right now. |
1715 */ | 1090 */ |
1777 return; | 1152 return; |
1778 find_and_call_menu_selection (f, f->menu_bar_items_used, | 1153 find_and_call_menu_selection (f, f->menu_bar_items_used, |
1779 f->menu_bar_vector, client_data); | 1154 f->menu_bar_vector, client_data); |
1780 } | 1155 } |
1781 #endif /* not USE_GTK */ | 1156 #endif /* not USE_GTK */ |
1782 | |
1783 /* Allocate a widget_value, blocking input. */ | |
1784 | |
1785 widget_value * | |
1786 xmalloc_widget_value () | |
1787 { | |
1788 widget_value *value; | |
1789 | |
1790 BLOCK_INPUT; | |
1791 value = malloc_widget_value (); | |
1792 UNBLOCK_INPUT; | |
1793 | |
1794 return value; | |
1795 } | |
1796 | |
1797 /* This recursively calls free_widget_value on the tree of widgets. | |
1798 It must free all data that was malloc'ed for these widget_values. | |
1799 In Emacs, many slots are pointers into the data of Lisp_Strings, and | |
1800 must be left alone. */ | |
1801 | |
1802 void | |
1803 free_menubar_widget_value_tree (wv) | |
1804 widget_value *wv; | |
1805 { | |
1806 if (! wv) return; | |
1807 | |
1808 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; | |
1809 | |
1810 if (wv->contents && (wv->contents != (widget_value*)1)) | |
1811 { | |
1812 free_menubar_widget_value_tree (wv->contents); | |
1813 wv->contents = (widget_value *) 0xDEADBEEF; | |
1814 } | |
1815 if (wv->next) | |
1816 { | |
1817 free_menubar_widget_value_tree (wv->next); | |
1818 wv->next = (widget_value *) 0xDEADBEEF; | |
1819 } | |
1820 BLOCK_INPUT; | |
1821 free_widget_value (wv); | |
1822 UNBLOCK_INPUT; | |
1823 } | |
1824 | |
1825 /* Set up data in menu_items for a menu bar item | |
1826 whose event type is ITEM_KEY (with string ITEM_NAME) | |
1827 and whose contents come from the list of keymaps MAPS. */ | |
1828 | |
1829 static int | |
1830 parse_single_submenu (item_key, item_name, maps) | |
1831 Lisp_Object item_key, item_name, maps; | |
1832 { | |
1833 Lisp_Object length; | |
1834 int len; | |
1835 Lisp_Object *mapvec; | |
1836 int i; | |
1837 int top_level_items = 0; | |
1838 | |
1839 length = Flength (maps); | |
1840 len = XINT (length); | |
1841 | |
1842 /* Convert the list MAPS into a vector MAPVEC. */ | |
1843 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); | |
1844 for (i = 0; i < len; i++) | |
1845 { | |
1846 mapvec[i] = Fcar (maps); | |
1847 maps = Fcdr (maps); | |
1848 } | |
1849 | |
1850 /* Loop over the given keymaps, making a pane for each map. | |
1851 But don't make a pane that is empty--ignore that map instead. */ | |
1852 for (i = 0; i < len; i++) | |
1853 { | |
1854 if (!KEYMAPP (mapvec[i])) | |
1855 { | |
1856 /* Here we have a command at top level in the menu bar | |
1857 as opposed to a submenu. */ | |
1858 top_level_items = 1; | |
1859 push_menu_pane (Qnil, Qnil); | |
1860 push_menu_item (item_name, Qt, item_key, mapvec[i], | |
1861 Qnil, Qnil, Qnil, Qnil); | |
1862 } | |
1863 else | |
1864 { | |
1865 Lisp_Object prompt; | |
1866 prompt = Fkeymap_prompt (mapvec[i]); | |
1867 single_keymap_panes (mapvec[i], | |
1868 !NILP (prompt) ? prompt : item_name, | |
1869 item_key, 0, 10); | |
1870 } | |
1871 } | |
1872 | |
1873 return top_level_items; | |
1874 } | |
1875 | |
1876 /* Create a tree of widget_value objects | |
1877 representing the panes and items | |
1878 in menu_items starting at index START, up to index END. */ | |
1879 | |
1880 static widget_value * | |
1881 digest_single_submenu (start, end, top_level_items) | |
1882 int start, end, top_level_items; | |
1883 { | |
1884 widget_value *wv, *prev_wv, *save_wv, *first_wv; | |
1885 int i; | |
1886 int submenu_depth = 0; | |
1887 widget_value **submenu_stack; | |
1888 int panes_seen = 0; | |
1889 | |
1890 submenu_stack | |
1891 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); | |
1892 wv = xmalloc_widget_value (); | |
1893 wv->name = "menu"; | |
1894 wv->value = 0; | |
1895 wv->enabled = 1; | |
1896 wv->button_type = BUTTON_TYPE_NONE; | |
1897 wv->help = Qnil; | |
1898 first_wv = wv; | |
1899 save_wv = 0; | |
1900 prev_wv = 0; | |
1901 | |
1902 /* Loop over all panes and items made by the preceding call | |
1903 to parse_single_submenu and construct a tree of widget_value objects. | |
1904 Ignore the panes and items used by previous calls to | |
1905 digest_single_submenu, even though those are also in menu_items. */ | |
1906 i = start; | |
1907 while (i < end) | |
1908 { | |
1909 if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) | |
1910 { | |
1911 submenu_stack[submenu_depth++] = save_wv; | |
1912 save_wv = prev_wv; | |
1913 prev_wv = 0; | |
1914 i++; | |
1915 } | |
1916 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) | |
1917 { | |
1918 prev_wv = save_wv; | |
1919 save_wv = submenu_stack[--submenu_depth]; | |
1920 i++; | |
1921 } | |
1922 else if (EQ (XVECTOR (menu_items)->contents[i], Qt) | |
1923 && submenu_depth != 0) | |
1924 i += MENU_ITEMS_PANE_LENGTH; | |
1925 /* Ignore a nil in the item list. | |
1926 It's meaningful only for dialog boxes. */ | |
1927 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) | |
1928 i += 1; | |
1929 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) | |
1930 { | |
1931 /* Create a new pane. */ | |
1932 Lisp_Object pane_name, prefix; | |
1933 char *pane_string; | |
1934 | |
1935 panes_seen++; | |
1936 | |
1937 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; | |
1938 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; | |
1939 | |
1940 #ifndef HAVE_MULTILINGUAL_MENU | |
1941 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) | |
1942 { | |
1943 pane_name = ENCODE_MENU_STRING (pane_name); | |
1944 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name); | |
1945 } | |
1946 #endif | |
1947 pane_string = (NILP (pane_name) | |
1948 ? "" : (char *) SDATA (pane_name)); | |
1949 /* If there is just one top-level pane, put all its items directly | |
1950 under the top-level menu. */ | |
1951 if (menu_items_n_panes == 1) | |
1952 pane_string = ""; | |
1953 | |
1954 /* If the pane has a meaningful name, | |
1955 make the pane a top-level menu item | |
1956 with its items as a submenu beneath it. */ | |
1957 if (strcmp (pane_string, "")) | |
1958 { | |
1959 wv = xmalloc_widget_value (); | |
1960 if (save_wv) | |
1961 save_wv->next = wv; | |
1962 else | |
1963 first_wv->contents = wv; | |
1964 wv->lname = pane_name; | |
1965 /* Set value to 1 so update_submenu_strings can handle '@' */ | |
1966 wv->value = (char *)1; | |
1967 wv->enabled = 1; | |
1968 wv->button_type = BUTTON_TYPE_NONE; | |
1969 wv->help = Qnil; | |
1970 save_wv = wv; | |
1971 } | |
1972 else | |
1973 save_wv = first_wv; | |
1974 | |
1975 prev_wv = 0; | |
1976 i += MENU_ITEMS_PANE_LENGTH; | |
1977 } | |
1978 else | |
1979 { | |
1980 /* Create a new item within current pane. */ | |
1981 Lisp_Object item_name, enable, descrip, def, type, selected; | |
1982 Lisp_Object help; | |
1983 | |
1984 /* All items should be contained in panes. */ | |
1985 if (panes_seen == 0) | |
1986 abort (); | |
1987 | |
1988 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); | |
1989 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); | |
1990 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); | |
1991 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); | |
1992 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE); | |
1993 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); | |
1994 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); | |
1995 | |
1996 #ifndef HAVE_MULTILINGUAL_MENU | |
1997 if (STRING_MULTIBYTE (item_name)) | |
1998 { | |
1999 item_name = ENCODE_MENU_STRING (item_name); | |
2000 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name); | |
2001 } | |
2002 | |
2003 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) | |
2004 { | |
2005 descrip = ENCODE_MENU_STRING (descrip); | |
2006 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); | |
2007 } | |
2008 #endif /* not HAVE_MULTILINGUAL_MENU */ | |
2009 | |
2010 wv = xmalloc_widget_value (); | |
2011 if (prev_wv) | |
2012 prev_wv->next = wv; | |
2013 else | |
2014 save_wv->contents = wv; | |
2015 | |
2016 wv->lname = item_name; | |
2017 if (!NILP (descrip)) | |
2018 wv->lkey = descrip; | |
2019 wv->value = 0; | |
2020 /* The EMACS_INT cast avoids a warning. There's no problem | |
2021 as long as pointers have enough bits to hold small integers. */ | |
2022 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); | |
2023 wv->enabled = !NILP (enable); | |
2024 | |
2025 if (NILP (type)) | |
2026 wv->button_type = BUTTON_TYPE_NONE; | |
2027 else if (EQ (type, QCradio)) | |
2028 wv->button_type = BUTTON_TYPE_RADIO; | |
2029 else if (EQ (type, QCtoggle)) | |
2030 wv->button_type = BUTTON_TYPE_TOGGLE; | |
2031 else | |
2032 abort (); | |
2033 | |
2034 wv->selected = !NILP (selected); | |
2035 if (! STRINGP (help)) | |
2036 help = Qnil; | |
2037 | |
2038 wv->help = help; | |
2039 | |
2040 prev_wv = wv; | |
2041 | |
2042 i += MENU_ITEMS_ITEM_LENGTH; | |
2043 } | |
2044 } | |
2045 | |
2046 /* If we have just one "menu item" | |
2047 that was originally a button, return it by itself. */ | |
2048 if (top_level_items && first_wv->contents && first_wv->contents->next == 0) | |
2049 { | |
2050 wv = first_wv->contents; | |
2051 free_widget_value (first_wv); | |
2052 return wv; | |
2053 } | |
2054 | |
2055 return first_wv; | |
2056 } | |
2057 | |
2058 /* Walk through the widget_value tree starting at FIRST_WV and update | |
2059 the char * pointers from the corresponding lisp values. | |
2060 We do this after building the whole tree, since GC may happen while the | |
2061 tree is constructed, and small strings are relocated. So we must wait | |
2062 until no GC can happen before storing pointers into lisp values. */ | |
2063 static void | |
2064 update_submenu_strings (first_wv) | |
2065 widget_value *first_wv; | |
2066 { | |
2067 widget_value *wv; | |
2068 | |
2069 for (wv = first_wv; wv; wv = wv->next) | |
2070 { | |
2071 if (STRINGP (wv->lname)) | |
2072 { | |
2073 wv->name = (char *) SDATA (wv->lname); | |
2074 | |
2075 /* Ignore the @ that means "separate pane". | |
2076 This is a kludge, but this isn't worth more time. */ | |
2077 if (wv->value == (char *)1) | |
2078 { | |
2079 if (wv->name[0] == '@') | |
2080 wv->name++; | |
2081 wv->value = 0; | |
2082 } | |
2083 } | |
2084 | |
2085 if (STRINGP (wv->lkey)) | |
2086 wv->key = (char *) SDATA (wv->lkey); | |
2087 | |
2088 if (wv->contents) | |
2089 update_submenu_strings (wv->contents); | |
2090 } | |
2091 } | |
2092 | |
2093 | 1157 |
2094 /* Recompute all the widgets of frame F, when the menu bar has been | 1158 /* Recompute all the widgets of frame F, when the menu bar has been |
2095 changed. Value is non-zero if widgets were updated. */ | 1159 changed. Value is non-zero if widgets were updated. */ |
2096 | 1160 |
2097 static int | 1161 static int |
2328 | 1392 |
2329 /* The menu items are different, so store them in the frame. */ | 1393 /* The menu items are different, so store them in the frame. */ |
2330 f->menu_bar_vector = menu_items; | 1394 f->menu_bar_vector = menu_items; |
2331 f->menu_bar_items_used = menu_items_used; | 1395 f->menu_bar_items_used = menu_items_used; |
2332 | 1396 |
2333 /* This calls restore_menu_items to restore menu_items, etc., | 1397 /* This undoes save_menu_items. */ |
2334 as they were outside. */ | |
2335 unbind_to (specpdl_count, Qnil); | 1398 unbind_to (specpdl_count, Qnil); |
2336 | 1399 |
2337 /* Now GC cannot happen during the lifetime of the widget_value, | 1400 /* Now GC cannot happen during the lifetime of the widget_value, |
2338 so it's safe to store data from a Lisp_String. */ | 1401 so it's safe to store data from a Lisp_String. */ |
2339 wv = first_wv->contents; | 1402 wv = first_wv->contents; |
3816 } | 2879 } |
3817 | 2880 |
3818 void | 2881 void |
3819 syms_of_xmenu () | 2882 syms_of_xmenu () |
3820 { | 2883 { |
3821 staticpro (&menu_items); | |
3822 menu_items = Qnil; | |
3823 menu_items_inuse = Qnil; | |
3824 | |
3825 Qdebug_on_next_call = intern ("debug-on-next-call"); | 2884 Qdebug_on_next_call = intern ("debug-on-next-call"); |
3826 staticpro (&Qdebug_on_next_call); | 2885 staticpro (&Qdebug_on_next_call); |
3827 | 2886 |
3828 #ifdef USE_X_TOOLKIT | 2887 #ifdef USE_X_TOOLKIT |
3829 widget_id_tick = (1<<16); | 2888 widget_id_tick = (1<<16); |