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