1 /* Menu support for GNU Emacs on Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 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 3, 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). */
30 #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 .. 233 */
68 MAC_MENU_M_APPLE
, /* 234 (== M_APPLE) */
69 MAC_MENU_POPUP
, /* 235 */
70 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
71 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
72 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
73 MAC_MENU_END
/* 32768 */
76 static const int min_menu_id
[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
78 #define DIALOG_WINDOW_RESOURCE 130
80 #if TARGET_API_MAC_CARBON
81 #define HAVE_DIALOGS 1
84 #undef HAVE_MULTILINGUAL_MENU
86 /******************************************************************/
87 /* Definitions copied from lwlib.h */
89 typedef void * XtPointer
;
98 /* This structure is based on the one in ../lwlib/lwlib.h, modified
100 typedef struct _widget_value
105 /* value (meaning depend on widget type) */
107 /* keyboard equivalent. no implications for XtTranslations */
110 /* Help string or nil if none.
111 GC finds this string through the frame's menu_bar_vector
112 or through menu_items. */
114 /* true if enabled */
116 /* true if selected */
118 /* The type of a button. */
119 enum button_type button_type
;
120 /* true if menu title */
123 /* true if was edited (maintained by get_value) */
125 /* true if has changed (maintained by lw library) */
127 /* true if this widget itself has changed,
128 but not counting the other widgets found in the `next' field. */
129 change_type this_one_change
;
131 /* Contents of the sub-widgets, also selected slot for checkbox */
132 struct _widget_value
* contents
;
133 /* data passed to callback */
135 /* next one in the list */
136 struct _widget_value
* next
;
138 /* slot for the toolkit dependent part. Always initialize to NULL. */
140 /* tell us if we should free the toolkit data slot when freeing the
141 widget_value itself. */
142 Boolean free_toolkit_data
;
144 /* we resource the widget_value structures; this points to the next
145 one on the free list if this one has been deallocated.
147 struct _widget_value
*free_list
;
151 /* Assumed by other routines to zero area returned. */
152 #define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
153 0, (sizeof (widget_value)))
154 #define free_widget_value(wv) xfree (wv)
156 /******************************************************************/
163 Lisp_Object Qdebug_on_next_call
;
165 extern Lisp_Object Vmenu_updating_frame
;
167 extern Lisp_Object Qmenu_bar
, Qmac_apple_event
;
169 extern Lisp_Object QCtoggle
, QCradio
;
171 extern Lisp_Object Voverriding_local_map
;
172 extern Lisp_Object Voverriding_local_map_menu_flag
;
174 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
176 extern Lisp_Object Qmenu_bar_update_hook
;
178 void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
180 #if TARGET_API_MAC_CARBON
181 #define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
183 #define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
186 static void push_menu_item
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
187 Lisp_Object
, Lisp_Object
, Lisp_Object
,
188 Lisp_Object
, Lisp_Object
));
190 static Lisp_Object mac_dialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
,
191 Lisp_Object
, char **));
193 static Lisp_Object mac_menu_show
P_ ((struct frame
*, int, int, int, int,
194 Lisp_Object
, char **));
195 static void keymap_panes
P_ ((Lisp_Object
*, int, int));
196 static void single_keymap_panes
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
198 static void list_of_panes
P_ ((Lisp_Object
));
199 static void list_of_items
P_ ((Lisp_Object
));
201 static void find_and_call_menu_selection
P_ ((FRAME_PTR
, int, Lisp_Object
,
203 static int fill_menu
P_ ((MenuRef
, widget_value
*, enum mac_menu_kind
, int));
204 static void fill_menubar
P_ ((widget_value
*, int));
205 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
208 /* This holds a Lisp vector that holds the results of decoding
209 the keymaps or alist-of-alists that specify a menu.
211 It describes the panes and items within the panes.
213 Each pane is described by 3 elements in the vector:
214 t, the pane name, the pane's prefix key.
215 Then follow the pane's items, with 5 elements per item:
216 the item string, the enable flag, the item's value,
217 the definition, and the equivalent keyboard key's description string.
219 In some cases, multiple levels of menus may be described.
220 A single vector slot containing nil indicates the start of a submenu.
221 A single vector slot containing lambda indicates the end of a submenu.
222 The submenu follows a menu item which is the way to reach the submenu.
224 A single vector slot containing quote indicates that the
225 following items should appear on the right of a dialog box.
227 Using a Lisp vector to hold this information while we decode it
228 takes care of protecting all the data from GC. */
230 #define MENU_ITEMS_PANE_NAME 1
231 #define MENU_ITEMS_PANE_PREFIX 2
232 #define MENU_ITEMS_PANE_LENGTH 3
236 MENU_ITEMS_ITEM_NAME
= 0,
237 MENU_ITEMS_ITEM_ENABLE
,
238 MENU_ITEMS_ITEM_VALUE
,
239 MENU_ITEMS_ITEM_EQUIV_KEY
,
240 MENU_ITEMS_ITEM_DEFINITION
,
241 MENU_ITEMS_ITEM_TYPE
,
242 MENU_ITEMS_ITEM_SELECTED
,
243 MENU_ITEMS_ITEM_HELP
,
244 MENU_ITEMS_ITEM_LENGTH
247 static Lisp_Object menu_items
;
249 /* Number of slots currently allocated in menu_items. */
250 static int menu_items_allocated
;
252 /* This is the index in menu_items of the first empty slot. */
253 static int menu_items_used
;
255 /* The number of panes currently recorded in menu_items,
256 excluding those within submenus. */
257 static int menu_items_n_panes
;
259 /* Current depth within submenus. */
260 static int menu_items_submenu_depth
;
262 /* Nonzero means a menu is currently active. */
263 static int popup_activated_flag
;
265 /* This is set nonzero after the user activates the menu bar, and set
266 to zero again after the menu bars are redisplayed by prepare_menu_bar.
267 While it is nonzero, all calls to set_frame_menubar go deep.
269 I don't understand why this is needed, but it does seem to be
270 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
272 int pending_menu_activation
;
274 /* Initialize the menu_items structure if we haven't already done so.
275 Also mark it as currently empty. */
280 if (NILP (menu_items
))
282 menu_items_allocated
= 60;
283 menu_items
= Fmake_vector (make_number (menu_items_allocated
), Qnil
);
287 menu_items_n_panes
= 0;
288 menu_items_submenu_depth
= 0;
291 /* Call at the end of generating the data in menu_items. */
298 /* Call when finished using the data for the current menu
302 discard_menu_items ()
304 /* Free the structure if it is especially large.
305 Otherwise, hold on to it, to save time. */
306 if (menu_items_allocated
> 200)
309 menu_items_allocated
= 0;
313 /* This undoes save_menu_items, and it is called by the specpdl unwind
317 restore_menu_items (saved
)
320 menu_items
= XCAR (saved
);
321 menu_items_allocated
= (VECTORP (menu_items
) ? ASIZE (menu_items
) : 0);
322 saved
= XCDR (saved
);
323 menu_items_used
= XINT (XCAR (saved
));
324 saved
= XCDR (saved
);
325 menu_items_n_panes
= XINT (XCAR (saved
));
326 saved
= XCDR (saved
);
327 menu_items_submenu_depth
= XINT (XCAR (saved
));
331 /* Push the whole state of menu_items processing onto the specpdl.
332 It will be restored when the specpdl is unwound. */
337 Lisp_Object saved
= list4 (menu_items
,
338 make_number (menu_items_used
),
339 make_number (menu_items_n_panes
),
340 make_number (menu_items_submenu_depth
));
341 record_unwind_protect (restore_menu_items
, saved
);
345 /* Make the menu_items vector twice as large. */
350 menu_items_allocated
*= 2;
351 menu_items
= larger_vector (menu_items
, menu_items_allocated
, Qnil
);
354 /* Begin a submenu. */
357 push_submenu_start ()
359 if (menu_items_used
+ 1 > menu_items_allocated
)
362 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qnil
;
363 menu_items_submenu_depth
++;
371 if (menu_items_used
+ 1 > menu_items_allocated
)
374 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qlambda
;
375 menu_items_submenu_depth
--;
378 /* Indicate boundary between left and right. */
381 push_left_right_boundary ()
383 if (menu_items_used
+ 1 > menu_items_allocated
)
386 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qquote
;
389 /* Start a new menu pane in menu_items.
390 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
393 push_menu_pane (name
, prefix_vec
)
394 Lisp_Object name
, prefix_vec
;
396 if (menu_items_used
+ MENU_ITEMS_PANE_LENGTH
> menu_items_allocated
)
399 if (menu_items_submenu_depth
== 0)
400 menu_items_n_panes
++;
401 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qt
;
402 XVECTOR (menu_items
)->contents
[menu_items_used
++] = name
;
403 XVECTOR (menu_items
)->contents
[menu_items_used
++] = prefix_vec
;
406 /* Push one menu item into the current pane. NAME is the string to
407 display. ENABLE if non-nil means this item can be selected. KEY
408 is the key generated by choosing this item, or nil if this item
409 doesn't really have a definition. DEF is the definition of this
410 item. EQUIV is the textual description of the keyboard equivalent
411 for this item (or nil if none). TYPE is the type of this menu
412 item, one of nil, `toggle' or `radio'. */
415 push_menu_item (name
, enable
, key
, def
, equiv
, type
, selected
, help
)
416 Lisp_Object name
, enable
, key
, def
, equiv
, type
, selected
, help
;
418 if (menu_items_used
+ MENU_ITEMS_ITEM_LENGTH
> menu_items_allocated
)
421 XVECTOR (menu_items
)->contents
[menu_items_used
++] = name
;
422 XVECTOR (menu_items
)->contents
[menu_items_used
++] = enable
;
423 XVECTOR (menu_items
)->contents
[menu_items_used
++] = key
;
424 XVECTOR (menu_items
)->contents
[menu_items_used
++] = equiv
;
425 XVECTOR (menu_items
)->contents
[menu_items_used
++] = def
;
426 XVECTOR (menu_items
)->contents
[menu_items_used
++] = type
;
427 XVECTOR (menu_items
)->contents
[menu_items_used
++] = selected
;
428 XVECTOR (menu_items
)->contents
[menu_items_used
++] = help
;
431 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
432 and generate menu panes for them in menu_items.
433 If NOTREAL is nonzero,
434 don't bother really computing whether an item is enabled. */
437 keymap_panes (keymaps
, nmaps
, notreal
)
438 Lisp_Object
*keymaps
;
446 /* Loop over the given keymaps, making a pane for each map.
447 But don't make a pane that is empty--ignore that map instead.
448 P is the number of panes we have made so far. */
449 for (mapno
= 0; mapno
< nmaps
; mapno
++)
450 single_keymap_panes (keymaps
[mapno
],
451 Fkeymap_prompt (keymaps
[mapno
]), Qnil
, notreal
, 10);
453 finish_menu_items ();
456 /* Args passed between single_keymap_panes and single_menu_item. */
459 Lisp_Object pending_maps
;
460 int maxdepth
, notreal
;
463 static void single_menu_item
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
466 /* This is a recursive subroutine of keymap_panes.
467 It handles one keymap, KEYMAP.
468 The other arguments are passed along
469 or point to local variables of the previous function.
470 If NOTREAL is nonzero, only check for equivalent key bindings, don't
471 evaluate expressions in menu items and don't make any menu.
473 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
476 single_keymap_panes (keymap
, pane_name
, prefix
, notreal
, maxdepth
)
478 Lisp_Object pane_name
;
486 skp
.pending_maps
= Qnil
;
487 skp
.maxdepth
= maxdepth
;
488 skp
.notreal
= notreal
;
493 push_menu_pane (pane_name
, prefix
);
495 GCPRO1 (skp
.pending_maps
);
496 map_keymap (keymap
, single_menu_item
, Qnil
, &skp
, 1);
499 /* Process now any submenus which want to be panes at this level. */
500 while (CONSP (skp
.pending_maps
))
502 Lisp_Object elt
, eltcdr
, string
;
503 elt
= XCAR (skp
.pending_maps
);
505 string
= XCAR (eltcdr
);
506 /* We no longer discard the @ from the beginning of the string here.
507 Instead, we do this in mac_menu_show. */
508 single_keymap_panes (Fcar (elt
), string
,
509 XCDR (eltcdr
), notreal
, maxdepth
- 1);
510 skp
.pending_maps
= XCDR (skp
.pending_maps
);
514 /* This is a subroutine of single_keymap_panes that handles one
516 KEY is a key in a keymap and ITEM is its binding.
517 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
519 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
520 evaluate expressions in menu items and don't make any menu.
521 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. */
524 single_menu_item (key
, item
, dummy
, skp_v
)
525 Lisp_Object key
, item
, dummy
;
528 Lisp_Object map
, item_string
, enabled
;
529 struct gcpro gcpro1
, gcpro2
;
531 struct skp
*skp
= skp_v
;
533 /* Parse the menu item and leave the result in item_properties. */
535 res
= parse_menu_item (item
, skp
->notreal
, 0);
538 return; /* Not a menu item. */
540 map
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_MAP
];
544 /* We don't want to make a menu, just traverse the keymaps to
545 precompute equivalent key bindings. */
547 single_keymap_panes (map
, Qnil
, key
, 1, skp
->maxdepth
- 1);
551 enabled
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_ENABLE
];
552 item_string
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_NAME
];
554 if (!NILP (map
) && SREF (item_string
, 0) == '@')
557 /* An enabled separate pane. Remember this to handle it later. */
558 skp
->pending_maps
= Fcons (Fcons (map
, Fcons (item_string
, key
)),
563 push_menu_item (item_string
, enabled
, key
,
564 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_DEF
],
565 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_KEYEQ
],
566 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_TYPE
],
567 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_SELECTED
],
568 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_HELP
]);
570 /* Display a submenu using the toolkit. */
571 if (! (NILP (map
) || NILP (enabled
)))
573 push_submenu_start ();
574 single_keymap_panes (map
, Qnil
, key
, 0, skp
->maxdepth
- 1);
579 /* Push all the panes and items of a menu described by the
580 alist-of-alists MENU.
581 This handles old-fashioned calls to x-popup-menu. */
591 for (tail
= menu
; CONSP (tail
); tail
= XCDR (tail
))
593 Lisp_Object elt
, pane_name
, pane_data
;
595 pane_name
= Fcar (elt
);
596 CHECK_STRING (pane_name
);
597 push_menu_pane (ENCODE_MENU_STRING (pane_name
), Qnil
);
598 pane_data
= Fcdr (elt
);
599 CHECK_CONS (pane_data
);
600 list_of_items (pane_data
);
603 finish_menu_items ();
606 /* Push the items in a single pane defined by the alist PANE. */
612 Lisp_Object tail
, item
, item1
;
614 for (tail
= pane
; CONSP (tail
); tail
= XCDR (tail
))
618 push_menu_item (ENCODE_MENU_STRING (item
), Qnil
, Qnil
, Qt
,
619 Qnil
, Qnil
, Qnil
, Qnil
);
620 else if (CONSP (item
))
623 CHECK_STRING (item1
);
624 push_menu_item (ENCODE_MENU_STRING (item1
), Qt
, XCDR (item
),
625 Qt
, Qnil
, Qnil
, Qnil
, Qnil
);
628 push_left_right_boundary ();
634 cleanup_popup_menu (arg
)
637 discard_menu_items ();
641 DEFUN ("x-popup-menu", Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
642 doc
: /* Pop up a deck-of-cards menu and return user's selection.
643 POSITION is a position specification. This is either a mouse button event
644 or a list ((XOFFSET YOFFSET) WINDOW)
645 where XOFFSET and YOFFSET are positions in pixels from the top left
646 corner of WINDOW. (WINDOW may be a window or a frame object.)
647 This controls the position of the top left of the menu as a whole.
648 If POSITION is t, it means to use the current mouse position.
650 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
651 The menu items come from key bindings that have a menu string as well as
652 a definition; actually, the "definition" in such a key binding looks like
653 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
654 the keymap as a top-level element.
656 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
657 Otherwise, REAL-DEFINITION should be a valid key binding definition.
659 You can also use a list of keymaps as MENU.
660 Then each keymap makes a separate pane.
662 When MENU is a keymap or a list of keymaps, the return value is the
663 list of events corresponding to the user's choice. Note that
664 `x-popup-menu' does not actually execute the command bound to that
667 Alternatively, you can specify a menu of multiple panes
668 with a list of the form (TITLE PANE1 PANE2...),
669 where each pane is a list of form (TITLE ITEM1 ITEM2...).
670 Each ITEM is normally a cons cell (STRING . VALUE);
671 but a string can appear as an item--that makes a nonselectable line
673 With this form of menu, the return value is VALUE from the chosen item.
675 If POSITION is nil, don't display the menu at all, just precalculate the
676 cached information about equivalent key sequences.
678 If the user gets rid of the menu without making a valid choice, for
679 instance by clicking the mouse away from a valid choice or by typing
680 keyboard input, then this normally results in a quit and
681 `x-popup-menu' does not return. But if POSITION is a mouse button
682 event (indicating that the user invoked the menu with the mouse) then
683 no quit occurs and `x-popup-menu' returns nil. */)
685 Lisp_Object position
, menu
;
687 Lisp_Object keymap
, tem
;
688 int xpos
= 0, ypos
= 0;
690 char *error_name
= NULL
;
691 Lisp_Object selection
;
693 Lisp_Object x
, y
, window
;
696 int specpdl_count
= SPECPDL_INDEX ();
700 if (! NILP (position
))
704 /* Decode the first argument: find the window and the coordinates. */
705 if (EQ (position
, Qt
)
706 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
707 || EQ (XCAR (position
), Qtool_bar
)
708 || EQ (XCAR (position
), Qmac_apple_event
))))
710 /* Use the mouse's current position. */
711 FRAME_PTR new_f
= SELECTED_FRAME ();
712 Lisp_Object bar_window
;
713 enum scroll_bar_part part
;
716 if (FRAME_TERMINAL (new_f
)->mouse_position_hook
)
717 (*FRAME_TERMINAL (new_f
)->mouse_position_hook
) (&new_f
, 1, &bar_window
,
718 &part
, &x
, &y
, &time
);
720 XSETFRAME (window
, new_f
);
723 window
= selected_window
;
730 tem
= Fcar (position
);
733 window
= Fcar (Fcdr (position
));
735 y
= Fcar (XCDR (tem
));
740 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
741 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
742 tem
= Fcar (Fcdr (Fcdr (tem
))); /* POSN_WINDOW_POSN (tem) */
751 /* Decode where to put the menu. */
759 else if (WINDOWP (window
))
761 CHECK_LIVE_WINDOW (window
);
762 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
764 xpos
= WINDOW_LEFT_EDGE_X (XWINDOW (window
));
765 ypos
= WINDOW_TOP_EDGE_Y (XWINDOW (window
));
768 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
769 but I don't want to make one now. */
770 CHECK_WINDOW (window
);
775 XSETFRAME (Vmenu_updating_frame
, f
);
778 Vmenu_updating_frame
= Qnil
;
779 #endif /* HAVE_MENUS */
784 /* Decode the menu items from what was specified. */
786 keymap
= get_keymap (menu
, 0, 0);
789 /* We were given a keymap. Extract menu info from the keymap. */
792 /* Extract the detailed info to make one pane. */
793 keymap_panes (&menu
, 1, NILP (position
));
795 /* Search for a string appearing directly as an element of the keymap.
796 That string is the title of the menu. */
797 prompt
= Fkeymap_prompt (keymap
);
798 if (NILP (title
) && !NILP (prompt
))
801 /* Make that be the pane title of the first pane. */
802 if (!NILP (prompt
) && menu_items_n_panes
>= 0)
803 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
807 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
809 /* We were given a list of keymaps. */
810 int nmaps
= XFASTINT (Flength (menu
));
812 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
817 /* The first keymap that has a prompt string
818 supplies the menu title. */
819 for (tem
= menu
, i
= 0; CONSP (tem
); tem
= XCDR (tem
))
823 maps
[i
++] = keymap
= get_keymap (XCAR (tem
), 1, 0);
825 prompt
= Fkeymap_prompt (keymap
);
826 if (NILP (title
) && !NILP (prompt
))
830 /* Extract the detailed info to make one pane. */
831 keymap_panes (maps
, nmaps
, NILP (position
));
833 /* Make the title be the pane title of the first pane. */
834 if (!NILP (title
) && menu_items_n_panes
>= 0)
835 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title
;
841 /* We were given an old-fashioned menu. */
843 CHECK_STRING (title
);
845 list_of_panes (Fcdr (menu
));
852 discard_menu_items ();
858 /* Display them in a menu. */
859 record_unwind_protect (cleanup_popup_menu
, Qnil
);
862 selection
= mac_menu_show (f
, xpos
, ypos
, for_click
,
863 keymaps
, title
, &error_name
);
865 unbind_to (specpdl_count
, Qnil
);
868 #endif /* HAVE_MENUS */
870 if (error_name
) error (error_name
);
876 /* Regard ESC and C-g as Cancel even without the Cancel button. */
878 #if 0 /* defined (MAC_OSX) */
880 mac_dialog_modal_filter (dialog
, event
, item_hit
)
883 DialogItemIndex
*item_hit
;
887 result
= StdFilterProc (dialog
, event
, item_hit
);
889 && (event
->what
== keyDown
|| event
->what
== autoKey
)
890 && ((event
->message
& charCodeMask
) == kEscapeCharCode
891 || mac_quit_char_key_p (event
->modifiers
,
892 (event
->message
& keyCodeMask
) >> 8)))
894 *item_hit
= kStdCancelItemIndex
;
902 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
903 doc
: /* Pop up a dialog box and return user's selection.
904 POSITION specifies which frame to use.
905 This is normally a mouse button event or a window or frame.
906 If POSITION is t, it means to use the frame the mouse is on.
907 The dialog box appears in the middle of the specified frame.
909 CONTENTS specifies the alternatives to display in the dialog box.
910 It is a list of the form (DIALOG ITEM1 ITEM2...).
911 Each ITEM is a cons cell (STRING . VALUE).
912 The return value is VALUE from the chosen item.
914 An ITEM may also be just a string--that makes a nonselectable item.
915 An ITEM may also be nil--that means to put all preceding items
916 on the left of the dialog box and all following items on the right.
917 \(By default, approximately half appear on each side.)
919 If HEADER is non-nil, the frame title for the box is "Information",
920 otherwise it is "Question".
922 If the user gets rid of the dialog box without making a valid choice,
923 for instance using the window manager, then this produces a quit and
924 `x-popup-dialog' does not return. */)
925 (position
, contents
, header
)
926 Lisp_Object position
, contents
, header
;
933 /* Decode the first argument: find the window or frame to use. */
934 if (EQ (position
, Qt
)
935 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
936 || EQ (XCAR (position
), Qtool_bar
)
937 || EQ (XCAR (position
), Qmac_apple_event
))))
939 #if 0 /* Using the frame the mouse is on may not be right. */
940 /* Use the mouse's current position. */
941 FRAME_PTR new_f
= SELECTED_FRAME ();
942 Lisp_Object bar_window
;
943 enum scroll_bar_part part
;
947 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
950 XSETFRAME (window
, new_f
);
952 window
= selected_window
;
954 window
= selected_window
;
956 else if (CONSP (position
))
959 tem
= Fcar (position
);
961 window
= Fcar (Fcdr (position
));
964 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
965 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
968 else if (WINDOWP (position
) || FRAMEP (position
))
973 /* Decode where to put the menu. */
977 else if (WINDOWP (window
))
979 CHECK_LIVE_WINDOW (window
);
980 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
983 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
984 but I don't want to make one now. */
985 CHECK_WINDOW (window
);
987 #if 0 /* defined (MAC_OSX) */
988 /* Special treatment for Fmessage_box, Fyes_or_no_p, and Fy_or_n_p. */
989 if (EQ (position
, Qt
)
990 && STRINGP (Fcar (contents
))
991 && ((!NILP (Fequal (XCDR (contents
),
992 Fcons (Fcons (build_string ("OK"), Qt
), Qnil
)))
994 || (!NILP (Fequal (XCDR (contents
),
995 Fcons (Fcons (build_string ("Yes"), Qt
),
996 Fcons (Fcons (build_string ("No"), Qnil
),
1000 OSStatus err
= noErr
;
1001 AlertStdCFStringAlertParamRec param
;
1002 CFStringRef error_string
, explanation_string
;
1004 DialogItemIndex item_hit
;
1007 /* Force a redisplay before showing the dialog. If a frame is
1008 created just before showing the dialog, its contents may not
1009 have been fully drawn. */
1012 tem
= Fstring_match (concat3 (build_string ("\\("),
1013 call0 (intern ("sentence-end")),
1014 build_string ("\\)\n")),
1015 XCAR (contents
), Qnil
);
1019 error_string
= cfstring_create_with_string (XCAR (contents
));
1020 if (error_string
== NULL
)
1022 explanation_string
= NULL
;
1026 tem
= Fmatch_end (make_number (1));
1028 cfstring_create_with_string (Fsubstring (XCAR (contents
),
1029 make_number (0), tem
));
1030 if (error_string
== NULL
)
1034 XSETINT (tem
, XINT (tem
) + 1);
1035 explanation_string
=
1036 cfstring_create_with_string (Fsubstring (XCAR (contents
),
1038 if (explanation_string
== NULL
)
1040 CFRelease (error_string
);
1046 err
= GetStandardAlertDefaultParams (¶m
,
1047 kStdCFStringAlertVersionOne
);
1050 param
.movable
= true;
1051 param
.position
= kWindowAlertPositionParentWindow
;
1054 param
.defaultText
= CFSTR ("Yes");
1055 param
.otherText
= CFSTR ("No");
1057 param
.cancelText
= CFSTR ("Cancel");
1058 param
.cancelButton
= kAlertStdAlertCancelButton
;
1061 err
= CreateStandardAlert (kAlertNoteAlert
, error_string
,
1062 explanation_string
, ¶m
, &alert
);
1063 CFRelease (error_string
);
1064 if (explanation_string
)
1065 CFRelease (explanation_string
);
1068 err
= RunStandardAlert (alert
, mac_dialog_modal_filter
, &item_hit
);
1073 if (item_hit
== kStdCancelItemIndex
)
1074 Fsignal (Qquit
, Qnil
);
1075 else if (item_hit
== kStdOkItemIndex
)
1082 #ifndef HAVE_DIALOGS
1083 /* Display a menu with these alternatives
1084 in the middle of frame F. */
1086 Lisp_Object x
, y
, frame
, newpos
;
1087 XSETFRAME (frame
, f
);
1088 XSETINT (x
, x_pixel_width (f
) / 2);
1089 XSETINT (y
, x_pixel_height (f
) / 2);
1090 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
1092 return Fx_popup_menu (newpos
,
1093 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
1095 #else /* HAVE_DIALOGS */
1099 Lisp_Object selection
;
1100 int specpdl_count
= SPECPDL_INDEX ();
1102 /* Decode the dialog items from what was specified. */
1103 title
= Fcar (contents
);
1104 CHECK_STRING (title
);
1106 list_of_panes (Fcons (contents
, Qnil
));
1108 /* Display them in a dialog box. */
1109 record_unwind_protect (cleanup_popup_menu
, Qnil
);
1111 selection
= mac_dialog_show (f
, 0, title
, header
, &error_name
);
1113 unbind_to (specpdl_count
, Qnil
);
1115 if (error_name
) error (error_name
);
1118 #endif /* HAVE_DIALOGS */
1121 /* Activate the menu bar of frame F.
1122 This is called from keyboard.c when it gets the
1123 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
1125 To activate the menu bar, we use the button-press event location
1126 that was saved in saved_menu_event_location.
1128 But first we recompute the menu bar contents (the whole tree).
1130 The reason for saving the button event until here, instead of
1131 passing it to the toolkit right away, is that we can safely
1132 execute Lisp code. */
1135 x_activate_menubar (f
)
1139 SInt16 menu_id
, menu_item
;
1140 extern Point saved_menu_event_location
;
1142 set_frame_menubar (f
, 0, 1);
1145 popup_activated_flag
= 1;
1146 menu_choice
= MenuSelect (saved_menu_event_location
);
1147 popup_activated_flag
= 0;
1148 menu_id
= HiWord (menu_choice
);
1149 menu_item
= LoWord (menu_choice
);
1151 #if !TARGET_API_MAC_CARBON
1152 if (menu_id
== min_menu_id
[MAC_MENU_M_APPLE
])
1153 do_apple_menu (menu_item
);
1158 MenuRef menu
= GetMenuRef (menu_id
);
1164 GetMenuItemRefCon (menu
, menu_item
, &refcon
);
1165 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
1166 f
->menu_bar_vector
, (void *) refcon
);
1175 /* Find the menu selection and store it in the keyboard buffer.
1176 F is the frame the menu is on.
1177 MENU_BAR_ITEMS_USED is the length of VECTOR.
1178 VECTOR is an array of menu events for the whole menu. */
1181 find_and_call_menu_selection (f
, menu_bar_items_used
, vector
, client_data
)
1183 int menu_bar_items_used
;
1187 Lisp_Object prefix
, entry
;
1188 Lisp_Object
*subprefix_stack
;
1189 int submenu_depth
= 0;
1193 subprefix_stack
= (Lisp_Object
*) alloca (menu_bar_items_used
* sizeof (Lisp_Object
));
1197 while (i
< menu_bar_items_used
)
1199 if (EQ (XVECTOR (vector
)->contents
[i
], Qnil
))
1201 subprefix_stack
[submenu_depth
++] = prefix
;
1205 else if (EQ (XVECTOR (vector
)->contents
[i
], Qlambda
))
1207 prefix
= subprefix_stack
[--submenu_depth
];
1210 else if (EQ (XVECTOR (vector
)->contents
[i
], Qt
))
1212 prefix
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1213 i
+= MENU_ITEMS_PANE_LENGTH
;
1217 entry
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1218 /* The EMACS_INT cast avoids a warning. There's no problem
1219 as long as pointers have enough bits to hold small integers. */
1220 if ((int) (EMACS_INT
) client_data
== i
)
1223 struct input_event buf
;
1227 XSETFRAME (frame
, f
);
1228 buf
.kind
= MENU_BAR_EVENT
;
1229 buf
.frame_or_window
= frame
;
1231 kbd_buffer_store_event (&buf
);
1233 for (j
= 0; j
< submenu_depth
; j
++)
1234 if (!NILP (subprefix_stack
[j
]))
1236 buf
.kind
= MENU_BAR_EVENT
;
1237 buf
.frame_or_window
= frame
;
1238 buf
.arg
= subprefix_stack
[j
];
1239 kbd_buffer_store_event (&buf
);
1244 buf
.kind
= MENU_BAR_EVENT
;
1245 buf
.frame_or_window
= frame
;
1247 kbd_buffer_store_event (&buf
);
1250 buf
.kind
= MENU_BAR_EVENT
;
1251 buf
.frame_or_window
= frame
;
1253 kbd_buffer_store_event (&buf
);
1257 i
+= MENU_ITEMS_ITEM_LENGTH
;
1262 /* Allocate a widget_value, blocking input. */
1265 xmalloc_widget_value ()
1267 widget_value
*value
;
1270 value
= malloc_widget_value ();
1276 /* This recursively calls free_widget_value on the tree of widgets.
1277 It must free all data that was malloc'ed for these widget_values.
1278 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1279 must be left alone. */
1282 free_menubar_widget_value_tree (wv
)
1287 wv
->name
= wv
->value
= wv
->key
= (char *) 0xDEADBEEF;
1289 if (wv
->contents
&& (wv
->contents
!= (widget_value
*)1))
1291 free_menubar_widget_value_tree (wv
->contents
);
1292 wv
->contents
= (widget_value
*) 0xDEADBEEF;
1296 free_menubar_widget_value_tree (wv
->next
);
1297 wv
->next
= (widget_value
*) 0xDEADBEEF;
1300 free_widget_value (wv
);
1304 /* Set up data in menu_items for a menu bar item
1305 whose event type is ITEM_KEY (with string ITEM_NAME)
1306 and whose contents come from the list of keymaps MAPS. */
1309 parse_single_submenu (item_key
, item_name
, maps
)
1310 Lisp_Object item_key
, item_name
, maps
;
1314 Lisp_Object
*mapvec
;
1316 int top_level_items
= 0;
1318 length
= Flength (maps
);
1319 len
= XINT (length
);
1321 /* Convert the list MAPS into a vector MAPVEC. */
1322 mapvec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1323 for (i
= 0; i
< len
; i
++)
1325 mapvec
[i
] = Fcar (maps
);
1329 /* Loop over the given keymaps, making a pane for each map.
1330 But don't make a pane that is empty--ignore that map instead. */
1331 for (i
= 0; i
< len
; i
++)
1333 if (!KEYMAPP (mapvec
[i
]))
1335 /* Here we have a command at top level in the menu bar
1336 as opposed to a submenu. */
1337 top_level_items
= 1;
1338 push_menu_pane (Qnil
, Qnil
);
1339 push_menu_item (item_name
, Qt
, item_key
, mapvec
[i
],
1340 Qnil
, Qnil
, Qnil
, Qnil
);
1345 prompt
= Fkeymap_prompt (mapvec
[i
]);
1346 single_keymap_panes (mapvec
[i
],
1347 !NILP (prompt
) ? prompt
: item_name
,
1352 return top_level_items
;
1355 /* Create a tree of widget_value objects
1356 representing the panes and items
1357 in menu_items starting at index START, up to index END. */
1359 static widget_value
*
1360 digest_single_submenu (start
, end
, top_level_items
)
1361 int start
, end
, top_level_items
;
1363 widget_value
*wv
, *prev_wv
, *save_wv
, *first_wv
;
1365 int submenu_depth
= 0;
1366 widget_value
**submenu_stack
;
1370 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1371 wv
= xmalloc_widget_value ();
1375 wv
->button_type
= BUTTON_TYPE_NONE
;
1381 /* Loop over all panes and items made by the preceding call
1382 to parse_single_submenu and construct a tree of widget_value objects.
1383 Ignore the panes and items used by previous calls to
1384 digest_single_submenu, even though those are also in menu_items. */
1388 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1390 submenu_stack
[submenu_depth
++] = save_wv
;
1395 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1398 save_wv
= submenu_stack
[--submenu_depth
];
1401 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1402 && submenu_depth
!= 0)
1403 i
+= MENU_ITEMS_PANE_LENGTH
;
1404 /* Ignore a nil in the item list.
1405 It's meaningful only for dialog boxes. */
1406 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1408 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1410 /* Create a new pane. */
1411 Lisp_Object pane_name
, prefix
;
1416 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
1417 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1419 #ifndef HAVE_MULTILINGUAL_MENU
1420 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1422 pane_name
= ENCODE_MENU_STRING (pane_name
);
1423 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1426 pane_string
= (NILP (pane_name
)
1427 ? "" : (char *) SDATA (pane_name
));
1428 /* If there is just one top-level pane, put all its items directly
1429 under the top-level menu. */
1430 if (menu_items_n_panes
== 1)
1433 /* If the pane has a meaningful name,
1434 make the pane a top-level menu item
1435 with its items as a submenu beneath it. */
1436 if (strcmp (pane_string
, ""))
1438 wv
= xmalloc_widget_value ();
1442 first_wv
->contents
= wv
;
1443 wv
->lname
= pane_name
;
1444 /* Set value to 1 so update_submenu_strings can handle '@' */
1445 wv
->value
= (char *)1;
1447 wv
->button_type
= BUTTON_TYPE_NONE
;
1455 i
+= MENU_ITEMS_PANE_LENGTH
;
1459 /* Create a new item within current pane. */
1460 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
;
1463 /* All items should be contained in panes. */
1464 if (panes_seen
== 0)
1467 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1468 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1469 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1470 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1471 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1472 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1473 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1475 #ifndef HAVE_MULTILINGUAL_MENU
1476 if (STRING_MULTIBYTE (item_name
))
1478 item_name
= ENCODE_MENU_STRING (item_name
);
1479 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1482 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1484 descrip
= ENCODE_MENU_STRING (descrip
);
1485 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1487 #endif /* not HAVE_MULTILINGUAL_MENU */
1489 wv
= xmalloc_widget_value ();
1493 save_wv
->contents
= wv
;
1495 wv
->lname
= item_name
;
1496 if (!NILP (descrip
))
1499 /* The EMACS_INT cast avoids a warning. There's no problem
1500 as long as pointers have enough bits to hold small integers. */
1501 wv
->call_data
= (!NILP (def
) ? (void *) (EMACS_INT
) i
: 0);
1502 wv
->enabled
= !NILP (enable
);
1505 wv
->button_type
= BUTTON_TYPE_NONE
;
1506 else if (EQ (type
, QCradio
))
1507 wv
->button_type
= BUTTON_TYPE_RADIO
;
1508 else if (EQ (type
, QCtoggle
))
1509 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1513 wv
->selected
= !NILP (selected
);
1514 if (! STRINGP (help
))
1521 i
+= MENU_ITEMS_ITEM_LENGTH
;
1525 /* If we have just one "menu item"
1526 that was originally a button, return it by itself. */
1527 if (top_level_items
&& first_wv
->contents
&& first_wv
->contents
->next
== 0)
1529 wv
= first_wv
->contents
;
1530 free_widget_value (first_wv
);
1537 /* Walk through the widget_value tree starting at FIRST_WV and update
1538 the char * pointers from the corresponding lisp values.
1539 We do this after building the whole tree, since GC may happen while the
1540 tree is constructed, and small strings are relocated. So we must wait
1541 until no GC can happen before storing pointers into lisp values. */
1543 update_submenu_strings (first_wv
)
1544 widget_value
*first_wv
;
1548 for (wv
= first_wv
; wv
; wv
= wv
->next
)
1550 if (STRINGP (wv
->lname
))
1552 wv
->name
= SDATA (wv
->lname
);
1554 /* Ignore the @ that means "separate pane".
1555 This is a kludge, but this isn't worth more time. */
1556 if (wv
->value
== (char *)1)
1558 if (wv
->name
[0] == '@')
1564 if (STRINGP (wv
->lkey
))
1565 wv
->key
= SDATA (wv
->lkey
);
1568 update_submenu_strings (wv
->contents
);
1573 #if TARGET_API_MAC_CARBON
1574 extern Lisp_Object Vshow_help_function
;
1577 restore_show_help_function (old_show_help_function
)
1578 Lisp_Object old_show_help_function
;
1580 Vshow_help_function
= old_show_help_function
;
1585 static pascal OSStatus
1586 menu_target_item_handler (next_handler
, event
, data
)
1587 EventHandlerCallRef next_handler
;
1593 MenuItemIndex menu_item
;
1596 int specpdl_count
= SPECPDL_INDEX ();
1598 /* Don't be bothered with the overflowed toolbar items menu. */
1599 if (!popup_activated ())
1600 return eventNotHandledErr
;
1602 err
= GetEventParameter (event
, kEventParamDirectObject
, typeMenuRef
,
1603 NULL
, sizeof (MenuRef
), NULL
, &menu
);
1605 err
= GetEventParameter (event
, kEventParamMenuItemIndex
,
1606 typeMenuItemIndex
, NULL
,
1607 sizeof (MenuItemIndex
), NULL
, &menu_item
);
1609 err
= GetMenuItemProperty (menu
, menu_item
,
1610 MAC_EMACS_CREATOR_CODE
, 'help',
1611 sizeof (Lisp_Object
), NULL
, &help
);
1615 /* Temporarily bind Vshow_help_function to Qnil because we don't
1616 want tooltips during menu tracking. */
1617 record_unwind_protect (restore_show_help_function
, Vshow_help_function
);
1618 Vshow_help_function
= Qnil
;
1620 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
1622 unbind_to (specpdl_count
, Qnil
);
1624 return err
== noErr
? noErr
: eventNotHandledErr
;
1628 install_menu_target_item_handler ()
1630 static const EventTypeSpec specs
[] =
1631 {{kEventClassMenu
, kEventMenuTargetItem
}};
1633 return InstallApplicationEventHandler (NewEventHandlerUPP
1634 (menu_target_item_handler
),
1635 GetEventTypeCount (specs
),
1638 #endif /* TARGET_API_MAC_CARBON */
1640 /* Event handler function that pops down a menu on C-g. We can only pop
1641 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1643 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1644 static pascal OSStatus
1645 menu_quit_handler (nextHandler
, theEvent
, userData
)
1646 EventHandlerCallRef nextHandler
;
1652 UInt32 keyModifiers
;
1654 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
1655 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
1658 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
1659 typeUInt32
, NULL
, sizeof(UInt32
),
1660 NULL
, &keyModifiers
);
1662 if (err
== noErr
&& mac_quit_char_key_p (keyModifiers
, keyCode
))
1664 MenuRef menu
= userData
!= 0
1665 ? (MenuRef
)userData
: AcquireRootMenu ();
1667 CancelMenuTracking (menu
, true, 0);
1668 if (!userData
) ReleaseMenu (menu
);
1672 return CallNextEventHandler (nextHandler
, theEvent
);
1674 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1676 /* Add event handler to all menus that belong to KIND so we can detect
1677 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
1678 when C-g is detected. NULL means the menu bar. If
1679 CancelMenuTracking isn't available, do nothing. */
1682 install_menu_quit_handler (kind
, root_menu
)
1683 enum mac_menu_kind kind
;
1686 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1687 static const EventTypeSpec typesList
[] =
1688 {{kEventClassKeyboard
, kEventRawKeyDown
}};
1691 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1692 if (CancelMenuTracking
== NULL
)
1695 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
1697 MenuRef menu
= GetMenuRef (id
);
1701 InstallMenuEventHandler (menu
, menu_quit_handler
,
1702 GetEventTypeCount (typesList
),
1703 typesList
, root_menu
, NULL
);
1705 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1708 /* Set the contents of the menubar widgets of frame F.
1709 The argument FIRST_TIME is currently ignored;
1710 it is set the first time this is called, from initialize_frame_menubar. */
1713 set_frame_menubar (f
, first_time
, deep_p
)
1718 int menubar_widget
= f
->output_data
.mac
->menubar_widget
;
1720 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1722 int *submenu_start
, *submenu_end
;
1723 int *submenu_top_level_items
, *submenu_n_panes
;
1725 XSETFRAME (Vmenu_updating_frame
, f
);
1727 /* This seems to be unnecessary for Carbon. */
1729 if (! menubar_widget
)
1731 else if (pending_menu_activation
&& !deep_p
)
1737 /* Make a widget-value tree representing the entire menu trees. */
1739 struct buffer
*prev
= current_buffer
;
1741 int specpdl_count
= SPECPDL_INDEX ();
1742 int previous_menu_items_used
= f
->menu_bar_items_used
;
1743 Lisp_Object
*previous_items
1744 = (Lisp_Object
*) alloca (previous_menu_items_used
1745 * sizeof (Lisp_Object
));
1747 /* If we are making a new widget, its contents are empty,
1748 do always reinitialize them. */
1749 if (! menubar_widget
)
1750 previous_menu_items_used
= 0;
1752 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1753 specbind (Qinhibit_quit
, Qt
);
1754 /* Don't let the debugger step into this code
1755 because it is not reentrant. */
1756 specbind (Qdebug_on_next_call
, Qnil
);
1758 record_unwind_save_match_data ();
1759 if (NILP (Voverriding_local_map_menu_flag
))
1761 specbind (Qoverriding_terminal_local_map
, Qnil
);
1762 specbind (Qoverriding_local_map
, Qnil
);
1765 set_buffer_internal_1 (XBUFFER (buffer
));
1767 /* Run the Lucid hook. */
1768 safe_run_hooks (Qactivate_menubar_hook
);
1770 /* If it has changed current-menubar from previous value,
1771 really recompute the menubar from the value. */
1772 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1773 call0 (Qrecompute_lucid_menubar
);
1774 safe_run_hooks (Qmenu_bar_update_hook
);
1775 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1777 items
= FRAME_MENU_BAR_ITEMS (f
);
1779 /* Save the frame's previous menu bar contents data. */
1780 if (previous_menu_items_used
)
1781 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1782 previous_menu_items_used
* sizeof (Lisp_Object
));
1784 /* Fill in menu_items with the current menu bar contents.
1785 This can evaluate Lisp code. */
1788 menu_items
= f
->menu_bar_vector
;
1789 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1790 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1791 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1792 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1793 submenu_top_level_items
1794 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1796 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1798 Lisp_Object key
, string
, maps
;
1802 key
= XVECTOR (items
)->contents
[i
];
1803 string
= XVECTOR (items
)->contents
[i
+ 1];
1804 maps
= XVECTOR (items
)->contents
[i
+ 2];
1808 submenu_start
[i
] = menu_items_used
;
1810 menu_items_n_panes
= 0;
1811 submenu_top_level_items
[i
]
1812 = parse_single_submenu (key
, string
, maps
);
1813 submenu_n_panes
[i
] = menu_items_n_panes
;
1815 submenu_end
[i
] = menu_items_used
;
1818 finish_menu_items ();
1820 /* Convert menu_items into widget_value trees
1821 to display the menu. This cannot evaluate Lisp code. */
1823 wv
= xmalloc_widget_value ();
1824 wv
->name
= "menubar";
1827 wv
->button_type
= BUTTON_TYPE_NONE
;
1831 for (i
= 0; i
< last_i
; i
+= 4)
1833 menu_items_n_panes
= submenu_n_panes
[i
];
1834 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1835 submenu_top_level_items
[i
]);
1839 first_wv
->contents
= wv
;
1840 /* Don't set wv->name here; GC during the loop might relocate it. */
1842 wv
->button_type
= BUTTON_TYPE_NONE
;
1846 set_buffer_internal_1 (prev
);
1848 /* If there has been no change in the Lisp-level contents
1849 of the menu bar, skip redisplaying it. Just exit. */
1851 /* Compare the new menu items with the ones computed last time. */
1852 for (i
= 0; i
< previous_menu_items_used
; i
++)
1853 if (menu_items_used
== i
1854 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1856 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1858 /* The menu items have not changed. Don't bother updating
1859 the menus in any form, since it would be a no-op. */
1860 free_menubar_widget_value_tree (first_wv
);
1861 discard_menu_items ();
1862 unbind_to (specpdl_count
, Qnil
);
1866 /* The menu items are different, so store them in the frame. */
1867 f
->menu_bar_vector
= menu_items
;
1868 f
->menu_bar_items_used
= menu_items_used
;
1870 /* This calls restore_menu_items to restore menu_items, etc.,
1871 as they were outside. */
1872 unbind_to (specpdl_count
, Qnil
);
1874 /* Now GC cannot happen during the lifetime of the widget_value,
1875 so it's safe to store data from a Lisp_String. */
1876 wv
= first_wv
->contents
;
1877 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1880 string
= XVECTOR (items
)->contents
[i
+ 1];
1883 wv
->name
= (char *) SDATA (string
);
1884 update_submenu_strings (wv
->contents
);
1891 /* Make a widget-value tree containing
1892 just the top level menu bar strings. */
1894 wv
= xmalloc_widget_value ();
1895 wv
->name
= "menubar";
1898 wv
->button_type
= BUTTON_TYPE_NONE
;
1902 items
= FRAME_MENU_BAR_ITEMS (f
);
1903 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1907 string
= XVECTOR (items
)->contents
[i
+ 1];
1911 wv
= xmalloc_widget_value ();
1912 wv
->name
= (char *) SDATA (string
);
1915 wv
->button_type
= BUTTON_TYPE_NONE
;
1917 /* This prevents lwlib from assuming this
1918 menu item is really supposed to be empty. */
1919 /* The EMACS_INT cast avoids a warning.
1920 This value just has to be different from small integers. */
1921 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1926 first_wv
->contents
= wv
;
1930 /* Forget what we thought we knew about what is in the
1931 detailed contents of the menu bar menus.
1932 Changing the top level always destroys the contents. */
1933 f
->menu_bar_items_used
= 0;
1936 /* Create or update the menu bar widget. */
1940 /* Non-null value to indicate menubar has already been "created". */
1941 f
->output_data
.mac
->menubar_widget
= 1;
1943 fill_menubar (first_wv
->contents
, deep_p
);
1945 /* Add event handler so we can detect C-g. */
1946 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
1947 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
1948 free_menubar_widget_value_tree (first_wv
);
1953 /* Get rid of the menu bar of frame F, and free its storage.
1954 This is used when deleting a frame, and when turning off the menu bar. */
1957 free_frame_menubar (f
)
1960 f
->output_data
.mac
->menubar_widget
= 0;
1968 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1969 FRAME_PTR f
= p
->pointer
;
1970 MenuRef menu
= GetMenuRef (min_menu_id
[MAC_MENU_POPUP
]);
1974 /* Must reset this manually because the button release event is not
1975 passed to Emacs event loop. */
1976 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
1978 /* delete all menus */
1979 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
1980 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
1988 /* Mac_menu_show actually displays a menu using the panes and items in
1989 menu_items and returns the value selected from it; we assume input
1990 is blocked by the caller. */
1992 /* F is the frame the menu is for.
1993 X and Y are the frame-relative specified position,
1994 relative to the inside upper left corner of the frame F.
1995 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1996 KEYMAPS is 1 if this menu was specified with keymaps;
1997 in that case, we return a list containing the chosen item's value
1998 and perhaps also the pane's prefix.
1999 TITLE is the specified menu title.
2000 ERROR is a place to store an error message string in case of failure.
2001 (We return nil on failure, but the value doesn't actually matter.) */
2004 mac_menu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
2014 int menu_item_choice
;
2015 UInt32 menu_item_selection
;
2017 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
2018 widget_value
**submenu_stack
2019 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
2020 Lisp_Object
*subprefix_stack
2021 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
2022 int submenu_depth
= 0;
2025 int specpdl_count
= SPECPDL_INDEX ();
2029 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2031 *error
= "Empty menu";
2035 /* Create a tree of widget_value objects
2036 representing the panes and their items. */
2037 wv
= xmalloc_widget_value ();
2041 wv
->button_type
= BUTTON_TYPE_NONE
;
2046 /* Loop over all panes and items, filling in the tree. */
2048 while (i
< menu_items_used
)
2050 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2052 submenu_stack
[submenu_depth
++] = save_wv
;
2058 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2061 save_wv
= submenu_stack
[--submenu_depth
];
2065 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
2066 && submenu_depth
!= 0)
2067 i
+= MENU_ITEMS_PANE_LENGTH
;
2068 /* Ignore a nil in the item list.
2069 It's meaningful only for dialog boxes. */
2070 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2072 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2074 /* Create a new pane. */
2075 Lisp_Object pane_name
, prefix
;
2078 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2079 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2081 #ifndef HAVE_MULTILINGUAL_MENU
2082 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
2084 pane_name
= ENCODE_MENU_STRING (pane_name
);
2085 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
2088 pane_string
= (NILP (pane_name
)
2089 ? "" : (char *) SDATA (pane_name
));
2090 /* If there is just one top-level pane, put all its items directly
2091 under the top-level menu. */
2092 if (menu_items_n_panes
== 1)
2095 /* If the pane has a meaningful name,
2096 make the pane a top-level menu item
2097 with its items as a submenu beneath it. */
2098 if (!keymaps
&& strcmp (pane_string
, ""))
2100 wv
= xmalloc_widget_value ();
2104 first_wv
->contents
= wv
;
2105 wv
->name
= pane_string
;
2106 if (keymaps
&& !NILP (prefix
))
2110 wv
->button_type
= BUTTON_TYPE_NONE
;
2115 else if (first_pane
)
2121 i
+= MENU_ITEMS_PANE_LENGTH
;
2125 /* Create a new item within current pane. */
2126 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
2127 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2128 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2129 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2130 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
2131 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
2132 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
2133 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2135 #ifndef HAVE_MULTILINGUAL_MENU
2136 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
2138 item_name
= ENCODE_MENU_STRING (item_name
);
2139 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
2142 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
2144 descrip
= ENCODE_MENU_STRING (descrip
);
2145 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
2147 #endif /* not HAVE_MULTILINGUAL_MENU */
2149 wv
= xmalloc_widget_value ();
2153 save_wv
->contents
= wv
;
2154 wv
->name
= (char *) SDATA (item_name
);
2155 if (!NILP (descrip
))
2156 wv
->key
= (char *) SDATA (descrip
);
2158 /* Use the contents index as call_data, since we are
2159 restricted to 16-bits. */
2160 wv
->call_data
= !NILP (def
) ? (void *) (EMACS_INT
) i
: 0;
2161 wv
->enabled
= !NILP (enable
);
2164 wv
->button_type
= BUTTON_TYPE_NONE
;
2165 else if (EQ (type
, QCtoggle
))
2166 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
2167 else if (EQ (type
, QCradio
))
2168 wv
->button_type
= BUTTON_TYPE_RADIO
;
2172 wv
->selected
= !NILP (selected
);
2174 if (! STRINGP (help
))
2181 i
+= MENU_ITEMS_ITEM_LENGTH
;
2185 /* Deal with the title, if it is non-nil. */
2188 widget_value
*wv_title
= xmalloc_widget_value ();
2189 widget_value
*wv_sep
= xmalloc_widget_value ();
2191 /* Maybe replace this separator with a bitmap or owner-draw item
2192 so that it looks better. Having two separators looks odd. */
2193 wv_sep
->name
= "--";
2194 wv_sep
->next
= first_wv
->contents
;
2195 wv_sep
->help
= Qnil
;
2197 #ifndef HAVE_MULTILINGUAL_MENU
2198 if (STRING_MULTIBYTE (title
))
2199 title
= ENCODE_MENU_STRING (title
);
2202 wv_title
->name
= (char *) SDATA (title
);
2203 wv_title
->enabled
= FALSE
;
2204 wv_title
->title
= TRUE
;
2205 wv_title
->button_type
= BUTTON_TYPE_NONE
;
2206 wv_title
->help
= Qnil
;
2207 wv_title
->next
= wv_sep
;
2208 first_wv
->contents
= wv_title
;
2211 /* Actually create the menu. */
2212 menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
2213 InsertMenu (menu
, -1);
2214 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
2215 min_menu_id
[MAC_MENU_POPUP_SUB
]);
2217 /* Free the widget_value objects we used to specify the
2219 free_menubar_widget_value_tree (first_wv
);
2221 /* Adjust coordinates to be root-window-relative. */
2222 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
2223 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2225 /* No selection has been chosen yet. */
2226 menu_item_selection
= 0;
2228 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
2230 /* Add event handler so we can detect C-g. */
2231 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
2232 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
2234 /* Display the menu. */
2235 popup_activated_flag
= 1;
2236 menu_item_choice
= PopUpMenuSelect (menu
, y
, x
, 0);
2237 popup_activated_flag
= 0;
2239 /* Get the refcon to find the correct item */
2240 if (menu_item_choice
)
2242 MenuRef sel_menu
= GetMenuRef (HiWord (menu_item_choice
));
2245 GetMenuItemRefCon (sel_menu
, LoWord (menu_item_choice
),
2246 &menu_item_selection
);
2249 unbind_to (specpdl_count
, Qnil
);
2251 /* Find the selected item, and its pane, to return
2252 the proper value. */
2253 if (menu_item_selection
!= 0)
2255 Lisp_Object prefix
, entry
;
2257 prefix
= entry
= Qnil
;
2259 while (i
< menu_items_used
)
2261 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2263 subprefix_stack
[submenu_depth
++] = prefix
;
2267 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2269 prefix
= subprefix_stack
[--submenu_depth
];
2272 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2275 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2276 i
+= MENU_ITEMS_PANE_LENGTH
;
2278 /* Ignore a nil in the item list.
2279 It's meaningful only for dialog boxes. */
2280 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2285 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2286 if (menu_item_selection
== i
)
2292 entry
= Fcons (entry
, Qnil
);
2294 entry
= Fcons (prefix
, entry
);
2295 for (j
= submenu_depth
- 1; j
>= 0; j
--)
2296 if (!NILP (subprefix_stack
[j
]))
2297 entry
= Fcons (subprefix_stack
[j
], entry
);
2301 i
+= MENU_ITEMS_ITEM_LENGTH
;
2305 else if (!for_click
)
2306 /* Make "Cancel" equivalent to C-g. */
2307 Fsignal (Qquit
, Qnil
);
2314 /* Construct native Mac OS dialog based on widget_value tree. */
2316 #if TARGET_API_MAC_CARBON
2318 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
2319 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
2320 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
2321 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
2322 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
2323 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
2324 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
2326 extern EMACS_TIME timer_check
P_ ((int));
2327 static int quit_dialog_event_loop
;
2329 static pascal OSStatus
2330 mac_handle_dialog_event (next_handler
, event
, data
)
2331 EventHandlerCallRef next_handler
;
2335 OSStatus err
, result
= eventNotHandledErr
;
2336 WindowRef window
= (WindowRef
) data
;
2338 switch (GetEventClass (event
))
2340 case kEventClassCommand
:
2344 err
= GetEventParameter (event
, kEventParamDirectObject
,
2345 typeHICommand
, NULL
, sizeof (HICommand
),
2348 if (DIALOG_BUTTON_COMMAND_ID_P (command
.commandID
))
2350 SetWRefCon (window
, command
.commandID
);
2351 quit_dialog_event_loop
= 1;
2355 result
= CallNextEventHandler (next_handler
, event
);
2359 case kEventClassKeyboard
:
2364 result
= CallNextEventHandler (next_handler
, event
);
2365 if (result
!= eventNotHandledErr
)
2368 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
2369 typeChar
, NULL
, sizeof (char),
2374 case kEscapeCharCode
:
2375 quit_dialog_event_loop
= 1;
2380 UInt32 modifiers
, key_code
;
2382 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
2383 typeUInt32
, NULL
, sizeof (UInt32
),
2386 err
= GetEventParameter (event
, kEventParamKeyCode
,
2387 typeUInt32
, NULL
, sizeof (UInt32
),
2390 if (mac_quit_char_key_p (modifiers
, key_code
))
2391 quit_dialog_event_loop
= 1;
2402 if (quit_dialog_event_loop
)
2404 err
= QuitEventLoop (GetCurrentEventLoop ());
2413 install_dialog_event_handler (window
)
2416 static const EventTypeSpec specs
[] =
2417 {{kEventClassCommand
, kEventCommandProcess
},
2418 {kEventClassKeyboard
, kEventRawKeyDown
}};
2419 static EventHandlerUPP handle_dialog_eventUPP
= NULL
;
2421 if (handle_dialog_eventUPP
== NULL
)
2422 handle_dialog_eventUPP
= NewEventHandlerUPP (mac_handle_dialog_event
);
2423 return InstallWindowEventHandler (window
, handle_dialog_eventUPP
,
2424 GetEventTypeCount (specs
), specs
,
2428 #define DIALOG_LEFT_MARGIN (112)
2429 #define DIALOG_TOP_MARGIN (24)
2430 #define DIALOG_RIGHT_MARGIN (24)
2431 #define DIALOG_BOTTOM_MARGIN (20)
2432 #define DIALOG_MIN_INNER_WIDTH (338)
2433 #define DIALOG_MAX_INNER_WIDTH (564)
2434 #define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12)
2435 #define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12)
2436 #define DIALOG_BUTTON_MIN_WIDTH (68)
2437 #define DIALOG_TEXT_MIN_HEIGHT (50)
2438 #define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10)
2439 #define DIALOG_ICON_WIDTH (64)
2440 #define DIALOG_ICON_HEIGHT (64)
2441 #define DIALOG_ICON_LEFT_MARGIN (24)
2442 #define DIALOG_ICON_TOP_MARGIN (15)
2445 pop_down_dialog (arg
)
2448 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
2449 WindowRef window
= p
->pointer
;
2453 if (popup_activated_flag
)
2454 EndAppModalStateForWindow (window
);
2455 DisposeWindow (window
);
2456 popup_activated_flag
= 0;
2464 create_and_show_dialog (f
, first_wv
)
2466 widget_value
*first_wv
;
2469 char *dialog_name
, *message
;
2470 int nb_buttons
, first_group_count
, i
, result
= 0;
2472 short buttons_height
, text_height
, inner_width
, inner_height
;
2473 Rect empty_rect
, *rects
;
2474 WindowRef window
= NULL
;
2475 ControlRef
*buttons
, default_button
= NULL
, text
;
2476 int specpdl_count
= SPECPDL_INDEX ();
2478 dialog_name
= first_wv
->name
;
2479 nb_buttons
= dialog_name
[1] - '0';
2480 first_group_count
= nb_buttons
- (dialog_name
[4] - '0');
2482 wv
= first_wv
->contents
;
2483 message
= wv
->value
;
2486 SetRect (&empty_rect
, 0, 0, 0, 0);
2488 /* Create dialog window. */
2489 err
= CreateNewWindow (kMovableModalWindowClass
,
2490 kWindowStandardHandlerAttribute
,
2491 &empty_rect
, &window
);
2494 record_unwind_protect (pop_down_dialog
, make_save_value (window
, 0));
2495 err
= SetThemeWindowBackground (window
, kThemeBrushMovableModalBackground
,
2499 err
= SetWindowTitleWithCFString (window
, (dialog_name
[0] == 'Q'
2500 ? CFSTR ("Question")
2501 : CFSTR ("Information")));
2503 /* Create button controls and measure their optimal bounds. */
2506 buttons
= alloca (sizeof (ControlRef
) * nb_buttons
);
2507 rects
= alloca (sizeof (Rect
) * nb_buttons
);
2508 for (i
= 0; i
< nb_buttons
; i
++)
2510 CFStringRef label
= cfstring_create_with_utf8_cstring (wv
->value
);
2516 err
= CreatePushButtonControl (window
, &empty_rect
,
2517 label
, &buttons
[i
]);
2525 err
= DisableControl (buttons
[i
]);
2527 err
= DeactivateControl (buttons
[i
]);
2530 else if (default_button
== NULL
)
2531 default_button
= buttons
[i
];
2537 rects
[i
] = empty_rect
;
2538 err
= GetBestControlRect (buttons
[i
], &rects
[i
], &unused
);
2544 OffsetRect (&rects
[i
], -rects
[i
].left
, -rects
[i
].top
);
2545 if (rects
[i
].right
< DIALOG_BUTTON_MIN_WIDTH
)
2546 rects
[i
].right
= DIALOG_BUTTON_MIN_WIDTH
;
2547 else if (rects
[i
].right
> DIALOG_MAX_INNER_WIDTH
)
2548 rects
[i
].right
= DIALOG_MAX_INNER_WIDTH
;
2550 command_id
= DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv
->call_data
);
2551 err
= SetControlCommandID (buttons
[i
], command_id
);
2559 /* Layout buttons. rects[i] is set relative to the bottom-right
2560 corner of the inner box. */
2563 short bottom
, right
, max_height
, left_align_shift
;
2565 inner_width
= DIALOG_MIN_INNER_WIDTH
;
2566 bottom
= right
= max_height
= 0;
2567 for (i
= 0; i
< nb_buttons
; i
++)
2569 if (right
- rects
[i
].right
< - inner_width
)
2571 if (i
!= first_group_count
2572 && right
- rects
[i
].right
>= - DIALOG_MAX_INNER_WIDTH
)
2573 inner_width
= - (right
- rects
[i
].right
);
2576 bottom
-= max_height
+ DIALOG_BUTTON_BUTTON_VERTICAL_SPACE
;
2577 right
= max_height
= 0;
2580 if (max_height
< rects
[i
].bottom
)
2581 max_height
= rects
[i
].bottom
;
2582 OffsetRect (&rects
[i
], right
- rects
[i
].right
,
2583 bottom
- rects
[i
].bottom
);
2584 right
= rects
[i
].left
- DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
2585 if (i
== first_group_count
- 1)
2586 right
-= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
2588 buttons_height
= - (bottom
- max_height
);
2590 left_align_shift
= - (inner_width
+ rects
[nb_buttons
- 1].left
);
2591 for (i
= nb_buttons
- 1; i
>= first_group_count
; i
--)
2593 if (bottom
!= rects
[i
].bottom
)
2595 left_align_shift
= - (inner_width
+ rects
[i
].left
);
2596 bottom
= rects
[i
].bottom
;
2598 OffsetRect (&rects
[i
], left_align_shift
, 0);
2602 /* Create a static text control and measure its bounds. */
2605 CFStringRef message_string
;
2608 message_string
= cfstring_create_with_utf8_cstring (message
);
2609 if (message_string
== NULL
)
2613 ControlFontStyleRec text_style
;
2615 text_style
.flags
= 0;
2616 SetRect (&bounds
, 0, 0, inner_width
, 0);
2617 err
= CreateStaticTextControl (window
, &bounds
, message_string
,
2618 &text_style
, &text
);
2619 CFRelease (message_string
);
2625 bounds
= empty_rect
;
2626 err
= GetBestControlRect (text
, &bounds
, &unused
);
2630 text_height
= bounds
.bottom
- bounds
.top
;
2631 if (text_height
< DIALOG_TEXT_MIN_HEIGHT
)
2632 text_height
= DIALOG_TEXT_MIN_HEIGHT
;
2636 /* Place buttons. */
2639 inner_height
= (text_height
+ DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
2642 for (i
= 0; i
< nb_buttons
; i
++)
2644 OffsetRect (&rects
[i
], DIALOG_LEFT_MARGIN
+ inner_width
,
2645 DIALOG_TOP_MARGIN
+ inner_height
);
2646 SetControlBounds (buttons
[i
], &rects
[i
]);
2655 SetRect (&bounds
, DIALOG_LEFT_MARGIN
, DIALOG_TOP_MARGIN
,
2656 DIALOG_LEFT_MARGIN
+ inner_width
,
2657 DIALOG_TOP_MARGIN
+ text_height
);
2658 SetControlBounds (text
, &bounds
);
2661 /* Create the application icon at the upper-left corner. */
2664 ControlButtonContentInfo content
;
2666 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
2670 ProcessInfoRec pinfo
;
2675 content
.contentType
= kControlContentIconRef
;
2677 err
= GetProcessBundleLocation (&psn
, &app_location
);
2679 err
= GetIconRefFromFileInfo (&app_location
, 0, NULL
, 0, NULL
,
2680 kIconServicesNormalUsageFlag
,
2681 &content
.u
.iconRef
, &unused
);
2683 bzero (&pinfo
, sizeof (ProcessInfoRec
));
2684 pinfo
.processInfoLength
= sizeof (ProcessInfoRec
);
2685 pinfo
.processAppSpec
= &app_spec
;
2686 err
= GetProcessInformation (&psn
, &pinfo
);
2688 err
= GetIconRefFromFile (&app_spec
, &content
.u
.iconRef
, &unused
);
2694 SetRect (&bounds
, DIALOG_ICON_LEFT_MARGIN
, DIALOG_ICON_TOP_MARGIN
,
2695 DIALOG_ICON_LEFT_MARGIN
+ DIALOG_ICON_WIDTH
,
2696 DIALOG_ICON_TOP_MARGIN
+ DIALOG_ICON_HEIGHT
);
2697 err
= CreateIconControl (window
, &bounds
, &content
, true, &icon
);
2698 ReleaseIconRef (content
.u
.iconRef
);
2702 /* Show the dialog window and run event loop. */
2705 err
= SetWindowDefaultButton (window
, default_button
);
2707 err
= install_dialog_event_handler (window
);
2711 DIALOG_LEFT_MARGIN
+ inner_width
+ DIALOG_RIGHT_MARGIN
,
2712 DIALOG_TOP_MARGIN
+ inner_height
+ DIALOG_BOTTOM_MARGIN
,
2714 err
= RepositionWindow (window
, FRAME_MAC_WINDOW (f
),
2715 kWindowAlertPositionOnParentWindow
);
2719 SetWRefCon (window
, 0);
2720 ShowWindow (window
);
2721 BringToFront (window
);
2722 popup_activated_flag
= 1;
2723 err
= BeginAppModalStateForWindow (window
);
2727 EventTargetRef toolbox_dispatcher
= GetEventDispatcherTarget ();
2729 quit_dialog_event_loop
= 0;
2732 EMACS_TIME next_time
= timer_check (1);
2733 long secs
= EMACS_SECS (next_time
);
2734 long usecs
= EMACS_USECS (next_time
);
2735 EventTimeout timeout
;
2738 if (secs
< 0 || (secs
== 0 && usecs
== 0))
2740 /* Sometimes timer_check returns -1 (no timers) even if
2741 there are timers. So do a timeout anyway. */
2746 timeout
= (secs
* kEventDurationSecond
2747 + usecs
* kEventDurationMicrosecond
);
2748 err
= ReceiveNextEvent (0, NULL
, timeout
, kEventRemoveFromQueue
,
2752 SendEventToEventTarget (event
, toolbox_dispatcher
);
2753 ReleaseEvent (event
);
2756 else if (err
!= eventLoopTimedOutErr
)
2758 if (err
== eventLoopQuitErr
)
2763 /* The return value of ReceiveNextEvent seems to be
2764 unreliable. Use our own global variable instead. */
2765 if (quit_dialog_event_loop
)
2775 UInt32 command_id
= GetWRefCon (window
);
2777 if (DIALOG_BUTTON_COMMAND_ID_P (command_id
))
2778 result
= DIALOG_BUTTON_COMMAND_ID_VALUE (command_id
);
2781 unbind_to (specpdl_count
, Qnil
);
2785 #else /* not TARGET_API_MAC_CARBON */
2787 mac_dialog (widget_value
*wv
)
2791 char **button_labels
;
2798 WindowRef window_ptr
;
2801 EventRecord event_record
;
2803 int control_part_code
;
2806 dialog_name
= wv
->name
;
2807 nb_buttons
= dialog_name
[1] - '0';
2808 left_count
= nb_buttons
- (dialog_name
[4] - '0');
2809 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
2810 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
2813 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
2814 strcpy (prompt
, wv
->value
);
2818 for (i
= 0; i
< nb_buttons
; i
++)
2820 button_labels
[i
] = wv
->value
;
2821 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
2822 strcpy (button_labels
[i
], wv
->value
);
2823 c2pstr (button_labels
[i
]);
2824 ref_cons
[i
] = (UInt32
) wv
->call_data
;
2828 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowRef
) -1);
2830 SetPortWindowPort (window_ptr
);
2833 /* Left and right margins in the dialog are 13 pixels each.*/
2835 /* Calculate width of dialog box: 8 pixels on each side of the text
2836 label in each button, 12 pixels between buttons. */
2837 for (i
= 0; i
< nb_buttons
; i
++)
2838 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
2840 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
2843 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
2845 SizeWindow (window_ptr
, dialog_width
, 78, 0);
2846 ShowWindow (window_ptr
);
2848 SetPortWindowPort (window_ptr
);
2853 DrawString (prompt
);
2856 for (i
= 0; i
< nb_buttons
; i
++)
2858 int button_width
= StringWidth (button_labels
[i
]) + 16;
2859 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
2860 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
2861 kControlPushButtonProc
, ref_cons
[i
]);
2862 left
+= button_width
+ 12;
2863 if (i
== left_count
- 1)
2870 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
2871 if (event_record
.what
== mouseDown
)
2873 part_code
= FindWindow (event_record
.where
, &window_ptr
);
2874 if (part_code
== inContent
)
2876 mouse
= event_record
.where
;
2877 GlobalToLocal (&mouse
);
2878 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
2879 if (control_part_code
== kControlButtonPart
)
2880 if (TrackControl (ch
, mouse
, NULL
))
2881 i
= GetControlReference (ch
);
2886 DisposeWindow (window_ptr
);
2890 #endif /* not TARGET_API_MAC_CARBON */
2892 static char * button_names
[] = {
2893 "button1", "button2", "button3", "button4", "button5",
2894 "button6", "button7", "button8", "button9", "button10" };
2897 mac_dialog_show (f
, keymaps
, title
, header
, error_name
)
2900 Lisp_Object title
, header
;
2903 int i
, nb_buttons
=0;
2904 char dialog_name
[6];
2905 int menu_item_selection
;
2907 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2909 /* Number of elements seen so far, before boundary. */
2911 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2912 int boundary_seen
= 0;
2916 if (menu_items_n_panes
> 1)
2918 *error_name
= "Multiple panes in dialog box";
2922 /* Create a tree of widget_value objects
2923 representing the text label and buttons. */
2925 Lisp_Object pane_name
, prefix
;
2927 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2928 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2929 pane_string
= (NILP (pane_name
)
2930 ? "" : (char *) SDATA (pane_name
));
2931 prev_wv
= xmalloc_widget_value ();
2932 prev_wv
->value
= pane_string
;
2933 if (keymaps
&& !NILP (prefix
))
2935 prev_wv
->enabled
= 1;
2936 prev_wv
->name
= "message";
2937 prev_wv
->help
= Qnil
;
2940 /* Loop over all panes and items, filling in the tree. */
2941 i
= MENU_ITEMS_PANE_LENGTH
;
2942 while (i
< menu_items_used
)
2945 /* Create a new item within current pane. */
2946 Lisp_Object item_name
, enable
, descrip
;
2947 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2948 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2950 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2952 if (NILP (item_name
))
2954 free_menubar_widget_value_tree (first_wv
);
2955 *error_name
= "Submenu in dialog items";
2958 if (EQ (item_name
, Qquote
))
2960 /* This is the boundary between left-side elts
2961 and right-side elts. Stop incrementing right_count. */
2966 if (nb_buttons
>= 9)
2968 free_menubar_widget_value_tree (first_wv
);
2969 *error_name
= "Too many dialog items";
2973 wv
= xmalloc_widget_value ();
2975 wv
->name
= (char *) button_names
[nb_buttons
];
2976 if (!NILP (descrip
))
2977 wv
->key
= (char *) SDATA (descrip
);
2978 wv
->value
= (char *) SDATA (item_name
);
2979 wv
->call_data
= (void *) i
;
2980 /* menu item is identified by its index in menu_items table */
2981 wv
->enabled
= !NILP (enable
);
2985 if (! boundary_seen
)
2989 i
+= MENU_ITEMS_ITEM_LENGTH
;
2992 /* If the boundary was not specified,
2993 by default put half on the left and half on the right. */
2994 if (! boundary_seen
)
2995 left_count
= nb_buttons
- nb_buttons
/ 2;
2997 wv
= xmalloc_widget_value ();
2998 wv
->name
= dialog_name
;
3001 /* Frame title: 'Q' = Question, 'I' = Information.
3002 Can also have 'E' = Error if, one day, we want
3003 a popup for errors. */
3005 dialog_name
[0] = 'Q';
3007 dialog_name
[0] = 'I';
3009 /* Dialog boxes use a really stupid name encoding
3010 which specifies how many buttons to use
3011 and how many buttons are on the right. */
3012 dialog_name
[1] = '0' + nb_buttons
;
3013 dialog_name
[2] = 'B';
3014 dialog_name
[3] = 'R';
3015 /* Number of buttons to put on the right. */
3016 dialog_name
[4] = '0' + nb_buttons
- left_count
;
3018 wv
->contents
= first_wv
;
3022 /* Force a redisplay before showing the dialog. If a frame is created
3023 just before showing the dialog, its contents may not have been fully
3027 /* Actually create the dialog. */
3028 #if TARGET_API_MAC_CARBON
3029 menu_item_selection
= create_and_show_dialog (f
, first_wv
);
3031 menu_item_selection
= mac_dialog (first_wv
);
3034 /* Free the widget_value objects we used to specify the contents. */
3035 free_menubar_widget_value_tree (first_wv
);
3037 /* Find the selected item, and its pane, to return
3038 the proper value. */
3039 if (menu_item_selection
!= 0)
3045 while (i
< menu_items_used
)
3049 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
3052 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
3053 i
+= MENU_ITEMS_PANE_LENGTH
;
3055 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
3057 /* This is the boundary between left-side elts and
3064 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
3065 if (menu_item_selection
== i
)
3069 entry
= Fcons (entry
, Qnil
);
3071 entry
= Fcons (prefix
, entry
);
3075 i
+= MENU_ITEMS_ITEM_LENGTH
;
3080 /* Make "Cancel" equivalent to C-g. */
3081 Fsignal (Qquit
, Qnil
);
3085 #endif /* HAVE_DIALOGS */
3088 /* Is this item a separator? */
3090 name_is_separator (name
)
3093 const char *start
= name
;
3095 /* Check if name string consists of only dashes ('-'). */
3096 while (*name
== '-') name
++;
3097 /* Separators can also be of the form "--:TripleSuperMegaEtched"
3098 or "--deep-shadow". We don't implement them yet, se we just treat
3099 them like normal separators. */
3100 return (*name
== '\0' || start
+ 2 == name
);
3104 add_menu_item (menu
, pos
, wv
)
3109 #if TARGET_API_MAC_CARBON
3110 CFStringRef item_name
;
3115 if (name_is_separator (wv
->name
))
3116 AppendMenu (menu
, "\p-");
3119 AppendMenu (menu
, "\pX");
3121 #if TARGET_API_MAC_CARBON
3122 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
3124 if (wv
->key
!= NULL
)
3126 CFStringRef name
, key
;
3129 key
= cfstring_create_with_utf8_cstring (wv
->key
);
3130 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
3136 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
3137 CFRelease (item_name
);
3140 EnableMenuItem (menu
, pos
);
3142 DisableMenuItem (menu
, pos
);
3144 if (STRINGP (wv
->help
))
3145 SetMenuItemProperty (menu
, pos
, MAC_EMACS_CREATOR_CODE
, 'help',
3146 sizeof (Lisp_Object
), &wv
->help
);
3147 #else /* ! TARGET_API_MAC_CARBON */
3148 item_name
[sizeof (item_name
) - 1] = '\0';
3149 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
3150 if (wv
->key
!= NULL
)
3152 int len
= strlen (item_name
);
3154 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
3155 len
= strlen (item_name
);
3156 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
3159 SetMenuItemText (menu
, pos
, item_name
);
3162 EnableItem (menu
, pos
);
3164 DisableItem (menu
, pos
);
3165 #endif /* ! TARGET_API_MAC_CARBON */
3167 /* Draw radio buttons and tickboxes. */
3168 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
||
3169 wv
->button_type
== BUTTON_TYPE_RADIO
))
3170 SetItemMark (menu
, pos
, checkMark
);
3172 SetItemMark (menu
, pos
, noMark
);
3174 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
3178 /* Construct native Mac OS menu based on widget_value tree. */
3181 fill_menu (menu
, wv
, kind
, submenu_id
)
3184 enum mac_menu_kind kind
;
3189 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
3191 add_menu_item (menu
, pos
, wv
);
3192 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
3194 MenuRef submenu
= NewMenu (submenu_id
, "\pX");
3196 InsertMenu (submenu
, -1);
3197 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
3198 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
3205 /* Construct native Mac OS menubar based on widget_value tree. */
3208 fill_menubar (wv
, deep_p
)
3213 #if !TARGET_API_MAC_CARBON
3214 int title_changed_p
= 0;
3217 /* Clean up the menu bar when filled by the entire menu trees. */
3220 dispose_menus (MAC_MENU_MENU_BAR
, 0);
3221 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
3222 #if !TARGET_API_MAC_CARBON
3223 title_changed_p
= 1;
3227 /* Fill menu bar titles and submenus. Reuse the existing menu bar
3228 titles as much as possible to minimize redraw (if !deep_p). */
3229 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
3230 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
3231 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
3232 wv
= wv
->next
, id
++)
3234 OSStatus err
= noErr
;
3236 #if TARGET_API_MAC_CARBON
3239 title
= CFStringCreateWithCString (NULL
, wv
->name
,
3240 kCFStringEncodingMacRoman
);
3244 strncpy (title
, wv
->name
, 255);
3249 menu
= GetMenuRef (id
);
3252 #if TARGET_API_MAC_CARBON
3253 CFStringRef old_title
;
3255 err
= CopyMenuTitleAsCFString (menu
, &old_title
);
3258 if (CFStringCompare (title
, old_title
, 0) != kCFCompareEqualTo
)
3259 err
= SetMenuTitleWithCFString (menu
, title
);
3260 CFRelease (old_title
);
3263 err
= SetMenuTitleWithCFString (menu
, title
);
3264 #else /* !TARGET_API_MAC_CARBON */
3265 if (!EqualString (title
, (*menu
)->menuData
, false, false))
3269 menu
= NewMenu (id
, title
);
3270 InsertMenu (menu
, GetMenuRef (id
+ 1) ? id
+ 1 : 0);
3271 title_changed_p
= 1;
3273 #endif /* !TARGET_API_MAC_CARBON */
3278 #if TARGET_API_MAC_CARBON
3279 err
= CreateNewMenu (id
, 0, &menu
);
3281 err
= SetMenuTitleWithCFString (menu
, title
);
3283 menu
= NewMenu (id
, title
);
3287 InsertMenu (menu
, 0);
3288 #if !TARGET_API_MAC_CARBON
3289 title_changed_p
= 1;
3293 #if TARGET_API_MAC_CARBON
3299 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
3303 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuRef (id
))
3305 dispose_menus (MAC_MENU_MENU_BAR
, id
);
3306 #if !TARGET_API_MAC_CARBON
3307 title_changed_p
= 1;
3311 #if !TARGET_API_MAC_CARBON
3312 if (title_changed_p
)
3317 /* Dispose of menus that belong to KIND, and remove them from the menu
3318 list. ID is the lower bound of menu IDs that will be processed. */
3321 dispose_menus (kind
, id
)
3322 enum mac_menu_kind kind
;
3325 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
3327 MenuRef menu
= GetMenuRef (id
);
3336 #endif /* HAVE_MENUS */
3338 /* Detect if a menu is currently active. */
3343 return popup_activated_flag
;
3346 /* The following is used by delayed window autoselection. */
3348 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
3349 doc
: /* Return t if a menu or popup dialog is active. */)
3352 #if TARGET_API_MAC_CARBON
3353 return (popup_activated ()) ? Qt
: Qnil
;
3355 /* Always return Qnil since menu selection functions do not return
3356 until a selection has been made or cancelled. */
3364 staticpro (&menu_items
);
3367 Qdebug_on_next_call
= intern ("debug-on-next-call");
3368 staticpro (&Qdebug_on_next_call
);
3370 defsubr (&Sx_popup_menu
);
3371 defsubr (&Smenu_or_popup_active_p
);
3373 defsubr (&Sx_popup_dialog
);
3377 /* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce
3378 (do not change this comment) */