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