(defgroup table-hooks): New group.
[emacs.git] / src / macmenu.c
blob128235c027b3a07884c3e9785770b62343ac8693
1 /* Menu support for GNU Emacs on the for Mac OS.
2 Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
23 #include <config.h>
24 #include <signal.h>
26 #include <stdio.h>
27 #include "lisp.h"
28 #include "termhooks.h"
29 #include "keyboard.h"
30 #include "keymap.h"
31 #include "frame.h"
32 #include "window.h"
33 #include "blockinput.h"
34 #include "buffer.h"
35 #include "charset.h"
36 #include "coding.h"
38 #ifdef MAC_OSX
39 #undef mktime
40 #undef DEBUG
41 #undef Z
42 #undef free
43 #undef malloc
44 #undef realloc
45 /* Macros max and min defined in lisp.h conflict with those in
46 precompiled header Carbon.h. */
47 #undef max
48 #undef min
49 #undef init_process
50 #include <Carbon/Carbon.h>
51 #undef Z
52 #define Z (current_buffer->text->z)
53 #undef free
54 #define free unexec_free
55 #undef malloc
56 #define malloc unexec_malloc
57 #undef realloc
58 #define realloc unexec_realloc
59 #undef min
60 #define min(a, b) ((a) < (b) ? (a) : (b))
61 #undef max
62 #define max(a, b) ((a) > (b) ? (a) : (b))
63 #undef init_process
64 #define init_process emacs_init_process
65 #else /* not MAC_OSX */
66 #include <MacTypes.h>
67 #include <Menus.h>
68 #include <QuickDraw.h>
69 #include <ToolUtils.h>
70 #include <Fonts.h>
71 #include <Controls.h>
72 #include <Windows.h>
73 #include <Events.h>
74 #if defined (__MRC__) || (__MSL__ >= 0x6000)
75 #include <ControlDefinitions.h>
76 #endif
77 #endif /* not MAC_OSX */
79 /* This may include sys/types.h, and that somehow loses
80 if this is not done before the other system files. */
81 #include "macterm.h"
83 /* Load sys/types.h if not already loaded.
84 In some systems loading it twice is suicidal. */
85 #ifndef makedev
86 #include <sys/types.h>
87 #endif
89 #include "dispextern.h"
91 #define POPUP_SUBMENU_ID 235
92 #define MIN_MENU_ID 256
93 #define MIN_SUBMENU_ID 1
95 #define DIALOG_WINDOW_RESOURCE 130
97 #define HAVE_DIALOGS 1
99 #undef HAVE_MULTILINGUAL_MENU
100 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
102 /******************************************************************/
103 /* Definitions copied from lwlib.h */
105 typedef void * XtPointer;
107 enum button_type
109 BUTTON_TYPE_NONE,
110 BUTTON_TYPE_TOGGLE,
111 BUTTON_TYPE_RADIO
114 /* This structure is based on the one in ../lwlib/lwlib.h, modified
115 for Mac OS. */
116 typedef struct _widget_value
118 /* name of widget */
119 char* name;
120 /* value (meaning depend on widget type) */
121 char* value;
122 /* keyboard equivalent. no implications for XtTranslations */
123 char* key;
124 /* Help string or nil if none.
125 GC finds this string through the frame's menu_bar_vector
126 or through menu_items. */
127 Lisp_Object help;
128 /* true if enabled */
129 Boolean enabled;
130 /* true if selected */
131 Boolean selected;
132 /* The type of a button. */
133 enum button_type button_type;
134 /* true if menu title */
135 Boolean title;
136 #if 0
137 /* true if was edited (maintained by get_value) */
138 Boolean edited;
139 /* true if has changed (maintained by lw library) */
140 change_type change;
141 /* true if this widget itself has changed,
142 but not counting the other widgets found in the `next' field. */
143 change_type this_one_change;
144 #endif
145 /* Contents of the sub-widgets, also selected slot for checkbox */
146 struct _widget_value* contents;
147 /* data passed to callback */
148 XtPointer call_data;
149 /* next one in the list */
150 struct _widget_value* next;
151 #if 0
152 /* slot for the toolkit dependent part. Always initialize to NULL. */
153 void* toolkit_data;
154 /* tell us if we should free the toolkit data slot when freeing the
155 widget_value itself. */
156 Boolean free_toolkit_data;
158 /* we resource the widget_value structures; this points to the next
159 one on the free list if this one has been deallocated.
161 struct _widget_value *free_list;
162 #endif
163 } widget_value;
165 /* Assumed by other routines to zero area returned. */
166 #define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
167 0, (sizeof (widget_value)))
168 #define free_widget_value(wv) xfree (wv)
170 /******************************************************************/
172 #ifndef TRUE
173 #define TRUE 1
174 #define FALSE 0
175 #endif /* no TRUE */
177 Lisp_Object Vmenu_updating_frame;
179 Lisp_Object Qdebug_on_next_call;
181 extern Lisp_Object Qmenu_bar;
183 extern Lisp_Object QCtoggle, QCradio;
185 extern Lisp_Object Voverriding_local_map;
186 extern Lisp_Object Voverriding_local_map_menu_flag;
188 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
190 extern Lisp_Object Qmenu_bar_update_hook;
192 void set_frame_menubar ();
194 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
195 Lisp_Object, Lisp_Object, Lisp_Object,
196 Lisp_Object, Lisp_Object));
197 #ifdef HAVE_DIALOGS
198 static Lisp_Object mac_dialog_show ();
199 #endif
200 static Lisp_Object mac_menu_show ();
202 static void keymap_panes ();
203 static void single_keymap_panes ();
204 static void single_menu_item ();
205 static void list_of_panes ();
206 static void list_of_items ();
208 static void fill_submenu (MenuHandle, widget_value *, int);
209 static void fill_menubar (widget_value *);
212 /* This holds a Lisp vector that holds the results of decoding
213 the keymaps or alist-of-alists that specify a menu.
215 It describes the panes and items within the panes.
217 Each pane is described by 3 elements in the vector:
218 t, the pane name, the pane's prefix key.
219 Then follow the pane's items, with 5 elements per item:
220 the item string, the enable flag, the item's value,
221 the definition, and the equivalent keyboard key's description string.
223 In some cases, multiple levels of menus may be described.
224 A single vector slot containing nil indicates the start of a submenu.
225 A single vector slot containing lambda indicates the end of a submenu.
226 The submenu follows a menu item which is the way to reach the submenu.
228 A single vector slot containing quote indicates that the
229 following items should appear on the right of a dialog box.
231 Using a Lisp vector to hold this information while we decode it
232 takes care of protecting all the data from GC. */
234 #define MENU_ITEMS_PANE_NAME 1
235 #define MENU_ITEMS_PANE_PREFIX 2
236 #define MENU_ITEMS_PANE_LENGTH 3
238 enum menu_item_idx
240 MENU_ITEMS_ITEM_NAME = 0,
241 MENU_ITEMS_ITEM_ENABLE,
242 MENU_ITEMS_ITEM_VALUE,
243 MENU_ITEMS_ITEM_EQUIV_KEY,
244 MENU_ITEMS_ITEM_DEFINITION,
245 MENU_ITEMS_ITEM_TYPE,
246 MENU_ITEMS_ITEM_SELECTED,
247 MENU_ITEMS_ITEM_HELP,
248 MENU_ITEMS_ITEM_LENGTH
251 static Lisp_Object menu_items;
253 /* Number of slots currently allocated in menu_items. */
254 static int menu_items_allocated;
256 /* This is the index in menu_items of the first empty slot. */
257 static int menu_items_used;
259 /* The number of panes currently recorded in menu_items,
260 excluding those within submenus. */
261 static int menu_items_n_panes;
263 /* Current depth within submenus. */
264 static int menu_items_submenu_depth;
266 /* Flag which when set indicates a dialog or menu has been posted by
267 Xt on behalf of one of the widget sets. */
268 static int popup_activated_flag;
270 static int next_menubar_widget_id;
272 /* This is set nonzero after the user activates the menu bar, and set
273 to zero again after the menu bars are redisplayed by prepare_menu_bar.
274 While it is nonzero, all calls to set_frame_menubar go deep.
276 I don't understand why this is needed, but it does seem to be
277 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
279 int pending_menu_activation;
281 /* Initialize the menu_items structure if we haven't already done so.
282 Also mark it as currently empty. */
284 static void
285 init_menu_items ()
287 if (NILP (menu_items))
289 menu_items_allocated = 60;
290 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
293 menu_items_used = 0;
294 menu_items_n_panes = 0;
295 menu_items_submenu_depth = 0;
298 /* Call at the end of generating the data in menu_items.
299 This fills in the number of items in the last pane. */
301 static void
302 finish_menu_items ()
306 /* Call when finished using the data for the current menu
307 in menu_items. */
309 static void
310 discard_menu_items ()
312 /* Free the structure if it is especially large.
313 Otherwise, hold on to it, to save time. */
314 if (menu_items_allocated > 200)
316 menu_items = Qnil;
317 menu_items_allocated = 0;
321 /* Make the menu_items vector twice as large. */
323 static void
324 grow_menu_items ()
326 Lisp_Object old;
327 int old_size = menu_items_allocated;
328 old = menu_items;
330 menu_items_allocated *= 2;
331 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
332 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
333 old_size * sizeof (Lisp_Object));
336 /* Begin a submenu. */
338 static void
339 push_submenu_start ()
341 if (menu_items_used + 1 > menu_items_allocated)
342 grow_menu_items ();
344 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
345 menu_items_submenu_depth++;
348 /* End a submenu. */
350 static void
351 push_submenu_end ()
353 if (menu_items_used + 1 > menu_items_allocated)
354 grow_menu_items ();
356 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
357 menu_items_submenu_depth--;
360 /* Indicate boundary between left and right. */
362 static void
363 push_left_right_boundary ()
365 if (menu_items_used + 1 > menu_items_allocated)
366 grow_menu_items ();
368 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
371 /* Start a new menu pane in menu_items.
372 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
374 static void
375 push_menu_pane (name, prefix_vec)
376 Lisp_Object name, prefix_vec;
378 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
379 grow_menu_items ();
381 if (menu_items_submenu_depth == 0)
382 menu_items_n_panes++;
383 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
384 XVECTOR (menu_items)->contents[menu_items_used++] = name;
385 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
388 /* Push one menu item into the current pane. NAME is the string to
389 display. ENABLE if non-nil means this item can be selected. KEY
390 is the key generated by choosing this item, or nil if this item
391 doesn't really have a definition. DEF is the definition of this
392 item. EQUIV is the textual description of the keyboard equivalent
393 for this item (or nil if none). TYPE is the type of this menu
394 item, one of nil, `toggle' or `radio'. */
396 static void
397 push_menu_item (name, enable, key, def, equiv, type, selected, help)
398 Lisp_Object name, enable, key, def, equiv, type, selected, help;
400 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
401 grow_menu_items ();
403 XVECTOR (menu_items)->contents[menu_items_used++] = name;
404 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
405 XVECTOR (menu_items)->contents[menu_items_used++] = key;
406 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
407 XVECTOR (menu_items)->contents[menu_items_used++] = def;
408 XVECTOR (menu_items)->contents[menu_items_used++] = type;
409 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
410 XVECTOR (menu_items)->contents[menu_items_used++] = help;
413 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
414 and generate menu panes for them in menu_items.
415 If NOTREAL is nonzero,
416 don't bother really computing whether an item is enabled. */
418 static void
419 keymap_panes (keymaps, nmaps, notreal)
420 Lisp_Object *keymaps;
421 int nmaps;
422 int notreal;
424 int mapno;
426 init_menu_items ();
428 /* Loop over the given keymaps, making a pane for each map.
429 But don't make a pane that is empty--ignore that map instead.
430 P is the number of panes we have made so far. */
431 for (mapno = 0; mapno < nmaps; mapno++)
432 single_keymap_panes (keymaps[mapno],
433 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
435 finish_menu_items ();
438 /* This is a recursive subroutine of keymap_panes.
439 It handles one keymap, KEYMAP.
440 The other arguments are passed along
441 or point to local variables of the previous function.
442 If NOTREAL is nonzero, only check for equivalent key bindings, don't
443 evaluate expressions in menu items and don't make any menu.
445 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
447 static void
448 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
449 Lisp_Object keymap;
450 Lisp_Object pane_name;
451 Lisp_Object prefix;
452 int notreal;
453 int maxdepth;
455 Lisp_Object pending_maps = Qnil;
456 Lisp_Object tail, item;
457 struct gcpro gcpro1, gcpro2;
459 if (maxdepth <= 0)
460 return;
462 push_menu_pane (pane_name, prefix);
464 for (tail = keymap; CONSP (tail); tail = XCDR (tail))
466 GCPRO2 (keymap, pending_maps);
467 /* Look at each key binding, and if it is a menu item add it
468 to this menu. */
469 item = XCAR (tail);
470 if (CONSP (item))
471 single_menu_item (XCAR (item), XCDR (item),
472 &pending_maps, notreal, maxdepth);
473 else if (VECTORP (item))
475 /* Loop over the char values represented in the vector. */
476 int len = XVECTOR (item)->size;
477 int c;
478 for (c = 0; c < len; c++)
480 Lisp_Object character;
481 XSETFASTINT (character, c);
482 single_menu_item (character, XVECTOR (item)->contents[c],
483 &pending_maps, notreal, maxdepth);
486 UNGCPRO;
489 /* Process now any submenus which want to be panes at this level. */
490 while (!NILP (pending_maps))
492 Lisp_Object elt, eltcdr, string;
493 elt = Fcar (pending_maps);
494 eltcdr = XCDR (elt);
495 string = XCAR (eltcdr);
496 /* We no longer discard the @ from the beginning of the string here.
497 Instead, we do this in mac_menu_show. */
498 single_keymap_panes (Fcar (elt), string,
499 XCDR (eltcdr), notreal, maxdepth - 1);
500 pending_maps = Fcdr (pending_maps);
504 /* This is a subroutine of single_keymap_panes that handles one
505 keymap entry.
506 KEY is a key in a keymap and ITEM is its binding.
507 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
508 separate panes.
509 If NOTREAL is nonzero, only check for equivalent key bindings, don't
510 evaluate expressions in menu items and don't make any menu.
511 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
513 static void
514 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
515 Lisp_Object key, item;
516 Lisp_Object *pending_maps_ptr;
517 int maxdepth, notreal;
519 Lisp_Object map, item_string, enabled;
520 struct gcpro gcpro1, gcpro2;
521 int res;
523 /* Parse the menu item and leave the result in item_properties. */
524 GCPRO2 (key, item);
525 res = parse_menu_item (item, notreal, 0);
526 UNGCPRO;
527 if (!res)
528 return; /* Not a menu item. */
530 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
532 if (notreal)
534 /* We don't want to make a menu, just traverse the keymaps to
535 precompute equivalent key bindings. */
536 if (!NILP (map))
537 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
538 return;
541 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
542 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
544 if (!NILP (map) && SREF (item_string, 0) == '@')
546 if (!NILP (enabled))
547 /* An enabled separate pane. Remember this to handle it later. */
548 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
549 *pending_maps_ptr);
550 return;
553 push_menu_item (item_string, enabled, key,
554 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
555 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
556 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
557 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
558 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
560 /* Display a submenu using the toolkit. */
561 if (! (NILP (map) || NILP (enabled)))
563 push_submenu_start ();
564 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
565 push_submenu_end ();
569 /* Push all the panes and items of a menu described by the
570 alist-of-alists MENU.
571 This handles old-fashioned calls to x-popup-menu. */
573 static void
574 list_of_panes (menu)
575 Lisp_Object menu;
577 Lisp_Object tail;
579 init_menu_items ();
581 for (tail = menu; !NILP (tail); tail = Fcdr (tail))
583 Lisp_Object elt, pane_name, pane_data;
584 elt = Fcar (tail);
585 pane_name = Fcar (elt);
586 CHECK_STRING (pane_name);
587 push_menu_pane (pane_name, Qnil);
588 pane_data = Fcdr (elt);
589 CHECK_CONS (pane_data);
590 list_of_items (pane_data);
593 finish_menu_items ();
596 /* Push the items in a single pane defined by the alist PANE. */
598 static void
599 list_of_items (pane)
600 Lisp_Object pane;
602 Lisp_Object tail, item, item1;
604 for (tail = pane; !NILP (tail); tail = Fcdr (tail))
606 item = Fcar (tail);
607 if (STRINGP (item))
608 push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
609 else if (NILP (item))
610 push_left_right_boundary ();
611 else
613 CHECK_CONS (item);
614 item1 = Fcar (item);
615 CHECK_STRING (item1);
616 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
621 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
622 doc: /* Pop up a deck-of-cards menu and return user's selection.
623 POSITION is a position specification. This is either a mouse button
624 event or a list ((XOFFSET YOFFSET) WINDOW) where XOFFSET and YOFFSET
625 are positions in pixels from the top left corner of WINDOW's frame
626 \(WINDOW may be a frame object instead of a window). This controls the
627 position of the center of the first line in the first pane of the
628 menu, not the top left of the menu as a whole. If POSITION is t, it
629 means to use the current mouse position.
631 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
632 The menu items come from key bindings that have a menu string as well as
633 a definition; actually, the \"definition\" in such a key binding looks like
634 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
635 the keymap as a top-level element.
637 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
638 Otherwise, REAL-DEFINITION should be a valid key binding definition.
640 You can also use a list of keymaps as MENU. Then each keymap makes a
641 separate pane. When MENU is a keymap or a list of keymaps, the return
642 value is a list of events.
644 Alternatively, you can specify a menu of multiple panes with a list of
645 the form (TITLE PANE1 PANE2...), where each pane is a list of
646 form (TITLE ITEM1 ITEM2...).
647 Each ITEM is normally a cons cell (STRING . VALUE); but a string can
648 appear as an item--that makes a nonselectable line in the menu.
649 With this form of menu, the return value is VALUE from the chosen item.
651 If POSITION is nil, don't display the menu at all, just precalculate the
652 cached information about equivalent key sequences. */)
653 (position, menu)
654 Lisp_Object position, menu;
656 Lisp_Object keymap, tem;
657 int xpos = 0, ypos = 0;
658 Lisp_Object title;
659 char *error_name;
660 Lisp_Object selection;
661 FRAME_PTR f = NULL;
662 Lisp_Object x, y, window;
663 int keymaps = 0;
664 int for_click = 0;
665 struct gcpro gcpro1;
667 #ifdef HAVE_MENUS
668 if (! NILP (position))
670 check_mac ();
672 /* Decode the first argument: find the window and the coordinates. */
673 if (EQ (position, Qt)
674 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
675 || EQ (XCAR (position), Qtool_bar))))
677 /* Use the mouse's current position. */
678 FRAME_PTR new_f = SELECTED_FRAME ();
679 Lisp_Object bar_window;
680 enum scroll_bar_part part;
681 unsigned long time;
683 if (mouse_position_hook)
684 (*mouse_position_hook) (&new_f, 1, &bar_window,
685 &part, &x, &y, &time);
686 if (new_f != 0)
687 XSETFRAME (window, new_f);
688 else
690 window = selected_window;
691 XSETFASTINT (x, 0);
692 XSETFASTINT (y, 0);
695 else
697 tem = Fcar (position);
698 if (CONSP (tem))
700 window = Fcar (Fcdr (position));
701 x = Fcar (tem);
702 y = Fcar (Fcdr (tem));
704 else
706 for_click = 1;
707 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
708 window = Fcar (tem); /* POSN_WINDOW (tem) */
709 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
710 x = Fcar (tem);
711 y = Fcdr (tem);
715 CHECK_NUMBER (x);
716 CHECK_NUMBER (y);
718 /* Decode where to put the menu. */
720 if (FRAMEP (window))
722 f = XFRAME (window);
723 xpos = 0;
724 ypos = 0;
726 else if (WINDOWP (window))
728 CHECK_LIVE_WINDOW (window);
729 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
731 xpos = (FONT_WIDTH (FRAME_FONT (f))
732 * XFASTINT (XWINDOW (window)->left));
733 ypos = (FRAME_LINE_HEIGHT (f)
734 * XFASTINT (XWINDOW (window)->top));
736 else
737 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
738 but I don't want to make one now. */
739 CHECK_WINDOW (window);
741 xpos += XINT (x);
742 ypos += XINT (y);
744 XSETFRAME (Vmenu_updating_frame, f);
746 Vmenu_updating_frame = Qnil;
747 #endif /* HAVE_MENUS */
749 title = Qnil;
750 GCPRO1 (title);
752 /* Decode the menu items from what was specified. */
754 keymap = get_keymap (menu, 0, 0);
755 if (CONSP (keymap))
757 /* We were given a keymap. Extract menu info from the keymap. */
758 Lisp_Object prompt;
760 /* Extract the detailed info to make one pane. */
761 keymap_panes (&menu, 1, NILP (position));
763 /* Search for a string appearing directly as an element of the keymap.
764 That string is the title of the menu. */
765 prompt = Fkeymap_prompt (keymap);
766 if (NILP (title) && !NILP (prompt))
767 title = prompt;
769 /* Make that be the pane title of the first pane. */
770 if (!NILP (prompt) && menu_items_n_panes >= 0)
771 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
773 keymaps = 1;
775 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
777 /* We were given a list of keymaps. */
778 int nmaps = XFASTINT (Flength (menu));
779 Lisp_Object *maps
780 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
781 int i;
783 title = Qnil;
785 /* The first keymap that has a prompt string
786 supplies the menu title. */
787 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
789 Lisp_Object prompt;
791 maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
793 prompt = Fkeymap_prompt (keymap);
794 if (NILP (title) && !NILP (prompt))
795 title = prompt;
798 /* Extract the detailed info to make one pane. */
799 keymap_panes (maps, nmaps, NILP (position));
801 /* Make the title be the pane title of the first pane. */
802 if (!NILP (title) && menu_items_n_panes >= 0)
803 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
805 keymaps = 1;
807 else
809 /* We were given an old-fashioned menu. */
810 title = Fcar (menu);
811 CHECK_STRING (title);
813 list_of_panes (Fcdr (menu));
815 keymaps = 0;
818 if (NILP (position))
820 discard_menu_items ();
821 UNGCPRO;
822 return Qnil;
825 #ifdef HAVE_MENUS
826 /* Display them in a menu. */
827 BLOCK_INPUT;
829 selection = mac_menu_show (f, xpos, ypos, for_click,
830 keymaps, title, &error_name);
831 UNBLOCK_INPUT;
833 discard_menu_items ();
835 UNGCPRO;
836 #endif /* HAVE_MENUS */
838 if (error_name) error (error_name);
839 return selection;
842 #ifdef HAVE_MENUS
844 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
845 doc: /* Pop up a dialog box and return user's selection.
846 POSITION specifies which frame to use.
847 This is normally a mouse button event or a window or frame.
848 If POSITION is t, it means to use the frame the mouse is on.
849 The dialog box appears in the middle of the specified frame.
851 CONTENTS specifies the alternatives to display in the dialog box.
852 It is a list of the form (TITLE ITEM1 ITEM2...).
853 Each ITEM is a cons cell (STRING . VALUE).
854 The return value is VALUE from the chosen item.
856 An ITEM may also be just a string--that makes a nonselectable item.
857 An ITEM may also be nil--that means to put all preceding items
858 on the left of the dialog box and all following items on the right.
859 \(By default, approximately half appear on each side.) */)
860 (position, contents)
861 Lisp_Object position, contents;
863 FRAME_PTR f = NULL;
864 Lisp_Object window;
866 check_mac ();
868 /* Decode the first argument: find the window or frame to use. */
869 if (EQ (position, Qt)
870 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
871 || EQ (XCAR (position), Qtool_bar))))
873 #if 0 /* Using the frame the mouse is on may not be right. */
874 /* Use the mouse's current position. */
875 FRAME_PTR new_f = SELECTED_FRAME ();
876 Lisp_Object bar_window;
877 enum scroll_bar_part part;
878 unsigned long time;
879 Lisp_Object x, y;
881 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
883 if (new_f != 0)
884 XSETFRAME (window, new_f);
885 else
886 window = selected_window;
887 #endif
888 window = selected_window;
890 else if (CONSP (position))
892 Lisp_Object tem;
893 tem = Fcar (position);
894 if (CONSP (tem))
895 window = Fcar (Fcdr (position));
896 else
898 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
899 window = Fcar (tem); /* POSN_WINDOW (tem) */
902 else if (WINDOWP (position) || FRAMEP (position))
903 window = position;
904 else
905 window = Qnil;
907 /* Decode where to put the menu. */
909 if (FRAMEP (window))
910 f = XFRAME (window);
911 else if (WINDOWP (window))
913 CHECK_LIVE_WINDOW (window);
914 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
916 else
917 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
918 but I don't want to make one now. */
919 CHECK_WINDOW (window);
921 #ifndef HAVE_DIALOGS
922 /* Display a menu with these alternatives
923 in the middle of frame F. */
925 Lisp_Object x, y, frame, newpos;
926 XSETFRAME (frame, f);
927 XSETINT (x, x_pixel_width (f) / 2);
928 XSETINT (y, x_pixel_height (f) / 2);
929 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
931 return Fx_popup_menu (newpos,
932 Fcons (Fcar (contents), Fcons (contents, Qnil)));
934 #else /* HAVE_DIALOGS */
936 Lisp_Object title;
937 char *error_name;
938 Lisp_Object selection;
940 /* Decode the dialog items from what was specified. */
941 title = Fcar (contents);
942 CHECK_STRING (title);
944 list_of_panes (Fcons (contents, Qnil));
946 /* Display them in a dialog box. */
947 BLOCK_INPUT;
948 selection = mac_dialog_show (f, 0, title, &error_name);
949 UNBLOCK_INPUT;
951 discard_menu_items ();
953 if (error_name) error (error_name);
954 return selection;
956 #endif /* HAVE_DIALOGS */
959 /* Activate the menu bar of frame F.
960 This is called from keyboard.c when it gets the
961 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
963 To activate the menu bar, we signal to the input thread that it can
964 return from the WM_INITMENU message, allowing the normal Windows
965 processing of the menus.
967 But first we recompute the menu bar contents (the whole tree).
969 This way we can safely execute Lisp code. */
971 void
972 x_activate_menubar (f)
973 FRAME_PTR f;
975 SInt32 menu_choice;
976 extern Point saved_menu_event_location;
978 set_frame_menubar (f, 0, 1);
979 BLOCK_INPUT;
981 menu_choice = MenuSelect (saved_menu_event_location);
982 do_menu_choice (menu_choice);
984 UNBLOCK_INPUT;
987 /* This callback is called from the menu bar pulldown menu
988 when the user makes a selection.
989 Figure out what the user chose
990 and put the appropriate events into the keyboard buffer. */
992 void
993 menubar_selection_callback (FRAME_PTR f, int client_data)
995 Lisp_Object prefix, entry;
996 Lisp_Object vector;
997 Lisp_Object *subprefix_stack;
998 int submenu_depth = 0;
999 int i;
1001 if (!f)
1002 return;
1003 entry = Qnil;
1004 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
1005 vector = f->menu_bar_vector;
1006 prefix = Qnil;
1007 i = 0;
1008 while (i < f->menu_bar_items_used)
1010 if (EQ (XVECTOR (vector)->contents[i], Qnil))
1012 subprefix_stack[submenu_depth++] = prefix;
1013 prefix = entry;
1014 i++;
1016 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
1018 prefix = subprefix_stack[--submenu_depth];
1019 i++;
1021 else if (EQ (XVECTOR (vector)->contents[i], Qt))
1023 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
1024 i += MENU_ITEMS_PANE_LENGTH;
1026 else
1028 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1029 /* The EMACS_INT cast avoids a warning. There's no problem
1030 as long as pointers have enough bits to hold small integers. */
1031 if ((int) (EMACS_INT) client_data == i)
1033 int j;
1034 struct input_event buf;
1035 Lisp_Object frame;
1037 XSETFRAME (frame, f);
1038 buf.kind = MENU_BAR_EVENT;
1039 buf.frame_or_window = frame;
1040 buf.arg = frame;
1041 kbd_buffer_store_event (&buf);
1043 for (j = 0; j < submenu_depth; j++)
1044 if (!NILP (subprefix_stack[j]))
1046 buf.kind = MENU_BAR_EVENT;
1047 buf.frame_or_window = frame;
1048 buf.arg = subprefix_stack[j];
1049 kbd_buffer_store_event (&buf);
1052 if (!NILP (prefix))
1054 buf.kind = MENU_BAR_EVENT;
1055 buf.frame_or_window = frame;
1056 buf.arg = prefix;
1057 kbd_buffer_store_event (&buf);
1060 buf.kind = MENU_BAR_EVENT;
1061 buf.frame_or_window = frame;
1062 buf.arg = entry;
1063 kbd_buffer_store_event (&buf);
1065 f->output_data.mac->menu_command_in_progress = 0;
1066 f->output_data.mac->menubar_active = 0;
1067 return;
1069 i += MENU_ITEMS_ITEM_LENGTH;
1072 f->output_data.mac->menu_command_in_progress = 0;
1073 f->output_data.mac->menubar_active = 0;
1076 /* Allocate a widget_value, blocking input. */
1078 widget_value *
1079 xmalloc_widget_value ()
1081 widget_value *value;
1083 BLOCK_INPUT;
1084 value = malloc_widget_value ();
1085 UNBLOCK_INPUT;
1087 return value;
1090 /* This recursively calls free_widget_value on the tree of widgets.
1091 It must free all data that was malloc'ed for these widget_values.
1092 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1093 must be left alone. */
1095 void
1096 free_menubar_widget_value_tree (wv)
1097 widget_value *wv;
1099 if (! wv) return;
1101 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1103 if (wv->contents && (wv->contents != (widget_value*)1))
1105 free_menubar_widget_value_tree (wv->contents);
1106 wv->contents = (widget_value *) 0xDEADBEEF;
1108 if (wv->next)
1110 free_menubar_widget_value_tree (wv->next);
1111 wv->next = (widget_value *) 0xDEADBEEF;
1113 BLOCK_INPUT;
1114 free_widget_value (wv);
1115 UNBLOCK_INPUT;
1118 /* Return a tree of widget_value structures for a menu bar item
1119 whose event type is ITEM_KEY (with string ITEM_NAME)
1120 and whose contents come from the list of keymaps MAPS. */
1122 static widget_value *
1123 single_submenu (item_key, item_name, maps)
1124 Lisp_Object item_key, item_name, maps;
1126 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1127 int i;
1128 int submenu_depth = 0;
1129 Lisp_Object length;
1130 int len;
1131 Lisp_Object *mapvec;
1132 widget_value **submenu_stack;
1133 int previous_items = menu_items_used;
1134 int top_level_items = 0;
1136 length = Flength (maps);
1137 len = XINT (length);
1139 /* Convert the list MAPS into a vector MAPVEC. */
1140 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1141 for (i = 0; i < len; i++)
1143 mapvec[i] = Fcar (maps);
1144 maps = Fcdr (maps);
1147 menu_items_n_panes = 0;
1149 /* Loop over the given keymaps, making a pane for each map.
1150 But don't make a pane that is empty--ignore that map instead. */
1151 for (i = 0; i < len; i++)
1153 if (SYMBOLP (mapvec[i])
1154 || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
1156 /* Here we have a command at top level in the menu bar
1157 as opposed to a submenu. */
1158 top_level_items = 1;
1159 push_menu_pane (Qnil, Qnil);
1160 push_menu_item (item_name, Qt, item_key, mapvec[i],
1161 Qnil, Qnil, Qnil, Qnil);
1163 else
1164 single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
1167 /* Create a tree of widget_value objects
1168 representing the panes and their items. */
1170 submenu_stack
1171 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1172 wv = xmalloc_widget_value ();
1173 wv->name = "menu";
1174 wv->value = 0;
1175 wv->enabled = 1;
1176 wv->button_type = BUTTON_TYPE_NONE;
1177 wv->help = Qnil;
1178 first_wv = wv;
1179 save_wv = 0;
1180 prev_wv = 0;
1182 /* Loop over all panes and items made during this call
1183 and construct a tree of widget_value objects.
1184 Ignore the panes and items made by previous calls to
1185 single_submenu, even though those are also in menu_items. */
1186 i = previous_items;
1187 while (i < menu_items_used)
1189 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1191 submenu_stack[submenu_depth++] = save_wv;
1192 save_wv = prev_wv;
1193 prev_wv = 0;
1194 i++;
1196 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1198 prev_wv = save_wv;
1199 save_wv = submenu_stack[--submenu_depth];
1200 i++;
1202 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1203 && submenu_depth != 0)
1204 i += MENU_ITEMS_PANE_LENGTH;
1205 /* Ignore a nil in the item list.
1206 It's meaningful only for dialog boxes. */
1207 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1208 i += 1;
1209 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1211 /* Create a new pane. */
1212 Lisp_Object pane_name, prefix;
1213 char *pane_string;
1215 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1216 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1218 #ifndef HAVE_MULTILINGUAL_MENU
1219 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1221 pane_name = ENCODE_SYSTEM (pane_name);
1222 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1224 #endif
1225 pane_string = (NILP (pane_name)
1226 ? "" : (char *) SDATA (pane_name));
1227 /* If there is just one top-level pane, put all its items directly
1228 under the top-level menu. */
1229 if (menu_items_n_panes == 1)
1230 pane_string = "";
1232 /* If the pane has a meaningful name,
1233 make the pane a top-level menu item
1234 with its items as a submenu beneath it. */
1235 if (strcmp (pane_string, ""))
1237 wv = xmalloc_widget_value ();
1238 if (save_wv)
1239 save_wv->next = wv;
1240 else
1241 first_wv->contents = wv;
1242 wv->name = pane_string;
1243 /* Ignore the @ that means "separate pane".
1244 This is a kludge, but this isn't worth more time. */
1245 if (!NILP (prefix) && wv->name[0] == '@')
1246 wv->name++;
1247 wv->value = 0;
1248 wv->enabled = 1;
1249 wv->button_type = BUTTON_TYPE_NONE;
1250 wv->help = Qnil;
1252 save_wv = wv;
1253 prev_wv = 0;
1254 i += MENU_ITEMS_PANE_LENGTH;
1256 else
1258 /* Create a new item within current pane. */
1259 Lisp_Object item_name, enable, descrip, def, type, selected;
1260 Lisp_Object help;
1262 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1263 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1264 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1265 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1266 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1267 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1268 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1270 #ifndef HAVE_MULTILINGUAL_MENU
1271 if (STRING_MULTIBYTE (item_name))
1273 item_name = ENCODE_SYSTEM (item_name);
1274 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1277 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1279 descrip = ENCODE_SYSTEM (descrip);
1280 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1282 #endif /* not HAVE_MULTILINGUAL_MENU */
1284 wv = xmalloc_widget_value ();
1285 if (prev_wv)
1286 prev_wv->next = wv;
1287 else
1288 save_wv->contents = wv;
1290 wv->name = (char *) SDATA (item_name);
1291 if (!NILP (descrip))
1292 wv->key = (char *) SDATA (descrip);
1293 wv->value = 0;
1294 /* The EMACS_INT cast avoids a warning. There's no problem
1295 as long as pointers have enough bits to hold small integers. */
1296 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1297 wv->enabled = !NILP (enable);
1299 if (NILP (type))
1300 wv->button_type = BUTTON_TYPE_NONE;
1301 else if (EQ (type, QCradio))
1302 wv->button_type = BUTTON_TYPE_RADIO;
1303 else if (EQ (type, QCtoggle))
1304 wv->button_type = BUTTON_TYPE_TOGGLE;
1305 else
1306 abort ();
1308 wv->selected = !NILP (selected);
1309 if (!STRINGP (help))
1310 help = Qnil;
1312 wv->help = help;
1314 prev_wv = wv;
1316 i += MENU_ITEMS_ITEM_LENGTH;
1320 /* If we have just one "menu item"
1321 that was originally a button, return it by itself. */
1322 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
1324 wv = first_wv->contents;
1325 free_widget_value (first_wv);
1326 return wv;
1329 return first_wv;
1332 /* Set the contents of the menubar widgets of frame F.
1333 The argument FIRST_TIME is currently ignored;
1334 it is set the first time this is called, from initialize_frame_menubar. */
1336 void
1337 set_frame_menubar (f, first_time, deep_p)
1338 FRAME_PTR f;
1339 int first_time;
1340 int deep_p;
1342 int menubar_widget = f->output_data.mac->menubar_widget;
1343 Lisp_Object items;
1344 widget_value *wv, *first_wv, *prev_wv = 0;
1345 int i;
1347 /* We must not change the menubar when actually in use. */
1348 if (f->output_data.mac->menubar_active)
1349 return;
1351 XSETFRAME (Vmenu_updating_frame, f);
1353 if (! menubar_widget)
1354 deep_p = 1;
1355 else if (pending_menu_activation && !deep_p)
1356 deep_p = 1;
1358 wv = xmalloc_widget_value ();
1359 wv->name = "menubar";
1360 wv->value = 0;
1361 wv->enabled = 1;
1362 wv->button_type = BUTTON_TYPE_NONE;
1363 wv->help = Qnil;
1364 first_wv = wv;
1366 if (deep_p)
1368 /* Make a widget-value tree representing the entire menu trees. */
1370 struct buffer *prev = current_buffer;
1371 Lisp_Object buffer;
1372 int specpdl_count = SPECPDL_INDEX ();
1373 int previous_menu_items_used = f->menu_bar_items_used;
1374 Lisp_Object *previous_items
1375 = (Lisp_Object *) alloca (previous_menu_items_used
1376 * sizeof (Lisp_Object));
1378 /* If we are making a new widget, its contents are empty,
1379 do always reinitialize them. */
1380 if (! menubar_widget)
1381 previous_menu_items_used = 0;
1383 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1384 specbind (Qinhibit_quit, Qt);
1385 /* Don't let the debugger step into this code
1386 because it is not reentrant. */
1387 specbind (Qdebug_on_next_call, Qnil);
1389 record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
1390 if (NILP (Voverriding_local_map_menu_flag))
1392 specbind (Qoverriding_terminal_local_map, Qnil);
1393 specbind (Qoverriding_local_map, Qnil);
1396 set_buffer_internal_1 (XBUFFER (buffer));
1398 /* Run the Lucid hook. */
1399 safe_run_hooks (Qactivate_menubar_hook);
1400 /* If it has changed current-menubar from previous value,
1401 really recompute the menubar from the value. */
1402 if (! NILP (Vlucid_menu_bar_dirty_flag))
1403 call0 (Qrecompute_lucid_menubar);
1404 safe_run_hooks (Qmenu_bar_update_hook);
1405 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1407 items = FRAME_MENU_BAR_ITEMS (f);
1409 inhibit_garbage_collection ();
1411 /* Save the frame's previous menu bar contents data. */
1412 if (previous_menu_items_used)
1413 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1414 previous_menu_items_used * sizeof (Lisp_Object));
1416 /* Fill in the current menu bar contents. */
1417 menu_items = f->menu_bar_vector;
1418 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1419 init_menu_items ();
1420 for (i = 0; i < XVECTOR (items)->size; i += 4)
1422 Lisp_Object key, string, maps;
1424 key = XVECTOR (items)->contents[i];
1425 string = XVECTOR (items)->contents[i + 1];
1426 maps = XVECTOR (items)->contents[i + 2];
1427 if (NILP (string))
1428 break;
1430 wv = single_submenu (key, string, maps);
1431 if (prev_wv)
1432 prev_wv->next = wv;
1433 else
1434 first_wv->contents = wv;
1435 /* Don't set wv->name here; GC during the loop might relocate it. */
1436 wv->enabled = 1;
1437 wv->button_type = BUTTON_TYPE_NONE;
1438 prev_wv = wv;
1441 finish_menu_items ();
1443 set_buffer_internal_1 (prev);
1444 unbind_to (specpdl_count, Qnil);
1446 /* If there has been no change in the Lisp-level contents
1447 of the menu bar, skip redisplaying it. Just exit. */
1449 for (i = 0; i < previous_menu_items_used; i++)
1450 if (menu_items_used == i
1451 || (!Fequal (previous_items[i], XVECTOR (menu_items)->contents[i])))
1452 break;
1453 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1455 free_menubar_widget_value_tree (first_wv);
1456 menu_items = Qnil;
1458 return;
1461 /* Now GC cannot happen during the lifetime of the widget_value,
1462 so it's safe to store data from a Lisp_String, as long as
1463 local copies are made when the actual menu is created.
1464 Windows takes care of this for normal string items, but
1465 not for owner-drawn items or additional item-info. */
1466 wv = first_wv->contents;
1467 for (i = 0; i < XVECTOR (items)->size; i += 4)
1469 Lisp_Object string;
1470 string = XVECTOR (items)->contents[i + 1];
1471 if (NILP (string))
1472 break;
1473 wv->name = (char *) SDATA (string);
1474 wv = wv->next;
1477 f->menu_bar_vector = menu_items;
1478 f->menu_bar_items_used = menu_items_used;
1479 menu_items = Qnil;
1481 else
1483 /* Make a widget-value tree containing
1484 just the top level menu bar strings. */
1486 items = FRAME_MENU_BAR_ITEMS (f);
1487 for (i = 0; i < XVECTOR (items)->size; i += 4)
1489 Lisp_Object string;
1491 string = XVECTOR (items)->contents[i + 1];
1492 if (NILP (string))
1493 break;
1495 wv = xmalloc_widget_value ();
1496 wv->name = (char *) SDATA (string);
1497 wv->value = 0;
1498 wv->enabled = 1;
1499 wv->button_type = BUTTON_TYPE_NONE;
1500 wv->help = Qnil;
1501 /* This prevents lwlib from assuming this
1502 menu item is really supposed to be empty. */
1503 /* The EMACS_INT cast avoids a warning.
1504 This value just has to be different from small integers. */
1505 wv->call_data = (void *) (EMACS_INT) (-1);
1507 if (prev_wv)
1508 prev_wv->next = wv;
1509 else
1510 first_wv->contents = wv;
1511 prev_wv = wv;
1514 /* Forget what we thought we knew about what is in the
1515 detailed contents of the menu bar menus.
1516 Changing the top level always destroys the contents. */
1517 f->menu_bar_items_used = 0;
1520 /* Create or update the menu bar widget. */
1522 BLOCK_INPUT;
1524 /* Non-null value to indicate menubar has already been "created". */
1525 f->output_data.mac->menubar_widget = 1;
1528 int i = MIN_MENU_ID;
1529 MenuHandle menu = GetMenuHandle (i);
1530 while (menu != NULL)
1532 DeleteMenu (i);
1533 DisposeMenu (menu);
1534 menu = GetMenuHandle (++i);
1537 i = MIN_SUBMENU_ID;
1538 menu = GetMenuHandle (i);
1539 while (menu != NULL)
1541 DeleteMenu (i);
1542 DisposeMenu (menu);
1543 menu = GetMenuHandle (++i);
1547 fill_menubar (first_wv->contents);
1549 DrawMenuBar ();
1551 free_menubar_widget_value_tree (first_wv);
1553 UNBLOCK_INPUT;
1556 /* Called from Fx_create_frame to create the initial menubar of a frame
1557 before it is mapped, so that the window is mapped with the menubar already
1558 there instead of us tacking it on later and thrashing the window after it
1559 is visible. */
1561 void
1562 initialize_frame_menubar (f)
1563 FRAME_PTR f;
1565 /* This function is called before the first chance to redisplay
1566 the frame. It has to be, so the frame will have the right size. */
1567 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1568 set_frame_menubar (f, 1, 1);
1571 /* Get rid of the menu bar of frame F, and free its storage.
1572 This is used when deleting a frame, and when turning off the menu bar. */
1574 void
1575 free_frame_menubar (f)
1576 FRAME_PTR f;
1578 f->output_data.mac->menubar_widget = NULL;
1582 /* mac_menu_show actually displays a menu using the panes and items in
1583 menu_items and returns the value selected from it; we assume input
1584 is blocked by the caller. */
1586 /* F is the frame the menu is for.
1587 X and Y are the frame-relative specified position,
1588 relative to the inside upper left corner of the frame F.
1589 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1590 KEYMAPS is 1 if this menu was specified with keymaps;
1591 in that case, we return a list containing the chosen item's value
1592 and perhaps also the pane's prefix.
1593 TITLE is the specified menu title.
1594 ERROR is a place to store an error message string in case of failure.
1595 (We return nil on failure, but the value doesn't actually matter.) */
1597 static Lisp_Object
1598 mac_menu_show (f, x, y, for_click, keymaps, title, error)
1599 FRAME_PTR f;
1600 int x;
1601 int y;
1602 int for_click;
1603 int keymaps;
1604 Lisp_Object title;
1605 char **error;
1607 int i;
1608 int menu_item_selection;
1609 MenuHandle menu;
1610 Point pos;
1611 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1612 widget_value **submenu_stack
1613 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1614 Lisp_Object *subprefix_stack
1615 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1616 int submenu_depth = 0;
1617 int first_pane;
1619 *error = NULL;
1621 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1623 *error = "Empty menu";
1624 return Qnil;
1627 /* Create a tree of widget_value objects
1628 representing the panes and their items. */
1629 wv = xmalloc_widget_value ();
1630 wv->name = "menu";
1631 wv->value = 0;
1632 wv->enabled = 1;
1633 wv->button_type = BUTTON_TYPE_NONE;
1634 wv->help = Qnil;
1635 first_wv = wv;
1636 first_pane = 1;
1638 /* Loop over all panes and items, filling in the tree. */
1639 i = 0;
1640 while (i < menu_items_used)
1642 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1644 submenu_stack[submenu_depth++] = save_wv;
1645 save_wv = prev_wv;
1646 prev_wv = 0;
1647 first_pane = 1;
1648 i++;
1650 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1652 prev_wv = save_wv;
1653 save_wv = submenu_stack[--submenu_depth];
1654 first_pane = 0;
1655 i++;
1657 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1658 && submenu_depth != 0)
1659 i += MENU_ITEMS_PANE_LENGTH;
1660 /* Ignore a nil in the item list.
1661 It's meaningful only for dialog boxes. */
1662 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1663 i += 1;
1664 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1666 /* Create a new pane. */
1667 Lisp_Object pane_name, prefix;
1668 char *pane_string;
1669 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1670 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1671 #ifndef HAVE_MULTILINGUAL_MENU
1672 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1674 pane_name = ENCODE_SYSTEM (pane_name);
1675 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1677 #endif
1678 pane_string = (NILP (pane_name)
1679 ? "" : (char *) SDATA (pane_name));
1680 /* If there is just one top-level pane, put all its items directly
1681 under the top-level menu. */
1682 if (menu_items_n_panes == 1)
1683 pane_string = "";
1685 /* If the pane has a meaningful name,
1686 make the pane a top-level menu item
1687 with its items as a submenu beneath it. */
1688 if (!keymaps && strcmp (pane_string, ""))
1690 wv = xmalloc_widget_value ();
1691 if (save_wv)
1692 save_wv->next = wv;
1693 else
1694 first_wv->contents = wv;
1695 wv->name = pane_string;
1696 if (keymaps && !NILP (prefix))
1697 wv->name++;
1698 wv->value = 0;
1699 wv->enabled = 1;
1700 wv->button_type = BUTTON_TYPE_NONE;
1701 wv->help = Qnil;
1702 save_wv = wv;
1703 prev_wv = 0;
1705 else if (first_pane)
1707 save_wv = wv;
1708 prev_wv = 0;
1710 first_pane = 0;
1711 i += MENU_ITEMS_PANE_LENGTH;
1713 else
1715 /* Create a new item within current pane. */
1716 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1718 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1719 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1720 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1721 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1722 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1723 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1724 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1726 #ifndef HAVE_MULTILINGUAL_MENU
1727 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1729 item_name = ENCODE_SYSTEM (item_name);
1730 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1732 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1734 descrip = ENCODE_SYSTEM (descrip);
1735 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1737 #endif /* not HAVE_MULTILINGUAL_MENU */
1739 wv = xmalloc_widget_value ();
1740 if (prev_wv)
1741 prev_wv->next = wv;
1742 else
1743 save_wv->contents = wv;
1744 wv->name = (char *) SDATA (item_name);
1745 if (!NILP (descrip))
1746 wv->key = (char *) SDATA (descrip);
1747 wv->value = 0;
1748 /* Use the contents index as call_data, since we are
1749 restricted to 16-bits. */
1750 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
1751 wv->enabled = !NILP (enable);
1753 if (NILP (type))
1754 wv->button_type = BUTTON_TYPE_NONE;
1755 else if (EQ (type, QCtoggle))
1756 wv->button_type = BUTTON_TYPE_TOGGLE;
1757 else if (EQ (type, QCradio))
1758 wv->button_type = BUTTON_TYPE_RADIO;
1759 else
1760 abort ();
1762 wv->selected = !NILP (selected);
1763 if (!STRINGP (help))
1764 help = Qnil;
1766 wv->help = help;
1768 prev_wv = wv;
1770 i += MENU_ITEMS_ITEM_LENGTH;
1774 /* Deal with the title, if it is non-nil. */
1775 if (!NILP (title))
1777 widget_value *wv_title = xmalloc_widget_value ();
1778 widget_value *wv_sep = xmalloc_widget_value ();
1780 /* Maybe replace this separator with a bitmap or owner-draw item
1781 so that it looks better. Having two separators looks odd. */
1782 wv_sep->name = "--";
1783 wv_sep->next = first_wv->contents;
1784 wv_sep->help = Qnil;
1786 #ifndef HAVE_MULTILINGUAL_MENU
1787 if (STRING_MULTIBYTE (title))
1788 title = ENCODE_SYSTEM (title);
1789 #endif
1790 wv_title->name = (char *) SDATA (title);
1791 wv_title->enabled = TRUE;
1792 wv_title->title = TRUE;
1793 wv_title->button_type = BUTTON_TYPE_NONE;
1794 wv_title->help = Qnil;
1795 wv_title->next = wv_sep;
1796 first_wv->contents = wv_title;
1799 /* Actually create the menu. */
1800 menu = NewMenu (POPUP_SUBMENU_ID, "\p");
1801 fill_submenu (menu, first_wv->contents, 0);
1803 /* Adjust coordinates to be root-window-relative. */
1804 pos.h = x;
1805 pos.v = y;
1807 #if TARGET_API_MAC_CARBON
1808 SetPort (GetWindowPort (FRAME_MAC_WINDOW (f)));
1809 #else
1810 SetPort (FRAME_MAC_WINDOW (f));
1811 #endif
1813 LocalToGlobal (&pos);
1815 /* No selection has been chosen yet. */
1816 menu_item_selection = 0;
1818 InsertMenu (menu, -1);
1820 /* Display the menu. */
1821 menu_item_selection = LoWord (PopUpMenuSelect (menu, pos.v, pos.h, 0));
1823 DeleteMenu (POPUP_SUBMENU_ID);
1825 #if 0
1826 /* Clean up extraneous mouse events which might have been generated
1827 during the call. */
1828 discard_mouse_events ();
1829 #endif
1831 /* Free the widget_value objects we used to specify the
1832 contents. */
1833 free_menubar_widget_value_tree (first_wv);
1835 DisposeMenu (menu);
1837 /* Find the selected item, and its pane, to return
1838 the proper value. */
1839 if (menu_item_selection != 0)
1841 Lisp_Object prefix, entry;
1842 int j = 1;
1844 prefix = entry = Qnil;
1845 i = 0;
1846 while (i < menu_items_used)
1848 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1850 subprefix_stack[submenu_depth++] = prefix;
1851 prefix = entry;
1852 i++;
1854 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1856 prefix = subprefix_stack[--submenu_depth];
1857 i++;
1859 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1861 prefix
1862 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1863 i += MENU_ITEMS_PANE_LENGTH;
1864 j += 2;
1866 /* Ignore a nil in the item list.
1867 It's meaningful only for dialog boxes. */
1868 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1869 i += 1;
1870 else
1872 entry
1873 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1874 if (menu_item_selection == j)
1876 if (keymaps != 0)
1878 int j;
1880 entry = Fcons (entry, Qnil);
1881 if (!NILP (prefix))
1882 entry = Fcons (prefix, entry);
1883 for (j = submenu_depth - 1; j >= 0; j--)
1884 if (!NILP (subprefix_stack[j]))
1885 entry = Fcons (subprefix_stack[j], entry);
1887 return entry;
1889 i += MENU_ITEMS_ITEM_LENGTH;
1890 j++;
1895 return Qnil;
1899 #ifdef HAVE_DIALOGS
1900 /* Construct native Mac OS menubar based on widget_value tree. */
1902 static int
1903 mac_dialog (widget_value *wv)
1905 char *dialog_name;
1906 char *prompt;
1907 char **button_labels;
1908 UInt32 *ref_cons;
1909 int nb_buttons;
1910 int left_count;
1911 int i;
1912 int dialog_width;
1913 Rect rect;
1914 WindowPtr window_ptr;
1915 ControlHandle ch;
1916 int left;
1917 EventRecord event_record;
1918 SInt16 part_code;
1919 int control_part_code;
1920 Point mouse;
1922 dialog_name = wv->name;
1923 nb_buttons = dialog_name[1] - '0';
1924 left_count = nb_buttons - (dialog_name[4] - '0');
1925 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
1926 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
1928 wv = wv->contents;
1929 prompt = (char *) alloca (strlen (wv->value) + 1);
1930 strcpy (prompt, wv->value);
1931 c2pstr (prompt);
1933 wv = wv->next;
1934 for (i = 0; i < nb_buttons; i++)
1936 button_labels[i] = wv->value;
1937 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
1938 strcpy (button_labels[i], wv->value);
1939 c2pstr (button_labels[i]);
1940 ref_cons[i] = (UInt32) wv->call_data;
1941 wv = wv->next;
1944 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
1946 #if TARGET_API_MAC_CARBON
1947 SetPort (GetWindowPort (window_ptr));
1948 #else
1949 SetPort (window_ptr);
1950 #endif
1952 TextFont (0);
1953 /* Left and right margins in the dialog are 13 pixels each.*/
1954 dialog_width = 14;
1955 /* Calculate width of dialog box: 8 pixels on each side of the text
1956 label in each button, 12 pixels between buttons. */
1957 for (i = 0; i < nb_buttons; i++)
1958 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
1960 if (left_count != 0 && nb_buttons - left_count != 0)
1961 dialog_width += 12;
1963 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
1965 SizeWindow (window_ptr, dialog_width, 78, 0);
1966 ShowWindow (window_ptr);
1968 #if TARGET_API_MAC_CARBON
1969 SetPort (GetWindowPort (window_ptr));
1970 #else
1971 SetPort (window_ptr);
1972 #endif
1974 TextFont (0);
1976 MoveTo (13, 29);
1977 DrawString (prompt);
1979 left = 13;
1980 for (i = 0; i < nb_buttons; i++)
1982 int button_width = StringWidth (button_labels[i]) + 16;
1983 SetRect (&rect, left, 45, left + button_width, 65);
1984 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
1985 kControlPushButtonProc, ref_cons[i]);
1986 left += button_width + 12;
1987 if (i == left_count - 1)
1988 left += 12;
1991 i = 0;
1992 while (!i)
1994 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
1995 if (event_record.what == mouseDown)
1997 part_code = FindWindow (event_record.where, &window_ptr);
1998 if (part_code == inContent)
2000 mouse = event_record.where;
2001 GlobalToLocal (&mouse);
2002 control_part_code = FindControl (mouse, window_ptr, &ch);
2003 if (control_part_code == kControlButtonPart)
2004 if (TrackControl (ch, mouse, NULL))
2005 i = GetControlReference (ch);
2010 DisposeWindow (window_ptr);
2012 return i;
2015 static char * button_names [] = {
2016 "button1", "button2", "button3", "button4", "button5",
2017 "button6", "button7", "button8", "button9", "button10" };
2019 static Lisp_Object
2020 mac_dialog_show (f, keymaps, title, error)
2021 FRAME_PTR f;
2022 int keymaps;
2023 Lisp_Object title;
2024 char **error;
2026 int i, nb_buttons=0;
2027 char dialog_name[6];
2028 int menu_item_selection;
2030 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2032 /* Number of elements seen so far, before boundary. */
2033 int left_count = 0;
2034 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2035 int boundary_seen = 0;
2037 *error = NULL;
2039 if (menu_items_n_panes > 1)
2041 *error = "Multiple panes in dialog box";
2042 return Qnil;
2045 /* Create a tree of widget_value objects
2046 representing the text label and buttons. */
2048 Lisp_Object pane_name, prefix;
2049 char *pane_string;
2050 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2051 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2052 pane_string = (NILP (pane_name)
2053 ? "" : (char *) SDATA (pane_name));
2054 prev_wv = xmalloc_widget_value ();
2055 prev_wv->value = pane_string;
2056 if (keymaps && !NILP (prefix))
2057 prev_wv->name++;
2058 prev_wv->enabled = 1;
2059 prev_wv->name = "message";
2060 prev_wv->help = Qnil;
2061 first_wv = prev_wv;
2063 /* Loop over all panes and items, filling in the tree. */
2064 i = MENU_ITEMS_PANE_LENGTH;
2065 while (i < menu_items_used)
2068 /* Create a new item within current pane. */
2069 Lisp_Object item_name, enable, descrip, help;
2071 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2072 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2073 descrip
2074 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2075 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2077 if (NILP (item_name))
2079 free_menubar_widget_value_tree (first_wv);
2080 *error = "Submenu in dialog items";
2081 return Qnil;
2083 if (EQ (item_name, Qquote))
2085 /* This is the boundary between left-side elts
2086 and right-side elts. Stop incrementing right_count. */
2087 boundary_seen = 1;
2088 i++;
2089 continue;
2091 if (nb_buttons >= 9)
2093 free_menubar_widget_value_tree (first_wv);
2094 *error = "Too many dialog items";
2095 return Qnil;
2098 wv = xmalloc_widget_value ();
2099 prev_wv->next = wv;
2100 wv->name = (char *) button_names[nb_buttons];
2101 if (!NILP (descrip))
2102 wv->key = (char *) SDATA (descrip);
2103 wv->value = (char *) SDATA (item_name);
2104 wv->call_data = (void *) i;
2105 /* menu item is identified by its index in menu_items table */
2106 wv->enabled = !NILP (enable);
2107 wv->help = Qnil;
2108 prev_wv = wv;
2110 if (! boundary_seen)
2111 left_count++;
2113 nb_buttons++;
2114 i += MENU_ITEMS_ITEM_LENGTH;
2117 /* If the boundary was not specified,
2118 by default put half on the left and half on the right. */
2119 if (! boundary_seen)
2120 left_count = nb_buttons - nb_buttons / 2;
2122 wv = xmalloc_widget_value ();
2123 wv->name = dialog_name;
2124 wv->help = Qnil;
2126 /* Dialog boxes use a really stupid name encoding
2127 which specifies how many buttons to use
2128 and how many buttons are on the right.
2129 The Q means something also. */
2130 dialog_name[0] = 'Q';
2131 dialog_name[1] = '0' + nb_buttons;
2132 dialog_name[2] = 'B';
2133 dialog_name[3] = 'R';
2134 /* Number of buttons to put on the right. */
2135 dialog_name[4] = '0' + nb_buttons - left_count;
2136 dialog_name[5] = 0;
2137 wv->contents = first_wv;
2138 first_wv = wv;
2141 /* Actually create the dialog. */
2142 #ifdef HAVE_DIALOGS
2143 menu_item_selection = mac_dialog (first_wv);
2144 #else
2145 menu_item_selection = 0;
2146 #endif
2148 /* Free the widget_value objects we used to specify the contents. */
2149 free_menubar_widget_value_tree (first_wv);
2151 /* Find the selected item, and its pane, to return the proper
2152 value. */
2153 if (menu_item_selection != 0)
2155 Lisp_Object prefix;
2157 prefix = Qnil;
2158 i = 0;
2159 while (i < menu_items_used)
2161 Lisp_Object entry;
2163 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2165 prefix
2166 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2167 i += MENU_ITEMS_PANE_LENGTH;
2169 else
2171 entry
2172 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2173 if (menu_item_selection == i)
2175 if (keymaps != 0)
2177 entry = Fcons (entry, Qnil);
2178 if (!NILP (prefix))
2179 entry = Fcons (prefix, entry);
2181 return entry;
2183 i += MENU_ITEMS_ITEM_LENGTH;
2188 return Qnil;
2190 #endif /* HAVE_DIALOGS */
2193 /* Is this item a separator? */
2194 static int
2195 name_is_separator (name)
2196 char *name;
2198 char *start = name;
2200 /* Check if name string consists of only dashes ('-'). */
2201 while (*name == '-') name++;
2202 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2203 or "--deep-shadow". We don't implement them yet, se we just treat
2204 them like normal separators. */
2205 return (*name == '\0' || start + 2 == name);
2208 static void
2209 add_menu_item (MenuHandle menu, widget_value *wv, int submenu, int indent,
2210 int force_disable)
2212 Str255 item_name;
2213 int pos, i;
2215 if (name_is_separator (wv->name))
2216 AppendMenu (menu, "\p-");
2217 else
2219 AppendMenu (menu, "\pX");
2221 #if TARGET_API_MAC_CARBON
2222 pos = CountMenuItems (menu);
2223 #else
2224 pos = CountMItems (menu);
2225 #endif
2227 strcpy (item_name, "");
2228 for (i = 0; i < indent; i++)
2229 strcat (item_name, " ");
2230 strcat (item_name, wv->name);
2231 if (wv->key != NULL)
2233 strcat (item_name, " ");
2234 strcat (item_name, wv->key);
2236 c2pstr (item_name);
2237 SetMenuItemText (menu, pos, item_name);
2239 if (wv->enabled && !force_disable)
2240 #if TARGET_API_MAC_CARBON
2241 EnableMenuItem (menu, pos);
2242 #else
2243 EnableItem (menu, pos);
2244 #endif
2245 else
2246 #if TARGET_API_MAC_CARBON
2247 DisableMenuItem (menu, pos);
2248 #else
2249 DisableItem (menu, pos);
2250 #endif
2252 /* Draw radio buttons and tickboxes. */
2254 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
2255 wv->button_type == BUTTON_TYPE_RADIO))
2256 SetItemMark (menu, pos, checkMark);
2257 else
2258 SetItemMark (menu, pos, noMark);
2262 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
2264 if (submenu != NULL)
2265 SetMenuItemHierarchicalID (menu, pos, submenu);
2268 static int submenu_id;
2270 /* Construct native Mac OS menubar based on widget_value tree. */
2272 static void
2273 fill_submenu (MenuHandle menu, widget_value *wv, int indent)
2275 for ( ; wv != NULL; wv = wv->next)
2276 if (wv->contents)
2278 add_menu_item (menu, wv, NULL, indent, 1);
2280 fill_submenu (menu, wv->contents, indent + 1);
2282 else
2283 add_menu_item (menu, wv, NULL, indent, 0);
2287 /* Construct native Mac OS menu based on widget_value tree. */
2289 static void
2290 fill_menu (MenuHandle menu, widget_value *wv)
2292 for ( ; wv != NULL; wv = wv->next)
2293 if (wv->contents)
2295 MenuHandle submenu = NewMenu (submenu_id, "\pX");
2296 fill_submenu (submenu, wv->contents, 0);
2297 InsertMenu (submenu, -1);
2298 add_menu_item (menu, wv, submenu_id, 0, 0);
2299 submenu_id++;
2301 else
2302 add_menu_item (menu, wv, NULL, 0, 0);
2305 /* Construct native Mac OS menubar based on widget_value tree. */
2307 static void
2308 fill_menubar (widget_value *wv)
2310 int id;
2312 submenu_id = MIN_SUBMENU_ID;
2314 for (id = MIN_MENU_ID; wv != NULL; wv = wv->next, id++)
2316 MenuHandle menu;
2317 Str255 title;
2319 strcpy (title, wv->name);
2320 c2pstr (title);
2321 menu = NewMenu (id, title);
2323 if (wv->contents)
2324 fill_menu (menu, wv->contents);
2326 InsertMenu (menu, 0);
2330 #endif /* HAVE_MENUS */
2333 void
2334 syms_of_macmenu ()
2336 staticpro (&menu_items);
2337 menu_items = Qnil;
2339 Qdebug_on_next_call = intern ("debug-on-next-call");
2340 staticpro (&Qdebug_on_next_call);
2342 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
2343 doc: /* Frame for which we are updating a menu.
2344 The enable predicate for a menu command should check this variable. */);
2345 Vmenu_updating_frame = Qnil;
2347 defsubr (&Sx_popup_menu);
2348 #ifdef HAVE_MENUS
2349 defsubr (&Sx_popup_dialog);
2350 #endif