1 /* Menu support for GNU Emacs on the for Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 /* Contributed by Andrew Choi (akochoi@mac.com). */
28 #include "termhooks.h"
33 #include "blockinput.h"
38 #if !TARGET_API_MAC_CARBON
41 #include <QuickDraw.h>
42 #include <ToolUtils.h>
47 #if defined (__MRC__) || (__MSL__ >= 0x6000)
48 #include <ControlDefinitions.h>
50 #endif /* not TARGET_API_MAC_CARBON */
52 /* This may include sys/types.h, and that somehow loses
53 if this is not done before the other system files. */
56 /* Load sys/types.h if not already loaded.
57 In some systems loading it twice is suicidal. */
59 #include <sys/types.h>
62 #include "dispextern.h"
64 #define POPUP_SUBMENU_ID 235
65 #define MIN_POPUP_SUBMENU_ID 512
66 #define MIN_MENU_ID 256
67 #define MIN_SUBMENU_ID 1
69 #define DIALOG_WINDOW_RESOURCE 130
71 #define HAVE_DIALOGS 1
73 #undef HAVE_MULTILINGUAL_MENU
74 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
76 /******************************************************************/
77 /* Definitions copied from lwlib.h */
79 typedef void * XtPointer
;
88 /* This structure is based on the one in ../lwlib/lwlib.h, modified
90 typedef struct _widget_value
95 /* value (meaning depend on widget type) */
97 /* keyboard equivalent. no implications for XtTranslations */
100 /* Help string or nil if none.
101 GC finds this string through the frame's menu_bar_vector
102 or through menu_items. */
104 /* true if enabled */
106 /* true if selected */
108 /* The type of a button. */
109 enum button_type button_type
;
110 /* true if menu title */
113 /* true if was edited (maintained by get_value) */
115 /* true if has changed (maintained by lw library) */
117 /* true if this widget itself has changed,
118 but not counting the other widgets found in the `next' field. */
119 change_type this_one_change
;
121 /* Contents of the sub-widgets, also selected slot for checkbox */
122 struct _widget_value
* contents
;
123 /* data passed to callback */
125 /* next one in the list */
126 struct _widget_value
* next
;
128 /* slot for the toolkit dependent part. Always initialize to NULL. */
130 /* tell us if we should free the toolkit data slot when freeing the
131 widget_value itself. */
132 Boolean free_toolkit_data
;
134 /* we resource the widget_value structures; this points to the next
135 one on the free list if this one has been deallocated.
137 struct _widget_value
*free_list
;
141 /* Assumed by other routines to zero area returned. */
142 #define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
143 0, (sizeof (widget_value)))
144 #define free_widget_value(wv) xfree (wv)
146 /******************************************************************/
153 Lisp_Object Vmenu_updating_frame
;
155 Lisp_Object Qdebug_on_next_call
;
157 extern Lisp_Object Qmenu_bar
;
159 extern Lisp_Object QCtoggle
, QCradio
;
161 extern Lisp_Object Voverriding_local_map
;
162 extern Lisp_Object Voverriding_local_map_menu_flag
;
164 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
166 extern Lisp_Object Qmenu_bar_update_hook
;
168 #if TARGET_API_MAC_CARBON
169 #define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
171 #define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
174 void set_frame_menubar ();
176 static void push_menu_item
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
177 Lisp_Object
, Lisp_Object
, Lisp_Object
,
178 Lisp_Object
, Lisp_Object
));
180 static Lisp_Object
mac_dialog_show ();
182 static Lisp_Object
mac_menu_show ();
184 static void keymap_panes ();
185 static void single_keymap_panes ();
186 static void single_menu_item ();
187 static void list_of_panes ();
188 static void list_of_items ();
190 static void fill_submenu (MenuHandle
, widget_value
*);
191 static void fill_menubar (widget_value
*);
194 /* This holds a Lisp vector that holds the results of decoding
195 the keymaps or alist-of-alists that specify a menu.
197 It describes the panes and items within the panes.
199 Each pane is described by 3 elements in the vector:
200 t, the pane name, the pane's prefix key.
201 Then follow the pane's items, with 5 elements per item:
202 the item string, the enable flag, the item's value,
203 the definition, and the equivalent keyboard key's description string.
205 In some cases, multiple levels of menus may be described.
206 A single vector slot containing nil indicates the start of a submenu.
207 A single vector slot containing lambda indicates the end of a submenu.
208 The submenu follows a menu item which is the way to reach the submenu.
210 A single vector slot containing quote indicates that the
211 following items should appear on the right of a dialog box.
213 Using a Lisp vector to hold this information while we decode it
214 takes care of protecting all the data from GC. */
216 #define MENU_ITEMS_PANE_NAME 1
217 #define MENU_ITEMS_PANE_PREFIX 2
218 #define MENU_ITEMS_PANE_LENGTH 3
222 MENU_ITEMS_ITEM_NAME
= 0,
223 MENU_ITEMS_ITEM_ENABLE
,
224 MENU_ITEMS_ITEM_VALUE
,
225 MENU_ITEMS_ITEM_EQUIV_KEY
,
226 MENU_ITEMS_ITEM_DEFINITION
,
227 MENU_ITEMS_ITEM_TYPE
,
228 MENU_ITEMS_ITEM_SELECTED
,
229 MENU_ITEMS_ITEM_HELP
,
230 MENU_ITEMS_ITEM_LENGTH
233 static Lisp_Object menu_items
;
235 /* Number of slots currently allocated in menu_items. */
236 static int menu_items_allocated
;
238 /* This is the index in menu_items of the first empty slot. */
239 static int menu_items_used
;
241 /* The number of panes currently recorded in menu_items,
242 excluding those within submenus. */
243 static int menu_items_n_panes
;
245 /* Current depth within submenus. */
246 static int menu_items_submenu_depth
;
248 /* Flag which when set indicates a dialog or menu has been posted by
249 Xt on behalf of one of the widget sets. */
250 static int popup_activated_flag
;
252 /* Index of the next submenu */
253 static int submenu_id
;
255 static int next_menubar_widget_id
;
257 /* This is set nonzero after the user activates the menu bar, and set
258 to zero again after the menu bars are redisplayed by prepare_menu_bar.
259 While it is nonzero, all calls to set_frame_menubar go deep.
261 I don't understand why this is needed, but it does seem to be
262 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
264 int pending_menu_activation
;
266 /* Initialize the menu_items structure if we haven't already done so.
267 Also mark it as currently empty. */
272 if (NILP (menu_items
))
274 menu_items_allocated
= 60;
275 menu_items
= Fmake_vector (make_number (menu_items_allocated
), Qnil
);
279 menu_items_n_panes
= 0;
280 menu_items_submenu_depth
= 0;
283 /* Call at the end of generating the data in menu_items.
284 This fills in the number of items in the last pane. */
291 /* Call when finished using the data for the current menu
295 discard_menu_items ()
297 /* Free the structure if it is especially large.
298 Otherwise, hold on to it, to save time. */
299 if (menu_items_allocated
> 200)
302 menu_items_allocated
= 0;
306 /* Make the menu_items vector twice as large. */
312 int old_size
= menu_items_allocated
;
315 menu_items_allocated
*= 2;
316 menu_items
= Fmake_vector (make_number (menu_items_allocated
), Qnil
);
317 bcopy (XVECTOR (old
)->contents
, XVECTOR (menu_items
)->contents
,
318 old_size
* sizeof (Lisp_Object
));
321 /* Begin a submenu. */
324 push_submenu_start ()
326 if (menu_items_used
+ 1 > menu_items_allocated
)
329 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qnil
;
330 menu_items_submenu_depth
++;
338 if (menu_items_used
+ 1 > menu_items_allocated
)
341 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qlambda
;
342 menu_items_submenu_depth
--;
345 /* Indicate boundary between left and right. */
348 push_left_right_boundary ()
350 if (menu_items_used
+ 1 > menu_items_allocated
)
353 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qquote
;
356 /* Start a new menu pane in menu_items.
357 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
360 push_menu_pane (name
, prefix_vec
)
361 Lisp_Object name
, prefix_vec
;
363 if (menu_items_used
+ MENU_ITEMS_PANE_LENGTH
> menu_items_allocated
)
366 if (menu_items_submenu_depth
== 0)
367 menu_items_n_panes
++;
368 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qt
;
369 XVECTOR (menu_items
)->contents
[menu_items_used
++] = name
;
370 XVECTOR (menu_items
)->contents
[menu_items_used
++] = prefix_vec
;
373 /* Push one menu item into the current pane. NAME is the string to
374 display. ENABLE if non-nil means this item can be selected. KEY
375 is the key generated by choosing this item, or nil if this item
376 doesn't really have a definition. DEF is the definition of this
377 item. EQUIV is the textual description of the keyboard equivalent
378 for this item (or nil if none). TYPE is the type of this menu
379 item, one of nil, `toggle' or `radio'. */
382 push_menu_item (name
, enable
, key
, def
, equiv
, type
, selected
, help
)
383 Lisp_Object name
, enable
, key
, def
, equiv
, type
, selected
, help
;
385 if (menu_items_used
+ MENU_ITEMS_ITEM_LENGTH
> menu_items_allocated
)
388 XVECTOR (menu_items
)->contents
[menu_items_used
++] = name
;
389 XVECTOR (menu_items
)->contents
[menu_items_used
++] = enable
;
390 XVECTOR (menu_items
)->contents
[menu_items_used
++] = key
;
391 XVECTOR (menu_items
)->contents
[menu_items_used
++] = equiv
;
392 XVECTOR (menu_items
)->contents
[menu_items_used
++] = def
;
393 XVECTOR (menu_items
)->contents
[menu_items_used
++] = type
;
394 XVECTOR (menu_items
)->contents
[menu_items_used
++] = selected
;
395 XVECTOR (menu_items
)->contents
[menu_items_used
++] = help
;
398 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
399 and generate menu panes for them in menu_items.
400 If NOTREAL is nonzero,
401 don't bother really computing whether an item is enabled. */
404 keymap_panes (keymaps
, nmaps
, notreal
)
405 Lisp_Object
*keymaps
;
413 /* Loop over the given keymaps, making a pane for each map.
414 But don't make a pane that is empty--ignore that map instead.
415 P is the number of panes we have made so far. */
416 for (mapno
= 0; mapno
< nmaps
; mapno
++)
417 single_keymap_panes (keymaps
[mapno
],
418 Fkeymap_prompt (keymaps
[mapno
]), Qnil
, notreal
, 10);
420 finish_menu_items ();
423 /* This is a recursive subroutine of keymap_panes.
424 It handles one keymap, KEYMAP.
425 The other arguments are passed along
426 or point to local variables of the previous function.
427 If NOTREAL is nonzero, only check for equivalent key bindings, don't
428 evaluate expressions in menu items and don't make any menu.
430 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
433 single_keymap_panes (keymap
, pane_name
, prefix
, notreal
, maxdepth
)
435 Lisp_Object pane_name
;
440 Lisp_Object pending_maps
= Qnil
;
441 Lisp_Object tail
, item
;
442 struct gcpro gcpro1
, gcpro2
;
447 push_menu_pane (pane_name
, prefix
);
449 for (tail
= keymap
; CONSP (tail
); tail
= XCDR (tail
))
451 GCPRO2 (keymap
, pending_maps
);
452 /* Look at each key binding, and if it is a menu item add it
456 single_menu_item (XCAR (item
), XCDR (item
),
457 &pending_maps
, notreal
, maxdepth
);
458 else if (VECTORP (item
))
460 /* Loop over the char values represented in the vector. */
461 int len
= XVECTOR (item
)->size
;
463 for (c
= 0; c
< len
; c
++)
465 Lisp_Object character
;
466 XSETFASTINT (character
, c
);
467 single_menu_item (character
, XVECTOR (item
)->contents
[c
],
468 &pending_maps
, notreal
, maxdepth
);
474 /* Process now any submenus which want to be panes at this level. */
475 while (!NILP (pending_maps
))
477 Lisp_Object elt
, eltcdr
, string
;
478 elt
= Fcar (pending_maps
);
480 string
= XCAR (eltcdr
);
481 /* We no longer discard the @ from the beginning of the string here.
482 Instead, we do this in mac_menu_show. */
483 single_keymap_panes (Fcar (elt
), string
,
484 XCDR (eltcdr
), notreal
, maxdepth
- 1);
485 pending_maps
= Fcdr (pending_maps
);
489 /* This is a subroutine of single_keymap_panes that handles one
491 KEY is a key in a keymap and ITEM is its binding.
492 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
494 If NOTREAL is nonzero, only check for equivalent key bindings, don't
495 evaluate expressions in menu items and don't make any menu.
496 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
499 single_menu_item (key
, item
, pending_maps_ptr
, notreal
, maxdepth
)
500 Lisp_Object key
, item
;
501 Lisp_Object
*pending_maps_ptr
;
502 int maxdepth
, notreal
;
504 Lisp_Object map
, item_string
, enabled
;
505 struct gcpro gcpro1
, gcpro2
;
508 /* Parse the menu item and leave the result in item_properties. */
510 res
= parse_menu_item (item
, notreal
, 0);
513 return; /* Not a menu item. */
515 map
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_MAP
];
519 /* We don't want to make a menu, just traverse the keymaps to
520 precompute equivalent key bindings. */
522 single_keymap_panes (map
, Qnil
, key
, 1, maxdepth
- 1);
526 enabled
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_ENABLE
];
527 item_string
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_NAME
];
529 if (!NILP (map
) && SREF (item_string
, 0) == '@')
532 /* An enabled separate pane. Remember this to handle it later. */
533 *pending_maps_ptr
= Fcons (Fcons (map
, Fcons (item_string
, key
)),
538 push_menu_item (item_string
, enabled
, key
,
539 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_DEF
],
540 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_KEYEQ
],
541 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_TYPE
],
542 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_SELECTED
],
543 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_HELP
]);
545 /* Display a submenu using the toolkit. */
546 if (! (NILP (map
) || NILP (enabled
)))
548 push_submenu_start ();
549 single_keymap_panes (map
, Qnil
, key
, 0, maxdepth
- 1);
554 /* Push all the panes and items of a menu described by the
555 alist-of-alists MENU.
556 This handles old-fashioned calls to x-popup-menu. */
566 for (tail
= menu
; !NILP (tail
); tail
= Fcdr (tail
))
568 Lisp_Object elt
, pane_name
, pane_data
;
570 pane_name
= Fcar (elt
);
571 CHECK_STRING (pane_name
);
572 push_menu_pane (pane_name
, Qnil
);
573 pane_data
= Fcdr (elt
);
574 CHECK_CONS (pane_data
);
575 list_of_items (pane_data
);
578 finish_menu_items ();
581 /* Push the items in a single pane defined by the alist PANE. */
587 Lisp_Object tail
, item
, item1
;
589 for (tail
= pane
; !NILP (tail
); tail
= Fcdr (tail
))
593 push_menu_item (item
, Qnil
, Qnil
, Qt
, Qnil
, Qnil
, Qnil
, Qnil
);
594 else if (NILP (item
))
595 push_left_right_boundary ();
600 CHECK_STRING (item1
);
601 push_menu_item (item1
, Qt
, Fcdr (item
), Qt
, Qnil
, Qnil
, Qnil
, Qnil
);
607 cleanup_popup_menu (arg
)
610 discard_menu_items ();
613 DEFUN ("x-popup-menu", Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
614 doc
: /* Pop up a deck-of-cards menu and return user's selection.
615 POSITION is a position specification. This is either a mouse button event
616 or a list ((XOFFSET YOFFSET) WINDOW)
617 where XOFFSET and YOFFSET are positions in pixels from the top left
618 corner of WINDOW. (WINDOW may be a window or a frame object.)
619 This controls the position of the top left of the menu as a whole.
620 If POSITION is t, it means to use the current mouse position.
622 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
623 The menu items come from key bindings that have a menu string as well as
624 a definition; actually, the "definition" in such a key binding looks like
625 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
626 the keymap as a top-level element.
628 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
629 Otherwise, REAL-DEFINITION should be a valid key binding definition.
631 You can also use a list of keymaps as MENU.
632 Then each keymap makes a separate pane.
634 When MENU is a keymap or a list of keymaps, the return value is the
635 list of events corresponding to the user's choice. Note that
636 `x-popup-menu' does not actually execute the command bound to that
639 Alternatively, you can specify a menu of multiple panes
640 with a list of the form (TITLE PANE1 PANE2...),
641 where each pane is a list of form (TITLE ITEM1 ITEM2...).
642 Each ITEM is normally a cons cell (STRING . VALUE);
643 but a string can appear as an item--that makes a nonselectable line
645 With this form of menu, the return value is VALUE from the chosen item.
647 If POSITION is nil, don't display the menu at all, just precalculate the
648 cached information about equivalent key sequences.
650 If the user gets rid of the menu without making a valid choice, for
651 instance by clicking the mouse away from a valid choice or by typing
652 keyboard input, then this normally results in a quit and
653 `x-popup-menu' does not return. But if POSITION is a mouse button
654 event (indicating that the user invoked the menu with the mouse) then
655 no quit occurs and `x-popup-menu' returns nil. */)
657 Lisp_Object position
, menu
;
659 Lisp_Object keymap
, tem
;
660 int xpos
= 0, ypos
= 0;
663 Lisp_Object selection
;
665 Lisp_Object x
, y
, window
;
669 int specpdl_count
= SPECPDL_INDEX ();
673 if (! NILP (position
))
677 /* Decode the first argument: find the window and the coordinates. */
678 if (EQ (position
, Qt
)
679 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
680 || EQ (XCAR (position
), Qtool_bar
))))
682 /* Use the mouse's current position. */
683 FRAME_PTR new_f
= SELECTED_FRAME ();
684 Lisp_Object bar_window
;
685 enum scroll_bar_part part
;
688 if (mouse_position_hook
)
689 (*mouse_position_hook
) (&new_f
, 1, &bar_window
,
690 &part
, &x
, &y
, &time
);
692 XSETFRAME (window
, new_f
);
695 window
= selected_window
;
702 tem
= Fcar (position
);
705 window
= Fcar (Fcdr (position
));
707 y
= Fcar (Fcdr (tem
));
712 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
713 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
714 tem
= Fcar (Fcdr (Fcdr (tem
))); /* POSN_WINDOW_POSN (tem) */
723 /* Decode where to put the menu. */
731 else if (WINDOWP (window
))
733 CHECK_LIVE_WINDOW (window
);
734 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
736 xpos
= WINDOW_LEFT_EDGE_X (XWINDOW (window
));
737 ypos
= WINDOW_TOP_EDGE_Y (XWINDOW (window
));
740 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
741 but I don't want to make one now. */
742 CHECK_WINDOW (window
);
747 XSETFRAME (Vmenu_updating_frame
, f
);
749 Vmenu_updating_frame
= Qnil
;
750 #endif /* HAVE_MENUS */
755 /* Decode the menu items from what was specified. */
757 keymap
= get_keymap (menu
, 0, 0);
760 /* We were given a keymap. Extract menu info from the keymap. */
763 /* Extract the detailed info to make one pane. */
764 keymap_panes (&menu
, 1, NILP (position
));
766 /* Search for a string appearing directly as an element of the keymap.
767 That string is the title of the menu. */
768 prompt
= Fkeymap_prompt (keymap
);
769 if (NILP (title
) && !NILP (prompt
))
772 /* Make that be the pane title of the first pane. */
773 if (!NILP (prompt
) && menu_items_n_panes
>= 0)
774 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
778 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
780 /* We were given a list of keymaps. */
781 int nmaps
= XFASTINT (Flength (menu
));
783 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
788 /* The first keymap that has a prompt string
789 supplies the menu title. */
790 for (tem
= menu
, i
= 0; CONSP (tem
); tem
= Fcdr (tem
))
794 maps
[i
++] = keymap
= get_keymap (Fcar (tem
), 1, 0);
796 prompt
= Fkeymap_prompt (keymap
);
797 if (NILP (title
) && !NILP (prompt
))
801 /* Extract the detailed info to make one pane. */
802 keymap_panes (maps
, nmaps
, NILP (position
));
804 /* Make the title be the pane title of the first pane. */
805 if (!NILP (title
) && menu_items_n_panes
>= 0)
806 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title
;
812 /* We were given an old-fashioned menu. */
814 CHECK_STRING (title
);
816 list_of_panes (Fcdr (menu
));
823 discard_menu_items ();
829 /* Display them in a menu. */
830 record_unwind_protect (cleanup_popup_menu
, Qnil
);
833 selection
= mac_menu_show (f
, xpos
, ypos
, for_click
,
834 keymaps
, title
, &error_name
);
836 unbind_to (specpdl_count
, Qnil
);
839 #endif /* HAVE_MENUS */
841 if (error_name
) error (error_name
);
847 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
848 doc
: /* Pop up a dialog box and return user's selection.
849 POSITION specifies which frame to use.
850 This is normally a mouse button event or a window or frame.
851 If POSITION is t, it means to use the frame the mouse is on.
852 The dialog box appears in the middle of the specified frame.
854 CONTENTS specifies the alternatives to display in the dialog box.
855 It is a list of the form (DIALOG ITEM1 ITEM2...).
856 Each ITEM is a cons cell (STRING . VALUE).
857 The return value is VALUE from the chosen item.
859 An ITEM may also be just a string--that makes a nonselectable item.
860 An ITEM may also be nil--that means to put all preceding items
861 on the left of the dialog box and all following items on the right.
862 \(By default, approximately half appear on each side.)
864 If HEADER is non-nil, the frame title for the box is "Information",
865 otherwise it is "Question".
867 If the user gets rid of the dialog box without making a valid choice,
868 for instance using the window manager, then this produces a quit and
869 `x-popup-dialog' does not return. */)
870 (position
, contents
, header
)
871 Lisp_Object position
, contents
, header
;
878 /* Decode the first argument: find the window or frame to use. */
879 if (EQ (position
, Qt
)
880 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
881 || EQ (XCAR (position
), Qtool_bar
))))
883 #if 0 /* Using the frame the mouse is on may not be right. */
884 /* Use the mouse's current position. */
885 FRAME_PTR new_f
= SELECTED_FRAME ();
886 Lisp_Object bar_window
;
887 enum scroll_bar_part part
;
891 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
894 XSETFRAME (window
, new_f
);
896 window
= selected_window
;
898 window
= selected_window
;
900 else if (CONSP (position
))
903 tem
= Fcar (position
);
905 window
= Fcar (Fcdr (position
));
908 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
909 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
912 else if (WINDOWP (position
) || FRAMEP (position
))
917 /* Decode where to put the menu. */
921 else if (WINDOWP (window
))
923 CHECK_LIVE_WINDOW (window
);
924 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
927 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
928 but I don't want to make one now. */
929 CHECK_WINDOW (window
);
932 /* Display a menu with these alternatives
933 in the middle of frame F. */
935 Lisp_Object x
, y
, frame
, newpos
;
936 XSETFRAME (frame
, f
);
937 XSETINT (x
, x_pixel_width (f
) / 2);
938 XSETINT (y
, x_pixel_height (f
) / 2);
939 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
941 return Fx_popup_menu (newpos
,
942 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
944 #else /* HAVE_DIALOGS */
948 Lisp_Object selection
;
950 /* Decode the dialog items from what was specified. */
951 title
= Fcar (contents
);
952 CHECK_STRING (title
);
954 list_of_panes (Fcons (contents
, Qnil
));
956 /* Display them in a dialog box. */
958 selection
= mac_dialog_show (f
, 0, title
, header
, &error_name
);
961 discard_menu_items ();
963 if (error_name
) error (error_name
);
966 #endif /* HAVE_DIALOGS */
969 /* Activate the menu bar of frame F.
970 This is called from keyboard.c when it gets the
971 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
973 To activate the menu bar, we signal to the input thread that it can
974 return from the WM_INITMENU message, allowing the normal Windows
975 processing of the menus.
977 But first we recompute the menu bar contents (the whole tree).
979 This way we can safely execute Lisp code. */
982 x_activate_menubar (f
)
986 extern Point saved_menu_event_location
;
988 set_frame_menubar (f
, 0, 1);
991 menu_choice
= MenuSelect (saved_menu_event_location
);
992 do_menu_choice (menu_choice
);
997 /* This callback is called from the menu bar pulldown menu
998 when the user makes a selection.
999 Figure out what the user chose
1000 and put the appropriate events into the keyboard buffer. */
1003 menubar_selection_callback (FRAME_PTR f
, int client_data
)
1005 Lisp_Object prefix
, entry
;
1007 Lisp_Object
*subprefix_stack
;
1008 int submenu_depth
= 0;
1014 subprefix_stack
= (Lisp_Object
*) alloca (f
->menu_bar_items_used
* sizeof (Lisp_Object
));
1015 vector
= f
->menu_bar_vector
;
1018 while (i
< f
->menu_bar_items_used
)
1020 if (EQ (XVECTOR (vector
)->contents
[i
], Qnil
))
1022 subprefix_stack
[submenu_depth
++] = prefix
;
1026 else if (EQ (XVECTOR (vector
)->contents
[i
], Qlambda
))
1028 prefix
= subprefix_stack
[--submenu_depth
];
1031 else if (EQ (XVECTOR (vector
)->contents
[i
], Qt
))
1033 prefix
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1034 i
+= MENU_ITEMS_PANE_LENGTH
;
1038 entry
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1039 /* The EMACS_INT cast avoids a warning. There's no problem
1040 as long as pointers have enough bits to hold small integers. */
1041 if ((int) (EMACS_INT
) client_data
== i
)
1044 struct input_event buf
;
1048 XSETFRAME (frame
, f
);
1049 buf
.kind
= MENU_BAR_EVENT
;
1050 buf
.frame_or_window
= frame
;
1052 kbd_buffer_store_event (&buf
);
1054 for (j
= 0; j
< submenu_depth
; j
++)
1055 if (!NILP (subprefix_stack
[j
]))
1057 buf
.kind
= MENU_BAR_EVENT
;
1058 buf
.frame_or_window
= frame
;
1059 buf
.arg
= subprefix_stack
[j
];
1060 kbd_buffer_store_event (&buf
);
1065 buf
.kind
= MENU_BAR_EVENT
;
1066 buf
.frame_or_window
= frame
;
1068 kbd_buffer_store_event (&buf
);
1071 buf
.kind
= MENU_BAR_EVENT
;
1072 buf
.frame_or_window
= frame
;
1074 kbd_buffer_store_event (&buf
);
1076 f
->output_data
.mac
->menu_command_in_progress
= 0;
1077 f
->output_data
.mac
->menubar_active
= 0;
1080 i
+= MENU_ITEMS_ITEM_LENGTH
;
1083 f
->output_data
.mac
->menu_command_in_progress
= 0;
1084 f
->output_data
.mac
->menubar_active
= 0;
1087 /* Allocate a widget_value, blocking input. */
1090 xmalloc_widget_value ()
1092 widget_value
*value
;
1095 value
= malloc_widget_value ();
1101 /* This recursively calls free_widget_value on the tree of widgets.
1102 It must free all data that was malloc'ed for these widget_values.
1103 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1104 must be left alone. */
1107 free_menubar_widget_value_tree (wv
)
1112 wv
->name
= wv
->value
= wv
->key
= (char *) 0xDEADBEEF;
1114 if (wv
->contents
&& (wv
->contents
!= (widget_value
*)1))
1116 free_menubar_widget_value_tree (wv
->contents
);
1117 wv
->contents
= (widget_value
*) 0xDEADBEEF;
1121 free_menubar_widget_value_tree (wv
->next
);
1122 wv
->next
= (widget_value
*) 0xDEADBEEF;
1125 free_widget_value (wv
);
1129 /* Return a tree of widget_value structures for a menu bar item
1130 whose event type is ITEM_KEY (with string ITEM_NAME)
1131 and whose contents come from the list of keymaps MAPS. */
1133 static widget_value
*
1134 single_submenu (item_key
, item_name
, maps
)
1135 Lisp_Object item_key
, item_name
, maps
;
1137 widget_value
*wv
, *prev_wv
, *save_wv
, *first_wv
;
1139 int submenu_depth
= 0;
1142 Lisp_Object
*mapvec
;
1143 widget_value
**submenu_stack
;
1144 int previous_items
= menu_items_used
;
1145 int top_level_items
= 0;
1147 length
= Flength (maps
);
1148 len
= XINT (length
);
1150 /* Convert the list MAPS into a vector MAPVEC. */
1151 mapvec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1152 for (i
= 0; i
< len
; i
++)
1154 mapvec
[i
] = Fcar (maps
);
1158 menu_items_n_panes
= 0;
1160 /* Loop over the given keymaps, making a pane for each map.
1161 But don't make a pane that is empty--ignore that map instead. */
1162 for (i
= 0; i
< len
; i
++)
1164 if (SYMBOLP (mapvec
[i
])
1165 || (CONSP (mapvec
[i
]) && !KEYMAPP (mapvec
[i
])))
1167 /* Here we have a command at top level in the menu bar
1168 as opposed to a submenu. */
1169 top_level_items
= 1;
1170 push_menu_pane (Qnil
, Qnil
);
1171 push_menu_item (item_name
, Qt
, item_key
, mapvec
[i
],
1172 Qnil
, Qnil
, Qnil
, Qnil
);
1175 single_keymap_panes (mapvec
[i
], item_name
, item_key
, 0, 10);
1178 /* Create a tree of widget_value objects
1179 representing the panes and their items. */
1182 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1183 wv
= xmalloc_widget_value ();
1187 wv
->button_type
= BUTTON_TYPE_NONE
;
1193 /* Loop over all panes and items made during this call
1194 and construct a tree of widget_value objects.
1195 Ignore the panes and items made by previous calls to
1196 single_submenu, even though those are also in menu_items. */
1198 while (i
< menu_items_used
)
1200 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1202 submenu_stack
[submenu_depth
++] = save_wv
;
1207 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1210 save_wv
= submenu_stack
[--submenu_depth
];
1213 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1214 && submenu_depth
!= 0)
1215 i
+= MENU_ITEMS_PANE_LENGTH
;
1216 /* Ignore a nil in the item list.
1217 It's meaningful only for dialog boxes. */
1218 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1220 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1222 /* Create a new pane. */
1223 Lisp_Object pane_name
, prefix
;
1226 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
1227 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1229 #ifndef HAVE_MULTILINGUAL_MENU
1230 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1232 pane_name
= ENCODE_SYSTEM (pane_name
);
1233 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1236 pane_string
= (NILP (pane_name
)
1237 ? "" : (char *) SDATA (pane_name
));
1238 /* If there is just one top-level pane, put all its items directly
1239 under the top-level menu. */
1240 if (menu_items_n_panes
== 1)
1243 /* If the pane has a meaningful name,
1244 make the pane a top-level menu item
1245 with its items as a submenu beneath it. */
1246 if (strcmp (pane_string
, ""))
1248 wv
= xmalloc_widget_value ();
1252 first_wv
->contents
= wv
;
1253 wv
->lname
= pane_name
;
1254 /* Set value to 1 so update_submenu_strings can handle '@' */
1255 wv
->value
= (char *)1;
1257 wv
->button_type
= BUTTON_TYPE_NONE
;
1262 i
+= MENU_ITEMS_PANE_LENGTH
;
1266 /* Create a new item within current pane. */
1267 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
;
1270 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1271 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1272 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1273 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1274 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1275 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1276 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1278 #ifndef HAVE_MULTILINGUAL_MENU
1279 if (STRING_MULTIBYTE (item_name
))
1281 item_name
= ENCODE_MENU_STRING (item_name
);
1282 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1285 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1287 descrip
= ENCODE_MENU_STRING (descrip
);
1288 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1290 #endif /* not HAVE_MULTILINGUAL_MENU */
1292 wv
= xmalloc_widget_value ();
1296 save_wv
->contents
= wv
;
1298 wv
->lname
= item_name
;
1299 if (!NILP (descrip
))
1302 /* The EMACS_INT cast avoids a warning. There's no problem
1303 as long as pointers have enough bits to hold small integers. */
1304 wv
->call_data
= (!NILP (def
) ? (void *) (EMACS_INT
) i
: 0);
1305 wv
->enabled
= !NILP (enable
);
1308 wv
->button_type
= BUTTON_TYPE_NONE
;
1309 else if (EQ (type
, QCradio
))
1310 wv
->button_type
= BUTTON_TYPE_RADIO
;
1311 else if (EQ (type
, QCtoggle
))
1312 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1316 wv
->selected
= !NILP (selected
);
1317 if (!STRINGP (help
))
1324 i
+= MENU_ITEMS_ITEM_LENGTH
;
1328 /* If we have just one "menu item"
1329 that was originally a button, return it by itself. */
1330 if (top_level_items
&& first_wv
->contents
&& first_wv
->contents
->next
== 0)
1332 wv
= first_wv
->contents
;
1333 free_widget_value (first_wv
);
1339 /* Walk through the widget_value tree starting at FIRST_WV and update
1340 the char * pointers from the corresponding lisp values.
1341 We do this after building the whole tree, since GC may happen while the
1342 tree is constructed, and small strings are relocated. So we must wait
1343 until no GC can happen before storing pointers into lisp values. */
1345 update_submenu_strings (first_wv
)
1346 widget_value
*first_wv
;
1350 for (wv
= first_wv
; wv
; wv
= wv
->next
)
1352 if (STRINGP (wv
->lname
))
1354 wv
->name
= SDATA (wv
->lname
);
1356 /* Ignore the @ that means "separate pane".
1357 This is a kludge, but this isn't worth more time. */
1358 if (wv
->value
== (char *)1)
1360 if (wv
->name
[0] == '@')
1366 if (STRINGP (wv
->lkey
))
1367 wv
->key
= SDATA (wv
->lkey
);
1370 update_submenu_strings (wv
->contents
);
1375 /* Event handler function that pops down a menu on C-g. We can only pop
1376 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1378 #ifdef HAVE_CANCELMENUTRACKING
1379 static pascal OSStatus
1380 menu_quit_handler (nextHandler
, theEvent
, userData
)
1381 EventHandlerCallRef nextHandler
;
1386 UInt32 keyModifiers
;
1387 extern int mac_quit_char_modifiers
;
1388 extern int mac_quit_char_keycode
;
1390 GetEventParameter (theEvent
, kEventParamKeyCode
,
1391 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
1393 GetEventParameter (theEvent
, kEventParamKeyModifiers
,
1394 typeUInt32
, NULL
, sizeof(UInt32
),
1395 NULL
, &keyModifiers
);
1397 if (keyCode
== mac_quit_char_keycode
1398 && keyModifiers
== mac_quit_char_modifiers
)
1400 MenuRef menu
= userData
!= 0
1401 ? (MenuRef
)userData
: AcquireRootMenu ();
1403 CancelMenuTracking (menu
, true, 0);
1404 if (!userData
) ReleaseMenu (menu
);
1408 return CallNextEventHandler (nextHandler
, theEvent
);
1410 #endif /* HAVE_CANCELMENUTRACKING */
1412 /* Add event handler for MENU_HANDLE so we can detect C-g.
1413 If MENU_HANDLE is NULL, install handler for all menus in the menu bar.
1414 If CancelMenuTracking isn't available, do nothing. */
1417 install_menu_quit_handler (MenuHandle menu_handle
)
1419 #ifdef HAVE_CANCELMENUTRACKING
1420 EventHandlerUPP handler
= NewEventHandlerUPP(menu_quit_handler
);
1421 UInt32 numTypes
= 1;
1422 EventTypeSpec typesList
[] = { { kEventClassKeyboard
, kEventRawKeyDown
} };
1423 int i
= MIN_MENU_ID
;
1424 MenuHandle menu
= menu_handle
? menu_handle
: GetMenuHandle (i
);
1426 while (menu
!= NULL
)
1428 InstallMenuEventHandler (menu
, handler
, GetEventTypeCount (typesList
),
1429 typesList
, menu_handle
, NULL
);
1430 if (menu_handle
) break;
1431 menu
= GetMenuHandle (++i
);
1433 DisposeEventHandlerUPP (handler
);
1434 #endif /* HAVE_CANCELMENUTRACKING */
1437 /* Set the contents of the menubar widgets of frame F.
1438 The argument FIRST_TIME is currently ignored;
1439 it is set the first time this is called, from initialize_frame_menubar. */
1442 set_frame_menubar (f
, first_time
, deep_p
)
1447 int menubar_widget
= f
->output_data
.mac
->menubar_widget
;
1449 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1452 /* We must not change the menubar when actually in use. */
1453 if (f
->output_data
.mac
->menubar_active
)
1456 XSETFRAME (Vmenu_updating_frame
, f
);
1458 if (! menubar_widget
)
1460 else if (pending_menu_activation
&& !deep_p
)
1463 wv
= xmalloc_widget_value ();
1464 wv
->name
= "menubar";
1467 wv
->button_type
= BUTTON_TYPE_NONE
;
1473 /* Make a widget-value tree representing the entire menu trees. */
1475 struct buffer
*prev
= current_buffer
;
1477 int specpdl_count
= SPECPDL_INDEX ();
1478 int previous_menu_items_used
= f
->menu_bar_items_used
;
1479 Lisp_Object
*previous_items
1480 = (Lisp_Object
*) alloca (previous_menu_items_used
1481 * sizeof (Lisp_Object
));
1483 /* If we are making a new widget, its contents are empty,
1484 do always reinitialize them. */
1485 if (! menubar_widget
)
1486 previous_menu_items_used
= 0;
1488 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1489 specbind (Qinhibit_quit
, Qt
);
1490 /* Don't let the debugger step into this code
1491 because it is not reentrant. */
1492 specbind (Qdebug_on_next_call
, Qnil
);
1494 record_unwind_save_match_data ();
1495 if (NILP (Voverriding_local_map_menu_flag
))
1497 specbind (Qoverriding_terminal_local_map
, Qnil
);
1498 specbind (Qoverriding_local_map
, Qnil
);
1501 set_buffer_internal_1 (XBUFFER (buffer
));
1503 /* Run the Lucid hook. */
1504 safe_run_hooks (Qactivate_menubar_hook
);
1505 /* If it has changed current-menubar from previous value,
1506 really recompute the menubar from the value. */
1507 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1508 call0 (Qrecompute_lucid_menubar
);
1509 safe_run_hooks (Qmenu_bar_update_hook
);
1510 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1512 items
= FRAME_MENU_BAR_ITEMS (f
);
1514 /* Save the frame's previous menu bar contents data. */
1515 if (previous_menu_items_used
)
1516 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1517 previous_menu_items_used
* sizeof (Lisp_Object
));
1519 /* Fill in the current menu bar contents. */
1520 menu_items
= f
->menu_bar_vector
;
1521 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1523 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1525 Lisp_Object key
, string
, maps
;
1527 key
= XVECTOR (items
)->contents
[i
];
1528 string
= XVECTOR (items
)->contents
[i
+ 1];
1529 maps
= XVECTOR (items
)->contents
[i
+ 2];
1533 wv
= single_submenu (key
, string
, maps
);
1537 first_wv
->contents
= wv
;
1538 /* Don't set wv->name here; GC during the loop might relocate it. */
1540 wv
->button_type
= BUTTON_TYPE_NONE
;
1544 finish_menu_items ();
1546 set_buffer_internal_1 (prev
);
1547 unbind_to (specpdl_count
, Qnil
);
1549 /* If there has been no change in the Lisp-level contents
1550 of the menu bar, skip redisplaying it. Just exit. */
1552 for (i
= 0; i
< previous_menu_items_used
; i
++)
1553 if (menu_items_used
== i
1554 || (NILP (Fequal (previous_items
[i
],
1555 XVECTOR (menu_items
)->contents
[i
]))))
1557 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1559 free_menubar_widget_value_tree (first_wv
);
1565 /* Now GC cannot happen during the lifetime of the widget_value,
1566 so it's safe to store data from a Lisp_String, as long as
1567 local copies are made when the actual menu is created.
1568 Windows takes care of this for normal string items, but
1569 not for owner-drawn items or additional item-info. */
1570 wv
= first_wv
->contents
;
1571 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1574 string
= XVECTOR (items
)->contents
[i
+ 1];
1577 wv
->name
= (char *) SDATA (string
);
1578 update_submenu_strings (wv
->contents
);
1582 f
->menu_bar_vector
= menu_items
;
1583 f
->menu_bar_items_used
= menu_items_used
;
1588 /* Make a widget-value tree containing
1589 just the top level menu bar strings. */
1591 items
= FRAME_MENU_BAR_ITEMS (f
);
1592 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1596 string
= XVECTOR (items
)->contents
[i
+ 1];
1600 wv
= xmalloc_widget_value ();
1601 wv
->name
= (char *) SDATA (string
);
1604 wv
->button_type
= BUTTON_TYPE_NONE
;
1606 /* This prevents lwlib from assuming this
1607 menu item is really supposed to be empty. */
1608 /* The EMACS_INT cast avoids a warning.
1609 This value just has to be different from small integers. */
1610 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1615 first_wv
->contents
= wv
;
1619 /* Forget what we thought we knew about what is in the
1620 detailed contents of the menu bar menus.
1621 Changing the top level always destroys the contents. */
1622 f
->menu_bar_items_used
= 0;
1625 /* Create or update the menu bar widget. */
1629 /* Non-null value to indicate menubar has already been "created". */
1630 f
->output_data
.mac
->menubar_widget
= 1;
1633 int i
= MIN_MENU_ID
;
1634 MenuHandle menu
= GetMenuHandle (i
);
1635 while (menu
!= NULL
)
1639 menu
= GetMenuHandle (++i
);
1643 menu
= GetMenuHandle (i
);
1644 while (menu
!= NULL
)
1648 menu
= GetMenuHandle (++i
);
1652 fill_menubar (first_wv
->contents
);
1656 /* Add event handler so we can detect C-g. */
1657 install_menu_quit_handler (NULL
);
1658 free_menubar_widget_value_tree (first_wv
);
1663 /* Called from Fx_create_frame to create the initial menubar of a frame
1664 before it is mapped, so that the window is mapped with the menubar already
1665 there instead of us tacking it on later and thrashing the window after it
1669 initialize_frame_menubar (f
)
1672 /* This function is called before the first chance to redisplay
1673 the frame. It has to be, so the frame will have the right size. */
1674 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1675 set_frame_menubar (f
, 1, 1);
1678 /* Get rid of the menu bar of frame F, and free its storage.
1679 This is used when deleting a frame, and when turning off the menu bar. */
1682 free_frame_menubar (f
)
1685 f
->output_data
.mac
->menubar_widget
= NULL
;
1693 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
1694 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
1696 FRAME_PTR f
= p1
->pointer
;
1697 MenuHandle
*menu
= p2
->pointer
;
1701 /* Must reset this manually because the button release event is not
1702 passed to Emacs event loop. */
1703 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
1705 /* delete all menus */
1707 int i
= MIN_POPUP_SUBMENU_ID
;
1708 MenuHandle submenu
= GetMenuHandle (i
);
1709 while (submenu
!= NULL
)
1712 DisposeMenu (submenu
);
1713 submenu
= GetMenuHandle (++i
);
1717 DeleteMenu (POPUP_SUBMENU_ID
);
1718 DisposeMenu (*menu
);
1725 /* Mac_menu_show actually displays a menu using the panes and items in
1726 menu_items and returns the value selected from it; we assume input
1727 is blocked by the caller. */
1729 /* F is the frame the menu is for.
1730 X and Y are the frame-relative specified position,
1731 relative to the inside upper left corner of the frame F.
1732 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1733 KEYMAPS is 1 if this menu was specified with keymaps;
1734 in that case, we return a list containing the chosen item's value
1735 and perhaps also the pane's prefix.
1736 TITLE is the specified menu title.
1737 ERROR is a place to store an error message string in case of failure.
1738 (We return nil on failure, but the value doesn't actually matter.) */
1741 mac_menu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
1752 int menu_item_choice
;
1753 int menu_item_selection
;
1756 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1757 widget_value
**submenu_stack
1758 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1759 Lisp_Object
*subprefix_stack
1760 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1761 int submenu_depth
= 0;
1763 int specpdl_count
= SPECPDL_INDEX ();
1767 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1769 *error
= "Empty menu";
1773 /* Create a tree of widget_value objects
1774 representing the panes and their items. */
1775 wv
= xmalloc_widget_value ();
1779 wv
->button_type
= BUTTON_TYPE_NONE
;
1784 /* Loop over all panes and items, filling in the tree. */
1786 while (i
< menu_items_used
)
1788 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1790 submenu_stack
[submenu_depth
++] = save_wv
;
1796 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1799 save_wv
= submenu_stack
[--submenu_depth
];
1803 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1804 && submenu_depth
!= 0)
1805 i
+= MENU_ITEMS_PANE_LENGTH
;
1806 /* Ignore a nil in the item list.
1807 It's meaningful only for dialog boxes. */
1808 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1810 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1812 /* Create a new pane. */
1813 Lisp_Object pane_name
, prefix
;
1815 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1816 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1817 #ifndef HAVE_MULTILINGUAL_MENU
1818 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1820 pane_name
= ENCODE_SYSTEM (pane_name
);
1821 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1824 pane_string
= (NILP (pane_name
)
1825 ? "" : (char *) SDATA (pane_name
));
1826 /* If there is just one top-level pane, put all its items directly
1827 under the top-level menu. */
1828 if (menu_items_n_panes
== 1)
1831 /* If the pane has a meaningful name,
1832 make the pane a top-level menu item
1833 with its items as a submenu beneath it. */
1834 if (!keymaps
&& strcmp (pane_string
, ""))
1836 wv
= xmalloc_widget_value ();
1840 first_wv
->contents
= wv
;
1841 wv
->name
= pane_string
;
1842 if (keymaps
&& !NILP (prefix
))
1846 wv
->button_type
= BUTTON_TYPE_NONE
;
1851 else if (first_pane
)
1857 i
+= MENU_ITEMS_PANE_LENGTH
;
1861 /* Create a new item within current pane. */
1862 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1864 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1865 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1866 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1867 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1868 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1869 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1870 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1872 #ifndef HAVE_MULTILINGUAL_MENU
1873 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1875 item_name
= ENCODE_MENU_STRING (item_name
);
1876 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1878 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1880 descrip
= ENCODE_MENU_STRING (descrip
);
1881 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1883 #endif /* not HAVE_MULTILINGUAL_MENU */
1885 wv
= xmalloc_widget_value ();
1889 save_wv
->contents
= wv
;
1890 wv
->name
= (char *) SDATA (item_name
);
1891 if (!NILP (descrip
))
1892 wv
->key
= (char *) SDATA (descrip
);
1894 /* Use the contents index as call_data, since we are
1895 restricted to 16-bits. */
1896 wv
->call_data
= !NILP (def
) ? (void *) (EMACS_INT
) i
: 0;
1897 wv
->enabled
= !NILP (enable
);
1900 wv
->button_type
= BUTTON_TYPE_NONE
;
1901 else if (EQ (type
, QCtoggle
))
1902 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1903 else if (EQ (type
, QCradio
))
1904 wv
->button_type
= BUTTON_TYPE_RADIO
;
1908 wv
->selected
= !NILP (selected
);
1909 if (!STRINGP (help
))
1916 i
+= MENU_ITEMS_ITEM_LENGTH
;
1920 /* Deal with the title, if it is non-nil. */
1923 widget_value
*wv_title
= xmalloc_widget_value ();
1924 widget_value
*wv_sep
= xmalloc_widget_value ();
1926 /* Maybe replace this separator with a bitmap or owner-draw item
1927 so that it looks better. Having two separators looks odd. */
1928 wv_sep
->name
= "--";
1929 wv_sep
->next
= first_wv
->contents
;
1930 wv_sep
->help
= Qnil
;
1932 #ifndef HAVE_MULTILINGUAL_MENU
1933 if (STRING_MULTIBYTE (title
))
1934 title
= ENCODE_MENU_STRING (title
);
1936 wv_title
->name
= (char *) SDATA (title
);
1937 wv_title
->enabled
= FALSE
;
1938 wv_title
->title
= TRUE
;
1939 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1940 wv_title
->help
= Qnil
;
1941 wv_title
->next
= wv_sep
;
1942 first_wv
->contents
= wv_title
;
1945 /* Actually create the menu. */
1946 menu
= NewMenu (POPUP_SUBMENU_ID
, "\p");
1947 submenu_id
= MIN_POPUP_SUBMENU_ID
;
1948 fill_submenu (menu
, first_wv
->contents
);
1950 /* Free the widget_value objects we used to specify the
1952 free_menubar_widget_value_tree (first_wv
);
1954 /* Adjust coordinates to be root-window-relative. */
1958 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1960 LocalToGlobal (&pos
);
1962 /* No selection has been chosen yet. */
1963 menu_item_choice
= 0;
1964 menu_item_selection
= 0;
1966 InsertMenu (menu
, -1);
1968 record_unwind_protect (pop_down_menu
,
1969 Fcons (make_save_value (f
, 0),
1970 make_save_value (&menu
, 0)));
1972 /* Add event handler so we can detect C-g. */
1973 install_menu_quit_handler (menu
);
1975 /* Display the menu. */
1976 menu_item_choice
= PopUpMenuSelect (menu
, pos
.v
, pos
.h
, 0);
1977 menu_item_selection
= LoWord (menu_item_choice
);
1979 /* Get the refcon to find the correct item */
1980 if (menu_item_selection
)
1982 MenuHandle sel_menu
= GetMenuHandle (HiWord (menu_item_choice
));
1984 GetMenuItemRefCon (sel_menu
, menu_item_selection
, &refcon
);
1987 else if (! for_click
)
1988 /* Make "Cancel" equivalent to C-g unless this menu was popped up by
1990 Fsignal (Qquit
, Qnil
);
1992 /* Find the selected item, and its pane, to return
1993 the proper value. */
1994 if (menu_item_selection
!= 0)
1996 Lisp_Object prefix
, entry
;
1998 prefix
= entry
= Qnil
;
2000 while (i
< menu_items_used
)
2002 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2004 subprefix_stack
[submenu_depth
++] = prefix
;
2008 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2010 prefix
= subprefix_stack
[--submenu_depth
];
2013 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2016 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2017 i
+= MENU_ITEMS_PANE_LENGTH
;
2019 /* Ignore a nil in the item list.
2020 It's meaningful only for dialog boxes. */
2021 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2026 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2027 if ((int) (EMACS_INT
) refcon
== i
)
2033 entry
= Fcons (entry
, Qnil
);
2035 entry
= Fcons (prefix
, entry
);
2036 for (j
= submenu_depth
- 1; j
>= 0; j
--)
2037 if (!NILP (subprefix_stack
[j
]))
2038 entry
= Fcons (subprefix_stack
[j
], entry
);
2042 i
+= MENU_ITEMS_ITEM_LENGTH
;
2046 else if (!for_click
)
2047 /* Make "Cancel" equivalent to C-g. */
2048 Fsignal (Qquit
, Qnil
);
2050 unbind_to (specpdl_count
, Qnil
);
2057 /* Construct native Mac OS menubar based on widget_value tree. */
2060 mac_dialog (widget_value
*wv
)
2064 char **button_labels
;
2071 WindowPtr window_ptr
;
2074 EventRecord event_record
;
2076 int control_part_code
;
2079 dialog_name
= wv
->name
;
2080 nb_buttons
= dialog_name
[1] - '0';
2081 left_count
= nb_buttons
- (dialog_name
[4] - '0');
2082 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
2083 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
2086 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
2087 strcpy (prompt
, wv
->value
);
2091 for (i
= 0; i
< nb_buttons
; i
++)
2093 button_labels
[i
] = wv
->value
;
2094 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
2095 strcpy (button_labels
[i
], wv
->value
);
2096 c2pstr (button_labels
[i
]);
2097 ref_cons
[i
] = (UInt32
) wv
->call_data
;
2101 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowPtr
) -1);
2103 SetPortWindowPort (window_ptr
);
2106 /* Left and right margins in the dialog are 13 pixels each.*/
2108 /* Calculate width of dialog box: 8 pixels on each side of the text
2109 label in each button, 12 pixels between buttons. */
2110 for (i
= 0; i
< nb_buttons
; i
++)
2111 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
2113 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
2116 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
2118 SizeWindow (window_ptr
, dialog_width
, 78, 0);
2119 ShowWindow (window_ptr
);
2121 SetPortWindowPort (window_ptr
);
2126 DrawString (prompt
);
2129 for (i
= 0; i
< nb_buttons
; i
++)
2131 int button_width
= StringWidth (button_labels
[i
]) + 16;
2132 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
2133 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
2134 kControlPushButtonProc
, ref_cons
[i
]);
2135 left
+= button_width
+ 12;
2136 if (i
== left_count
- 1)
2143 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
2144 if (event_record
.what
== mouseDown
)
2146 part_code
= FindWindow (event_record
.where
, &window_ptr
);
2147 if (part_code
== inContent
)
2149 mouse
= event_record
.where
;
2150 GlobalToLocal (&mouse
);
2151 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
2152 if (control_part_code
== kControlButtonPart
)
2153 if (TrackControl (ch
, mouse
, NULL
))
2154 i
= GetControlReference (ch
);
2159 DisposeWindow (window_ptr
);
2164 static char * button_names
[] = {
2165 "button1", "button2", "button3", "button4", "button5",
2166 "button6", "button7", "button8", "button9", "button10" };
2169 mac_dialog_show (f
, keymaps
, title
, header
, error
)
2172 Lisp_Object title
, header
;
2175 int i
, nb_buttons
=0;
2176 char dialog_name
[6];
2177 int menu_item_selection
;
2179 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2181 /* Number of elements seen so far, before boundary. */
2183 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2184 int boundary_seen
= 0;
2188 if (menu_items_n_panes
> 1)
2190 *error
= "Multiple panes in dialog box";
2194 /* Create a tree of widget_value objects
2195 representing the text label and buttons. */
2197 Lisp_Object pane_name
, prefix
;
2199 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2200 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2201 pane_string
= (NILP (pane_name
)
2202 ? "" : (char *) SDATA (pane_name
));
2203 prev_wv
= xmalloc_widget_value ();
2204 prev_wv
->value
= pane_string
;
2205 if (keymaps
&& !NILP (prefix
))
2207 prev_wv
->enabled
= 1;
2208 prev_wv
->name
= "message";
2209 prev_wv
->help
= Qnil
;
2212 /* Loop over all panes and items, filling in the tree. */
2213 i
= MENU_ITEMS_PANE_LENGTH
;
2214 while (i
< menu_items_used
)
2217 /* Create a new item within current pane. */
2218 Lisp_Object item_name
, enable
, descrip
, help
;
2220 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2221 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2223 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2224 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2226 if (NILP (item_name
))
2228 free_menubar_widget_value_tree (first_wv
);
2229 *error
= "Submenu in dialog items";
2232 if (EQ (item_name
, Qquote
))
2234 /* This is the boundary between left-side elts
2235 and right-side elts. Stop incrementing right_count. */
2240 if (nb_buttons
>= 9)
2242 free_menubar_widget_value_tree (first_wv
);
2243 *error
= "Too many dialog items";
2247 wv
= xmalloc_widget_value ();
2249 wv
->name
= (char *) button_names
[nb_buttons
];
2250 if (!NILP (descrip
))
2251 wv
->key
= (char *) SDATA (descrip
);
2252 wv
->value
= (char *) SDATA (item_name
);
2253 wv
->call_data
= (void *) i
;
2254 /* menu item is identified by its index in menu_items table */
2255 wv
->enabled
= !NILP (enable
);
2259 if (! boundary_seen
)
2263 i
+= MENU_ITEMS_ITEM_LENGTH
;
2266 /* If the boundary was not specified,
2267 by default put half on the left and half on the right. */
2268 if (! boundary_seen
)
2269 left_count
= nb_buttons
- nb_buttons
/ 2;
2271 wv
= xmalloc_widget_value ();
2272 wv
->name
= dialog_name
;
2275 /* Frame title: 'Q' = Question, 'I' = Information.
2276 Can also have 'E' = Error if, one day, we want
2277 a popup for errors. */
2279 dialog_name
[0] = 'Q';
2281 dialog_name
[0] = 'I';
2283 /* Dialog boxes use a really stupid name encoding
2284 which specifies how many buttons to use
2285 and how many buttons are on the right. */
2286 dialog_name
[1] = '0' + nb_buttons
;
2287 dialog_name
[2] = 'B';
2288 dialog_name
[3] = 'R';
2289 /* Number of buttons to put on the right. */
2290 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2292 wv
->contents
= first_wv
;
2296 /* Actually create the dialog. */
2298 menu_item_selection
= mac_dialog (first_wv
);
2300 menu_item_selection
= 0;
2303 /* Free the widget_value objects we used to specify the contents. */
2304 free_menubar_widget_value_tree (first_wv
);
2306 /* Find the selected item, and its pane, to return the proper
2308 if (menu_item_selection
!= 0)
2314 while (i
< menu_items_used
)
2318 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2321 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2322 i
+= MENU_ITEMS_PANE_LENGTH
;
2327 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2328 if (menu_item_selection
== i
)
2332 entry
= Fcons (entry
, Qnil
);
2334 entry
= Fcons (prefix
, entry
);
2338 i
+= MENU_ITEMS_ITEM_LENGTH
;
2345 #endif /* HAVE_DIALOGS */
2348 /* Is this item a separator? */
2350 name_is_separator (name
)
2355 /* Check if name string consists of only dashes ('-'). */
2356 while (*name
== '-') name
++;
2357 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2358 or "--deep-shadow". We don't implement them yet, se we just treat
2359 them like normal separators. */
2360 return (*name
== '\0' || start
+ 2 == name
);
2364 add_menu_item (MenuHandle menu
, widget_value
*wv
, int submenu
,
2370 if (name_is_separator (wv
->name
))
2371 AppendMenu (menu
, "\p-");
2374 AppendMenu (menu
, "\pX");
2376 #if TARGET_API_MAC_CARBON
2377 pos
= CountMenuItems (menu
);
2379 pos
= CountMItems (menu
);
2382 strcpy (item_name
, "");
2383 strncat (item_name
, wv
->name
, 255);
2384 if (wv
->key
!= NULL
)
2386 strncat (item_name
, " ", 255);
2387 strncat (item_name
, wv
->key
, 255);
2390 #if TARGET_API_MAC_CARBON
2392 CFStringRef string
= cfstring_create_with_utf8_cstring (item_name
);
2394 SetMenuItemTextWithCFString (menu
, pos
, string
);
2399 SetMenuItemText (menu
, pos
, item_name
);
2402 if (wv
->enabled
&& !force_disable
)
2403 #if TARGET_API_MAC_CARBON
2404 EnableMenuItem (menu
, pos
);
2406 EnableItem (menu
, pos
);
2409 #if TARGET_API_MAC_CARBON
2410 DisableMenuItem (menu
, pos
);
2412 DisableItem (menu
, pos
);
2415 /* Draw radio buttons and tickboxes. */
2417 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
||
2418 wv
->button_type
== BUTTON_TYPE_RADIO
))
2419 SetItemMark (menu
, pos
, checkMark
);
2421 SetItemMark (menu
, pos
, noMark
);
2424 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
2427 if (submenu
!= NULL
)
2428 SetMenuItemHierarchicalID (menu
, pos
, submenu
);
2431 /* Construct native Mac OS menubar based on widget_value tree. */
2434 fill_submenu (MenuHandle menu
, widget_value
*wv
)
2436 for ( ; wv
!= NULL
; wv
= wv
->next
)
2439 int cur_submenu
= submenu_id
++;
2440 MenuHandle submenu
= NewMenu (cur_submenu
, "\pX");
2441 fill_submenu (submenu
, wv
->contents
);
2442 InsertMenu (submenu
, -1);
2443 add_menu_item (menu
, wv
, cur_submenu
, 0);
2446 add_menu_item (menu
, wv
, NULL
, 0);
2450 /* Construct native Mac OS menu based on widget_value tree. */
2453 fill_menu (MenuHandle menu
, widget_value
*wv
)
2455 for ( ; wv
!= NULL
; wv
= wv
->next
)
2458 int cur_submenu
= submenu_id
++;
2459 MenuHandle submenu
= NewMenu (cur_submenu
, "\pX");
2460 fill_submenu (submenu
, wv
->contents
);
2461 InsertMenu (submenu
, -1);
2462 add_menu_item (menu
, wv
, cur_submenu
, 0);
2465 add_menu_item (menu
, wv
, NULL
, 0);
2468 /* Construct native Mac OS menubar based on widget_value tree. */
2471 fill_menubar (widget_value
*wv
)
2475 submenu_id
= MIN_SUBMENU_ID
;
2477 for (id
= MIN_MENU_ID
; wv
!= NULL
; wv
= wv
->next
, id
++)
2482 strncpy (title
, wv
->name
, 255);
2485 menu
= NewMenu (id
, title
);
2488 fill_menu (menu
, wv
->contents
);
2490 InsertMenu (menu
, 0);
2494 #endif /* HAVE_MENUS */
2500 staticpro (&menu_items
);
2503 Qdebug_on_next_call
= intern ("debug-on-next-call");
2504 staticpro (&Qdebug_on_next_call
);
2506 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame
,
2507 doc
: /* Frame for which we are updating a menu.
2508 The enable predicate for a menu command should check this variable. */);
2509 Vmenu_updating_frame
= Qnil
;
2511 defsubr (&Sx_popup_menu
);
2513 defsubr (&Sx_popup_dialog
);
2517 /* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce
2518 (do not change this comment) */