root/trunk/mac/src/macmenu.c

Revision 3104, 59.8 kB (checked in by himi, 6 years ago)

set svn:eol-style

  • Property svn:eol-style set to native
Line 
1 /* Menu support for GNU Emacs on the for Mac OS.
2    Copyright (C) 2000 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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.
10
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.
15
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.  */
20
21 /* Contributed by Andrew Choi (akochoi@users.sourceforge.net).  */
22
23 #include <config.h>
24 #include <signal.h>
25
26 #include <stdio.h>
27 #include "lisp.h"
28 #include "termhooks.h"
29 #include "frame.h"
30 #include "window.h"
31 #include "keyboard.h"
32 #include "blockinput.h"
33 #include "buffer.h"
34 #include "charset.h"
35 #include "coding.h"
36
37 #include <MacTypes.h>
38 #include <Menus.h>
39 #include <QuickDraw.h>
40 #include <ToolUtils.h>
41 #include <Fonts.h>
42 #include <Controls.h>
43 #include <Windows.h>
44 #include <Events.h>
45 #if defined (__MRC__) || defined (CODEWARRIOR_VERSION_6)
46 #include <ControlDefinitions.h>
47 #endif
48
49 /* This may include sys/types.h, and that somehow loses
50    if this is not done before the other system files.  */
51 #include "macterm.h"
52
53 /* Load sys/types.h if not already loaded.
54    In some systems loading it twice is suicidal.  */
55 #ifndef makedev
56 #include <sys/types.h>
57 #endif
58
59 #include "dispextern.h"
60
61 #define POPUP_SUBMENU_ID 235
62 #define MIN_MENU_ID 256
63 #define MIN_SUBMENU_ID 1
64
65 #define DIALOG_WINDOW_RESOURCE 130
66
67 #define HAVE_DIALOGS 1
68
69 #undef HAVE_MULTILINGUAL_MENU
70
71 /******************************************************************/
72 /* Definitions copied from lwlib.h */
73
74 typedef void * XtPointer;
75
76 #define True 1
77 #define False 0
78
79 enum button_type
80 {
81   BUTTON_TYPE_NONE,
82   BUTTON_TYPE_TOGGLE,
83   BUTTON_TYPE_RADIO
84 };
85
86 typedef struct _widget_value
87 {
88   /* name of widget */
89   char*         name;
90   /* value (meaning depend on widget type) */
91   char*         value;
92   /* keyboard equivalent. no implications for XtTranslations */
93   char*         key;
94   /* Help string or null if none.  */
95   char          *help;
96   /* true if enabled */
97   Boolean       enabled;
98   /* true if selected */
99   Boolean       selected;
100   /* The type of a button.  */
101   enum button_type button_type;
102   /* true if menu title */
103   Boolean       title;
104 #if 0
105   /* true if was edited (maintained by get_value) */
106   Boolean       edited;
107   /* true if has changed (maintained by lw library) */
108   change_type   change;
109   /* true if this widget itself has changed,
110      but not counting the other widgets found in the `next' field.  */
111   change_type   this_one_change;
112 #endif
113   /* Contents of the sub-widgets, also selected slot for checkbox */
114   struct _widget_value* contents;
115   /* data passed to callback */
116   XtPointer     call_data;
117   /* next one in the list */
118   struct _widget_value* next;
119 #if 0
120   /* slot for the toolkit dependent part.  Always initialize to NULL. */
121   void* toolkit_data;
122   /* tell us if we should free the toolkit data slot when freeing the
123      widget_value itself. */
124   Boolean free_toolkit_data;
125
126   /* we resource the widget_value structures; this points to the next
127      one on the free list if this one has been deallocated.
128    */
129   struct _widget_value *free_list;
130 #endif
131 } widget_value;
132
133 /* Assumed by other routines to zero area returned.  */
134 #define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
135                                               0, (sizeof (widget_value)))
136 #define free_widget_value(wv) xfree (wv)
137
138 /******************************************************************/
139
140 #define min(x,y) (((x) < (y)) ? (x) : (y))
141 #define max(x,y) (((x) > (y)) ? (x) : (y))
142
143 #ifndef TRUE
144 #define TRUE 1
145 #define FALSE 0
146 #endif /* no TRUE */
147
148 Lisp_Object Vmenu_updating_frame;
149
150 Lisp_Object Qdebug_on_next_call;
151
152 extern Lisp_Object Qmenu_bar;
153 extern Lisp_Object Qmouse_click, Qevent_kind;
154
155 extern Lisp_Object QCtoggle, QCradio;
156
157 extern Lisp_Object Voverriding_local_map;
158 extern Lisp_Object Voverriding_local_map_menu_flag;
159
160 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
161
162 extern Lisp_Object Qmenu_bar_update_hook;
163
164 void set_frame_menubar ();
165
166 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
167                                 Lisp_Object, Lisp_Object, Lisp_Object,
168                                 Lisp_Object, Lisp_Object));
169 static Lisp_Object mac_dialog_show ();
170 static Lisp_Object mac_menu_show ();
171
172 static void keymap_panes ();
173 static void single_keymap_panes ();
174 static void single_menu_item ();
175 static void list_of_panes ();
176 static void list_of_items ();
177
178 static void fill_submenu (MenuHandle, widget_value *, int);
179 static void fill_menubar (widget_value *);
180
181
182 /* This holds a Lisp vector that holds the results of decoding
183    the keymaps or alist-of-alists that specify a menu.
184
185    It describes the panes and items within the panes.
186
187    Each pane is described by 3 elements in the vector:
188    t, the pane name, the pane's prefix key.
189    Then follow the pane's items, with 5 elements per item:
190    the item string, the enable flag, the item's value,
191    the definition, and the equivalent keyboard key's description string.
192
193    In some cases, multiple levels of menus may be described.
194    A single vector slot containing nil indicates the start of a submenu.
195    A single vector slot containing lambda indicates the end of a submenu.
196    The submenu follows a menu item which is the way to reach the submenu.
197
198    A single vector slot containing quote indicates that the
199    following items should appear on the right of a dialog box.
200
201    Using a Lisp vector to hold this information while we decode it
202    takes care of protecting all the data from GC.  */
203
204 #define MENU_ITEMS_PANE_NAME 1
205 #define MENU_ITEMS_PANE_PREFIX 2
206 #define MENU_ITEMS_PANE_LENGTH 3
207
208 enum menu_item_idx
209 {
210   MENU_ITEMS_ITEM_NAME = 0,
211   MENU_ITEMS_ITEM_ENABLE,
212   MENU_ITEMS_ITEM_VALUE,
213   MENU_ITEMS_ITEM_EQUIV_KEY,
214   MENU_ITEMS_ITEM_DEFINITION,
215   MENU_ITEMS_ITEM_TYPE,
216   MENU_ITEMS_ITEM_SELECTED,
217   MENU_ITEMS_ITEM_HELP,
218   MENU_ITEMS_ITEM_LENGTH
219 };
220
221 static Lisp_Object menu_items;
222
223 /* Number of slots currently allocated in menu_items.  */
224 static int menu_items_allocated;
225
226 /* This is the index in menu_items of the first empty slot.  */
227 static int menu_items_used;
228
229 /* The number of panes currently recorded in menu_items,
230    excluding those within submenus.  */
231 static int menu_items_n_panes;
232
233 /* Current depth within submenus.  */
234 static int menu_items_submenu_depth;
235
236 /* Flag which when set indicates a dialog or menu has been posted by
237    Xt on behalf of one of the widget sets.  */
238 static int popup_activated_flag;
239
240 static int next_menubar_widget_id;
241
242 /* This is set nonzero after the user activates the menu bar, and set
243    to zero again after the menu bars are redisplayed by prepare_menu_bar.
244    While it is nonzero, all calls to set_frame_menubar go deep.
245
246    I don't understand why this is needed, but it does seem to be
247    needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>.  */
248
249 int pending_menu_activation;
250
251 /* Initialize the menu_items structure if we haven't already done so.
252    Also mark it as currently empty.  */
253
254 static void
255 init_menu_items ()
256 {
257   if (NILP (menu_items))
258     {
259       menu_items_allocated = 60;
260       menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
261     }
262
263   menu_items_used = 0;
264   menu_items_n_panes = 0;
265   menu_items_submenu_depth = 0;
266 }
267
268 /* Call at the end of generating the data in menu_items.
269    This fills in the number of items in the last pane.  */
270
271 static void
272 finish_menu_items ()
273 {
274 }
275
276 /* Call when finished using the data for the current menu
277    in menu_items.  */
278
279 static void
280 discard_menu_items ()
281 {
282   /* Free the structure if it is especially large.
283      Otherwise, hold on to it, to save time.  */
284   if (menu_items_allocated > 200)
285     {
286       menu_items = Qnil;
287       menu_items_allocated = 0;
288     }
289 }
290
291 /* Make the menu_items vector twice as large.  */
292
293 static void
294 grow_menu_items ()
295 {
296   Lisp_Object old;
297   int old_size = menu_items_allocated;
298   old = menu_items;
299
300   menu_items_allocated *= 2;
301   menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
302   bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
303          old_size * sizeof (Lisp_Object));
304 }
305
306 /* Begin a submenu.  */
307
308 static void
309 push_submenu_start ()
310 {
311   if (menu_items_used + 1 > menu_items_allocated)
312     grow_menu_items ();
313
314   XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
315   menu_items_submenu_depth++;
316 }
317
318 /* End a submenu.  */
319
320 static void
321 push_submenu_end ()
322 {
323   if (menu_items_used + 1 > menu_items_allocated)
324     grow_menu_items ();
325
326   XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
327   menu_items_submenu_depth--;
328 }
329
330 /* Indicate boundary between left and right.  */
331
332 static void
333 push_left_right_boundary ()
334 {
335   if (menu_items_used + 1 > menu_items_allocated)
336     grow_menu_items ();
337
338   XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
339 }
340
341 /* Start a new menu pane in menu_items..
342    NAME is the pane name.  PREFIX_VEC is a prefix key for this pane.  */
343
344 static void
345 push_menu_pane (name, prefix_vec)
346      Lisp_Object name, prefix_vec;
347 {
348   if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
349     grow_menu_items ();
350
351   if (menu_items_submenu_depth == 0)
352     menu_items_n_panes++;
353   XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
354   XVECTOR (menu_items)->contents[menu_items_used++] = name;
355   XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
356 }
357
358 /* Push one menu item into the current pane.  NAME is the string to
359    display.  ENABLE if non-nil means this item can be selected.  KEY
360    is the key generated by choosing this item, or nil if this item
361    doesn't really have a definition.  DEF is the definition of this
362    item.  EQUIV is the textual description of the keyboard equivalent
363    for this item (or nil if none).  TYPE is the type of this menu
364    item, one of nil, `toggle' or `radio'. */
365
366 static void
367 push_menu_item (name, enable, key, def, equiv, type, selected, help)
368      Lisp_Object name, enable, key, def, equiv, type, selected, help;
369 {
370   if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
371     grow_menu_items ();
372
373   XVECTOR (menu_items)->contents[menu_items_used++] = name;
374   XVECTOR (menu_items)->contents[menu_items_used++] = enable;
375   XVECTOR (menu_items)->contents[menu_items_used++] = key;
376   XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
377   XVECTOR (menu_items)->contents[menu_items_used++] = def;
378   XVECTOR (menu_items)->contents[menu_items_used++] = type;
379   XVECTOR (menu_items)->contents[menu_items_used++] = selected;
380   XVECTOR (menu_items)->contents[menu_items_used++] = help;
381 }
382
383 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
384    and generate menu panes for them in menu_items.
385    If NOTREAL is nonzero,
386    don't bother really computing whether an item is enabled.  */
387
388 static void
389 keymap_panes (keymaps, nmaps, notreal)
390      Lisp_Object *keymaps;
391      int nmaps;
392      int notreal;
393 {
394   int mapno;
395
396   init_menu_items ();
397
398   /* Loop over the given keymaps, making a pane for each map.
399      But don't make a pane that is empty--ignore that map instead.
400      P is the number of panes we have made so far.  */
401   for (mapno = 0; mapno < nmaps; mapno++)
402     single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
403
404   finish_menu_items ();
405 }
406
407 /* This is a recursive subroutine of keymap_panes.
408    It handles one keymap, KEYMAP.
409    The other arguments are passed along
410    or point to local variables of the previous function.
411    If NOTREAL is nonzero, only check for equivalent key bindings, don't
412    evaluate expressions in menu items and don't make any menu.
413
414    If we encounter submenus deeper than MAXDEPTH levels, ignore them.  */
415
416 static void
417 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
418      Lisp_Object keymap;
419      Lisp_Object pane_name;
420      Lisp_Object prefix;
421      int notreal;
422      int maxdepth;
423 {
424   Lisp_Object pending_maps = Qnil;
425   Lisp_Object tail, item;
426   struct gcpro gcpro1, gcpro2;
427
428   if (maxdepth <= 0)
429     return;
430
431   push_menu_pane (pane_name, prefix);
432
433   for (tail = keymap; CONSP (tail); tail = XCDR (tail))
434     {
435       GCPRO2 (keymap, pending_maps);
436       /* Look at each key binding, and if it is a menu item add it
437          to this menu.  */
438       item = XCAR (tail);
439       if (CONSP (item))
440         single_menu_item (XCAR (item), XCDR (item),
441                           &pending_maps, notreal, maxdepth);
442       else if (VECTORP (item))
443         {
444           /* Loop over the char values represented in the vector.  */
445           int len = XVECTOR (item)->size;
446           int c;
447           for (c = 0; c < len; c++)
448             {
449               Lisp_Object character;
450               XSETFASTINT (character, c);
451               single_menu_item (character, XVECTOR (item)->contents[c],
452                                 &pending_maps, notreal, maxdepth);
453             }
454         }
455       UNGCPRO;
456     }
457
458   /* Process now any submenus which want to be panes at this level.  */
459   while (!NILP (pending_maps))
460     {
461       Lisp_Object elt, eltcdr, string;
462       elt = Fcar (pending_maps);
463       eltcdr = XCDR (elt);
464       string = XCAR (eltcdr);
465       /* We no longer discard the @ from the beginning of the string here.
466          Instead, we do this in mac_menu_show.  */
467       single_keymap_panes (Fcar (elt), string,
468                            XCDR (eltcdr), notreal, maxdepth - 1);
469       pending_maps = Fcdr (pending_maps);
470     }
471 }
472
473 /* This is a subroutine of single_keymap_panes that handles one
474    keymap entry.
475    KEY is a key in a keymap and ITEM is its binding.
476    PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
477    separate panes.
478    If NOTREAL is nonzero, only check for equivalent key bindings, don't
479    evaluate expressions in menu items and don't make any menu.
480    If we encounter submenus deeper than MAXDEPTH levels, ignore them.  */
481
482 static void
483 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
484      Lisp_Object key, item;
485      Lisp_Object *pending_maps_ptr;
486      int maxdepth, notreal;
487 {
488   Lisp_Object map, item_string, enabled;
489   struct gcpro gcpro1, gcpro2;
490   int res;
491  
492   /* Parse the menu item and leave the result in item_properties.  */
493   GCPRO2 (key, item);
494   res = parse_menu_item (item, notreal, 0);
495   UNGCPRO;
496   if (!res)
497     return;                     /* Not a menu item.  */
498
499   map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
500  
501   if (notreal)
502     {
503       /* We don't want to make a menu, just traverse the keymaps to
504          precompute equivalent key bindings.  */
505       if (!NILP (map))
506         single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
507       return;
508     }
509
510   enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
511   item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
512
513   if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
514     {
515       if (!NILP (enabled))
516         /* An enabled separate pane. Remember this to handle it later.  */
517         *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
518                                    *pending_maps_ptr);
519       return;
520     }
521
522   push_menu_item (item_string, enabled, key,
523                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
524                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
525                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
526                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
527                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
528
529   /* Display a submenu using the toolkit.  */
530   if (! (NILP (map) || NILP (enabled)))
531     {
532       push_submenu_start ();
533       single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
534       push_submenu_end ();
535     }
536 }
537
538 /* Push all the panes and items of a menu described by the
539    alist-of-alists MENU.
540    This handles old-fashioned calls to x-popup-menu.  */
541
542 static void
543 list_of_panes (menu)
544      Lisp_Object menu;
545 {
546   Lisp_Object tail;
547
548   init_menu_items ();
549
550   for (tail = menu; !NILP (tail); tail = Fcdr (tail))
551     {
552       Lisp_Object elt, pane_name, pane_data;
553       elt = Fcar (tail);
554       pane_name = Fcar (elt);
555       CHECK_STRING (pane_name, 0);
556       push_menu_pane (pane_name, Qnil);
557       pane_data = Fcdr (elt);
558       CHECK_CONS (pane_data, 0);
559       list_of_items (pane_data);
560     }
561
562   finish_menu_items ();
563 }
564
565 /* Push the items in a single pane defined by the alist PANE.  */
566
567 static void
568 list_of_items (pane)
569      Lisp_Object pane;
570 {
571   Lisp_Object tail, item, item1;
572
573   for (tail = pane; !NILP (tail); tail = Fcdr (tail))
574     {
575       item = Fcar (tail);
576       if (STRINGP (item))
577         push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
578       else if (NILP (item))
579         push_left_right_boundary ();
580       else
581         {
582           CHECK_CONS (item, 0);
583           item1 = Fcar (item);
584           CHECK_STRING (item1, 1);
585           push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
586         }
587     }
588 }
589
590 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
591   "Pop up a deck-of-cards menu and return user's selection.\n\
592 POSITION is a position specification.  This is either a mouse button event\n\
593 or a list ((XOFFSET YOFFSET) WINDOW)\n\
594 where XOFFSET and YOFFSET are positions in pixels from the top left\n\
595 corner of WINDOW's frame.  (WINDOW may be a frame object instead of a window.)\n\
596 This controls the position of the center of the first line\n\
597 in the first pane of the menu, not the top left of the menu as a whole.\n\
598 If POSITION is t, it means to use the current mouse position.\n\
599 \n\
600 MENU is a specifier for a menu.  For the simplest case, MENU is a keymap.\n\
601 The menu items come from key bindings that have a menu string as well as\n\
602 a definition; actually, the \"definition\" in such a key binding looks like\n\
603 \(STRING . REAL-DEFINITION).  To give the menu a title, put a string into\n\
604 the keymap as a top-level element.\n\n\
605 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.\n\
606 Otherwise, REAL-DEFINITION should be a valid key binding definition.\n\
607 \n\
608 You can also use a list of keymaps as MENU.\n\
609   Then each keymap makes a separate pane.\n\
610 When MENU is a keymap or a list of keymaps, the return value\n\
611 is a list of events.\n\n\
612 \n\
613 Alternatively, you can specify a menu of multiple panes\n\
614   with a list of the form (TITLE PANE1 PANE2...),\n\
615 where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
616 Each ITEM is normally a cons cell (STRING . VALUE);\n\
617 but a string can appear as an item--that makes a nonselectable line\n\
618 in the menu.\n\
619 With this form of menu, the return value is VALUE from the chosen item.\n\
620 \n\
621 If POSITION is nil, don't display the menu at all, just precalculate the\n\
622 cached information about equivalent key sequences.")
623   (position, menu)
624      Lisp_Object position, menu;
625 {
626   Lisp_Object keymap, tem;
627   int xpos, ypos;
628   Lisp_Object title;
629   char *error_name;
630   Lisp_Object selection;
631   FRAME_PTR f;
632   Lisp_Object x, y, window;
633   int keymaps = 0;
634   int for_click = 0;
635   struct gcpro gcpro1;
636
637 #ifdef HAVE_MENUS
638   if (! NILP (position))
639     {
640       check_mac ();
641
642       /* Decode the first argument: find the window and the coordinates.  */
643       if (EQ (position, Qt)
644           || (CONSP (position) && EQ (XCAR (position), Qmenu_bar)))
645         {
646           /* Use the mouse's current position.  */
647           FRAME_PTR new_f = SELECTED_FRAME ();
648           Lisp_Object bar_window;
649           enum scroll_bar_part part;
650           unsigned long time;
651
652           if (mouse_position_hook)
653             (*mouse_position_hook) (&new_f, 1, &bar_window,
654                                     &part, &x, &y, &time);
655           if (new_f != 0)
656             XSETFRAME (window, new_f);
657           else
658             {
659               window = selected_window;
660               XSETFASTINT (x, 0);
661               XSETFASTINT (y, 0);