Use macro SPECPDL_INDEX.
[bpt/emacs.git] / src / w32menu.c
1 /* Menu support for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1986, 88, 93, 94, 96, 98, 1999 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 #include <config.h>
22 #include <signal.h>
23
24 #include <stdio.h>
25 #include "lisp.h"
26 #include "termhooks.h"
27 #include "keyboard.h"
28 #include "keymap.h"
29 #include "frame.h"
30 #include "window.h"
31 #include "blockinput.h"
32 #include "buffer.h"
33 #include "charset.h"
34 #include "coding.h"
35
36 /* This may include sys/types.h, and that somehow loses
37 if this is not done before the other system files. */
38 #include "w32term.h"
39
40 /* Load sys/types.h if not already loaded.
41 In some systems loading it twice is suicidal. */
42 #ifndef makedev
43 #include <sys/types.h>
44 #endif
45
46 #include "dispextern.h"
47
48 #undef HAVE_MULTILINGUAL_MENU
49 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
50
51 /******************************************************************/
52 /* Definitions copied from lwlib.h */
53
54 typedef void * XtPointer;
55 typedef char Boolean;
56
57 enum button_type
58 {
59 BUTTON_TYPE_NONE,
60 BUTTON_TYPE_TOGGLE,
61 BUTTON_TYPE_RADIO
62 };
63
64 /* This structure is based on the one in ../lwlib/lwlib.h, modified
65 for Windows. */
66 typedef struct _widget_value
67 {
68 /* name of widget */
69 char* name;
70 /* value (meaning depend on widget type) */
71 char* value;
72 /* keyboard equivalent. no implications for XtTranslations */
73 char* key;
74 /* Help string or nil if none.
75 GC finds this string through the frame's menu_bar_vector
76 or through menu_items. */
77 Lisp_Object help;
78 /* true if enabled */
79 Boolean enabled;
80 /* true if selected */
81 Boolean selected;
82 /* The type of a button. */
83 enum button_type button_type;
84 /* true if menu title */
85 Boolean title;
86 #if 0
87 /* true if was edited (maintained by get_value) */
88 Boolean edited;
89 /* true if has changed (maintained by lw library) */
90 change_type change;
91 /* true if this widget itself has changed,
92 but not counting the other widgets found in the `next' field. */
93 change_type this_one_change;
94 #endif
95 /* Contents of the sub-widgets, also selected slot for checkbox */
96 struct _widget_value* contents;
97 /* data passed to callback */
98 XtPointer call_data;
99 /* next one in the list */
100 struct _widget_value* next;
101 #if 0
102 /* slot for the toolkit dependent part. Always initialize to NULL. */
103 void* toolkit_data;
104 /* tell us if we should free the toolkit data slot when freeing the
105 widget_value itself. */
106 Boolean free_toolkit_data;
107
108 /* we resource the widget_value structures; this points to the next
109 one on the free list if this one has been deallocated.
110 */
111 struct _widget_value *free_list;
112 #endif
113 } widget_value;
114
115 /* LocalAlloc/Free is a reasonably good allocator. */
116 #define malloc_widget_value() (void*)LocalAlloc (LMEM_ZEROINIT, sizeof (widget_value))
117 #define free_widget_value(wv) LocalFree (wv)
118
119 /******************************************************************/
120
121 #ifndef TRUE
122 #define TRUE 1
123 #define FALSE 0
124 #endif /* no TRUE */
125
126 static HMENU current_popup_menu;
127
128 FARPROC get_menu_item_info;
129 FARPROC set_menu_item_info;
130
131 Lisp_Object Vmenu_updating_frame;
132
133 Lisp_Object Qdebug_on_next_call;
134
135 extern Lisp_Object Qmenu_bar;
136 extern Lisp_Object Qmouse_click, Qevent_kind;
137
138 extern Lisp_Object QCtoggle, QCradio;
139
140 extern Lisp_Object Voverriding_local_map;
141 extern Lisp_Object Voverriding_local_map_menu_flag;
142
143 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
144
145 extern Lisp_Object Qmenu_bar_update_hook;
146
147 void set_frame_menubar ();
148
149 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
150 Lisp_Object, Lisp_Object, Lisp_Object,
151 Lisp_Object, Lisp_Object));
152 #ifdef HAVE_DIALOGS
153 static Lisp_Object w32_dialog_show ();
154 #endif
155 static Lisp_Object w32_menu_show ();
156
157 static void keymap_panes ();
158 static void single_keymap_panes ();
159 static void single_menu_item ();
160 static void list_of_panes ();
161 static void list_of_items ();
162 void w32_free_menu_strings (HWND);
163 \f
164 /* This holds a Lisp vector that holds the results of decoding
165 the keymaps or alist-of-alists that specify a menu.
166
167 It describes the panes and items within the panes.
168
169 Each pane is described by 3 elements in the vector:
170 t, the pane name, the pane's prefix key.
171 Then follow the pane's items, with 5 elements per item:
172 the item string, the enable flag, the item's value,
173 the definition, and the equivalent keyboard key's description string.
174
175 In some cases, multiple levels of menus may be described.
176 A single vector slot containing nil indicates the start of a submenu.
177 A single vector slot containing lambda indicates the end of a submenu.
178 The submenu follows a menu item which is the way to reach the submenu.
179
180 A single vector slot containing quote indicates that the
181 following items should appear on the right of a dialog box.
182
183 Using a Lisp vector to hold this information while we decode it
184 takes care of protecting all the data from GC. */
185
186 #define MENU_ITEMS_PANE_NAME 1
187 #define MENU_ITEMS_PANE_PREFIX 2
188 #define MENU_ITEMS_PANE_LENGTH 3
189
190 enum menu_item_idx
191 {
192 MENU_ITEMS_ITEM_NAME = 0,
193 MENU_ITEMS_ITEM_ENABLE,
194 MENU_ITEMS_ITEM_VALUE,
195 MENU_ITEMS_ITEM_EQUIV_KEY,
196 MENU_ITEMS_ITEM_DEFINITION,
197 MENU_ITEMS_ITEM_TYPE,
198 MENU_ITEMS_ITEM_SELECTED,
199 MENU_ITEMS_ITEM_HELP,
200 MENU_ITEMS_ITEM_LENGTH
201 };
202
203 static Lisp_Object menu_items;
204
205 /* Number of slots currently allocated in menu_items. */
206 static int menu_items_allocated;
207
208 /* This is the index in menu_items of the first empty slot. */
209 static int menu_items_used;
210
211 /* The number of panes currently recorded in menu_items,
212 excluding those within submenus. */
213 static int menu_items_n_panes;
214
215 /* Current depth within submenus. */
216 static int menu_items_submenu_depth;
217
218 /* Flag which when set indicates a dialog or menu has been posted by
219 Xt on behalf of one of the widget sets. */
220 static int popup_activated_flag;
221
222 static int next_menubar_widget_id;
223
224 /* This is set nonzero after the user activates the menu bar, and set
225 to zero again after the menu bars are redisplayed by prepare_menu_bar.
226 While it is nonzero, all calls to set_frame_menubar go deep.
227
228 I don't understand why this is needed, but it does seem to be
229 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
230
231 int pending_menu_activation;
232 \f
233
234 /* Return the frame whose ->output_data.w32->menubar_widget equals
235 ID, or 0 if none. */
236
237 static struct frame *
238 menubar_id_to_frame (id)
239 HMENU id;
240 {
241 Lisp_Object tail, frame;
242 FRAME_PTR f;
243
244 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
245 {
246 frame = XCAR (tail);
247 if (!GC_FRAMEP (frame))
248 continue;
249 f = XFRAME (frame);
250 if (!FRAME_WINDOW_P (f))
251 continue;
252 if (f->output_data.w32->menubar_widget == id)
253 return f;
254 }
255 return 0;
256 }
257 \f
258 /* Initialize the menu_items structure if we haven't already done so.
259 Also mark it as currently empty. */
260
261 static void
262 init_menu_items ()
263 {
264 if (NILP (menu_items))
265 {
266 menu_items_allocated = 60;
267 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
268 }
269
270 menu_items_used = 0;
271 menu_items_n_panes = 0;
272 menu_items_submenu_depth = 0;
273 }
274
275 /* Call at the end of generating the data in menu_items.
276 This fills in the number of items in the last pane. */
277
278 static void
279 finish_menu_items ()
280 {
281 }
282
283 /* Call when finished using the data for the current menu
284 in menu_items. */
285
286 static void
287 discard_menu_items ()
288 {
289 /* Free the structure if it is especially large.
290 Otherwise, hold on to it, to save time. */
291 if (menu_items_allocated > 200)
292 {
293 menu_items = Qnil;
294 menu_items_allocated = 0;
295 }
296 }
297
298 /* Make the menu_items vector twice as large. */
299
300 static void
301 grow_menu_items ()
302 {
303 Lisp_Object old;
304 int old_size = menu_items_allocated;
305 old = menu_items;
306
307 menu_items_allocated *= 2;
308 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
309 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
310 old_size * sizeof (Lisp_Object));
311 }
312
313 /* Begin a submenu. */
314
315 static void
316 push_submenu_start ()
317 {
318 if (menu_items_used + 1 > menu_items_allocated)
319 grow_menu_items ();
320
321 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
322 menu_items_submenu_depth++;
323 }
324
325 /* End a submenu. */
326
327 static void
328 push_submenu_end ()
329 {
330 if (menu_items_used + 1 > menu_items_allocated)
331 grow_menu_items ();
332
333 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
334 menu_items_submenu_depth--;
335 }
336
337 /* Indicate boundary between left and right. */
338
339 static void
340 push_left_right_boundary ()
341 {
342 if (menu_items_used + 1 > menu_items_allocated)
343 grow_menu_items ();
344
345 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
346 }
347
348 /* Start a new menu pane in menu_items.
349 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
350
351 static void
352 push_menu_pane (name, prefix_vec)
353 Lisp_Object name, prefix_vec;
354 {
355 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
356 grow_menu_items ();
357
358 if (menu_items_submenu_depth == 0)
359 menu_items_n_panes++;
360 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
361 XVECTOR (menu_items)->contents[menu_items_used++] = name;
362 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
363 }
364
365 /* Push one menu item into the current pane. NAME is the string to
366 display. ENABLE if non-nil means this item can be selected. KEY
367 is the key generated by choosing this item, or nil if this item
368 doesn't really have a definition. DEF is the definition of this
369 item. EQUIV is the textual description of the keyboard equivalent
370 for this item (or nil if none). TYPE is the type of this menu
371 item, one of nil, `toggle' or `radio'. */
372
373 static void
374 push_menu_item (name, enable, key, def, equiv, type, selected, help)
375 Lisp_Object name, enable, key, def, equiv, type, selected, help;
376 {
377 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
378 grow_menu_items ();
379
380 XVECTOR (menu_items)->contents[menu_items_used++] = name;
381 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
382 XVECTOR (menu_items)->contents[menu_items_used++] = key;
383 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
384 XVECTOR (menu_items)->contents[menu_items_used++] = def;
385 XVECTOR (menu_items)->contents[menu_items_used++] = type;
386 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
387 XVECTOR (menu_items)->contents[menu_items_used++] = help;
388 }
389 \f
390 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
391 and generate menu panes for them in menu_items.
392 If NOTREAL is nonzero,
393 don't bother really computing whether an item is enabled. */
394
395 static void
396 keymap_panes (keymaps, nmaps, notreal)
397 Lisp_Object *keymaps;
398 int nmaps;
399 int notreal;
400 {
401 int mapno;
402
403 init_menu_items ();
404
405 /* Loop over the given keymaps, making a pane for each map.
406 But don't make a pane that is empty--ignore that map instead.
407 P is the number of panes we have made so far. */
408 for (mapno = 0; mapno < nmaps; mapno++)
409 single_keymap_panes (keymaps[mapno],
410 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
411
412 finish_menu_items ();
413 }
414
415 /* This is a recursive subroutine of keymap_panes.
416 It handles one keymap, KEYMAP.
417 The other arguments are passed along
418 or point to local variables of the previous function.
419 If NOTREAL is nonzero, only check for equivalent key bindings, don't
420 evaluate expressions in menu items and don't make any menu.
421
422 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
423
424 static void
425 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
426 Lisp_Object keymap;
427 Lisp_Object pane_name;
428 Lisp_Object prefix;
429 int notreal;
430 int maxdepth;
431 {
432 Lisp_Object pending_maps = Qnil;
433 Lisp_Object tail, item;
434 struct gcpro gcpro1, gcpro2;
435
436 if (maxdepth <= 0)
437 return;
438
439 push_menu_pane (pane_name, prefix);
440
441 for (tail = keymap; CONSP (tail); tail = XCDR (tail))
442 {
443 GCPRO2 (keymap, pending_maps);
444 /* Look at each key binding, and if it is a menu item add it
445 to this menu. */
446 item = XCAR (tail);
447 if (CONSP (item))
448 single_menu_item (XCAR (item), XCDR (item),
449 &pending_maps, notreal, maxdepth);
450 else if (VECTORP (item))
451 {
452 /* Loop over the char values represented in the vector. */
453 int len = XVECTOR (item)->size;
454 int c;
455 for (c = 0; c < len; c++)
456 {
457 Lisp_Object character;
458 XSETFASTINT (character, c);
459 single_menu_item (character, XVECTOR (item)->contents[c],
460 &pending_maps, notreal, maxdepth);
461 }
462 }
463 UNGCPRO;
464 }
465
466 /* Process now any submenus which want to be panes at this level. */
467 while (!NILP (pending_maps))
468 {
469 Lisp_Object elt, eltcdr, string;
470 elt = Fcar (pending_maps);
471 eltcdr = XCDR (elt);
472 string = XCAR (eltcdr);
473 /* We no longer discard the @ from the beginning of the string here.
474 Instead, we do this in w32_menu_show. */
475 single_keymap_panes (Fcar (elt), string,
476 XCDR (eltcdr), notreal, maxdepth - 1);
477 pending_maps = Fcdr (pending_maps);
478 }
479 }
480 \f
481 /* This is a subroutine of single_keymap_panes that handles one
482 keymap entry.
483 KEY is a key in a keymap and ITEM is its binding.
484 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
485 separate panes.
486 If NOTREAL is nonzero, only check for equivalent key bindings, don't
487 evaluate expressions in menu items and don't make any menu.
488 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
489
490 static void
491 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
492 Lisp_Object key, item;
493 Lisp_Object *pending_maps_ptr;
494 int maxdepth, notreal;
495 {
496 Lisp_Object map, item_string, enabled;
497 struct gcpro gcpro1, gcpro2;
498 int res;
499
500 /* Parse the menu item and leave the result in item_properties. */
501 GCPRO2 (key, item);
502 res = parse_menu_item (item, notreal, 0);
503 UNGCPRO;
504 if (!res)
505 return; /* Not a menu item. */
506
507 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
508
509 if (notreal)
510 {
511 /* We don't want to make a menu, just traverse the keymaps to
512 precompute equivalent key bindings. */
513 if (!NILP (map))
514 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
515 return;
516 }
517
518 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
519 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
520
521 if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
522 {
523 if (!NILP (enabled))
524 /* An enabled separate pane. Remember this to handle it later. */
525 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
526 *pending_maps_ptr);
527 return;
528 }
529
530 push_menu_item (item_string, enabled, key,
531 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
532 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
533 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
534 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
535 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
536
537 /* Display a submenu using the toolkit. */
538 if (! (NILP (map) || NILP (enabled)))
539 {
540 push_submenu_start ();
541 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
542 push_submenu_end ();
543 }
544 }
545 \f
546 /* Push all the panes and items of a menu described by the
547 alist-of-alists MENU.
548 This handles old-fashioned calls to x-popup-menu. */
549
550 static void
551 list_of_panes (menu)
552 Lisp_Object menu;
553 {
554 Lisp_Object tail;
555
556 init_menu_items ();
557
558 for (tail = menu; !NILP (tail); tail = Fcdr (tail))
559 {
560 Lisp_Object elt, pane_name, pane_data;
561 elt = Fcar (tail);
562 pane_name = Fcar (elt);
563 CHECK_STRING (pane_name);
564 push_menu_pane (pane_name, Qnil);
565 pane_data = Fcdr (elt);
566 CHECK_CONS (pane_data);
567 list_of_items (pane_data);
568 }
569
570 finish_menu_items ();
571 }
572
573 /* Push the items in a single pane defined by the alist PANE. */
574
575 static void
576 list_of_items (pane)
577 Lisp_Object pane;
578 {
579 Lisp_Object tail, item, item1;
580
581 for (tail = pane; !NILP (tail); tail = Fcdr (tail))
582 {
583 item = Fcar (tail);
584 if (STRINGP (item))
585 push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
586 else if (NILP (item))
587 push_left_right_boundary ();
588 else
589 {
590 CHECK_CONS (item);
591 item1 = Fcar (item);
592 CHECK_STRING (item1);
593 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
594 }
595 }
596 }
597 \f
598 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
599 doc: /* Pop up a deck-of-cards menu and return user's selection.
600 POSITION is a position specification. This is either a mouse button
601 event or a list ((XOFFSET YOFFSET) WINDOW) where XOFFSET and YOFFSET
602 are positions in pixels from the top left corner of WINDOW's frame
603 \(WINDOW may be a frame object instead of a window). This controls the
604 position of the center of the first line in the first pane of the
605 menu, not the top left of the menu as a whole. If POSITION is t, it
606 means to use the current mouse position.
607
608 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
609 The menu items come from key bindings that have a menu string as well as
610 a definition; actually, the \"definition\" in such a key binding looks like
611 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
612 the keymap as a top-level element.
613
614 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
615 Otherwise, REAL-DEFINITION should be a valid key binding definition.
616
617 You can also use a list of keymaps as MENU. Then each keymap makes a
618 separate pane. When MENU is a keymap or a list of keymaps, the return
619 value is a list of events.
620
621 Alternatively, you can specify a menu of multiple panes with a list of
622 the form (TITLE PANE1 PANE2...), where each pane is a list of
623 form (TITLE ITEM1 ITEM2...).
624 Each ITEM is normally a cons cell (STRING . VALUE); but a string can
625 appear as an item--that makes a nonselectable line in the menu.
626 With this form of menu, the return value is VALUE from the chosen item.
627
628 If POSITION is nil, don't display the menu at all, just precalculate the
629 cached information about equivalent key sequences. */)
630 (position, menu)
631 Lisp_Object position, menu;
632 {
633 Lisp_Object keymap, tem;
634 int xpos = 0, ypos = 0;
635 Lisp_Object title;
636 char *error_name;
637 Lisp_Object selection;
638 FRAME_PTR f = NULL;
639 Lisp_Object x, y, window;
640 int keymaps = 0;
641 int for_click = 0;
642 struct gcpro gcpro1;
643
644 #ifdef HAVE_MENUS
645 if (! NILP (position))
646 {
647 check_w32 ();
648
649 /* Decode the first argument: find the window and the coordinates. */
650 if (EQ (position, Qt)
651 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
652 || EQ (XCAR (position), Qtool_bar))))
653 {
654 /* Use the mouse's current position. */
655 FRAME_PTR new_f = SELECTED_FRAME ();
656 Lisp_Object bar_window;
657 enum scroll_bar_part part;
658 unsigned long time;
659
660 if (mouse_position_hook)
661 (*mouse_position_hook) (&new_f, 1, &bar_window,
662 &part, &x, &y, &time);
663 if (new_f != 0)
664 XSETFRAME (window, new_f);
665 else
666 {
667 window = selected_window;
668 XSETFASTINT (x, 0);
669 XSETFASTINT (y, 0);
670 }
671 }
672 else
673 {
674 tem = Fcar (position);
675 if (CONSP (tem))
676 {
677 window = Fcar (Fcdr (position));
678 x = Fcar (tem);
679 y = Fcar (Fcdr (tem));
680 }
681 else
682 {
683 for_click = 1;
684 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
685 window = Fcar (tem); /* POSN_WINDOW (tem) */
686 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
687 x = Fcar (tem);
688 y = Fcdr (tem);
689 }
690 }
691
692 CHECK_NUMBER (x);
693 CHECK_NUMBER (y);
694
695 /* Decode where to put the menu. */
696
697 if (FRAMEP (window))
698 {
699 f = XFRAME (window);
700 xpos = 0;
701 ypos = 0;
702 }
703 else if (WINDOWP (window))
704 {
705 CHECK_LIVE_WINDOW (window);
706 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
707
708 xpos = (FONT_WIDTH (FRAME_FONT (f))
709 * XFASTINT (XWINDOW (window)->left));
710 ypos = (FRAME_LINE_HEIGHT (f)
711 * XFASTINT (XWINDOW (window)->top));
712 }
713 else
714 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
715 but I don't want to make one now. */
716 CHECK_WINDOW (window);
717
718 xpos += XINT (x);
719 ypos += XINT (y);
720
721 XSETFRAME (Vmenu_updating_frame, f);
722 }
723 Vmenu_updating_frame = Qnil;
724 #endif /* HAVE_MENUS */
725
726 title = Qnil;
727 GCPRO1 (title);
728
729 /* Decode the menu items from what was specified. */
730
731 keymap = get_keymap (menu, 0, 0);
732 if (CONSP (keymap))
733 {
734 /* We were given a keymap. Extract menu info from the keymap. */
735 Lisp_Object prompt;
736
737 /* Extract the detailed info to make one pane. */
738 keymap_panes (&menu, 1, NILP (position));
739
740 /* Search for a string appearing directly as an element of the keymap.
741 That string is the title of the menu. */
742 prompt = Fkeymap_prompt (keymap);
743 if (NILP (title) && !NILP (prompt))
744 title = prompt;
745
746 /* Make that be the pane title of the first pane. */
747 if (!NILP (prompt) && menu_items_n_panes >= 0)
748 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
749
750 keymaps = 1;
751 }
752 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
753 {
754 /* We were given a list of keymaps. */
755 int nmaps = XFASTINT (Flength (menu));
756 Lisp_Object *maps
757 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
758 int i;
759
760 title = Qnil;
761
762 /* The first keymap that has a prompt string
763 supplies the menu title. */
764 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
765 {
766 Lisp_Object prompt;
767
768 maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
769
770 prompt = Fkeymap_prompt (keymap);
771 if (NILP (title) && !NILP (prompt))
772 title = prompt;
773 }
774
775 /* Extract the detailed info to make one pane. */
776 keymap_panes (maps, nmaps, NILP (position));
777
778 /* Make the title be the pane title of the first pane. */
779 if (!NILP (title) && menu_items_n_panes >= 0)
780 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
781
782 keymaps = 1;
783 }
784 else
785 {
786 /* We were given an old-fashioned menu. */
787 title = Fcar (menu);
788 CHECK_STRING (title);
789
790 list_of_panes (Fcdr (menu));
791
792 keymaps = 0;
793 }
794
795 if (NILP (position))
796 {
797 discard_menu_items ();
798 UNGCPRO;
799 return Qnil;
800 }
801
802 #ifdef HAVE_MENUS
803 /* Display them in a menu. */
804 BLOCK_INPUT;
805
806 selection = w32_menu_show (f, xpos, ypos, for_click,
807 keymaps, title, &error_name);
808 UNBLOCK_INPUT;
809
810 discard_menu_items ();
811
812 UNGCPRO;
813 #endif /* HAVE_MENUS */
814
815 if (error_name) error (error_name);
816 return selection;
817 }
818
819 #ifdef HAVE_MENUS
820
821 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
822 doc: /* Pop up a dialog box and return user's selection.
823 POSITION specifies which frame to use.
824 This is normally a mouse button event or a window or frame.
825 If POSITION is t, it means to use the frame the mouse is on.
826 The dialog box appears in the middle of the specified frame.
827
828 CONTENTS specifies the alternatives to display in the dialog box.
829 It is a list of the form (TITLE ITEM1 ITEM2...).
830 Each ITEM is a cons cell (STRING . VALUE).
831 The return value is VALUE from the chosen item.
832
833 An ITEM may also be just a string--that makes a nonselectable item.
834 An ITEM may also be nil--that means to put all preceding items
835 on the left of the dialog box and all following items on the right.
836 \(By default, approximately half appear on each side.) */)
837 (position, contents)
838 Lisp_Object position, contents;
839 {
840 FRAME_PTR f = NULL;
841 Lisp_Object window;
842
843 check_w32 ();
844
845 /* Decode the first argument: find the window or frame to use. */
846 if (EQ (position, Qt)
847 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
848 || EQ (XCAR (position), Qtool_bar))))
849 {
850 #if 0 /* Using the frame the mouse is on may not be right. */
851 /* Use the mouse's current position. */
852 FRAME_PTR new_f = SELECTED_FRAME ();
853 Lisp_Object bar_window;
854 enum scroll_bar_part part;
855 unsigned long time;
856 Lisp_Object x, y;
857
858 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
859
860 if (new_f != 0)
861 XSETFRAME (window, new_f);
862 else
863 window = selected_window;
864 #endif
865 window = selected_window;
866 }
867 else if (CONSP (position))
868 {
869 Lisp_Object tem;
870 tem = Fcar (position);
871 if (CONSP (tem))
872 window = Fcar (Fcdr (position));
873 else
874 {
875 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
876 window = Fcar (tem); /* POSN_WINDOW (tem) */
877 }
878 }
879 else if (WINDOWP (position) || FRAMEP (position))
880 window = position;
881 else
882 window = Qnil;
883
884 /* Decode where to put the menu. */
885
886 if (FRAMEP (window))
887 f = XFRAME (window);
888 else if (WINDOWP (window))
889 {
890 CHECK_LIVE_WINDOW (window);
891 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
892 }
893 else
894 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
895 but I don't want to make one now. */
896 CHECK_WINDOW (window);
897
898 #ifndef HAVE_DIALOGS
899 /* Display a menu with these alternatives
900 in the middle of frame F. */
901 {
902 Lisp_Object x, y, frame, newpos;
903 XSETFRAME (frame, f);
904 XSETINT (x, x_pixel_width (f) / 2);
905 XSETINT (y, x_pixel_height (f) / 2);
906 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
907
908 return Fx_popup_menu (newpos,
909 Fcons (Fcar (contents), Fcons (contents, Qnil)));
910 }
911 #else /* HAVE_DIALOGS */
912 {
913 Lisp_Object title;
914 char *error_name;
915 Lisp_Object selection;
916
917 /* Decode the dialog items from what was specified. */
918 title = Fcar (contents);
919 CHECK_STRING (title);
920
921 list_of_panes (Fcons (contents, Qnil));
922
923 /* Display them in a dialog box. */
924 BLOCK_INPUT;
925 selection = w32_dialog_show (f, 0, title, &error_name);
926 UNBLOCK_INPUT;
927
928 discard_menu_items ();
929
930 if (error_name) error (error_name);
931 return selection;
932 }
933 #endif /* HAVE_DIALOGS */
934 }
935
936 /* Activate the menu bar of frame F.
937 This is called from keyboard.c when it gets the
938 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
939
940 To activate the menu bar, we signal to the input thread that it can
941 return from the WM_INITMENU message, allowing the normal Windows
942 processing of the menus.
943
944 But first we recompute the menu bar contents (the whole tree).
945
946 This way we can safely execute Lisp code. */
947
948 void
949 x_activate_menubar (f)
950 FRAME_PTR f;
951 {
952 set_frame_menubar (f, 0, 1);
953
954 /* Lock out further menubar changes while active. */
955 f->output_data.w32->menubar_active = 1;
956
957 /* Signal input thread to return from WM_INITMENU. */
958 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
959 }
960
961 /* This callback is called from the menu bar pulldown menu
962 when the user makes a selection.
963 Figure out what the user chose
964 and put the appropriate events into the keyboard buffer. */
965
966 void
967 menubar_selection_callback (FRAME_PTR f, void * client_data)
968 {
969 Lisp_Object prefix, entry;
970 Lisp_Object vector;
971 Lisp_Object *subprefix_stack;
972 int submenu_depth = 0;
973 int i;
974
975 if (!f)
976 return;
977 entry = Qnil;
978 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
979 vector = f->menu_bar_vector;
980 prefix = Qnil;
981 i = 0;
982 while (i < f->menu_bar_items_used)
983 {
984 if (EQ (XVECTOR (vector)->contents[i], Qnil))
985 {
986 subprefix_stack[submenu_depth++] = prefix;
987 prefix = entry;
988 i++;
989 }
990 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
991 {
992 prefix = subprefix_stack[--submenu_depth];
993 i++;
994 }
995 else if (EQ (XVECTOR (vector)->contents[i], Qt))
996 {
997 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
998 i += MENU_ITEMS_PANE_LENGTH;
999 }
1000 else
1001 {
1002 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1003 /* The EMACS_INT cast avoids a warning. There's no problem
1004 as long as pointers have enough bits to hold small integers. */
1005 if ((int) (EMACS_INT) client_data == i)
1006 {
1007 int j;
1008 struct input_event buf;
1009 Lisp_Object frame;
1010
1011 XSETFRAME (frame, f);
1012 buf.kind = MENU_BAR_EVENT;
1013 buf.frame_or_window = frame;
1014 buf.arg = frame;
1015 kbd_buffer_store_event (&buf);
1016
1017 for (j = 0; j < submenu_depth; j++)
1018 if (!NILP (subprefix_stack[j]))
1019 {
1020 buf.kind = MENU_BAR_EVENT;
1021 buf.frame_or_window = frame;
1022 buf.arg = subprefix_stack[j];
1023 kbd_buffer_store_event (&buf);
1024 }
1025
1026 if (!NILP (prefix))
1027 {
1028 buf.kind = MENU_BAR_EVENT;
1029 buf.frame_or_window = frame;
1030 buf.arg = prefix;
1031 kbd_buffer_store_event (&buf);
1032 }
1033
1034 buf.kind = MENU_BAR_EVENT;
1035 buf.frame_or_window = frame;
1036 buf.arg = entry;
1037 kbd_buffer_store_event (&buf);
1038
1039 /* Free memory used by owner-drawn and help-echo strings. */
1040 w32_free_menu_strings (FRAME_W32_WINDOW (f));
1041 f->output_data.w32->menu_command_in_progress = 0;
1042 f->output_data.w32->menubar_active = 0;
1043 return;
1044 }
1045 i += MENU_ITEMS_ITEM_LENGTH;
1046 }
1047 }
1048 /* Free memory used by owner-drawn and help-echo strings. */
1049 w32_free_menu_strings (FRAME_W32_WINDOW (f));
1050 f->output_data.w32->menu_command_in_progress = 0;
1051 f->output_data.w32->menubar_active = 0;
1052 }
1053
1054 /* Allocate a widget_value, blocking input. */
1055
1056 widget_value *
1057 xmalloc_widget_value ()
1058 {
1059 widget_value *value;
1060
1061 BLOCK_INPUT;
1062 value = malloc_widget_value ();
1063 UNBLOCK_INPUT;
1064
1065 return value;
1066 }
1067
1068 /* This recursively calls free_widget_value on the tree of widgets.
1069 It must free all data that was malloc'ed for these widget_values.
1070 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1071 must be left alone. */
1072
1073 void
1074 free_menubar_widget_value_tree (wv)
1075 widget_value *wv;
1076 {
1077 if (! wv) return;
1078
1079 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1080
1081 if (wv->contents && (wv->contents != (widget_value*)1))
1082 {
1083 free_menubar_widget_value_tree (wv->contents);
1084 wv->contents = (widget_value *) 0xDEADBEEF;
1085 }
1086 if (wv->next)
1087 {
1088 free_menubar_widget_value_tree (wv->next);
1089 wv->next = (widget_value *) 0xDEADBEEF;
1090 }
1091 BLOCK_INPUT;
1092 free_widget_value (wv);
1093 UNBLOCK_INPUT;
1094 }
1095 \f
1096 /* Return a tree of widget_value structures for a menu bar item
1097 whose event type is ITEM_KEY (with string ITEM_NAME)
1098 and whose contents come from the list of keymaps MAPS. */
1099
1100 static widget_value *
1101 single_submenu (item_key, item_name, maps)
1102 Lisp_Object item_key, item_name, maps;
1103 {
1104 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1105 int i;
1106 int submenu_depth = 0;
1107 Lisp_Object length;
1108 int len;
1109 Lisp_Object *mapvec;
1110 widget_value **submenu_stack;
1111 int previous_items = menu_items_used;
1112 int top_level_items = 0;
1113
1114 length = Flength (maps);
1115 len = XINT (length);
1116
1117 /* Convert the list MAPS into a vector MAPVEC. */
1118 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1119 for (i = 0; i < len; i++)
1120 {
1121 mapvec[i] = Fcar (maps);
1122 maps = Fcdr (maps);
1123 }
1124
1125 menu_items_n_panes = 0;
1126
1127 /* Loop over the given keymaps, making a pane for each map.
1128 But don't make a pane that is empty--ignore that map instead. */
1129 for (i = 0; i < len; i++)
1130 {
1131 if (SYMBOLP (mapvec[i])
1132 || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
1133 {
1134 /* Here we have a command at top level in the menu bar
1135 as opposed to a submenu. */
1136 top_level_items = 1;
1137 push_menu_pane (Qnil, Qnil);
1138 push_menu_item (item_name, Qt, item_key, mapvec[i],
1139 Qnil, Qnil, Qnil, Qnil);
1140 }
1141 else
1142 single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
1143 }
1144
1145 /* Create a tree of widget_value objects
1146 representing the panes and their items. */
1147
1148 submenu_stack
1149 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1150 wv = xmalloc_widget_value ();
1151 wv->name = "menu";
1152 wv->value = 0;
1153 wv->enabled = 1;
1154 wv->button_type = BUTTON_TYPE_NONE;
1155 wv->help = Qnil;
1156 first_wv = wv;
1157 save_wv = 0;
1158 prev_wv = 0;
1159
1160 /* Loop over all panes and items made during this call
1161 and construct a tree of widget_value objects.
1162 Ignore the panes and items made by previous calls to
1163 single_submenu, even though those are also in menu_items. */
1164 i = previous_items;
1165 while (i < menu_items_used)
1166 {
1167 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1168 {
1169 submenu_stack[submenu_depth++] = save_wv;
1170 save_wv = prev_wv;
1171 prev_wv = 0;
1172 i++;
1173 }
1174 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1175 {
1176 prev_wv = save_wv;
1177 save_wv = submenu_stack[--submenu_depth];
1178 i++;
1179 }
1180 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1181 && submenu_depth != 0)
1182 i += MENU_ITEMS_PANE_LENGTH;
1183 /* Ignore a nil in the item list.
1184 It's meaningful only for dialog boxes. */
1185 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1186 i += 1;
1187 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1188 {
1189 /* Create a new pane. */
1190 Lisp_Object pane_name, prefix;
1191 char *pane_string;
1192
1193 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1194 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1195
1196 #ifndef HAVE_MULTILINGUAL_MENU
1197 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1198 {
1199 pane_name = ENCODE_SYSTEM (pane_name);
1200 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1201 }
1202 #endif
1203 pane_string = (NILP (pane_name)
1204 ? "" : (char *) XSTRING (pane_name)->data);
1205 /* If there is just one top-level pane, put all its items directly
1206 under the top-level menu. */
1207 if (menu_items_n_panes == 1)
1208 pane_string = "";
1209
1210 /* If the pane has a meaningful name,
1211 make the pane a top-level menu item
1212 with its items as a submenu beneath it. */
1213 if (strcmp (pane_string, ""))
1214 {
1215 wv = xmalloc_widget_value ();
1216 if (save_wv)
1217 save_wv->next = wv;
1218 else
1219 first_wv->contents = wv;
1220 wv->name = pane_string;
1221 /* Ignore the @ that means "separate pane".
1222 This is a kludge, but this isn't worth more time. */
1223 if (!NILP (prefix) && wv->name[0] == '@')
1224 wv->name++;
1225 wv->value = 0;
1226 wv->enabled = 1;
1227 wv->button_type = BUTTON_TYPE_NONE;
1228 wv->help = Qnil;
1229 }
1230 save_wv = wv;
1231 prev_wv = 0;
1232 i += MENU_ITEMS_PANE_LENGTH;
1233 }
1234 else
1235 {
1236 /* Create a new item within current pane. */
1237 Lisp_Object item_name, enable, descrip, def, type, selected;
1238 Lisp_Object help;
1239
1240 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1241 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1242 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1243 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1244 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1245 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1246 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1247
1248 #ifndef HAVE_MULTILINGUAL_MENU
1249 if (STRING_MULTIBYTE (item_name))
1250 {
1251 item_name = ENCODE_SYSTEM (item_name);
1252 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1253 }
1254
1255 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1256 {
1257 descrip = ENCODE_SYSTEM (descrip);
1258 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1259 }
1260 #endif /* not HAVE_MULTILINGUAL_MENU */
1261
1262 wv = xmalloc_widget_value ();
1263 if (prev_wv)
1264 prev_wv->next = wv;
1265 else
1266 save_wv->contents = wv;
1267
1268 wv->name = (char *) XSTRING (item_name)->data;
1269 if (!NILP (descrip))
1270 wv->key = (char *) XSTRING (descrip)->data;
1271 wv->value = 0;
1272 /* The EMACS_INT cast avoids a warning. There's no problem
1273 as long as pointers have enough bits to hold small integers. */
1274 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1275 wv->enabled = !NILP (enable);
1276
1277 if (NILP (type))
1278 wv->button_type = BUTTON_TYPE_NONE;
1279 else if (EQ (type, QCradio))
1280 wv->button_type = BUTTON_TYPE_RADIO;
1281 else if (EQ (type, QCtoggle))
1282 wv->button_type = BUTTON_TYPE_TOGGLE;
1283 else
1284 abort ();
1285
1286 wv->selected = !NILP (selected);
1287 if (!STRINGP (help))
1288 help = Qnil;
1289
1290 wv->help = help;
1291
1292 prev_wv = wv;
1293
1294 i += MENU_ITEMS_ITEM_LENGTH;
1295 }
1296 }
1297
1298 /* If we have just one "menu item"
1299 that was originally a button, return it by itself. */
1300 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
1301 {
1302 wv = first_wv->contents;
1303 free_widget_value (first_wv);
1304 return wv;
1305 }
1306
1307 return first_wv;
1308 }
1309 \f
1310 /* Set the contents of the menubar widgets of frame F.
1311 The argument FIRST_TIME is currently ignored;
1312 it is set the first time this is called, from initialize_frame_menubar. */
1313
1314 void
1315 set_frame_menubar (f, first_time, deep_p)
1316 FRAME_PTR f;
1317 int first_time;
1318 int deep_p;
1319 {
1320 HMENU menubar_widget = f->output_data.w32->menubar_widget;
1321 Lisp_Object items;
1322 widget_value *wv, *first_wv, *prev_wv = 0;
1323 int i;
1324
1325 /* We must not change the menubar when actually in use. */
1326 if (f->output_data.w32->menubar_active)
1327 return;
1328
1329 XSETFRAME (Vmenu_updating_frame, f);
1330
1331 if (! menubar_widget)
1332 deep_p = 1;
1333 else if (pending_menu_activation && !deep_p)
1334 deep_p = 1;
1335
1336 wv = xmalloc_widget_value ();
1337 wv->name = "menubar";
1338 wv->value = 0;
1339 wv->enabled = 1;
1340 wv->button_type = BUTTON_TYPE_NONE;
1341 wv->help = Qnil;
1342 first_wv = wv;
1343
1344 if (deep_p)
1345 {
1346 /* Make a widget-value tree representing the entire menu trees. */
1347
1348 struct buffer *prev = current_buffer;
1349 Lisp_Object buffer;
1350 int specpdl_count = SPECPDL_INDEX ();
1351 int previous_menu_items_used = f->menu_bar_items_used;
1352 Lisp_Object *previous_items
1353 = (Lisp_Object *) alloca (previous_menu_items_used
1354 * sizeof (Lisp_Object));
1355
1356 /* If we are making a new widget, its contents are empty,
1357 do always reinitialize them. */
1358 if (! menubar_widget)
1359 previous_menu_items_used = 0;
1360
1361 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1362 specbind (Qinhibit_quit, Qt);
1363 /* Don't let the debugger step into this code
1364 because it is not reentrant. */
1365 specbind (Qdebug_on_next_call, Qnil);
1366
1367 record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
1368 if (NILP (Voverriding_local_map_menu_flag))
1369 {
1370 specbind (Qoverriding_terminal_local_map, Qnil);
1371 specbind (Qoverriding_local_map, Qnil);
1372 }
1373
1374 set_buffer_internal_1 (XBUFFER (buffer));
1375
1376 /* Run the Lucid hook. */
1377 safe_run_hooks (Qactivate_menubar_hook);
1378 /* If it has changed current-menubar from previous value,
1379 really recompute the menubar from the value. */
1380 if (! NILP (Vlucid_menu_bar_dirty_flag))
1381 call0 (Qrecompute_lucid_menubar);
1382 safe_run_hooks (Qmenu_bar_update_hook);
1383 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1384
1385 items = FRAME_MENU_BAR_ITEMS (f);
1386
1387 inhibit_garbage_collection ();
1388
1389 /* Save the frame's previous menu bar contents data. */
1390 if (previous_menu_items_used)
1391 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1392 previous_menu_items_used * sizeof (Lisp_Object));
1393
1394 /* Fill in the current menu bar contents. */
1395 menu_items = f->menu_bar_vector;
1396 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1397 init_menu_items ();
1398 for (i = 0; i < XVECTOR (items)->size; i += 4)
1399 {
1400 Lisp_Object key, string, maps;
1401
1402 key = XVECTOR (items)->contents[i];
1403 string = XVECTOR (items)->contents[i + 1];
1404 maps = XVECTOR (items)->contents[i + 2];
1405 if (NILP (string))
1406 break;
1407
1408 wv = single_submenu (key, string, maps);
1409 if (prev_wv)
1410 prev_wv->next = wv;
1411 else
1412 first_wv->contents = wv;
1413 /* Don't set wv->name here; GC during the loop might relocate it. */
1414 wv->enabled = 1;
1415 wv->button_type = BUTTON_TYPE_NONE;
1416 prev_wv = wv;
1417 }
1418
1419 finish_menu_items ();
1420
1421 set_buffer_internal_1 (prev);
1422 unbind_to (specpdl_count, Qnil);
1423
1424 /* If there has been no change in the Lisp-level contents
1425 of the menu bar, skip redisplaying it. Just exit. */
1426
1427 for (i = 0; i < previous_menu_items_used; i++)
1428 if (menu_items_used == i
1429 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1430 break;
1431 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1432 {
1433 free_menubar_widget_value_tree (first_wv);
1434 menu_items = Qnil;
1435
1436 return;
1437 }
1438
1439 /* Now GC cannot happen during the lifetime of the widget_value,
1440 so it's safe to store data from a Lisp_String, as long as
1441 local copies are made when the actual menu is created.
1442 Windows takes care of this for normal string items, but
1443 not for owner-drawn items or additional item-info. */
1444 wv = first_wv->contents;
1445 for (i = 0; i < XVECTOR (items)->size; i += 4)
1446 {
1447 Lisp_Object string;
1448 string = XVECTOR (items)->contents[i + 1];
1449 if (NILP (string))
1450 break;
1451 wv->name = (char *) XSTRING (string)->data;
1452 wv = wv->next;
1453 }
1454
1455 f->menu_bar_vector = menu_items;
1456 f->menu_bar_items_used = menu_items_used;
1457 menu_items = Qnil;
1458 }
1459 else
1460 {
1461 /* Make a widget-value tree containing
1462 just the top level menu bar strings. */
1463
1464 items = FRAME_MENU_BAR_ITEMS (f);
1465 for (i = 0; i < XVECTOR (items)->size; i += 4)
1466 {
1467 Lisp_Object string;
1468
1469 string = XVECTOR (items)->contents[i + 1];
1470 if (NILP (string))
1471 break;
1472
1473 wv = xmalloc_widget_value ();
1474 wv->name = (char *) XSTRING (string)->data;
1475 wv->value = 0;
1476 wv->enabled = 1;
1477 wv->button_type = BUTTON_TYPE_NONE;
1478 wv->help = Qnil;
1479 /* This prevents lwlib from assuming this
1480 menu item is really supposed to be empty. */
1481 /* The EMACS_INT cast avoids a warning.
1482 This value just has to be different from small integers. */
1483 wv->call_data = (void *) (EMACS_INT) (-1);
1484
1485 if (prev_wv)
1486 prev_wv->next = wv;
1487 else
1488 first_wv->contents = wv;
1489 prev_wv = wv;
1490 }
1491
1492 /* Forget what we thought we knew about what is in the
1493 detailed contents of the menu bar menus.
1494 Changing the top level always destroys the contents. */
1495 f->menu_bar_items_used = 0;
1496 }
1497
1498 /* Create or update the menu bar widget. */
1499
1500 BLOCK_INPUT;
1501
1502 if (menubar_widget)
1503 {
1504 /* Empty current menubar, rather than creating a fresh one. */
1505 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
1506 ;
1507 }
1508 else
1509 {
1510 menubar_widget = CreateMenu ();
1511 }
1512 fill_in_menu (menubar_widget, first_wv->contents);
1513
1514 free_menubar_widget_value_tree (first_wv);
1515
1516 {
1517 HMENU old_widget = f->output_data.w32->menubar_widget;
1518
1519 f->output_data.w32->menubar_widget = menubar_widget;
1520 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
1521 /* Causes flicker when menu bar is updated
1522 DrawMenuBar (FRAME_W32_WINDOW (f)); */
1523
1524 /* Force the window size to be recomputed so that the frame's text
1525 area remains the same, if menubar has just been created. */
1526 if (old_widget == NULL)
1527 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
1528 }
1529
1530 UNBLOCK_INPUT;
1531 }
1532
1533 /* Called from Fx_create_frame to create the initial menubar of a frame
1534 before it is mapped, so that the window is mapped with the menubar already
1535 there instead of us tacking it on later and thrashing the window after it
1536 is visible. */
1537
1538 void
1539 initialize_frame_menubar (f)
1540 FRAME_PTR f;
1541 {
1542 /* This function is called before the first chance to redisplay
1543 the frame. It has to be, so the frame will have the right size. */
1544 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1545 set_frame_menubar (f, 1, 1);
1546 }
1547
1548 /* Get rid of the menu bar of frame F, and free its storage.
1549 This is used when deleting a frame, and when turning off the menu bar. */
1550
1551 void
1552 free_frame_menubar (f)
1553 FRAME_PTR f;
1554 {
1555 BLOCK_INPUT;
1556
1557 {
1558 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
1559 SetMenu (FRAME_W32_WINDOW (f), NULL);
1560 f->output_data.w32->menubar_widget = NULL;
1561 DestroyMenu (old);
1562 }
1563
1564 UNBLOCK_INPUT;
1565 }
1566
1567 \f
1568 /* w32_menu_show actually displays a menu using the panes and items in
1569 menu_items and returns the value selected from it; we assume input
1570 is blocked by the caller. */
1571
1572 /* F is the frame the menu is for.
1573 X and Y are the frame-relative specified position,
1574 relative to the inside upper left corner of the frame F.
1575 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1576 KEYMAPS is 1 if this menu was specified with keymaps;
1577 in that case, we return a list containing the chosen item's value
1578 and perhaps also the pane's prefix.
1579 TITLE is the specified menu title.
1580 ERROR is a place to store an error message string in case of failure.
1581 (We return nil on failure, but the value doesn't actually matter.) */
1582
1583 static Lisp_Object
1584 w32_menu_show (f, x, y, for_click, keymaps, title, error)
1585 FRAME_PTR f;
1586 int x;
1587 int y;
1588 int for_click;
1589 int keymaps;
1590 Lisp_Object title;
1591 char **error;
1592 {
1593 int i;
1594 int menu_item_selection;
1595 HMENU menu;
1596 POINT pos;
1597 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1598 widget_value **submenu_stack
1599 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1600 Lisp_Object *subprefix_stack
1601 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1602 int submenu_depth = 0;
1603 int first_pane;
1604
1605 *error = NULL;
1606
1607 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1608 {
1609 *error = "Empty menu";
1610 return Qnil;
1611 }
1612
1613 /* Create a tree of widget_value objects
1614 representing the panes and their items. */
1615 wv = xmalloc_widget_value ();
1616 wv->name = "menu";
1617 wv->value = 0;
1618 wv->enabled = 1;
1619 wv->button_type = BUTTON_TYPE_NONE;
1620 wv->help = Qnil;
1621 first_wv = wv;
1622 first_pane = 1;
1623
1624 /* Loop over all panes and items, filling in the tree. */
1625 i = 0;
1626 while (i < menu_items_used)
1627 {
1628 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1629 {
1630 submenu_stack[submenu_depth++] = save_wv;
1631 save_wv = prev_wv;
1632 prev_wv = 0;
1633 first_pane = 1;
1634 i++;
1635 }
1636 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1637 {
1638 prev_wv = save_wv;
1639 save_wv = submenu_stack[--submenu_depth];
1640 first_pane = 0;
1641 i++;
1642 }
1643 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1644 && submenu_depth != 0)
1645 i += MENU_ITEMS_PANE_LENGTH;
1646 /* Ignore a nil in the item list.
1647 It's meaningful only for dialog boxes. */
1648 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1649 i += 1;
1650 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1651 {
1652 /* Create a new pane. */
1653 Lisp_Object pane_name, prefix;
1654 char *pane_string;
1655 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1656 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1657 #ifndef HAVE_MULTILINGUAL_MENU
1658 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1659 {
1660 pane_name = ENCODE_SYSTEM (pane_name);
1661 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1662 }
1663 #endif
1664 pane_string = (NILP (pane_name)
1665 ? "" : (char *) XSTRING (pane_name)->data);
1666 /* If there is just one top-level pane, put all its items directly
1667 under the top-level menu. */
1668 if (menu_items_n_panes == 1)
1669 pane_string = "";
1670
1671 /* If the pane has a meaningful name,
1672 make the pane a top-level menu item
1673 with its items as a submenu beneath it. */
1674 if (!keymaps && strcmp (pane_string, ""))
1675 {
1676 wv = xmalloc_widget_value ();
1677 if (save_wv)
1678 save_wv->next = wv;
1679 else
1680 first_wv->contents = wv;
1681 wv->name = pane_string;
1682 if (keymaps && !NILP (prefix))
1683 wv->name++;
1684 wv->value = 0;
1685 wv->enabled = 1;
1686 wv->button_type = BUTTON_TYPE_NONE;
1687 wv->help = Qnil;
1688 save_wv = wv;
1689 prev_wv = 0;
1690 }
1691 else if (first_pane)
1692 {
1693 save_wv = wv;
1694 prev_wv = 0;
1695 }
1696 first_pane = 0;
1697 i += MENU_ITEMS_PANE_LENGTH;
1698 }
1699 else
1700 {
1701 /* Create a new item within current pane. */
1702 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1703
1704 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1705 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1706 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1707 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1708 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1709 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1710 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1711
1712 #ifndef HAVE_MULTILINGUAL_MENU
1713 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1714 {
1715 item_name = ENCODE_SYSTEM (item_name);
1716 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1717 }
1718 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1719 {
1720 descrip = ENCODE_SYSTEM (descrip);
1721 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1722 }
1723 #endif /* not HAVE_MULTILINGUAL_MENU */
1724
1725 wv = xmalloc_widget_value ();
1726 if (prev_wv)
1727 prev_wv->next = wv;
1728 else
1729 save_wv->contents = wv;
1730 wv->name = (char *) XSTRING (item_name)->data;
1731 if (!NILP (descrip))
1732 wv->key = (char *) XSTRING (descrip)->data;
1733 wv->value = 0;
1734 /* Use the contents index as call_data, since we are
1735 restricted to 16-bits. */
1736 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
1737 wv->enabled = !NILP (enable);
1738
1739 if (NILP (type))
1740 wv->button_type = BUTTON_TYPE_NONE;
1741 else if (EQ (type, QCtoggle))
1742 wv->button_type = BUTTON_TYPE_TOGGLE;
1743 else if (EQ (type, QCradio))
1744 wv->button_type = BUTTON_TYPE_RADIO;
1745 else
1746 abort ();
1747
1748 wv->selected = !NILP (selected);
1749 if (!STRINGP (help))
1750 help = Qnil;
1751
1752 wv->help = help;
1753
1754 prev_wv = wv;
1755
1756 i += MENU_ITEMS_ITEM_LENGTH;
1757 }
1758 }
1759
1760 /* Deal with the title, if it is non-nil. */
1761 if (!NILP (title))
1762 {
1763 widget_value *wv_title = xmalloc_widget_value ();
1764 widget_value *wv_sep = xmalloc_widget_value ();
1765
1766 /* Maybe replace this separator with a bitmap or owner-draw item
1767 so that it looks better. Having two separators looks odd. */
1768 wv_sep->name = "--";
1769 wv_sep->next = first_wv->contents;
1770 wv_sep->help = Qnil;
1771
1772 #ifndef HAVE_MULTILINGUAL_MENU
1773 if (STRING_MULTIBYTE (title))
1774 title = ENCODE_SYSTEM (title);
1775 #endif
1776 wv_title->name = (char *) XSTRING (title)->data;
1777 wv_title->enabled = TRUE;
1778 wv_title->title = TRUE;
1779 wv_title->button_type = BUTTON_TYPE_NONE;
1780 wv_title->help = Qnil;
1781 wv_title->next = wv_sep;
1782 first_wv->contents = wv_title;
1783 }
1784
1785 /* Actually create the menu. */
1786 current_popup_menu = menu = CreatePopupMenu ();
1787 fill_in_menu (menu, first_wv->contents);
1788
1789 /* Adjust coordinates to be root-window-relative. */
1790 pos.x = x;
1791 pos.y = y;
1792 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
1793
1794 /* No selection has been chosen yet. */
1795 menu_item_selection = 0;
1796
1797 /* Display the menu. */
1798 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
1799 WM_EMACS_TRACKPOPUPMENU,
1800 (WPARAM)menu, (LPARAM)&pos);
1801
1802 /* Clean up extraneous mouse events which might have been generated
1803 during the call. */
1804 discard_mouse_events ();
1805
1806 /* Free the widget_value objects we used to specify the contents. */
1807 free_menubar_widget_value_tree (first_wv);
1808
1809 DestroyMenu (menu);
1810
1811 /* Find the selected item, and its pane, to return
1812 the proper value. */
1813 if (menu_item_selection != 0)
1814 {
1815 Lisp_Object prefix, entry;
1816
1817 prefix = entry = Qnil;
1818 i = 0;
1819 while (i < menu_items_used)
1820 {
1821 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1822 {
1823 subprefix_stack[submenu_depth++] = prefix;
1824 prefix = entry;
1825 i++;
1826 }
1827 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1828 {
1829 prefix = subprefix_stack[--submenu_depth];
1830 i++;
1831 }
1832 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1833 {
1834 prefix
1835 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1836 i += MENU_ITEMS_PANE_LENGTH;
1837 }
1838 /* Ignore a nil in the item list.
1839 It's meaningful only for dialog boxes. */
1840 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1841 i += 1;
1842 else
1843 {
1844 entry
1845 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1846 if (menu_item_selection == i)
1847 {
1848 if (keymaps != 0)
1849 {
1850 int j;
1851
1852 entry = Fcons (entry, Qnil);
1853 if (!NILP (prefix))
1854 entry = Fcons (prefix, entry);
1855 for (j = submenu_depth - 1; j >= 0; j--)
1856 if (!NILP (subprefix_stack[j]))
1857 entry = Fcons (subprefix_stack[j], entry);
1858 }
1859 return entry;
1860 }
1861 i += MENU_ITEMS_ITEM_LENGTH;
1862 }
1863 }
1864 }
1865
1866 return Qnil;
1867 }
1868 \f
1869
1870 #ifdef HAVE_DIALOGS
1871 static char * button_names [] = {
1872 "button1", "button2", "button3", "button4", "button5",
1873 "button6", "button7", "button8", "button9", "button10" };
1874
1875 static Lisp_Object
1876 w32_dialog_show (f, keymaps, title, error)
1877 FRAME_PTR f;
1878 int keymaps;
1879 Lisp_Object title;
1880 char **error;
1881 {
1882 int i, nb_buttons=0;
1883 char dialog_name[6];
1884 int menu_item_selection;
1885
1886 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1887
1888 /* Number of elements seen so far, before boundary. */
1889 int left_count = 0;
1890 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1891 int boundary_seen = 0;
1892
1893 *error = NULL;
1894
1895 if (menu_items_n_panes > 1)
1896 {
1897 *error = "Multiple panes in dialog box";
1898 return Qnil;
1899 }
1900
1901 /* Create a tree of widget_value objects
1902 representing the text label and buttons. */
1903 {
1904 Lisp_Object pane_name, prefix;
1905 char *pane_string;
1906 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
1907 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
1908 pane_string = (NILP (pane_name)
1909 ? "" : (char *) XSTRING (pane_name)->data);
1910 prev_wv = xmalloc_widget_value ();
1911 prev_wv->value = pane_string;
1912 if (keymaps && !NILP (prefix))
1913 prev_wv->name++;
1914 prev_wv->enabled = 1;
1915 prev_wv->name = "message";
1916 prev_wv->help = Qnil;
1917 first_wv = prev_wv;
1918
1919 /* Loop over all panes and items, filling in the tree. */
1920 i = MENU_ITEMS_PANE_LENGTH;
1921 while (i < menu_items_used)
1922 {
1923
1924 /* Create a new item within current pane. */
1925 Lisp_Object item_name, enable, descrip, help;
1926
1927 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1928 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1929 descrip
1930 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
1931 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
1932
1933 if (NILP (item_name))
1934 {
1935 free_menubar_widget_value_tree (first_wv);
1936 *error = "Submenu in dialog items";
1937 return Qnil;
1938 }
1939 if (EQ (item_name, Qquote))
1940 {
1941 /* This is the boundary between left-side elts
1942 and right-side elts. Stop incrementing right_count. */
1943 boundary_seen = 1;
1944 i++;
1945 continue;
1946 }
1947 if (nb_buttons >= 9)
1948 {
1949 free_menubar_widget_value_tree (first_wv);
1950 *error = "Too many dialog items";
1951 return Qnil;
1952 }
1953
1954 wv = xmalloc_widget_value ();
1955 prev_wv->next = wv;
1956 wv->name = (char *) button_names[nb_buttons];
1957 if (!NILP (descrip))
1958 wv->key = (char *) XSTRING (descrip)->data;
1959 wv->value = (char *) XSTRING (item_name)->data;
1960 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
1961 wv->enabled = !NILP (enable);
1962 wv->help = Qnil;
1963 prev_wv = wv;
1964
1965 if (! boundary_seen)
1966 left_count++;
1967
1968 nb_buttons++;
1969 i += MENU_ITEMS_ITEM_LENGTH;
1970 }
1971
1972 /* If the boundary was not specified,
1973 by default put half on the left and half on the right. */
1974 if (! boundary_seen)
1975 left_count = nb_buttons - nb_buttons / 2;
1976
1977 wv = xmalloc_widget_value ();
1978 wv->name = dialog_name;
1979 wv->help = Qnil;
1980
1981 /* Dialog boxes use a really stupid name encoding
1982 which specifies how many buttons to use
1983 and how many buttons are on the right.
1984 The Q means something also. */
1985 dialog_name[0] = 'Q';
1986 dialog_name[1] = '0' + nb_buttons;
1987 dialog_name[2] = 'B';
1988 dialog_name[3] = 'R';
1989 /* Number of buttons to put on the right. */
1990 dialog_name[4] = '0' + nb_buttons - left_count;
1991 dialog_name[5] = 0;
1992 wv->contents = first_wv;
1993 first_wv = wv;
1994 }
1995
1996 /* Actually create the dialog. */
1997 dialog_id = widget_id_tick++;
1998 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1999 f->output_data.w32->widget, 1, 0,
2000 dialog_selection_callback, 0);
2001 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
2002
2003 /* Free the widget_value objects we used to specify the contents. */
2004 free_menubar_widget_value_tree (first_wv);
2005
2006 /* No selection has been chosen yet. */
2007 menu_item_selection = 0;
2008
2009 /* Display the menu. */
2010 lw_pop_up_all_widgets (dialog_id);
2011 popup_activated_flag = 1;
2012
2013 /* Process events that apply to the menu. */
2014 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
2015
2016 lw_destroy_all_widgets (dialog_id);
2017
2018 /* Find the selected item, and its pane, to return
2019 the proper value. */
2020 if (menu_item_selection != 0)
2021 {
2022 Lisp_Object prefix;
2023
2024 prefix = Qnil;
2025 i = 0;
2026 while (i < menu_items_used)
2027 {
2028 Lisp_Object entry;
2029
2030 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2031 {
2032 prefix
2033 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2034 i += MENU_ITEMS_PANE_LENGTH;
2035 }
2036 else
2037 {
2038 entry
2039 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2040 if (menu_item_selection == i)
2041 {
2042 if (keymaps != 0)
2043 {
2044 entry = Fcons (entry, Qnil);
2045 if (!NILP (prefix))
2046 entry = Fcons (prefix, entry);
2047 }
2048 return entry;
2049 }
2050 i += MENU_ITEMS_ITEM_LENGTH;
2051 }
2052 }
2053 }
2054
2055 return Qnil;
2056 }
2057 #endif /* HAVE_DIALOGS */
2058 \f
2059
2060 /* Is this item a separator? */
2061 static int
2062 name_is_separator (name)
2063 char *name;
2064 {
2065 char *start = name;
2066
2067 /* Check if name string consists of only dashes ('-'). */
2068 while (*name == '-') name++;
2069 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2070 or "--deep-shadow". We don't implement them yet, se we just treat
2071 them like normal separators. */
2072 return (*name == '\0' || start + 2 == name);
2073 }
2074
2075
2076 /* Indicate boundary between left and right. */
2077 static int
2078 add_left_right_boundary (HMENU menu)
2079 {
2080 return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL);
2081 }
2082
2083 static int
2084 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
2085 {
2086 UINT fuFlags;
2087 char *out_string;
2088 int return_value;
2089
2090 if (name_is_separator (wv->name))
2091 {
2092 fuFlags = MF_SEPARATOR;
2093 out_string = NULL;
2094 }
2095 else
2096 {
2097 if (wv->enabled)
2098 fuFlags = MF_STRING;
2099 else
2100 fuFlags = MF_STRING | MF_GRAYED;
2101
2102 if (wv->key != NULL)
2103 {
2104 out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2);
2105 strcpy (out_string, wv->name);
2106 strcat (out_string, "\t");
2107 strcat (out_string, wv->key);
2108 }
2109 else
2110 out_string = wv->name;
2111
2112 if (item != NULL)
2113 fuFlags = MF_POPUP;
2114 else if (wv->title || wv->call_data == 0)
2115 {
2116 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
2117 we can't deallocate the memory otherwise. */
2118 if (get_menu_item_info)
2119 {
2120 out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1);
2121 #ifdef MENU_DEBUG
2122 DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData);
2123 #endif
2124 strcpy (out_string, wv->name);
2125 fuFlags = MF_OWNERDRAW | MF_DISABLED;
2126 }
2127 else
2128 fuFlags = MF_DISABLED;
2129 }
2130
2131 /* Draw radio buttons and tickboxes. */
2132 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
2133 wv->button_type == BUTTON_TYPE_RADIO))
2134 fuFlags |= MF_CHECKED;
2135 else
2136 fuFlags |= MF_UNCHECKED;
2137 }
2138
2139 return_value =
2140 AppendMenu (menu,
2141 fuFlags,
2142 item != NULL ? (UINT) item : (UINT) wv->call_data,
2143 out_string );
2144
2145 /* This must be done after the menu item is created. */
2146 if (!wv->title && wv->call_data != 0)
2147 {
2148 if (set_menu_item_info)
2149 {
2150 MENUITEMINFO info;
2151 bzero (&info, sizeof (info));
2152 info.cbSize = sizeof (info);
2153 info.fMask = MIIM_DATA;
2154
2155 /* Set help string for menu item. Leave it as a Lisp_Object
2156 until it is ready to be displayed, since GC can happen while
2157 menus are active. */
2158 if (wv->help)
2159 info.dwItemData = (DWORD) wv->help;
2160
2161 if (wv->button_type == BUTTON_TYPE_RADIO)
2162 {
2163 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
2164 RADIO items, but is not available on NT 3.51 and earlier. */
2165 info.fMask |= MIIM_TYPE | MIIM_STATE;
2166 info.fType = MFT_RADIOCHECK | MFT_STRING;
2167 info.dwTypeData = out_string;
2168 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
2169 }
2170
2171 set_menu_item_info (menu,
2172 item != NULL ? (UINT) item : (UINT) wv->call_data,
2173 FALSE, &info);
2174 }
2175 }
2176 return return_value;
2177 }
2178
2179 /* Construct native Windows menu(bar) based on widget_value tree. */
2180 int
2181 fill_in_menu (HMENU menu, widget_value *wv)
2182 {
2183 int items_added = 0;
2184
2185 for ( ; wv != NULL; wv = wv->next)
2186 {
2187 if (wv->contents)
2188 {
2189 HMENU sub_menu = CreatePopupMenu ();
2190
2191 if (sub_menu == NULL)
2192 return 0;
2193
2194 if (!fill_in_menu (sub_menu, wv->contents) ||
2195 !add_menu_item (menu, wv, sub_menu))
2196 {
2197 DestroyMenu (sub_menu);
2198 return 0;
2199 }
2200 }
2201 else
2202 {
2203 if (!add_menu_item (menu, wv, NULL))
2204 return 0;
2205 }
2206 }
2207 return 1;
2208 }
2209
2210 int
2211 popup_activated ()
2212 {
2213 /* popup_activated_flag not actually used on W32 */
2214 return 0;
2215 }
2216
2217 /* Display help string for currently pointed to menu item. Not
2218 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
2219 available. */
2220 void
2221 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
2222 {
2223 if (get_menu_item_info)
2224 {
2225 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
2226 Lisp_Object frame, help;
2227
2228 // No help echo on owner-draw menu items.
2229 if (flags & MF_OWNERDRAW || flags & MF_POPUP)
2230 help = Qnil;
2231 else
2232 {
2233 MENUITEMINFO info;
2234
2235 bzero (&info, sizeof (info));
2236 info.cbSize = sizeof (info);
2237 info.fMask = MIIM_DATA;
2238 get_menu_item_info (menu, item, FALSE, &info);
2239
2240 help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
2241 }
2242
2243 /* Store the help echo in the keyboard buffer as the X toolkit
2244 version does, rather than directly showing it. This seems to
2245 solve the GC problems that were present when we based the
2246 Windows code on the non-toolkit version. */
2247 if (f)
2248 {
2249 XSETFRAME (frame, f);
2250 kbd_buffer_store_help_event (frame, help);
2251 }
2252 else
2253 /* X version has a loop through frames here, which doesn't
2254 appear to do anything, unless it has some side effect. */
2255 show_help_echo (help, Qnil, Qnil, Qnil, 1);
2256 }
2257 }
2258
2259 /* Free memory used by owner-drawn strings. */
2260 static void
2261 w32_free_submenu_strings (menu)
2262 HMENU menu;
2263 {
2264 int i, num = GetMenuItemCount (menu);
2265 for (i = 0; i < num; i++)
2266 {
2267 MENUITEMINFO info;
2268 bzero (&info, sizeof (info));
2269 info.cbSize = sizeof (info);
2270 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
2271
2272 get_menu_item_info (menu, i, TRUE, &info);
2273
2274 /* Owner-drawn names are held in dwItemData. */
2275 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
2276 {
2277 #ifdef MENU_DEBUG
2278 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
2279 #endif
2280 LocalFree (info.dwItemData);
2281 }
2282
2283 /* Recurse down submenus. */
2284 if (info.hSubMenu)
2285 w32_free_submenu_strings (info.hSubMenu);
2286 }
2287 }
2288
2289 void
2290 w32_free_menu_strings (hwnd)
2291 HWND hwnd;
2292 {
2293 HMENU menu = current_popup_menu;
2294
2295 if (get_menu_item_info)
2296 {
2297 /* If there is no popup menu active, free the strings from the frame's
2298 menubar. */
2299 if (!menu)
2300 menu = GetMenu (hwnd);
2301
2302 if (menu)
2303 w32_free_submenu_strings (menu);
2304 }
2305
2306 current_popup_menu = NULL;
2307 }
2308
2309 #endif /* HAVE_MENUS */
2310
2311 \f
2312 syms_of_w32menu ()
2313 {
2314 /* See if Get/SetMenuItemInfo functions are available. */
2315 HMODULE user32 = GetModuleHandle ("user32.dll");
2316 get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
2317 set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
2318
2319 staticpro (&menu_items);
2320 menu_items = Qnil;
2321
2322 current_popup_menu = NULL;
2323
2324 Qdebug_on_next_call = intern ("debug-on-next-call");
2325 staticpro (&Qdebug_on_next_call);
2326
2327 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
2328 doc: /* Frame for which we are updating a menu.
2329 The enable predicate for a menu command should check this variable. */);
2330 Vmenu_updating_frame = Qnil;
2331
2332 defsubr (&Sx_popup_menu);
2333 #ifdef HAVE_MENUS
2334 defsubr (&Sx_popup_dialog);
2335 #endif
2336 }