1 /* Menu support for GNU Emacs on Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006 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). */
29 #include "termhooks.h"
34 #include "blockinput.h"
39 #if !TARGET_API_MAC_CARBON
42 #include <QuickDraw.h>
43 #include <ToolUtils.h>
48 #if defined (__MRC__) || (__MSL__ >= 0x6000)
49 #include <ControlDefinitions.h>
51 #endif /* not TARGET_API_MAC_CARBON */
53 /* This may include sys/types.h, and that somehow loses
54 if this is not done before the other system files. */
57 /* Load sys/types.h if not already loaded.
58 In some systems loading it twice is suicidal. */
60 #include <sys/types.h>
63 #include "dispextern.h"
65 enum mac_menu_kind
{ /* Menu ID range */
66 MAC_MENU_APPLE
, /* 0 (Reserved by Apple) */
67 MAC_MENU_MENU_BAR
, /* 1 .. 234 */
68 MAC_MENU_POPUP
, /* 235 */
69 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
70 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
71 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
72 MAC_MENU_END
/* 32768 */
75 static const int min_menu_id
[] = {0, 1, 235, 236, 256, 16384, 32768};
77 #define DIALOG_WINDOW_RESOURCE 130
79 #define HAVE_DIALOGS 1
81 #undef HAVE_MULTILINGUAL_MENU
82 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
84 /******************************************************************/
85 /* Definitions copied from lwlib.h */
87 typedef void * XtPointer
;
96 /* This structure is based on the one in ../lwlib/lwlib.h, modified
98 typedef struct _widget_value
103 /* value (meaning depend on widget type) */
105 /* keyboard equivalent. no implications for XtTranslations */
108 /* Help string or nil if none.
109 GC finds this string through the frame's menu_bar_vector
110 or through menu_items. */
112 /* true if enabled */
114 /* true if selected */
116 /* The type of a button. */
117 enum button_type button_type
;
118 /* true if menu title */
121 /* true if was edited (maintained by get_value) */
123 /* true if has changed (maintained by lw library) */
125 /* true if this widget itself has changed,
126 but not counting the other widgets found in the `next' field. */
127 change_type this_one_change
;
129 /* Contents of the sub-widgets, also selected slot for checkbox */
130 struct _widget_value
* contents
;
131 /* data passed to callback */
133 /* next one in the list */
134 struct _widget_value
* next
;
136 /* slot for the toolkit dependent part. Always initialize to NULL. */
138 /* tell us if we should free the toolkit data slot when freeing the
139 widget_value itself. */
140 Boolean free_toolkit_data
;
142 /* we resource the widget_value structures; this points to the next
143 one on the free list if this one has been deallocated.
145 struct _widget_value
*free_list
;
149 /* Assumed by other routines to zero area returned. */
150 #define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
151 0, (sizeof (widget_value)))
152 #define free_widget_value(wv) xfree (wv)
154 /******************************************************************/
161 Lisp_Object Vmenu_updating_frame
;
163 Lisp_Object Qdebug_on_next_call
;
165 extern Lisp_Object Qmenu_bar
, Qmac_apple_event
;
167 extern Lisp_Object QCtoggle
, QCradio
;
169 extern Lisp_Object Voverriding_local_map
;
170 extern Lisp_Object Voverriding_local_map_menu_flag
;
172 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
174 extern Lisp_Object Qmenu_bar_update_hook
;
176 void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
178 #if TARGET_API_MAC_CARBON
179 #define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
181 #define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
184 static void push_menu_item
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
185 Lisp_Object
, Lisp_Object
, Lisp_Object
,
186 Lisp_Object
, Lisp_Object
));
188 static Lisp_Object mac_dialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
,
189 Lisp_Object
, char **));
191 static Lisp_Object mac_menu_show
P_ ((struct frame
*, int, int, int, int,
192 Lisp_Object
, char **));
193 static void keymap_panes
P_ ((Lisp_Object
*, int, int));
194 static void single_keymap_panes
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
196 static void list_of_panes
P_ ((Lisp_Object
));
197 static void list_of_items
P_ ((Lisp_Object
));
199 static int fill_menu
P_ ((MenuHandle
, widget_value
*, enum mac_menu_kind
, int));
200 static void fill_menubar
P_ ((widget_value
*, int));
201 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
204 /* This holds a Lisp vector that holds the results of decoding
205 the keymaps or alist-of-alists that specify a menu.
207 It describes the panes and items within the panes.
209 Each pane is described by 3 elements in the vector:
210 t, the pane name, the pane's prefix key.
211 Then follow the pane's items, with 5 elements per item:
212 the item string, the enable flag, the item's value,
213 the definition, and the equivalent keyboard key's description string.
215 In some cases, multiple levels of menus may be described.
216 A single vector slot containing nil indicates the start of a submenu.
217 A single vector slot containing lambda indicates the end of a submenu.
218 The submenu follows a menu item which is the way to reach the submenu.
220 A single vector slot containing quote indicates that the
221 following items should appear on the right of a dialog box.
223 Using a Lisp vector to hold this information while we decode it
224 takes care of protecting all the data from GC. */
226 #define MENU_ITEMS_PANE_NAME 1
227 #define MENU_ITEMS_PANE_PREFIX 2
228 #define MENU_ITEMS_PANE_LENGTH 3
232 MENU_ITEMS_ITEM_NAME
= 0,
233 MENU_ITEMS_ITEM_ENABLE
,
234 MENU_ITEMS_ITEM_VALUE
,
235 MENU_ITEMS_ITEM_EQUIV_KEY
,
236 MENU_ITEMS_ITEM_DEFINITION
,
237 MENU_ITEMS_ITEM_TYPE
,
238 MENU_ITEMS_ITEM_SELECTED
,
239 MENU_ITEMS_ITEM_HELP
,
240 MENU_ITEMS_ITEM_LENGTH
243 static Lisp_Object menu_items
;
245 /* Number of slots currently allocated in menu_items. */
246 static int menu_items_allocated
;
248 /* This is the index in menu_items of the first empty slot. */
249 static int menu_items_used
;
251 /* The number of panes currently recorded in menu_items,
252 excluding those within submenus. */
253 static int menu_items_n_panes
;
255 /* Current depth within submenus. */
256 static int menu_items_submenu_depth
;
258 /* This is set nonzero after the user activates the menu bar, and set
259 to zero again after the menu bars are redisplayed by prepare_menu_bar.
260 While it is nonzero, all calls to set_frame_menubar go deep.
262 I don't understand why this is needed, but it does seem to be
263 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
265 int pending_menu_activation
;
267 /* Initialize the menu_items structure if we haven't already done so.
268 Also mark it as currently empty. */
273 if (NILP (menu_items
))
275 menu_items_allocated
= 60;
276 menu_items
= Fmake_vector (make_number (menu_items_allocated
), Qnil
);
280 menu_items_n_panes
= 0;
281 menu_items_submenu_depth
= 0;
284 /* Call at the end of generating the data in menu_items. */
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 /* Args passed between single_keymap_panes and single_menu_item. */
426 Lisp_Object pending_maps
;
427 int maxdepth
, notreal
;
430 static void single_menu_item
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
433 /* This is a recursive subroutine of keymap_panes.
434 It handles one keymap, KEYMAP.
435 The other arguments are passed along
436 or point to local variables of the previous function.
437 If NOTREAL is nonzero, only check for equivalent key bindings, don't
438 evaluate expressions in menu items and don't make any menu.
440 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
443 single_keymap_panes (keymap
, pane_name
, prefix
, notreal
, maxdepth
)
445 Lisp_Object pane_name
;
453 skp
.pending_maps
= Qnil
;
454 skp
.maxdepth
= maxdepth
;
455 skp
.notreal
= notreal
;
460 push_menu_pane (pane_name
, prefix
);
462 GCPRO1 (skp
.pending_maps
);
463 map_keymap (keymap
, single_menu_item
, Qnil
, &skp
, 1);
466 /* Process now any submenus which want to be panes at this level. */
467 while (CONSP (skp
.pending_maps
))
469 Lisp_Object elt
, eltcdr
, string
;
470 elt
= XCAR (skp
.pending_maps
);
472 string
= XCAR (eltcdr
);
473 /* We no longer discard the @ from the beginning of the string here.
474 Instead, we do this in mac_menu_show. */
475 single_keymap_panes (Fcar (elt
), string
,
476 XCDR (eltcdr
), notreal
, maxdepth
- 1);
477 skp
.pending_maps
= XCDR (skp
.pending_maps
);
481 /* This is a subroutine of single_keymap_panes that handles one
483 KEY is a key in a keymap and ITEM is its binding.
484 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
486 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
487 evaluate expressions in menu items and don't make any menu.
488 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. */
491 single_menu_item (key
, item
, dummy
, skp_v
)
492 Lisp_Object key
, item
, dummy
;
495 Lisp_Object map
, item_string
, enabled
;
496 struct gcpro gcpro1
, gcpro2
;
498 struct skp
*skp
= skp_v
;
500 /* Parse the menu item and leave the result in item_properties. */
502 res
= parse_menu_item (item
, skp
->notreal
, 0);
505 return; /* Not a menu item. */
507 map
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_MAP
];
511 /* We don't want to make a menu, just traverse the keymaps to
512 precompute equivalent key bindings. */
514 single_keymap_panes (map
, Qnil
, key
, 1, skp
->maxdepth
- 1);
518 enabled
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_ENABLE
];
519 item_string
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_NAME
];
521 if (!NILP (map
) && SREF (item_string
, 0) == '@')
524 /* An enabled separate pane. Remember this to handle it later. */
525 skp
->pending_maps
= Fcons (Fcons (map
, Fcons (item_string
, key
)),
530 push_menu_item (item_string
, enabled
, key
,
531 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_DEF
],
532 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_KEYEQ
],
533 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_TYPE
],
534 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_SELECTED
],
535 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_HELP
]);
537 /* Display a submenu using the toolkit. */
538 if (! (NILP (map
) || NILP (enabled
)))
540 push_submenu_start ();
541 single_keymap_panes (map
, Qnil
, key
, 0, skp
->maxdepth
- 1);
546 /* Push all the panes and items of a menu described by the
547 alist-of-alists MENU.
548 This handles old-fashioned calls to x-popup-menu. */
558 for (tail
= menu
; CONSP (tail
); tail
= XCDR (tail
))
560 Lisp_Object elt
, pane_name
, pane_data
;
562 pane_name
= Fcar (elt
);
563 CHECK_STRING (pane_name
);
564 push_menu_pane (ENCODE_MENU_STRING (pane_name
), Qnil
);
565 pane_data
= Fcdr (elt
);
566 CHECK_CONS (pane_data
);
567 list_of_items (pane_data
);
570 finish_menu_items ();
573 /* Push the items in a single pane defined by the alist PANE. */
579 Lisp_Object tail
, item
, item1
;
581 for (tail
= pane
; CONSP (tail
); tail
= XCDR (tail
))
585 push_menu_item (ENCODE_MENU_STRING (item
), Qnil
, Qnil
, Qt
,
586 Qnil
, Qnil
, Qnil
, Qnil
);
587 else if (CONSP (item
))
590 CHECK_STRING (item1
);
591 push_menu_item (ENCODE_MENU_STRING (item1
), Qt
, XCDR (item
),
592 Qt
, Qnil
, Qnil
, Qnil
, Qnil
);
595 push_left_right_boundary ();
601 cleanup_popup_menu (arg
)
604 discard_menu_items ();
607 DEFUN ("x-popup-menu", Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
608 doc
: /* Pop up a deck-of-cards menu and return user's selection.
609 POSITION is a position specification. This is either a mouse button event
610 or a list ((XOFFSET YOFFSET) WINDOW)
611 where XOFFSET and YOFFSET are positions in pixels from the top left
612 corner of WINDOW. (WINDOW may be a window or a frame object.)
613 This controls the position of the top left of the menu as a whole.
614 If POSITION is t, it means to use the current mouse position.
616 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
617 The menu items come from key bindings that have a menu string as well as
618 a definition; actually, the "definition" in such a key binding looks like
619 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
620 the keymap as a top-level element.
622 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
623 Otherwise, REAL-DEFINITION should be a valid key binding definition.
625 You can also use a list of keymaps as MENU.
626 Then each keymap makes a separate pane.
628 When MENU is a keymap or a list of keymaps, the return value is the
629 list of events corresponding to the user's choice. Note that
630 `x-popup-menu' does not actually execute the command bound to that
633 Alternatively, you can specify a menu of multiple panes
634 with a list of the form (TITLE PANE1 PANE2...),
635 where each pane is a list of form (TITLE ITEM1 ITEM2...).
636 Each ITEM is normally a cons cell (STRING . VALUE);
637 but a string can appear as an item--that makes a nonselectable line
639 With this form of menu, the return value is VALUE from the chosen item.
641 If POSITION is nil, don't display the menu at all, just precalculate the
642 cached information about equivalent key sequences.
644 If the user gets rid of the menu without making a valid choice, for
645 instance by clicking the mouse away from a valid choice or by typing
646 keyboard input, then this normally results in a quit and
647 `x-popup-menu' does not return. But if POSITION is a mouse button
648 event (indicating that the user invoked the menu with the mouse) then
649 no quit occurs and `x-popup-menu' returns nil. */)
651 Lisp_Object position
, menu
;
653 Lisp_Object keymap
, tem
;
654 int xpos
= 0, ypos
= 0;
656 char *error_name
= NULL
;
657 Lisp_Object selection
;
659 Lisp_Object x
, y
, window
;
662 int specpdl_count
= SPECPDL_INDEX ();
666 if (! NILP (position
))
670 /* Decode the first argument: find the window and the coordinates. */
671 if (EQ (position
, Qt
)
672 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
673 || EQ (XCAR (position
), Qtool_bar
)
674 || EQ (XCAR (position
), Qmac_apple_event
))))
676 /* Use the mouse's current position. */
677 FRAME_PTR new_f
= SELECTED_FRAME ();
678 Lisp_Object bar_window
;
679 enum scroll_bar_part part
;
682 if (mouse_position_hook
)
683 (*mouse_position_hook
) (&new_f
, 1, &bar_window
,
684 &part
, &x
, &y
, &time
);
686 XSETFRAME (window
, new_f
);
689 window
= selected_window
;
696 tem
= Fcar (position
);
699 window
= Fcar (Fcdr (position
));
701 y
= Fcar (XCDR (tem
));
706 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
707 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
708 tem
= Fcar (Fcdr (Fcdr (tem
))); /* POSN_WINDOW_POSN (tem) */
717 /* Decode where to put the menu. */
725 else if (WINDOWP (window
))
727 CHECK_LIVE_WINDOW (window
);
728 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
730 xpos
= WINDOW_LEFT_EDGE_X (XWINDOW (window
));
731 ypos
= WINDOW_TOP_EDGE_Y (XWINDOW (window
));
734 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
735 but I don't want to make one now. */
736 CHECK_WINDOW (window
);
741 XSETFRAME (Vmenu_updating_frame
, f
);
744 Vmenu_updating_frame
= Qnil
;
745 #endif /* HAVE_MENUS */
750 /* Decode the menu items from what was specified. */
752 keymap
= get_keymap (menu
, 0, 0);
755 /* We were given a keymap. Extract menu info from the keymap. */
758 /* Extract the detailed info to make one pane. */
759 keymap_panes (&menu
, 1, NILP (position
));
761 /* Search for a string appearing directly as an element of the keymap.
762 That string is the title of the menu. */
763 prompt
= Fkeymap_prompt (keymap
);
764 if (NILP (title
) && !NILP (prompt
))
767 /* Make that be the pane title of the first pane. */
768 if (!NILP (prompt
) && menu_items_n_panes
>= 0)
769 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
773 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
775 /* We were given a list of keymaps. */
776 int nmaps
= XFASTINT (Flength (menu
));
778 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
783 /* The first keymap that has a prompt string
784 supplies the menu title. */
785 for (tem
= menu
, i
= 0; CONSP (tem
); tem
= XCDR (tem
))
789 maps
[i
++] = keymap
= get_keymap (XCAR (tem
), 1, 0);
791 prompt
= Fkeymap_prompt (keymap
);
792 if (NILP (title
) && !NILP (prompt
))
796 /* Extract the detailed info to make one pane. */
797 keymap_panes (maps
, nmaps
, NILP (position
));
799 /* Make the title be the pane title of the first pane. */
800 if (!NILP (title
) && menu_items_n_panes
>= 0)
801 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title
;
807 /* We were given an old-fashioned menu. */
809 CHECK_STRING (title
);
811 list_of_panes (Fcdr (menu
));
818 discard_menu_items ();
824 /* Display them in a menu. */
825 record_unwind_protect (cleanup_popup_menu
, Qnil
);
828 selection
= mac_menu_show (f
, xpos
, ypos
, for_click
,
829 keymaps
, title
, &error_name
);
831 unbind_to (specpdl_count
, Qnil
);
834 #endif /* HAVE_MENUS */
836 if (error_name
) error (error_name
);
842 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
843 doc
: /* Pop up a dialog box and return user's selection.
844 POSITION specifies which frame to use.
845 This is normally a mouse button event or a window or frame.
846 If POSITION is t, it means to use the frame the mouse is on.
847 The dialog box appears in the middle of the specified frame.
849 CONTENTS specifies the alternatives to display in the dialog box.
850 It is a list of the form (DIALOG ITEM1 ITEM2...).
851 Each ITEM is a cons cell (STRING . VALUE).
852 The return value is VALUE from the chosen item.
854 An ITEM may also be just a string--that makes a nonselectable item.
855 An ITEM may also be nil--that means to put all preceding items
856 on the left of the dialog box and all following items on the right.
857 \(By default, approximately half appear on each side.)
859 If HEADER is non-nil, the frame title for the box is "Information",
860 otherwise it is "Question".
862 If the user gets rid of the dialog box without making a valid choice,
863 for instance using the window manager, then this produces a quit and
864 `x-popup-dialog' does not return. */)
865 (position
, contents
, header
)
866 Lisp_Object position
, contents
, header
;
873 /* Decode the first argument: find the window or frame to use. */
874 if (EQ (position
, Qt
)
875 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
876 || EQ (XCAR (position
), Qtool_bar
)
877 || EQ (XCAR (position
), Qmac_apple_event
))))
879 #if 0 /* Using the frame the mouse is on may not be right. */
880 /* Use the mouse's current position. */
881 FRAME_PTR new_f
= SELECTED_FRAME ();
882 Lisp_Object bar_window
;
883 enum scroll_bar_part part
;
887 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
890 XSETFRAME (window
, new_f
);
892 window
= selected_window
;
894 window
= selected_window
;
896 else if (CONSP (position
))
899 tem
= Fcar (position
);
901 window
= Fcar (Fcdr (position
));
904 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
905 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
908 else if (WINDOWP (position
) || FRAMEP (position
))
913 /* Decode where to put the menu. */
917 else if (WINDOWP (window
))
919 CHECK_LIVE_WINDOW (window
);
920 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
923 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
924 but I don't want to make one now. */
925 CHECK_WINDOW (window
);
928 /* Display a menu with these alternatives
929 in the middle of frame F. */
931 Lisp_Object x
, y
, frame
, newpos
;
932 XSETFRAME (frame
, f
);
933 XSETINT (x
, x_pixel_width (f
) / 2);
934 XSETINT (y
, x_pixel_height (f
) / 2);
935 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
937 return Fx_popup_menu (newpos
,
938 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
940 #else /* HAVE_DIALOGS */
944 Lisp_Object selection
;
945 int specpdl_count
= SPECPDL_INDEX ();
947 /* Decode the dialog items from what was specified. */
948 title
= Fcar (contents
);
949 CHECK_STRING (title
);
951 list_of_panes (Fcons (contents
, Qnil
));
953 /* Display them in a dialog box. */
954 record_unwind_protect (cleanup_popup_menu
, Qnil
);
956 selection
= mac_dialog_show (f
, 0, title
, header
, &error_name
);
958 unbind_to (specpdl_count
, Qnil
);
960 if (error_name
) error (error_name
);
963 #endif /* HAVE_DIALOGS */
966 /* Activate the menu bar of frame F.
967 This is called from keyboard.c when it gets the
968 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
970 To activate the menu bar, we use the button-press event location
971 that was saved in saved_menu_event_location.
973 But first we recompute the menu bar contents (the whole tree).
975 The reason for saving the button event until here, instead of
976 passing it to the toolkit right away, is that we can safely
977 execute Lisp code. */
980 x_activate_menubar (f
)
984 extern Point saved_menu_event_location
;
986 set_frame_menubar (f
, 0, 1);
989 menu_choice
= MenuSelect (saved_menu_event_location
);
990 do_menu_choice (menu_choice
);
995 /* This callback is called from the menu bar pulldown menu
996 when the user makes a selection.
997 Figure out what the user chose
998 and put the appropriate events into the keyboard buffer. */
1001 menubar_selection_callback (FRAME_PTR f
, int client_data
)
1003 Lisp_Object prefix
, entry
;
1005 Lisp_Object
*subprefix_stack
;
1006 int submenu_depth
= 0;
1012 subprefix_stack
= (Lisp_Object
*) alloca (f
->menu_bar_items_used
* sizeof (Lisp_Object
));
1013 vector
= f
->menu_bar_vector
;
1016 while (i
< f
->menu_bar_items_used
)
1018 if (EQ (XVECTOR (vector
)->contents
[i
], Qnil
))
1020 subprefix_stack
[submenu_depth
++] = prefix
;
1024 else if (EQ (XVECTOR (vector
)->contents
[i
], Qlambda
))
1026 prefix
= subprefix_stack
[--submenu_depth
];
1029 else if (EQ (XVECTOR (vector
)->contents
[i
], Qt
))
1031 prefix
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1032 i
+= MENU_ITEMS_PANE_LENGTH
;
1036 entry
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1037 /* The EMACS_INT cast avoids a warning. There's no problem
1038 as long as pointers have enough bits to hold small integers. */
1039 if ((int) (EMACS_INT
) client_data
== i
)
1042 struct input_event buf
;
1046 XSETFRAME (frame
, f
);
1047 buf
.kind
= MENU_BAR_EVENT
;
1048 buf
.frame_or_window
= frame
;
1050 kbd_buffer_store_event (&buf
);
1052 for (j
= 0; j
< submenu_depth
; j
++)
1053 if (!NILP (subprefix_stack
[j
]))
1055 buf
.kind
= MENU_BAR_EVENT
;
1056 buf
.frame_or_window
= frame
;
1057 buf
.arg
= subprefix_stack
[j
];
1058 kbd_buffer_store_event (&buf
);
1063 buf
.kind
= MENU_BAR_EVENT
;
1064 buf
.frame_or_window
= frame
;
1066 kbd_buffer_store_event (&buf
);
1069 buf
.kind
= MENU_BAR_EVENT
;
1070 buf
.frame_or_window
= frame
;
1072 kbd_buffer_store_event (&buf
);
1074 f
->output_data
.mac
->menubar_active
= 0;
1077 i
+= MENU_ITEMS_ITEM_LENGTH
;
1080 f
->output_data
.mac
->menubar_active
= 0;
1083 /* Allocate a widget_value, blocking input. */
1086 xmalloc_widget_value ()
1088 widget_value
*value
;
1091 value
= malloc_widget_value ();
1097 /* This recursively calls free_widget_value on the tree of widgets.
1098 It must free all data that was malloc'ed for these widget_values.
1099 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1100 must be left alone. */
1103 free_menubar_widget_value_tree (wv
)
1108 wv
->name
= wv
->value
= wv
->key
= (char *) 0xDEADBEEF;
1110 if (wv
->contents
&& (wv
->contents
!= (widget_value
*)1))
1112 free_menubar_widget_value_tree (wv
->contents
);
1113 wv
->contents
= (widget_value
*) 0xDEADBEEF;
1117 free_menubar_widget_value_tree (wv
->next
);
1118 wv
->next
= (widget_value
*) 0xDEADBEEF;
1121 free_widget_value (wv
);
1125 /* Set up data in menu_items for a menu bar item
1126 whose event type is ITEM_KEY (with string ITEM_NAME)
1127 and whose contents come from the list of keymaps MAPS. */
1130 parse_single_submenu (item_key
, item_name
, maps
)
1131 Lisp_Object item_key
, item_name
, maps
;
1135 Lisp_Object
*mapvec
;
1137 int top_level_items
= 0;
1139 length
= Flength (maps
);
1140 len
= XINT (length
);
1142 /* Convert the list MAPS into a vector MAPVEC. */
1143 mapvec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1144 for (i
= 0; i
< len
; i
++)
1146 mapvec
[i
] = Fcar (maps
);
1150 /* Loop over the given keymaps, making a pane for each map.
1151 But don't make a pane that is empty--ignore that map instead. */
1152 for (i
= 0; i
< len
; i
++)
1154 if (!KEYMAPP (mapvec
[i
]))
1156 /* Here we have a command at top level in the menu bar
1157 as opposed to a submenu. */
1158 top_level_items
= 1;
1159 push_menu_pane (Qnil
, Qnil
);
1160 push_menu_item (item_name
, Qt
, item_key
, mapvec
[i
],
1161 Qnil
, Qnil
, Qnil
, Qnil
);
1166 prompt
= Fkeymap_prompt (mapvec
[i
]);
1167 single_keymap_panes (mapvec
[i
],
1168 !NILP (prompt
) ? prompt
: item_name
,
1173 return top_level_items
;
1176 /* Create a tree of widget_value objects
1177 representing the panes and items
1178 in menu_items starting at index START, up to index END. */
1180 static widget_value
*
1181 digest_single_submenu (start
, end
, top_level_items
)
1182 int start
, end
, top_level_items
;
1184 widget_value
*wv
, *prev_wv
, *save_wv
, *first_wv
;
1186 int submenu_depth
= 0;
1187 widget_value
**submenu_stack
;
1190 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1191 wv
= xmalloc_widget_value ();
1195 wv
->button_type
= BUTTON_TYPE_NONE
;
1201 /* Loop over all panes and items made by the preceding call
1202 to parse_single_submenu and construct a tree of widget_value objects.
1203 Ignore the panes and items used by previous calls to
1204 digest_single_submenu, even though those are also in menu_items. */
1208 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1210 submenu_stack
[submenu_depth
++] = save_wv
;
1215 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1218 save_wv
= submenu_stack
[--submenu_depth
];
1221 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1222 && submenu_depth
!= 0)
1223 i
+= MENU_ITEMS_PANE_LENGTH
;
1224 /* Ignore a nil in the item list.
1225 It's meaningful only for dialog boxes. */
1226 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1228 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1230 /* Create a new pane. */
1231 Lisp_Object pane_name
, prefix
;
1234 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
1235 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1237 #ifndef HAVE_MULTILINGUAL_MENU
1238 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1240 pane_name
= ENCODE_MENU_STRING (pane_name
);
1241 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1244 pane_string
= (NILP (pane_name
)
1245 ? "" : (char *) SDATA (pane_name
));
1246 /* If there is just one top-level pane, put all its items directly
1247 under the top-level menu. */
1248 if (menu_items_n_panes
== 1)
1251 /* If the pane has a meaningful name,
1252 make the pane a top-level menu item
1253 with its items as a submenu beneath it. */
1254 if (strcmp (pane_string
, ""))
1256 wv
= xmalloc_widget_value ();
1260 first_wv
->contents
= wv
;
1261 wv
->lname
= pane_name
;
1262 /* Set value to 1 so update_submenu_strings can handle '@' */
1263 wv
->value
= (char *)1;
1265 wv
->button_type
= BUTTON_TYPE_NONE
;
1273 i
+= MENU_ITEMS_PANE_LENGTH
;
1277 /* Create a new item within current pane. */
1278 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
;
1281 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1282 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1283 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1284 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1285 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1286 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1287 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1289 #ifndef HAVE_MULTILINGUAL_MENU
1290 if (STRING_MULTIBYTE (item_name
))
1292 item_name
= ENCODE_MENU_STRING (item_name
);
1293 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1296 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1298 descrip
= ENCODE_MENU_STRING (descrip
);
1299 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1301 #endif /* not HAVE_MULTILINGUAL_MENU */
1303 wv
= xmalloc_widget_value ();
1307 save_wv
->contents
= wv
;
1309 wv
->lname
= item_name
;
1310 if (!NILP (descrip
))
1313 /* The EMACS_INT cast avoids a warning. There's no problem
1314 as long as pointers have enough bits to hold small integers. */
1315 wv
->call_data
= (!NILP (def
) ? (void *) (EMACS_INT
) i
: 0);
1316 wv
->enabled
= !NILP (enable
);
1319 wv
->button_type
= BUTTON_TYPE_NONE
;
1320 else if (EQ (type
, QCradio
))
1321 wv
->button_type
= BUTTON_TYPE_RADIO
;
1322 else if (EQ (type
, QCtoggle
))
1323 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1327 wv
->selected
= !NILP (selected
);
1328 if (! STRINGP (help
))
1335 i
+= MENU_ITEMS_ITEM_LENGTH
;
1339 /* If we have just one "menu item"
1340 that was originally a button, return it by itself. */
1341 if (top_level_items
&& first_wv
->contents
&& first_wv
->contents
->next
== 0)
1343 wv
= first_wv
->contents
;
1344 free_widget_value (first_wv
);
1351 /* Walk through the widget_value tree starting at FIRST_WV and update
1352 the char * pointers from the corresponding lisp values.
1353 We do this after building the whole tree, since GC may happen while the
1354 tree is constructed, and small strings are relocated. So we must wait
1355 until no GC can happen before storing pointers into lisp values. */
1357 update_submenu_strings (first_wv
)
1358 widget_value
*first_wv
;
1362 for (wv
= first_wv
; wv
; wv
= wv
->next
)
1364 if (STRINGP (wv
->lname
))
1366 wv
->name
= SDATA (wv
->lname
);
1368 /* Ignore the @ that means "separate pane".
1369 This is a kludge, but this isn't worth more time. */
1370 if (wv
->value
== (char *)1)
1372 if (wv
->name
[0] == '@')
1378 if (STRINGP (wv
->lkey
))
1379 wv
->key
= SDATA (wv
->lkey
);
1382 update_submenu_strings (wv
->contents
);
1387 /* Event handler function that pops down a menu on C-g. We can only pop
1388 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1390 #ifdef HAVE_CANCELMENUTRACKING
1391 static pascal OSStatus
1392 menu_quit_handler (nextHandler
, theEvent
, userData
)
1393 EventHandlerCallRef nextHandler
;
1399 UInt32 keyModifiers
;
1400 extern int mac_quit_char_modifiers
;
1401 extern int mac_quit_char_keycode
;
1403 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
1404 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
1407 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
1408 typeUInt32
, NULL
, sizeof(UInt32
),
1409 NULL
, &keyModifiers
);
1411 if (err
== noErr
&& keyCode
== mac_quit_char_keycode
1412 && keyModifiers
== mac_quit_char_modifiers
)
1414 MenuRef menu
= userData
!= 0
1415 ? (MenuRef
)userData
: AcquireRootMenu ();
1417 CancelMenuTracking (menu
, true, 0);
1418 if (!userData
) ReleaseMenu (menu
);
1422 return CallNextEventHandler (nextHandler
, theEvent
);
1424 #endif /* HAVE_CANCELMENUTRACKING */
1426 /* Add event handler to all menus that belong to KIND so we can detect C-g.
1427 MENU_HANDLE is the root menu of the tracking session to dismiss
1428 when C-g is detected. NULL means the menu bar.
1429 If CancelMenuTracking isn't available, do nothing. */
1432 install_menu_quit_handler (kind
, menu_handle
)
1433 enum mac_menu_kind kind
;
1434 MenuHandle menu_handle
;
1436 #ifdef HAVE_CANCELMENUTRACKING
1437 EventTypeSpec typesList
[] = { { kEventClassKeyboard
, kEventRawKeyDown
} };
1440 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
1442 MenuHandle menu
= GetMenuHandle (id
);
1446 InstallMenuEventHandler (menu
, menu_quit_handler
,
1447 GetEventTypeCount (typesList
),
1448 typesList
, menu_handle
, NULL
);
1450 #endif /* HAVE_CANCELMENUTRACKING */
1453 /* Set the contents of the menubar widgets of frame F.
1454 The argument FIRST_TIME is currently ignored;
1455 it is set the first time this is called, from initialize_frame_menubar. */
1458 set_frame_menubar (f
, first_time
, deep_p
)
1463 int menubar_widget
= f
->output_data
.mac
->menubar_widget
;
1465 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1467 int *submenu_start
, *submenu_end
;
1468 int *submenu_top_level_items
, *submenu_n_panes
;
1470 /* We must not change the menubar when actually in use. */
1471 if (f
->output_data
.mac
->menubar_active
)
1474 XSETFRAME (Vmenu_updating_frame
, f
);
1476 if (! menubar_widget
)
1478 else if (pending_menu_activation
&& !deep_p
)
1483 /* Make a widget-value tree representing the entire menu trees. */
1485 struct buffer
*prev
= current_buffer
;
1487 int specpdl_count
= SPECPDL_INDEX ();
1488 int previous_menu_items_used
= f
->menu_bar_items_used
;
1489 Lisp_Object
*previous_items
1490 = (Lisp_Object
*) alloca (previous_menu_items_used
1491 * sizeof (Lisp_Object
));
1493 /* If we are making a new widget, its contents are empty,
1494 do always reinitialize them. */
1495 if (! menubar_widget
)
1496 previous_menu_items_used
= 0;
1498 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1499 specbind (Qinhibit_quit
, Qt
);
1500 /* Don't let the debugger step into this code
1501 because it is not reentrant. */
1502 specbind (Qdebug_on_next_call
, Qnil
);
1504 record_unwind_save_match_data ();
1505 if (NILP (Voverriding_local_map_menu_flag
))
1507 specbind (Qoverriding_terminal_local_map
, Qnil
);
1508 specbind (Qoverriding_local_map
, Qnil
);
1511 set_buffer_internal_1 (XBUFFER (buffer
));
1513 /* Run the Lucid hook. */
1514 safe_run_hooks (Qactivate_menubar_hook
);
1516 /* If it has changed current-menubar from previous value,
1517 really recompute the menubar from the value. */
1518 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1519 call0 (Qrecompute_lucid_menubar
);
1520 safe_run_hooks (Qmenu_bar_update_hook
);
1521 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1523 items
= FRAME_MENU_BAR_ITEMS (f
);
1525 /* Save the frame's previous menu bar contents data. */
1526 if (previous_menu_items_used
)
1527 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1528 previous_menu_items_used
* sizeof (Lisp_Object
));
1530 /* Fill in menu_items with the current menu bar contents.
1531 This can evaluate Lisp code. */
1532 menu_items
= f
->menu_bar_vector
;
1533 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1534 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1535 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1536 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1537 submenu_top_level_items
1538 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1540 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1542 Lisp_Object key
, string
, maps
;
1546 key
= XVECTOR (items
)->contents
[i
];
1547 string
= XVECTOR (items
)->contents
[i
+ 1];
1548 maps
= XVECTOR (items
)->contents
[i
+ 2];
1552 submenu_start
[i
] = menu_items_used
;
1554 menu_items_n_panes
= 0;
1555 submenu_top_level_items
[i
]
1556 = parse_single_submenu (key
, string
, maps
);
1557 submenu_n_panes
[i
] = menu_items_n_panes
;
1559 submenu_end
[i
] = menu_items_used
;
1562 finish_menu_items ();
1564 /* Convert menu_items into widget_value trees
1565 to display the menu. This cannot evaluate Lisp code. */
1567 wv
= xmalloc_widget_value ();
1568 wv
->name
= "menubar";
1571 wv
->button_type
= BUTTON_TYPE_NONE
;
1575 for (i
= 0; i
< last_i
; i
+= 4)
1577 menu_items_n_panes
= submenu_n_panes
[i
];
1578 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1579 submenu_top_level_items
[i
]);
1583 first_wv
->contents
= wv
;
1584 /* Don't set wv->name here; GC during the loop might relocate it. */
1586 wv
->button_type
= BUTTON_TYPE_NONE
;
1590 set_buffer_internal_1 (prev
);
1591 unbind_to (specpdl_count
, Qnil
);
1593 /* If there has been no change in the Lisp-level contents
1594 of the menu bar, skip redisplaying it. Just exit. */
1596 for (i
= 0; i
< previous_menu_items_used
; i
++)
1597 if (menu_items_used
== i
1598 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1600 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1602 free_menubar_widget_value_tree (first_wv
);
1603 discard_menu_items ();
1608 /* Now GC cannot happen during the lifetime of the widget_value,
1609 so it's safe to store data from a Lisp_String. */
1610 wv
= first_wv
->contents
;
1611 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1614 string
= XVECTOR (items
)->contents
[i
+ 1];
1617 wv
->name
= (char *) SDATA (string
);
1618 update_submenu_strings (wv
->contents
);
1622 f
->menu_bar_vector
= menu_items
;
1623 f
->menu_bar_items_used
= menu_items_used
;
1624 discard_menu_items ();
1628 /* Make a widget-value tree containing
1629 just the top level menu bar strings. */
1631 wv
= xmalloc_widget_value ();
1632 wv
->name
= "menubar";
1635 wv
->button_type
= BUTTON_TYPE_NONE
;
1639 items
= FRAME_MENU_BAR_ITEMS (f
);
1640 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1644 string
= XVECTOR (items
)->contents
[i
+ 1];
1648 wv
= xmalloc_widget_value ();
1649 wv
->name
= (char *) SDATA (string
);
1652 wv
->button_type
= BUTTON_TYPE_NONE
;
1654 /* This prevents lwlib from assuming this
1655 menu item is really supposed to be empty. */
1656 /* The EMACS_INT cast avoids a warning.
1657 This value just has to be different from small integers. */
1658 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1663 first_wv
->contents
= wv
;
1667 /* Forget what we thought we knew about what is in the
1668 detailed contents of the menu bar menus.
1669 Changing the top level always destroys the contents. */
1670 f
->menu_bar_items_used
= 0;
1673 /* Create or update the menu bar widget. */
1677 /* Non-null value to indicate menubar has already been "created". */
1678 f
->output_data
.mac
->menubar_widget
= 1;
1680 fill_menubar (first_wv
->contents
, deep_p
);
1682 /* Add event handler so we can detect C-g. */
1683 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
1684 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
1685 free_menubar_widget_value_tree (first_wv
);
1690 /* Get rid of the menu bar of frame F, and free its storage.
1691 This is used when deleting a frame, and when turning off the menu bar. */
1694 free_frame_menubar (f
)
1697 f
->output_data
.mac
->menubar_widget
= 0;
1705 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1706 FRAME_PTR f
= p
->pointer
;
1707 MenuHandle menu
= GetMenuHandle (min_menu_id
[MAC_MENU_POPUP
]);
1711 /* Must reset this manually because the button release event is not
1712 passed to Emacs event loop. */
1713 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
1715 /* delete all menus */
1716 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
1717 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
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;
1764 int specpdl_count
= SPECPDL_INDEX ();
1768 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1770 *error
= "Empty menu";
1774 /* Create a tree of widget_value objects
1775 representing the panes and their items. */
1776 wv
= xmalloc_widget_value ();
1780 wv
->button_type
= BUTTON_TYPE_NONE
;
1785 /* Loop over all panes and items, filling in the tree. */
1787 while (i
< menu_items_used
)
1789 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1791 submenu_stack
[submenu_depth
++] = save_wv
;
1797 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1800 save_wv
= submenu_stack
[--submenu_depth
];
1804 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1805 && submenu_depth
!= 0)
1806 i
+= MENU_ITEMS_PANE_LENGTH
;
1807 /* Ignore a nil in the item list.
1808 It's meaningful only for dialog boxes. */
1809 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1811 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1813 /* Create a new pane. */
1814 Lisp_Object pane_name
, prefix
;
1817 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1818 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1820 #ifndef HAVE_MULTILINGUAL_MENU
1821 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1823 pane_name
= ENCODE_MENU_STRING (pane_name
);
1824 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1827 pane_string
= (NILP (pane_name
)
1828 ? "" : (char *) SDATA (pane_name
));
1829 /* If there is just one top-level pane, put all its items directly
1830 under the top-level menu. */
1831 if (menu_items_n_panes
== 1)
1834 /* If the pane has a meaningful name,
1835 make the pane a top-level menu item
1836 with its items as a submenu beneath it. */
1837 if (!keymaps
&& strcmp (pane_string
, ""))
1839 wv
= xmalloc_widget_value ();
1843 first_wv
->contents
= wv
;
1844 wv
->name
= pane_string
;
1845 if (keymaps
&& !NILP (prefix
))
1849 wv
->button_type
= BUTTON_TYPE_NONE
;
1854 else if (first_pane
)
1860 i
+= MENU_ITEMS_PANE_LENGTH
;
1864 /* Create a new item within current pane. */
1865 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1866 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1867 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1868 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1869 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1870 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1871 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1872 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1874 #ifndef HAVE_MULTILINGUAL_MENU
1875 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1877 item_name
= ENCODE_MENU_STRING (item_name
);
1878 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1881 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1883 descrip
= ENCODE_MENU_STRING (descrip
);
1884 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1886 #endif /* not HAVE_MULTILINGUAL_MENU */
1888 wv
= xmalloc_widget_value ();
1892 save_wv
->contents
= wv
;
1893 wv
->name
= (char *) SDATA (item_name
);
1894 if (!NILP (descrip
))
1895 wv
->key
= (char *) SDATA (descrip
);
1897 /* Use the contents index as call_data, since we are
1898 restricted to 16-bits. */
1899 wv
->call_data
= !NILP (def
) ? (void *) (EMACS_INT
) i
: 0;
1900 wv
->enabled
= !NILP (enable
);
1903 wv
->button_type
= BUTTON_TYPE_NONE
;
1904 else if (EQ (type
, QCtoggle
))
1905 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1906 else if (EQ (type
, QCradio
))
1907 wv
->button_type
= BUTTON_TYPE_RADIO
;
1911 wv
->selected
= !NILP (selected
);
1913 if (! STRINGP (help
))
1920 i
+= MENU_ITEMS_ITEM_LENGTH
;
1924 /* Deal with the title, if it is non-nil. */
1927 widget_value
*wv_title
= xmalloc_widget_value ();
1928 widget_value
*wv_sep
= xmalloc_widget_value ();
1930 /* Maybe replace this separator with a bitmap or owner-draw item
1931 so that it looks better. Having two separators looks odd. */
1932 wv_sep
->name
= "--";
1933 wv_sep
->next
= first_wv
->contents
;
1934 wv_sep
->help
= Qnil
;
1936 #ifndef HAVE_MULTILINGUAL_MENU
1937 if (STRING_MULTIBYTE (title
))
1938 title
= ENCODE_MENU_STRING (title
);
1941 wv_title
->name
= (char *) SDATA (title
);
1942 wv_title
->enabled
= FALSE
;
1943 wv_title
->title
= TRUE
;
1944 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1945 wv_title
->help
= Qnil
;
1946 wv_title
->next
= wv_sep
;
1947 first_wv
->contents
= wv_title
;
1950 /* Actually create the menu. */
1951 menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
1952 InsertMenu (menu
, -1);
1953 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
1954 min_menu_id
[MAC_MENU_POPUP_SUB
]);
1956 /* Free the widget_value objects we used to specify the
1958 free_menubar_widget_value_tree (first_wv
);
1960 /* Adjust coordinates to be root-window-relative. */
1964 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1965 LocalToGlobal (&pos
);
1967 /* No selection has been chosen yet. */
1968 menu_item_choice
= 0;
1969 menu_item_selection
= 0;
1971 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
1973 /* Add event handler so we can detect C-g. */
1974 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
1975 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
1977 /* Display the menu. */
1978 menu_item_choice
= PopUpMenuSelect (menu
, pos
.v
, pos
.h
, 0);
1979 menu_item_selection
= LoWord (menu_item_choice
);
1981 /* Get the refcon to find the correct item */
1982 if (menu_item_selection
)
1984 MenuHandle sel_menu
= GetMenuHandle (HiWord (menu_item_choice
));
1986 GetMenuItemRefCon (sel_menu
, menu_item_selection
, &refcon
);
1989 else if (! for_click
)
1990 /* Make "Cancel" equivalent to C-g unless this menu was popped up by
1992 Fsignal (Qquit
, Qnil
);
1994 /* Find the selected item, and its pane, to return
1995 the proper value. */
1996 if (menu_item_selection
!= 0)
1998 Lisp_Object prefix
, entry
;
2000 prefix
= entry
= Qnil
;
2002 while (i
< menu_items_used
)
2004 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2006 subprefix_stack
[submenu_depth
++] = prefix
;
2010 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2012 prefix
= subprefix_stack
[--submenu_depth
];
2015 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2018 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2019 i
+= MENU_ITEMS_PANE_LENGTH
;
2021 /* Ignore a nil in the item list.
2022 It's meaningful only for dialog boxes. */
2023 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2028 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2029 if ((int) (EMACS_INT
) refcon
== i
)
2035 entry
= Fcons (entry
, Qnil
);
2037 entry
= Fcons (prefix
, entry
);
2038 for (j
= submenu_depth
- 1; j
>= 0; j
--)
2039 if (!NILP (subprefix_stack
[j
]))
2040 entry
= Fcons (subprefix_stack
[j
], entry
);
2044 i
+= MENU_ITEMS_ITEM_LENGTH
;
2048 else if (!for_click
)
2049 /* Make "Cancel" equivalent to C-g. */
2050 Fsignal (Qquit
, Qnil
);
2052 unbind_to (specpdl_count
, Qnil
);
2059 /* Construct native Mac OS menubar based on widget_value tree. */
2062 mac_dialog (widget_value
*wv
)
2066 char **button_labels
;
2073 WindowPtr window_ptr
;
2076 EventRecord event_record
;
2078 int control_part_code
;
2081 dialog_name
= wv
->name
;
2082 nb_buttons
= dialog_name
[1] - '0';
2083 left_count
= nb_buttons
- (dialog_name
[4] - '0');
2084 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
2085 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
2088 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
2089 strcpy (prompt
, wv
->value
);
2093 for (i
= 0; i
< nb_buttons
; i
++)
2095 button_labels
[i
] = wv
->value
;
2096 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
2097 strcpy (button_labels
[i
], wv
->value
);
2098 c2pstr (button_labels
[i
]);
2099 ref_cons
[i
] = (UInt32
) wv
->call_data
;
2103 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowPtr
) -1);
2105 SetPortWindowPort (window_ptr
);
2108 /* Left and right margins in the dialog are 13 pixels each.*/
2110 /* Calculate width of dialog box: 8 pixels on each side of the text
2111 label in each button, 12 pixels between buttons. */
2112 for (i
= 0; i
< nb_buttons
; i
++)
2113 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
2115 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
2118 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
2120 SizeWindow (window_ptr
, dialog_width
, 78, 0);
2121 ShowWindow (window_ptr
);
2123 SetPortWindowPort (window_ptr
);
2128 DrawString (prompt
);
2131 for (i
= 0; i
< nb_buttons
; i
++)
2133 int button_width
= StringWidth (button_labels
[i
]) + 16;
2134 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
2135 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
2136 kControlPushButtonProc
, ref_cons
[i
]);
2137 left
+= button_width
+ 12;
2138 if (i
== left_count
- 1)
2145 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
2146 if (event_record
.what
== mouseDown
)
2148 part_code
= FindWindow (event_record
.where
, &window_ptr
);
2149 if (part_code
== inContent
)
2151 mouse
= event_record
.where
;
2152 GlobalToLocal (&mouse
);
2153 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
2154 if (control_part_code
== kControlButtonPart
)
2155 if (TrackControl (ch
, mouse
, NULL
))
2156 i
= GetControlReference (ch
);
2161 DisposeWindow (window_ptr
);
2166 static char * button_names
[] = {
2167 "button1", "button2", "button3", "button4", "button5",
2168 "button6", "button7", "button8", "button9", "button10" };
2171 mac_dialog_show (f
, keymaps
, title
, header
, error_name
)
2174 Lisp_Object title
, header
;
2177 int i
, nb_buttons
=0;
2178 char dialog_name
[6];
2179 int menu_item_selection
;
2181 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2183 /* Number of elements seen so far, before boundary. */
2185 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2186 int boundary_seen
= 0;
2190 if (menu_items_n_panes
> 1)
2192 *error_name
= "Multiple panes in dialog box";
2196 /* Create a tree of widget_value objects
2197 representing the text label and buttons. */
2199 Lisp_Object pane_name
, prefix
;
2201 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2202 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2203 pane_string
= (NILP (pane_name
)
2204 ? "" : (char *) SDATA (pane_name
));
2205 prev_wv
= xmalloc_widget_value ();
2206 prev_wv
->value
= pane_string
;
2207 if (keymaps
&& !NILP (prefix
))
2209 prev_wv
->enabled
= 1;
2210 prev_wv
->name
= "message";
2211 prev_wv
->help
= Qnil
;
2214 /* Loop over all panes and items, filling in the tree. */
2215 i
= MENU_ITEMS_PANE_LENGTH
;
2216 while (i
< menu_items_used
)
2219 /* Create a new item within current pane. */
2220 Lisp_Object item_name
, enable
, descrip
;
2221 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2222 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2224 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2226 if (NILP (item_name
))
2228 free_menubar_widget_value_tree (first_wv
);
2229 *error_name
= "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_name
= "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
2307 the proper value. */
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
;
2324 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2326 /* This is the boundary between left-side elts and
2333 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2334 if (menu_item_selection
== i
)
2338 entry
= Fcons (entry
, Qnil
);
2340 entry
= Fcons (prefix
, entry
);
2344 i
+= MENU_ITEMS_ITEM_LENGTH
;
2349 /* Make "Cancel" equivalent to C-g. */
2350 Fsignal (Qquit
, Qnil
);
2354 #endif /* HAVE_DIALOGS */
2357 /* Is this item a separator? */
2359 name_is_separator (name
)
2364 /* Check if name string consists of only dashes ('-'). */
2365 while (*name
== '-') name
++;
2366 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2367 or "--deep-shadow". We don't implement them yet, se we just treat
2368 them like normal separators. */
2369 return (*name
== '\0' || start
+ 2 == name
);
2373 add_menu_item (menu
, pos
, wv
)
2378 #if TARGET_API_MAC_CARBON
2379 CFStringRef item_name
;
2384 if (name_is_separator (wv
->name
))
2385 AppendMenu (menu
, "\p-");
2388 AppendMenu (menu
, "\pX");
2390 #if TARGET_API_MAC_CARBON
2391 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
2393 if (wv
->key
!= NULL
)
2395 CFStringRef name
, key
;
2398 key
= cfstring_create_with_utf8_cstring (wv
->key
);
2399 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
2405 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
2406 CFRelease (item_name
);
2409 EnableMenuItem (menu
, pos
);
2411 DisableMenuItem (menu
, pos
);
2412 #else /* ! TARGET_API_MAC_CARBON */
2413 item_name
[sizeof (item_name
) - 1] = '\0';
2414 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
2415 if (wv
->key
!= NULL
)
2417 int len
= strlen (item_name
);
2419 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
2420 len
= strlen (item_name
);
2421 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
2424 SetMenuItemText (menu
, pos
, item_name
);
2427 EnableItem (menu
, pos
);
2429 DisableItem (menu
, pos
);
2430 #endif /* ! TARGET_API_MAC_CARBON */
2432 /* Draw radio buttons and tickboxes. */
2433 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
||
2434 wv
->button_type
== BUTTON_TYPE_RADIO
))
2435 SetItemMark (menu
, pos
, checkMark
);
2437 SetItemMark (menu
, pos
, noMark
);
2439 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
2443 /* Construct native Mac OS menu based on widget_value tree. */
2446 fill_menu (menu
, wv
, kind
, submenu_id
)
2449 enum mac_menu_kind kind
;
2454 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
2456 add_menu_item (menu
, pos
, wv
);
2457 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
2459 MenuHandle submenu
= NewMenu (submenu_id
, "\pX");
2461 InsertMenu (submenu
, -1);
2462 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
2463 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
2470 /* Construct native Mac OS menubar based on widget_value tree. */
2473 fill_menubar (wv
, deep_p
)
2480 #if !TARGET_API_MAC_CARBON
2481 int title_changed_p
= 0;
2484 /* Clean up the menu bar when filled by the entire menu trees. */
2487 dispose_menus (MAC_MENU_MENU_BAR
, 0);
2488 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
2489 #if !TARGET_API_MAC_CARBON
2490 title_changed_p
= 1;
2494 /* Fill menu bar titles and submenus. Reuse the existing menu bar
2495 titles as much as possible to minimize redraw (if !deep_p). */
2496 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
2497 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
2498 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
2499 wv
= wv
->next
, id
++)
2501 strncpy (title
, wv
->name
, 255);
2505 menu
= GetMenuHandle (id
);
2508 #if TARGET_API_MAC_CARBON
2511 GetMenuTitle (menu
, old_title
);
2512 if (!EqualString (title
, old_title
, false, false))
2513 SetMenuTitle (menu
, title
);
2514 #else /* !TARGET_API_MAC_CARBON */
2515 if (!EqualString (title
, (*menu
)->menuData
, false, false))
2519 menu
= NewMenu (id
, title
);
2520 InsertMenu (menu
, GetMenuHandle (id
+ 1) ? id
+ 1 : 0);
2521 title_changed_p
= 1;
2523 #endif /* !TARGET_API_MAC_CARBON */
2527 menu
= NewMenu (id
, title
);
2528 InsertMenu (menu
, 0);
2529 #if !TARGET_API_MAC_CARBON
2530 title_changed_p
= 1;
2535 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
2539 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuHandle (id
))
2541 dispose_menus (MAC_MENU_MENU_BAR
, id
);
2542 #if !TARGET_API_MAC_CARBON
2543 title_changed_p
= 1;
2547 #if !TARGET_API_MAC_CARBON
2548 if (title_changed_p
)
2553 /* Dispose of menus that belong to KIND, and remove them from the menu
2554 list. ID is the lower bound of menu IDs that will be processed. */
2557 dispose_menus (kind
, id
)
2558 enum mac_menu_kind kind
;
2561 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
2563 MenuHandle menu
= GetMenuHandle (id
);
2572 #endif /* HAVE_MENUS */
2577 staticpro (&menu_items
);
2580 Qdebug_on_next_call
= intern ("debug-on-next-call");
2581 staticpro (&Qdebug_on_next_call
);
2583 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame
,
2584 doc
: /* Frame for which we are updating a menu.
2585 The enable predicate for a menu command should check this variable. */);
2586 Vmenu_updating_frame
= Qnil
;
2588 defsubr (&Sx_popup_menu
);
2590 defsubr (&Sx_popup_dialog
);
2594 /* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce
2595 (do not change this comment) */