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 /* This undoes save_menu_items, and it is called by the specpdl unwind
310 restore_menu_items (saved
)
313 menu_items
= XCAR (saved
);
314 menu_items_allocated
= (VECTORP (menu_items
) ? ASIZE (menu_items
) : 0);
315 saved
= XCDR (saved
);
316 menu_items_used
= XINT (XCAR (saved
));
317 saved
= XCDR (saved
);
318 menu_items_n_panes
= XINT (XCAR (saved
));
319 saved
= XCDR (saved
);
320 menu_items_submenu_depth
= XINT (XCAR (saved
));
323 /* Push the whole state of menu_items processing onto the specpdl.
324 It will be restored when the specpdl is unwound. */
329 Lisp_Object saved
= list4 (menu_items
,
330 make_number (menu_items_used
),
331 make_number (menu_items_n_panes
),
332 make_number (menu_items_submenu_depth
));
333 record_unwind_protect (restore_menu_items
, saved
);
337 /* Make the menu_items vector twice as large. */
343 int old_size
= menu_items_allocated
;
346 menu_items_allocated
*= 2;
348 menu_items
= Fmake_vector (make_number (menu_items_allocated
), Qnil
);
349 bcopy (XVECTOR (old
)->contents
, XVECTOR (menu_items
)->contents
,
350 old_size
* sizeof (Lisp_Object
));
353 /* Begin a submenu. */
356 push_submenu_start ()
358 if (menu_items_used
+ 1 > menu_items_allocated
)
361 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qnil
;
362 menu_items_submenu_depth
++;
370 if (menu_items_used
+ 1 > menu_items_allocated
)
373 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qlambda
;
374 menu_items_submenu_depth
--;
377 /* Indicate boundary between left and right. */
380 push_left_right_boundary ()
382 if (menu_items_used
+ 1 > menu_items_allocated
)
385 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qquote
;
388 /* Start a new menu pane in menu_items.
389 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
392 push_menu_pane (name
, prefix_vec
)
393 Lisp_Object name
, prefix_vec
;
395 if (menu_items_used
+ MENU_ITEMS_PANE_LENGTH
> menu_items_allocated
)
398 if (menu_items_submenu_depth
== 0)
399 menu_items_n_panes
++;
400 XVECTOR (menu_items
)->contents
[menu_items_used
++] = Qt
;
401 XVECTOR (menu_items
)->contents
[menu_items_used
++] = name
;
402 XVECTOR (menu_items
)->contents
[menu_items_used
++] = prefix_vec
;
405 /* Push one menu item into the current pane. NAME is the string to
406 display. ENABLE if non-nil means this item can be selected. KEY
407 is the key generated by choosing this item, or nil if this item
408 doesn't really have a definition. DEF is the definition of this
409 item. EQUIV is the textual description of the keyboard equivalent
410 for this item (or nil if none). TYPE is the type of this menu
411 item, one of nil, `toggle' or `radio'. */
414 push_menu_item (name
, enable
, key
, def
, equiv
, type
, selected
, help
)
415 Lisp_Object name
, enable
, key
, def
, equiv
, type
, selected
, help
;
417 if (menu_items_used
+ MENU_ITEMS_ITEM_LENGTH
> menu_items_allocated
)
420 XVECTOR (menu_items
)->contents
[menu_items_used
++] = name
;
421 XVECTOR (menu_items
)->contents
[menu_items_used
++] = enable
;
422 XVECTOR (menu_items
)->contents
[menu_items_used
++] = key
;
423 XVECTOR (menu_items
)->contents
[menu_items_used
++] = equiv
;
424 XVECTOR (menu_items
)->contents
[menu_items_used
++] = def
;
425 XVECTOR (menu_items
)->contents
[menu_items_used
++] = type
;
426 XVECTOR (menu_items
)->contents
[menu_items_used
++] = selected
;
427 XVECTOR (menu_items
)->contents
[menu_items_used
++] = help
;
430 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
431 and generate menu panes for them in menu_items.
432 If NOTREAL is nonzero,
433 don't bother really computing whether an item is enabled. */
436 keymap_panes (keymaps
, nmaps
, notreal
)
437 Lisp_Object
*keymaps
;
445 /* Loop over the given keymaps, making a pane for each map.
446 But don't make a pane that is empty--ignore that map instead.
447 P is the number of panes we have made so far. */
448 for (mapno
= 0; mapno
< nmaps
; mapno
++)
449 single_keymap_panes (keymaps
[mapno
],
450 Fkeymap_prompt (keymaps
[mapno
]), Qnil
, notreal
, 10);
452 finish_menu_items ();
455 /* Args passed between single_keymap_panes and single_menu_item. */
458 Lisp_Object pending_maps
;
459 int maxdepth
, notreal
;
462 static void single_menu_item
P_ ((Lisp_Object
, Lisp_Object
, Lisp_Object
,
465 /* This is a recursive subroutine of keymap_panes.
466 It handles one keymap, KEYMAP.
467 The other arguments are passed along
468 or point to local variables of the previous function.
469 If NOTREAL is nonzero, only check for equivalent key bindings, don't
470 evaluate expressions in menu items and don't make any menu.
472 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
475 single_keymap_panes (keymap
, pane_name
, prefix
, notreal
, maxdepth
)
477 Lisp_Object pane_name
;
485 skp
.pending_maps
= Qnil
;
486 skp
.maxdepth
= maxdepth
;
487 skp
.notreal
= notreal
;
492 push_menu_pane (pane_name
, prefix
);
494 GCPRO1 (skp
.pending_maps
);
495 map_keymap (keymap
, single_menu_item
, Qnil
, &skp
, 1);
498 /* Process now any submenus which want to be panes at this level. */
499 while (CONSP (skp
.pending_maps
))
501 Lisp_Object elt
, eltcdr
, string
;
502 elt
= XCAR (skp
.pending_maps
);
504 string
= XCAR (eltcdr
);
505 /* We no longer discard the @ from the beginning of the string here.
506 Instead, we do this in mac_menu_show. */
507 single_keymap_panes (Fcar (elt
), string
,
508 XCDR (eltcdr
), notreal
, maxdepth
- 1);
509 skp
.pending_maps
= XCDR (skp
.pending_maps
);
513 /* This is a subroutine of single_keymap_panes that handles one
515 KEY is a key in a keymap and ITEM is its binding.
516 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
518 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
519 evaluate expressions in menu items and don't make any menu.
520 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. */
523 single_menu_item (key
, item
, dummy
, skp_v
)
524 Lisp_Object key
, item
, dummy
;
527 Lisp_Object map
, item_string
, enabled
;
528 struct gcpro gcpro1
, gcpro2
;
530 struct skp
*skp
= skp_v
;
532 /* Parse the menu item and leave the result in item_properties. */
534 res
= parse_menu_item (item
, skp
->notreal
, 0);
537 return; /* Not a menu item. */
539 map
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_MAP
];
543 /* We don't want to make a menu, just traverse the keymaps to
544 precompute equivalent key bindings. */
546 single_keymap_panes (map
, Qnil
, key
, 1, skp
->maxdepth
- 1);
550 enabled
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_ENABLE
];
551 item_string
= XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_NAME
];
553 if (!NILP (map
) && SREF (item_string
, 0) == '@')
556 /* An enabled separate pane. Remember this to handle it later. */
557 skp
->pending_maps
= Fcons (Fcons (map
, Fcons (item_string
, key
)),
562 push_menu_item (item_string
, enabled
, key
,
563 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_DEF
],
564 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_KEYEQ
],
565 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_TYPE
],
566 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_SELECTED
],
567 XVECTOR (item_properties
)->contents
[ITEM_PROPERTY_HELP
]);
569 /* Display a submenu using the toolkit. */
570 if (! (NILP (map
) || NILP (enabled
)))
572 push_submenu_start ();
573 single_keymap_panes (map
, Qnil
, key
, 0, skp
->maxdepth
- 1);
578 /* Push all the panes and items of a menu described by the
579 alist-of-alists MENU.
580 This handles old-fashioned calls to x-popup-menu. */
590 for (tail
= menu
; CONSP (tail
); tail
= XCDR (tail
))
592 Lisp_Object elt
, pane_name
, pane_data
;
594 pane_name
= Fcar (elt
);
595 CHECK_STRING (pane_name
);
596 push_menu_pane (ENCODE_MENU_STRING (pane_name
), Qnil
);
597 pane_data
= Fcdr (elt
);
598 CHECK_CONS (pane_data
);
599 list_of_items (pane_data
);
602 finish_menu_items ();
605 /* Push the items in a single pane defined by the alist PANE. */
611 Lisp_Object tail
, item
, item1
;
613 for (tail
= pane
; CONSP (tail
); tail
= XCDR (tail
))
617 push_menu_item (ENCODE_MENU_STRING (item
), Qnil
, Qnil
, Qt
,
618 Qnil
, Qnil
, Qnil
, Qnil
);
619 else if (CONSP (item
))
622 CHECK_STRING (item1
);
623 push_menu_item (ENCODE_MENU_STRING (item1
), Qt
, XCDR (item
),
624 Qt
, Qnil
, Qnil
, Qnil
, Qnil
);
627 push_left_right_boundary ();
633 cleanup_popup_menu (arg
)
636 discard_menu_items ();
639 DEFUN ("x-popup-menu", Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
640 doc
: /* Pop up a deck-of-cards menu and return user's selection.
641 POSITION is a position specification. This is either a mouse button event
642 or a list ((XOFFSET YOFFSET) WINDOW)
643 where XOFFSET and YOFFSET are positions in pixels from the top left
644 corner of WINDOW. (WINDOW may be a window or a frame object.)
645 This controls the position of the top left of the menu as a whole.
646 If POSITION is t, it means to use the current mouse position.
648 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
649 The menu items come from key bindings that have a menu string as well as
650 a definition; actually, the "definition" in such a key binding looks like
651 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
652 the keymap as a top-level element.
654 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
655 Otherwise, REAL-DEFINITION should be a valid key binding definition.
657 You can also use a list of keymaps as MENU.
658 Then each keymap makes a separate pane.
660 When MENU is a keymap or a list of keymaps, the return value is the
661 list of events corresponding to the user's choice. Note that
662 `x-popup-menu' does not actually execute the command bound to that
665 Alternatively, you can specify a menu of multiple panes
666 with a list of the form (TITLE PANE1 PANE2...),
667 where each pane is a list of form (TITLE ITEM1 ITEM2...).
668 Each ITEM is normally a cons cell (STRING . VALUE);
669 but a string can appear as an item--that makes a nonselectable line
671 With this form of menu, the return value is VALUE from the chosen item.
673 If POSITION is nil, don't display the menu at all, just precalculate the
674 cached information about equivalent key sequences.
676 If the user gets rid of the menu without making a valid choice, for
677 instance by clicking the mouse away from a valid choice or by typing
678 keyboard input, then this normally results in a quit and
679 `x-popup-menu' does not return. But if POSITION is a mouse button
680 event (indicating that the user invoked the menu with the mouse) then
681 no quit occurs and `x-popup-menu' returns nil. */)
683 Lisp_Object position
, menu
;
685 Lisp_Object keymap
, tem
;
686 int xpos
= 0, ypos
= 0;
688 char *error_name
= NULL
;
689 Lisp_Object selection
;
691 Lisp_Object x
, y
, window
;
694 int specpdl_count
= SPECPDL_INDEX ();
698 if (! NILP (position
))
702 /* Decode the first argument: find the window and the coordinates. */
703 if (EQ (position
, Qt
)
704 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
705 || EQ (XCAR (position
), Qtool_bar
)
706 || EQ (XCAR (position
), Qmac_apple_event
))))
708 /* Use the mouse's current position. */
709 FRAME_PTR new_f
= SELECTED_FRAME ();
710 Lisp_Object bar_window
;
711 enum scroll_bar_part part
;
714 if (mouse_position_hook
)
715 (*mouse_position_hook
) (&new_f
, 1, &bar_window
,
716 &part
, &x
, &y
, &time
);
718 XSETFRAME (window
, new_f
);
721 window
= selected_window
;
728 tem
= Fcar (position
);
731 window
= Fcar (Fcdr (position
));
733 y
= Fcar (XCDR (tem
));
738 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
739 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
740 tem
= Fcar (Fcdr (Fcdr (tem
))); /* POSN_WINDOW_POSN (tem) */
749 /* Decode where to put the menu. */
757 else if (WINDOWP (window
))
759 CHECK_LIVE_WINDOW (window
);
760 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
762 xpos
= WINDOW_LEFT_EDGE_X (XWINDOW (window
));
763 ypos
= WINDOW_TOP_EDGE_Y (XWINDOW (window
));
766 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
767 but I don't want to make one now. */
768 CHECK_WINDOW (window
);
773 XSETFRAME (Vmenu_updating_frame
, f
);
776 Vmenu_updating_frame
= Qnil
;
777 #endif /* HAVE_MENUS */
782 /* Decode the menu items from what was specified. */
784 keymap
= get_keymap (menu
, 0, 0);
787 /* We were given a keymap. Extract menu info from the keymap. */
790 /* Extract the detailed info to make one pane. */
791 keymap_panes (&menu
, 1, NILP (position
));
793 /* Search for a string appearing directly as an element of the keymap.
794 That string is the title of the menu. */
795 prompt
= Fkeymap_prompt (keymap
);
796 if (NILP (title
) && !NILP (prompt
))
799 /* Make that be the pane title of the first pane. */
800 if (!NILP (prompt
) && menu_items_n_panes
>= 0)
801 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
805 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
807 /* We were given a list of keymaps. */
808 int nmaps
= XFASTINT (Flength (menu
));
810 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
815 /* The first keymap that has a prompt string
816 supplies the menu title. */
817 for (tem
= menu
, i
= 0; CONSP (tem
); tem
= XCDR (tem
))
821 maps
[i
++] = keymap
= get_keymap (XCAR (tem
), 1, 0);
823 prompt
= Fkeymap_prompt (keymap
);
824 if (NILP (title
) && !NILP (prompt
))
828 /* Extract the detailed info to make one pane. */
829 keymap_panes (maps
, nmaps
, NILP (position
));
831 /* Make the title be the pane title of the first pane. */
832 if (!NILP (title
) && menu_items_n_panes
>= 0)
833 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title
;
839 /* We were given an old-fashioned menu. */
841 CHECK_STRING (title
);
843 list_of_panes (Fcdr (menu
));
850 discard_menu_items ();
856 /* Display them in a menu. */
857 record_unwind_protect (cleanup_popup_menu
, Qnil
);
860 selection
= mac_menu_show (f
, xpos
, ypos
, for_click
,
861 keymaps
, title
, &error_name
);
863 unbind_to (specpdl_count
, Qnil
);
866 #endif /* HAVE_MENUS */
868 if (error_name
) error (error_name
);
874 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
875 doc
: /* Pop up a dialog box and return user's selection.
876 POSITION specifies which frame to use.
877 This is normally a mouse button event or a window or frame.
878 If POSITION is t, it means to use the frame the mouse is on.
879 The dialog box appears in the middle of the specified frame.
881 CONTENTS specifies the alternatives to display in the dialog box.
882 It is a list of the form (DIALOG ITEM1 ITEM2...).
883 Each ITEM is a cons cell (STRING . VALUE).
884 The return value is VALUE from the chosen item.
886 An ITEM may also be just a string--that makes a nonselectable item.
887 An ITEM may also be nil--that means to put all preceding items
888 on the left of the dialog box and all following items on the right.
889 \(By default, approximately half appear on each side.)
891 If HEADER is non-nil, the frame title for the box is "Information",
892 otherwise it is "Question".
894 If the user gets rid of the dialog box without making a valid choice,
895 for instance using the window manager, then this produces a quit and
896 `x-popup-dialog' does not return. */)
897 (position
, contents
, header
)
898 Lisp_Object position
, contents
, header
;
905 /* Decode the first argument: find the window or frame to use. */
906 if (EQ (position
, Qt
)
907 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
908 || EQ (XCAR (position
), Qtool_bar
)
909 || EQ (XCAR (position
), Qmac_apple_event
))))
911 #if 0 /* Using the frame the mouse is on may not be right. */
912 /* Use the mouse's current position. */
913 FRAME_PTR new_f
= SELECTED_FRAME ();
914 Lisp_Object bar_window
;
915 enum scroll_bar_part part
;
919 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
922 XSETFRAME (window
, new_f
);
924 window
= selected_window
;
926 window
= selected_window
;
928 else if (CONSP (position
))
931 tem
= Fcar (position
);
933 window
= Fcar (Fcdr (position
));
936 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
937 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
940 else if (WINDOWP (position
) || FRAMEP (position
))
945 /* Decode where to put the menu. */
949 else if (WINDOWP (window
))
951 CHECK_LIVE_WINDOW (window
);
952 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
955 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
956 but I don't want to make one now. */
957 CHECK_WINDOW (window
);
960 /* Display a menu with these alternatives
961 in the middle of frame F. */
963 Lisp_Object x
, y
, frame
, newpos
;
964 XSETFRAME (frame
, f
);
965 XSETINT (x
, x_pixel_width (f
) / 2);
966 XSETINT (y
, x_pixel_height (f
) / 2);
967 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
969 return Fx_popup_menu (newpos
,
970 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
972 #else /* HAVE_DIALOGS */
976 Lisp_Object selection
;
977 int specpdl_count
= SPECPDL_INDEX ();
979 /* Decode the dialog items from what was specified. */
980 title
= Fcar (contents
);
981 CHECK_STRING (title
);
983 list_of_panes (Fcons (contents
, Qnil
));
985 /* Display them in a dialog box. */
986 record_unwind_protect (cleanup_popup_menu
, Qnil
);
988 selection
= mac_dialog_show (f
, 0, title
, header
, &error_name
);
990 unbind_to (specpdl_count
, Qnil
);
992 if (error_name
) error (error_name
);
995 #endif /* HAVE_DIALOGS */
998 /* Activate the menu bar of frame F.
999 This is called from keyboard.c when it gets the
1000 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
1002 To activate the menu bar, we use the button-press event location
1003 that was saved in saved_menu_event_location.
1005 But first we recompute the menu bar contents (the whole tree).
1007 The reason for saving the button event until here, instead of
1008 passing it to the toolkit right away, is that we can safely
1009 execute Lisp code. */
1012 x_activate_menubar (f
)
1016 extern Point saved_menu_event_location
;
1018 set_frame_menubar (f
, 0, 1);
1021 menu_choice
= MenuSelect (saved_menu_event_location
);
1022 do_menu_choice (menu_choice
);
1027 /* This callback is called from the menu bar pulldown menu
1028 when the user makes a selection.
1029 Figure out what the user chose
1030 and put the appropriate events into the keyboard buffer. */
1033 menubar_selection_callback (FRAME_PTR f
, int client_data
)
1035 Lisp_Object prefix
, entry
;
1037 Lisp_Object
*subprefix_stack
;
1038 int submenu_depth
= 0;
1044 subprefix_stack
= (Lisp_Object
*) alloca (f
->menu_bar_items_used
* sizeof (Lisp_Object
));
1045 vector
= f
->menu_bar_vector
;
1048 while (i
< f
->menu_bar_items_used
)
1050 if (EQ (XVECTOR (vector
)->contents
[i
], Qnil
))
1052 subprefix_stack
[submenu_depth
++] = prefix
;
1056 else if (EQ (XVECTOR (vector
)->contents
[i
], Qlambda
))
1058 prefix
= subprefix_stack
[--submenu_depth
];
1061 else if (EQ (XVECTOR (vector
)->contents
[i
], Qt
))
1063 prefix
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1064 i
+= MENU_ITEMS_PANE_LENGTH
;
1068 entry
= XVECTOR (vector
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1069 /* The EMACS_INT cast avoids a warning. There's no problem
1070 as long as pointers have enough bits to hold small integers. */
1071 if ((int) (EMACS_INT
) client_data
== i
)
1074 struct input_event buf
;
1078 XSETFRAME (frame
, f
);
1079 buf
.kind
= MENU_BAR_EVENT
;
1080 buf
.frame_or_window
= frame
;
1082 kbd_buffer_store_event (&buf
);
1084 for (j
= 0; j
< submenu_depth
; j
++)
1085 if (!NILP (subprefix_stack
[j
]))
1087 buf
.kind
= MENU_BAR_EVENT
;
1088 buf
.frame_or_window
= frame
;
1089 buf
.arg
= subprefix_stack
[j
];
1090 kbd_buffer_store_event (&buf
);
1095 buf
.kind
= MENU_BAR_EVENT
;
1096 buf
.frame_or_window
= frame
;
1098 kbd_buffer_store_event (&buf
);
1101 buf
.kind
= MENU_BAR_EVENT
;
1102 buf
.frame_or_window
= frame
;
1104 kbd_buffer_store_event (&buf
);
1106 f
->output_data
.mac
->menubar_active
= 0;
1109 i
+= MENU_ITEMS_ITEM_LENGTH
;
1112 f
->output_data
.mac
->menubar_active
= 0;
1115 /* Allocate a widget_value, blocking input. */
1118 xmalloc_widget_value ()
1120 widget_value
*value
;
1123 value
= malloc_widget_value ();
1129 /* This recursively calls free_widget_value on the tree of widgets.
1130 It must free all data that was malloc'ed for these widget_values.
1131 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1132 must be left alone. */
1135 free_menubar_widget_value_tree (wv
)
1140 wv
->name
= wv
->value
= wv
->key
= (char *) 0xDEADBEEF;
1142 if (wv
->contents
&& (wv
->contents
!= (widget_value
*)1))
1144 free_menubar_widget_value_tree (wv
->contents
);
1145 wv
->contents
= (widget_value
*) 0xDEADBEEF;
1149 free_menubar_widget_value_tree (wv
->next
);
1150 wv
->next
= (widget_value
*) 0xDEADBEEF;
1153 free_widget_value (wv
);
1157 /* Set up data in menu_items for a menu bar item
1158 whose event type is ITEM_KEY (with string ITEM_NAME)
1159 and whose contents come from the list of keymaps MAPS. */
1162 parse_single_submenu (item_key
, item_name
, maps
)
1163 Lisp_Object item_key
, item_name
, maps
;
1167 Lisp_Object
*mapvec
;
1169 int top_level_items
= 0;
1171 length
= Flength (maps
);
1172 len
= XINT (length
);
1174 /* Convert the list MAPS into a vector MAPVEC. */
1175 mapvec
= (Lisp_Object
*) alloca (len
* sizeof (Lisp_Object
));
1176 for (i
= 0; i
< len
; i
++)
1178 mapvec
[i
] = Fcar (maps
);
1182 /* Loop over the given keymaps, making a pane for each map.
1183 But don't make a pane that is empty--ignore that map instead. */
1184 for (i
= 0; i
< len
; i
++)
1186 if (!KEYMAPP (mapvec
[i
]))
1188 /* Here we have a command at top level in the menu bar
1189 as opposed to a submenu. */
1190 top_level_items
= 1;
1191 push_menu_pane (Qnil
, Qnil
);
1192 push_menu_item (item_name
, Qt
, item_key
, mapvec
[i
],
1193 Qnil
, Qnil
, Qnil
, Qnil
);
1198 prompt
= Fkeymap_prompt (mapvec
[i
]);
1199 single_keymap_panes (mapvec
[i
],
1200 !NILP (prompt
) ? prompt
: item_name
,
1205 return top_level_items
;
1208 /* Create a tree of widget_value objects
1209 representing the panes and items
1210 in menu_items starting at index START, up to index END. */
1212 static widget_value
*
1213 digest_single_submenu (start
, end
, top_level_items
)
1214 int start
, end
, top_level_items
;
1216 widget_value
*wv
, *prev_wv
, *save_wv
, *first_wv
;
1218 int submenu_depth
= 0;
1219 widget_value
**submenu_stack
;
1223 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1224 wv
= xmalloc_widget_value ();
1228 wv
->button_type
= BUTTON_TYPE_NONE
;
1234 /* Loop over all panes and items made by the preceding call
1235 to parse_single_submenu and construct a tree of widget_value objects.
1236 Ignore the panes and items used by previous calls to
1237 digest_single_submenu, even though those are also in menu_items. */
1241 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1243 submenu_stack
[submenu_depth
++] = save_wv
;
1248 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1251 save_wv
= submenu_stack
[--submenu_depth
];
1254 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1255 && submenu_depth
!= 0)
1256 i
+= MENU_ITEMS_PANE_LENGTH
;
1257 /* Ignore a nil in the item list.
1258 It's meaningful only for dialog boxes. */
1259 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1261 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1263 /* Create a new pane. */
1264 Lisp_Object pane_name
, prefix
;
1269 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
1270 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1272 #ifndef HAVE_MULTILINGUAL_MENU
1273 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1275 pane_name
= ENCODE_MENU_STRING (pane_name
);
1276 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1279 pane_string
= (NILP (pane_name
)
1280 ? "" : (char *) SDATA (pane_name
));
1281 /* If there is just one top-level pane, put all its items directly
1282 under the top-level menu. */
1283 if (menu_items_n_panes
== 1)
1286 /* If the pane has a meaningful name,
1287 make the pane a top-level menu item
1288 with its items as a submenu beneath it. */
1289 if (strcmp (pane_string
, ""))
1291 wv
= xmalloc_widget_value ();
1295 first_wv
->contents
= wv
;
1296 wv
->lname
= pane_name
;
1297 /* Set value to 1 so update_submenu_strings can handle '@' */
1298 wv
->value
= (char *)1;
1300 wv
->button_type
= BUTTON_TYPE_NONE
;
1308 i
+= MENU_ITEMS_PANE_LENGTH
;
1312 /* Create a new item within current pane. */
1313 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
;
1316 /* All items should be contained in panes. */
1317 if (panes_seen
== 0)
1320 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1321 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1322 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1323 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1324 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1325 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1326 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1328 #ifndef HAVE_MULTILINGUAL_MENU
1329 if (STRING_MULTIBYTE (item_name
))
1331 item_name
= ENCODE_MENU_STRING (item_name
);
1332 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1335 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1337 descrip
= ENCODE_MENU_STRING (descrip
);
1338 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1340 #endif /* not HAVE_MULTILINGUAL_MENU */
1342 wv
= xmalloc_widget_value ();
1346 save_wv
->contents
= wv
;
1348 wv
->lname
= item_name
;
1349 if (!NILP (descrip
))
1352 /* The EMACS_INT cast avoids a warning. There's no problem
1353 as long as pointers have enough bits to hold small integers. */
1354 wv
->call_data
= (!NILP (def
) ? (void *) (EMACS_INT
) i
: 0);
1355 wv
->enabled
= !NILP (enable
);
1358 wv
->button_type
= BUTTON_TYPE_NONE
;
1359 else if (EQ (type
, QCradio
))
1360 wv
->button_type
= BUTTON_TYPE_RADIO
;
1361 else if (EQ (type
, QCtoggle
))
1362 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1366 wv
->selected
= !NILP (selected
);
1367 if (! STRINGP (help
))
1374 i
+= MENU_ITEMS_ITEM_LENGTH
;
1378 /* If we have just one "menu item"
1379 that was originally a button, return it by itself. */
1380 if (top_level_items
&& first_wv
->contents
&& first_wv
->contents
->next
== 0)
1382 wv
= first_wv
->contents
;
1383 free_widget_value (first_wv
);
1390 /* Walk through the widget_value tree starting at FIRST_WV and update
1391 the char * pointers from the corresponding lisp values.
1392 We do this after building the whole tree, since GC may happen while the
1393 tree is constructed, and small strings are relocated. So we must wait
1394 until no GC can happen before storing pointers into lisp values. */
1396 update_submenu_strings (first_wv
)
1397 widget_value
*first_wv
;
1401 for (wv
= first_wv
; wv
; wv
= wv
->next
)
1403 if (STRINGP (wv
->lname
))
1405 wv
->name
= SDATA (wv
->lname
);
1407 /* Ignore the @ that means "separate pane".
1408 This is a kludge, but this isn't worth more time. */
1409 if (wv
->value
== (char *)1)
1411 if (wv
->name
[0] == '@')
1417 if (STRINGP (wv
->lkey
))
1418 wv
->key
= SDATA (wv
->lkey
);
1421 update_submenu_strings (wv
->contents
);
1426 /* Event handler function that pops down a menu on C-g. We can only pop
1427 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1429 #ifdef HAVE_CANCELMENUTRACKING
1430 static pascal OSStatus
1431 menu_quit_handler (nextHandler
, theEvent
, userData
)
1432 EventHandlerCallRef nextHandler
;
1438 UInt32 keyModifiers
;
1439 extern int mac_quit_char_modifiers
;
1440 extern int mac_quit_char_keycode
;
1442 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
1443 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
1446 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
1447 typeUInt32
, NULL
, sizeof(UInt32
),
1448 NULL
, &keyModifiers
);
1450 if (err
== noErr
&& keyCode
== mac_quit_char_keycode
1451 && keyModifiers
== mac_quit_char_modifiers
)
1453 MenuRef menu
= userData
!= 0
1454 ? (MenuRef
)userData
: AcquireRootMenu ();
1456 CancelMenuTracking (menu
, true, 0);
1457 if (!userData
) ReleaseMenu (menu
);
1461 return CallNextEventHandler (nextHandler
, theEvent
);
1463 #endif /* HAVE_CANCELMENUTRACKING */
1465 /* Add event handler to all menus that belong to KIND so we can detect C-g.
1466 MENU_HANDLE is the root menu of the tracking session to dismiss
1467 when C-g is detected. NULL means the menu bar.
1468 If CancelMenuTracking isn't available, do nothing. */
1471 install_menu_quit_handler (kind
, menu_handle
)
1472 enum mac_menu_kind kind
;
1473 MenuHandle menu_handle
;
1475 #ifdef HAVE_CANCELMENUTRACKING
1476 EventTypeSpec typesList
[] = { { kEventClassKeyboard
, kEventRawKeyDown
} };
1479 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
1481 MenuHandle menu
= GetMenuHandle (id
);
1485 InstallMenuEventHandler (menu
, menu_quit_handler
,
1486 GetEventTypeCount (typesList
),
1487 typesList
, menu_handle
, NULL
);
1489 #endif /* HAVE_CANCELMENUTRACKING */
1492 /* Set the contents of the menubar widgets of frame F.
1493 The argument FIRST_TIME is currently ignored;
1494 it is set the first time this is called, from initialize_frame_menubar. */
1497 set_frame_menubar (f
, first_time
, deep_p
)
1502 int menubar_widget
= f
->output_data
.mac
->menubar_widget
;
1504 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1506 int *submenu_start
, *submenu_end
;
1507 int *submenu_top_level_items
, *submenu_n_panes
;
1509 /* We must not change the menubar when actually in use. */
1510 if (f
->output_data
.mac
->menubar_active
)
1513 XSETFRAME (Vmenu_updating_frame
, f
);
1515 if (! menubar_widget
)
1517 else if (pending_menu_activation
&& !deep_p
)
1522 /* Make a widget-value tree representing the entire menu trees. */
1524 struct buffer
*prev
= current_buffer
;
1526 int specpdl_count
= SPECPDL_INDEX ();
1527 int previous_menu_items_used
= f
->menu_bar_items_used
;
1528 Lisp_Object
*previous_items
1529 = (Lisp_Object
*) alloca (previous_menu_items_used
1530 * sizeof (Lisp_Object
));
1532 /* If we are making a new widget, its contents are empty,
1533 do always reinitialize them. */
1534 if (! menubar_widget
)
1535 previous_menu_items_used
= 0;
1537 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1538 specbind (Qinhibit_quit
, Qt
);
1539 /* Don't let the debugger step into this code
1540 because it is not reentrant. */
1541 specbind (Qdebug_on_next_call
, Qnil
);
1543 record_unwind_save_match_data ();
1544 if (NILP (Voverriding_local_map_menu_flag
))
1546 specbind (Qoverriding_terminal_local_map
, Qnil
);
1547 specbind (Qoverriding_local_map
, Qnil
);
1550 set_buffer_internal_1 (XBUFFER (buffer
));
1552 /* Run the Lucid hook. */
1553 safe_run_hooks (Qactivate_menubar_hook
);
1555 /* If it has changed current-menubar from previous value,
1556 really recompute the menubar from the value. */
1557 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1558 call0 (Qrecompute_lucid_menubar
);
1559 safe_run_hooks (Qmenu_bar_update_hook
);
1560 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1562 items
= FRAME_MENU_BAR_ITEMS (f
);
1564 /* Save the frame's previous menu bar contents data. */
1565 if (previous_menu_items_used
)
1566 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1567 previous_menu_items_used
* sizeof (Lisp_Object
));
1569 /* Fill in menu_items with the current menu bar contents.
1570 This can evaluate Lisp code. */
1573 menu_items
= f
->menu_bar_vector
;
1574 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1575 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1576 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1577 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1578 submenu_top_level_items
1579 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1581 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1583 Lisp_Object key
, string
, maps
;
1587 key
= XVECTOR (items
)->contents
[i
];
1588 string
= XVECTOR (items
)->contents
[i
+ 1];
1589 maps
= XVECTOR (items
)->contents
[i
+ 2];
1593 submenu_start
[i
] = menu_items_used
;
1595 menu_items_n_panes
= 0;
1596 submenu_top_level_items
[i
]
1597 = parse_single_submenu (key
, string
, maps
);
1598 submenu_n_panes
[i
] = menu_items_n_panes
;
1600 submenu_end
[i
] = menu_items_used
;
1603 finish_menu_items ();
1605 /* Convert menu_items into widget_value trees
1606 to display the menu. This cannot evaluate Lisp code. */
1608 wv
= xmalloc_widget_value ();
1609 wv
->name
= "menubar";
1612 wv
->button_type
= BUTTON_TYPE_NONE
;
1616 for (i
= 0; i
< last_i
; i
+= 4)
1618 menu_items_n_panes
= submenu_n_panes
[i
];
1619 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1620 submenu_top_level_items
[i
]);
1624 first_wv
->contents
= wv
;
1625 /* Don't set wv->name here; GC during the loop might relocate it. */
1627 wv
->button_type
= BUTTON_TYPE_NONE
;
1631 set_buffer_internal_1 (prev
);
1633 /* If there has been no change in the Lisp-level contents
1634 of the menu bar, skip redisplaying it. Just exit. */
1636 /* Compare the new menu items with the ones computed last time. */
1637 for (i
= 0; i
< previous_menu_items_used
; i
++)
1638 if (menu_items_used
== i
1639 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1641 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1643 /* The menu items have not changed. Don't bother updating
1644 the menus in any form, since it would be a no-op. */
1645 free_menubar_widget_value_tree (first_wv
);
1646 discard_menu_items ();
1647 unbind_to (specpdl_count
, Qnil
);
1651 /* The menu items are different, so store them in the frame. */
1652 f
->menu_bar_vector
= menu_items
;
1653 f
->menu_bar_items_used
= menu_items_used
;
1655 /* This calls restore_menu_items to restore menu_items, etc.,
1656 as they were outside. */
1657 unbind_to (specpdl_count
, Qnil
);
1659 /* Now GC cannot happen during the lifetime of the widget_value,
1660 so it's safe to store data from a Lisp_String. */
1661 wv
= first_wv
->contents
;
1662 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1665 string
= XVECTOR (items
)->contents
[i
+ 1];
1668 wv
->name
= (char *) SDATA (string
);
1669 update_submenu_strings (wv
->contents
);
1676 /* Make a widget-value tree containing
1677 just the top level menu bar strings. */
1679 wv
= xmalloc_widget_value ();
1680 wv
->name
= "menubar";
1683 wv
->button_type
= BUTTON_TYPE_NONE
;
1687 items
= FRAME_MENU_BAR_ITEMS (f
);
1688 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1692 string
= XVECTOR (items
)->contents
[i
+ 1];
1696 wv
= xmalloc_widget_value ();
1697 wv
->name
= (char *) SDATA (string
);
1700 wv
->button_type
= BUTTON_TYPE_NONE
;
1702 /* This prevents lwlib from assuming this
1703 menu item is really supposed to be empty. */
1704 /* The EMACS_INT cast avoids a warning.
1705 This value just has to be different from small integers. */
1706 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1711 first_wv
->contents
= wv
;
1715 /* Forget what we thought we knew about what is in the
1716 detailed contents of the menu bar menus.
1717 Changing the top level always destroys the contents. */
1718 f
->menu_bar_items_used
= 0;
1721 /* Create or update the menu bar widget. */
1725 /* Non-null value to indicate menubar has already been "created". */
1726 f
->output_data
.mac
->menubar_widget
= 1;
1728 fill_menubar (first_wv
->contents
, deep_p
);
1730 /* Add event handler so we can detect C-g. */
1731 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
1732 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
1733 free_menubar_widget_value_tree (first_wv
);
1738 /* Get rid of the menu bar of frame F, and free its storage.
1739 This is used when deleting a frame, and when turning off the menu bar. */
1742 free_frame_menubar (f
)
1745 f
->output_data
.mac
->menubar_widget
= 0;
1753 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1754 FRAME_PTR f
= p
->pointer
;
1755 MenuHandle menu
= GetMenuHandle (min_menu_id
[MAC_MENU_POPUP
]);
1759 /* Must reset this manually because the button release event is not
1760 passed to Emacs event loop. */
1761 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
1763 /* delete all menus */
1764 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
1765 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
1773 /* Mac_menu_show actually displays a menu using the panes and items in
1774 menu_items and returns the value selected from it; we assume input
1775 is blocked by the caller. */
1777 /* F is the frame the menu is for.
1778 X and Y are the frame-relative specified position,
1779 relative to the inside upper left corner of the frame F.
1780 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1781 KEYMAPS is 1 if this menu was specified with keymaps;
1782 in that case, we return a list containing the chosen item's value
1783 and perhaps also the pane's prefix.
1784 TITLE is the specified menu title.
1785 ERROR is a place to store an error message string in case of failure.
1786 (We return nil on failure, but the value doesn't actually matter.) */
1789 mac_menu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
1800 int menu_item_choice
;
1801 int menu_item_selection
;
1804 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1805 widget_value
**submenu_stack
1806 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1807 Lisp_Object
*subprefix_stack
1808 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1809 int submenu_depth
= 0;
1812 int specpdl_count
= SPECPDL_INDEX ();
1816 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1818 *error
= "Empty menu";
1822 /* Create a tree of widget_value objects
1823 representing the panes and their items. */
1824 wv
= xmalloc_widget_value ();
1828 wv
->button_type
= BUTTON_TYPE_NONE
;
1833 /* Loop over all panes and items, filling in the tree. */
1835 while (i
< menu_items_used
)
1837 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1839 submenu_stack
[submenu_depth
++] = save_wv
;
1845 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1848 save_wv
= submenu_stack
[--submenu_depth
];
1852 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1853 && submenu_depth
!= 0)
1854 i
+= MENU_ITEMS_PANE_LENGTH
;
1855 /* Ignore a nil in the item list.
1856 It's meaningful only for dialog boxes. */
1857 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1859 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1861 /* Create a new pane. */
1862 Lisp_Object pane_name
, prefix
;
1865 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1866 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1868 #ifndef HAVE_MULTILINGUAL_MENU
1869 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1871 pane_name
= ENCODE_MENU_STRING (pane_name
);
1872 AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
) = pane_name
;
1875 pane_string
= (NILP (pane_name
)
1876 ? "" : (char *) SDATA (pane_name
));
1877 /* If there is just one top-level pane, put all its items directly
1878 under the top-level menu. */
1879 if (menu_items_n_panes
== 1)
1882 /* If the pane has a meaningful name,
1883 make the pane a top-level menu item
1884 with its items as a submenu beneath it. */
1885 if (!keymaps
&& strcmp (pane_string
, ""))
1887 wv
= xmalloc_widget_value ();
1891 first_wv
->contents
= wv
;
1892 wv
->name
= pane_string
;
1893 if (keymaps
&& !NILP (prefix
))
1897 wv
->button_type
= BUTTON_TYPE_NONE
;
1902 else if (first_pane
)
1908 i
+= MENU_ITEMS_PANE_LENGTH
;
1912 /* Create a new item within current pane. */
1913 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1914 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1915 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1916 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1917 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1918 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1919 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1920 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1922 #ifndef HAVE_MULTILINGUAL_MENU
1923 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1925 item_name
= ENCODE_MENU_STRING (item_name
);
1926 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
) = item_name
;
1929 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1931 descrip
= ENCODE_MENU_STRING (descrip
);
1932 AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
) = descrip
;
1934 #endif /* not HAVE_MULTILINGUAL_MENU */
1936 wv
= xmalloc_widget_value ();
1940 save_wv
->contents
= wv
;
1941 wv
->name
= (char *) SDATA (item_name
);
1942 if (!NILP (descrip
))
1943 wv
->key
= (char *) SDATA (descrip
);
1945 /* Use the contents index as call_data, since we are
1946 restricted to 16-bits. */
1947 wv
->call_data
= !NILP (def
) ? (void *) (EMACS_INT
) i
: 0;
1948 wv
->enabled
= !NILP (enable
);
1951 wv
->button_type
= BUTTON_TYPE_NONE
;
1952 else if (EQ (type
, QCtoggle
))
1953 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1954 else if (EQ (type
, QCradio
))
1955 wv
->button_type
= BUTTON_TYPE_RADIO
;
1959 wv
->selected
= !NILP (selected
);
1961 if (! STRINGP (help
))
1968 i
+= MENU_ITEMS_ITEM_LENGTH
;
1972 /* Deal with the title, if it is non-nil. */
1975 widget_value
*wv_title
= xmalloc_widget_value ();
1976 widget_value
*wv_sep
= xmalloc_widget_value ();
1978 /* Maybe replace this separator with a bitmap or owner-draw item
1979 so that it looks better. Having two separators looks odd. */
1980 wv_sep
->name
= "--";
1981 wv_sep
->next
= first_wv
->contents
;
1982 wv_sep
->help
= Qnil
;
1984 #ifndef HAVE_MULTILINGUAL_MENU
1985 if (STRING_MULTIBYTE (title
))
1986 title
= ENCODE_MENU_STRING (title
);
1989 wv_title
->name
= (char *) SDATA (title
);
1990 wv_title
->enabled
= FALSE
;
1991 wv_title
->title
= TRUE
;
1992 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1993 wv_title
->help
= Qnil
;
1994 wv_title
->next
= wv_sep
;
1995 first_wv
->contents
= wv_title
;
1998 /* Actually create the menu. */
1999 menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
2000 InsertMenu (menu
, -1);
2001 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
2002 min_menu_id
[MAC_MENU_POPUP_SUB
]);
2004 /* Free the widget_value objects we used to specify the
2006 free_menubar_widget_value_tree (first_wv
);
2008 /* Adjust coordinates to be root-window-relative. */
2012 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
2013 LocalToGlobal (&pos
);
2015 /* No selection has been chosen yet. */
2016 menu_item_choice
= 0;
2017 menu_item_selection
= 0;
2019 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
2021 /* Add event handler so we can detect C-g. */
2022 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
2023 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
2025 /* Display the menu. */
2026 menu_item_choice
= PopUpMenuSelect (menu
, pos
.v
, pos
.h
, 0);
2027 menu_item_selection
= LoWord (menu_item_choice
);
2029 /* Get the refcon to find the correct item */
2030 if (menu_item_selection
)
2032 MenuHandle sel_menu
= GetMenuHandle (HiWord (menu_item_choice
));
2034 GetMenuItemRefCon (sel_menu
, menu_item_selection
, &refcon
);
2037 else if (! for_click
)
2038 /* Make "Cancel" equivalent to C-g unless this menu was popped up by
2040 Fsignal (Qquit
, Qnil
);
2042 /* Find the selected item, and its pane, to return
2043 the proper value. */
2044 if (menu_item_selection
!= 0)
2046 Lisp_Object prefix
, entry
;
2048 prefix
= entry
= Qnil
;
2050 while (i
< menu_items_used
)
2052 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2054 subprefix_stack
[submenu_depth
++] = prefix
;
2058 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2060 prefix
= subprefix_stack
[--submenu_depth
];
2063 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2066 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2067 i
+= MENU_ITEMS_PANE_LENGTH
;
2069 /* Ignore a nil in the item list.
2070 It's meaningful only for dialog boxes. */
2071 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2076 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2077 if ((int) (EMACS_INT
) refcon
== i
)
2083 entry
= Fcons (entry
, Qnil
);
2085 entry
= Fcons (prefix
, entry
);
2086 for (j
= submenu_depth
- 1; j
>= 0; j
--)
2087 if (!NILP (subprefix_stack
[j
]))
2088 entry
= Fcons (subprefix_stack
[j
], entry
);
2092 i
+= MENU_ITEMS_ITEM_LENGTH
;
2096 else if (!for_click
)
2097 /* Make "Cancel" equivalent to C-g. */
2098 Fsignal (Qquit
, Qnil
);
2100 unbind_to (specpdl_count
, Qnil
);
2107 /* Construct native Mac OS menubar based on widget_value tree. */
2110 mac_dialog (widget_value
*wv
)
2114 char **button_labels
;
2121 WindowPtr window_ptr
;
2124 EventRecord event_record
;
2126 int control_part_code
;
2129 dialog_name
= wv
->name
;
2130 nb_buttons
= dialog_name
[1] - '0';
2131 left_count
= nb_buttons
- (dialog_name
[4] - '0');
2132 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
2133 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
2136 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
2137 strcpy (prompt
, wv
->value
);
2141 for (i
= 0; i
< nb_buttons
; i
++)
2143 button_labels
[i
] = wv
->value
;
2144 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
2145 strcpy (button_labels
[i
], wv
->value
);
2146 c2pstr (button_labels
[i
]);
2147 ref_cons
[i
] = (UInt32
) wv
->call_data
;
2151 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowPtr
) -1);
2153 SetPortWindowPort (window_ptr
);
2156 /* Left and right margins in the dialog are 13 pixels each.*/
2158 /* Calculate width of dialog box: 8 pixels on each side of the text
2159 label in each button, 12 pixels between buttons. */
2160 for (i
= 0; i
< nb_buttons
; i
++)
2161 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
2163 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
2166 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
2168 SizeWindow (window_ptr
, dialog_width
, 78, 0);
2169 ShowWindow (window_ptr
);
2171 SetPortWindowPort (window_ptr
);
2176 DrawString (prompt
);
2179 for (i
= 0; i
< nb_buttons
; i
++)
2181 int button_width
= StringWidth (button_labels
[i
]) + 16;
2182 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
2183 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
2184 kControlPushButtonProc
, ref_cons
[i
]);
2185 left
+= button_width
+ 12;
2186 if (i
== left_count
- 1)
2193 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
2194 if (event_record
.what
== mouseDown
)
2196 part_code
= FindWindow (event_record
.where
, &window_ptr
);
2197 if (part_code
== inContent
)
2199 mouse
= event_record
.where
;
2200 GlobalToLocal (&mouse
);
2201 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
2202 if (control_part_code
== kControlButtonPart
)
2203 if (TrackControl (ch
, mouse
, NULL
))
2204 i
= GetControlReference (ch
);
2209 DisposeWindow (window_ptr
);
2214 static char * button_names
[] = {
2215 "button1", "button2", "button3", "button4", "button5",
2216 "button6", "button7", "button8", "button9", "button10" };
2219 mac_dialog_show (f
, keymaps
, title
, header
, error_name
)
2222 Lisp_Object title
, header
;
2225 int i
, nb_buttons
=0;
2226 char dialog_name
[6];
2227 int menu_item_selection
;
2229 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2231 /* Number of elements seen so far, before boundary. */
2233 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2234 int boundary_seen
= 0;
2238 if (menu_items_n_panes
> 1)
2240 *error_name
= "Multiple panes in dialog box";
2244 /* Create a tree of widget_value objects
2245 representing the text label and buttons. */
2247 Lisp_Object pane_name
, prefix
;
2249 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2250 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2251 pane_string
= (NILP (pane_name
)
2252 ? "" : (char *) SDATA (pane_name
));
2253 prev_wv
= xmalloc_widget_value ();
2254 prev_wv
->value
= pane_string
;
2255 if (keymaps
&& !NILP (prefix
))
2257 prev_wv
->enabled
= 1;
2258 prev_wv
->name
= "message";
2259 prev_wv
->help
= Qnil
;
2262 /* Loop over all panes and items, filling in the tree. */
2263 i
= MENU_ITEMS_PANE_LENGTH
;
2264 while (i
< menu_items_used
)
2267 /* Create a new item within current pane. */
2268 Lisp_Object item_name
, enable
, descrip
;
2269 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2270 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2272 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2274 if (NILP (item_name
))
2276 free_menubar_widget_value_tree (first_wv
);
2277 *error_name
= "Submenu in dialog items";
2280 if (EQ (item_name
, Qquote
))
2282 /* This is the boundary between left-side elts
2283 and right-side elts. Stop incrementing right_count. */
2288 if (nb_buttons
>= 9)
2290 free_menubar_widget_value_tree (first_wv
);
2291 *error_name
= "Too many dialog items";
2295 wv
= xmalloc_widget_value ();
2297 wv
->name
= (char *) button_names
[nb_buttons
];
2298 if (!NILP (descrip
))
2299 wv
->key
= (char *) SDATA (descrip
);
2300 wv
->value
= (char *) SDATA (item_name
);
2301 wv
->call_data
= (void *) i
;
2302 /* menu item is identified by its index in menu_items table */
2303 wv
->enabled
= !NILP (enable
);
2307 if (! boundary_seen
)
2311 i
+= MENU_ITEMS_ITEM_LENGTH
;
2314 /* If the boundary was not specified,
2315 by default put half on the left and half on the right. */
2316 if (! boundary_seen
)
2317 left_count
= nb_buttons
- nb_buttons
/ 2;
2319 wv
= xmalloc_widget_value ();
2320 wv
->name
= dialog_name
;
2323 /* Frame title: 'Q' = Question, 'I' = Information.
2324 Can also have 'E' = Error if, one day, we want
2325 a popup for errors. */
2327 dialog_name
[0] = 'Q';
2329 dialog_name
[0] = 'I';
2331 /* Dialog boxes use a really stupid name encoding
2332 which specifies how many buttons to use
2333 and how many buttons are on the right. */
2334 dialog_name
[1] = '0' + nb_buttons
;
2335 dialog_name
[2] = 'B';
2336 dialog_name
[3] = 'R';
2337 /* Number of buttons to put on the right. */
2338 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2340 wv
->contents
= first_wv
;
2344 /* Actually create the dialog. */
2346 menu_item_selection
= mac_dialog (first_wv
);
2348 menu_item_selection
= 0;
2351 /* Free the widget_value objects we used to specify the contents. */
2352 free_menubar_widget_value_tree (first_wv
);
2354 /* Find the selected item, and its pane, to return
2355 the proper value. */
2356 if (menu_item_selection
!= 0)
2362 while (i
< menu_items_used
)
2366 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2369 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2370 i
+= MENU_ITEMS_PANE_LENGTH
;
2372 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2374 /* This is the boundary between left-side elts and
2381 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2382 if (menu_item_selection
== i
)
2386 entry
= Fcons (entry
, Qnil
);
2388 entry
= Fcons (prefix
, entry
);
2392 i
+= MENU_ITEMS_ITEM_LENGTH
;
2397 /* Make "Cancel" equivalent to C-g. */
2398 Fsignal (Qquit
, Qnil
);
2402 #endif /* HAVE_DIALOGS */
2405 /* Is this item a separator? */
2407 name_is_separator (name
)
2412 /* Check if name string consists of only dashes ('-'). */
2413 while (*name
== '-') name
++;
2414 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2415 or "--deep-shadow". We don't implement them yet, se we just treat
2416 them like normal separators. */
2417 return (*name
== '\0' || start
+ 2 == name
);
2421 add_menu_item (menu
, pos
, wv
)
2426 #if TARGET_API_MAC_CARBON
2427 CFStringRef item_name
;
2432 if (name_is_separator (wv
->name
))
2433 AppendMenu (menu
, "\p-");
2436 AppendMenu (menu
, "\pX");
2438 #if TARGET_API_MAC_CARBON
2439 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
2441 if (wv
->key
!= NULL
)
2443 CFStringRef name
, key
;
2446 key
= cfstring_create_with_utf8_cstring (wv
->key
);
2447 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
2453 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
2454 CFRelease (item_name
);
2457 EnableMenuItem (menu
, pos
);
2459 DisableMenuItem (menu
, pos
);
2460 #else /* ! TARGET_API_MAC_CARBON */
2461 item_name
[sizeof (item_name
) - 1] = '\0';
2462 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
2463 if (wv
->key
!= NULL
)
2465 int len
= strlen (item_name
);
2467 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
2468 len
= strlen (item_name
);
2469 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
2472 SetMenuItemText (menu
, pos
, item_name
);
2475 EnableItem (menu
, pos
);
2477 DisableItem (menu
, pos
);
2478 #endif /* ! TARGET_API_MAC_CARBON */
2480 /* Draw radio buttons and tickboxes. */
2481 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
||
2482 wv
->button_type
== BUTTON_TYPE_RADIO
))
2483 SetItemMark (menu
, pos
, checkMark
);
2485 SetItemMark (menu
, pos
, noMark
);
2487 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
2491 /* Construct native Mac OS menu based on widget_value tree. */
2494 fill_menu (menu
, wv
, kind
, submenu_id
)
2497 enum mac_menu_kind kind
;
2502 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
2504 add_menu_item (menu
, pos
, wv
);
2505 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
2507 MenuHandle submenu
= NewMenu (submenu_id
, "\pX");
2509 InsertMenu (submenu
, -1);
2510 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
2511 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
2518 /* Construct native Mac OS menubar based on widget_value tree. */
2521 fill_menubar (wv
, deep_p
)
2528 #if !TARGET_API_MAC_CARBON
2529 int title_changed_p
= 0;
2532 /* Clean up the menu bar when filled by the entire menu trees. */
2535 dispose_menus (MAC_MENU_MENU_BAR
, 0);
2536 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
2537 #if !TARGET_API_MAC_CARBON
2538 title_changed_p
= 1;
2542 /* Fill menu bar titles and submenus. Reuse the existing menu bar
2543 titles as much as possible to minimize redraw (if !deep_p). */
2544 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
2545 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
2546 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
2547 wv
= wv
->next
, id
++)
2549 strncpy (title
, wv
->name
, 255);
2553 menu
= GetMenuHandle (id
);
2556 #if TARGET_API_MAC_CARBON
2559 GetMenuTitle (menu
, old_title
);
2560 if (!EqualString (title
, old_title
, false, false))
2561 SetMenuTitle (menu
, title
);
2562 #else /* !TARGET_API_MAC_CARBON */
2563 if (!EqualString (title
, (*menu
)->menuData
, false, false))
2567 menu
= NewMenu (id
, title
);
2568 InsertMenu (menu
, GetMenuHandle (id
+ 1) ? id
+ 1 : 0);
2569 title_changed_p
= 1;
2571 #endif /* !TARGET_API_MAC_CARBON */
2575 menu
= NewMenu (id
, title
);
2576 InsertMenu (menu
, 0);
2577 #if !TARGET_API_MAC_CARBON
2578 title_changed_p
= 1;
2583 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
2587 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuHandle (id
))
2589 dispose_menus (MAC_MENU_MENU_BAR
, id
);
2590 #if !TARGET_API_MAC_CARBON
2591 title_changed_p
= 1;
2595 #if !TARGET_API_MAC_CARBON
2596 if (title_changed_p
)
2601 /* Dispose of menus that belong to KIND, and remove them from the menu
2602 list. ID is the lower bound of menu IDs that will be processed. */
2605 dispose_menus (kind
, id
)
2606 enum mac_menu_kind kind
;
2609 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
2611 MenuHandle menu
= GetMenuHandle (id
);
2620 #endif /* HAVE_MENUS */
2625 staticpro (&menu_items
);
2628 Qdebug_on_next_call
= intern ("debug-on-next-call");
2629 staticpro (&Qdebug_on_next_call
);
2631 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame
,
2632 doc
: /* Frame for which we are updating a menu.
2633 The enable predicate for a menu command should check this variable. */);
2634 Vmenu_updating_frame
= Qnil
;
2636 defsubr (&Sx_popup_menu
);
2638 defsubr (&Sx_popup_dialog
);
2642 /* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce
2643 (do not change this comment) */