* doc/lispref/os.texi (Notifications): Copyedits.
[emacs.git] / src / w32menu.c
blob9091cb816276ad7c498b9b3663c676e60b1316b7
1 /* Menu support for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2012
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <mbstring.h>
25 #include <setjmp.h>
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 "coding.h"
37 #include "menu.h"
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"
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
49 #include "dispextern.h"
51 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
53 #ifndef TRUE
54 #define TRUE 1
55 #define FALSE 0
56 #endif /* no TRUE */
58 HMENU current_popup_menu;
60 void syms_of_w32menu (void);
61 void globals_of_w32menu (void);
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 typedef int (WINAPI * MessageBoxW_Proc) (
74 IN HWND window,
75 IN WCHAR *text,
76 IN WCHAR *caption,
77 IN UINT type);
79 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
80 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
81 AppendMenuW_Proc unicode_append_menu = NULL;
82 MessageBoxW_Proc unicode_message_box = NULL;
84 Lisp_Object Qdebug_on_next_call;
86 void set_frame_menubar (FRAME_PTR, int, int);
88 #ifdef HAVE_DIALOGS
89 static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**);
90 #else
91 static int is_simple_dialog (Lisp_Object);
92 static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object);
93 #endif
95 static void utf8to16 (unsigned char *, int, WCHAR *);
96 static int fill_in_menu (HMENU, widget_value *);
98 void w32_free_menu_strings (HWND);
101 /* This is set nonzero after the user activates the menu bar, and set
102 to zero again after the menu bars are redisplayed by prepare_menu_bar.
103 While it is nonzero, all calls to set_frame_menubar go deep.
105 I don't understand why this is needed, but it does seem to be
106 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
108 int pending_menu_activation;
110 #ifdef HAVE_MENUS
112 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
113 doc: /* Pop up a dialog box and return user's selection.
114 POSITION specifies which frame to use.
115 This is normally a mouse button event or a window or frame.
116 If POSITION is t, it means to use the frame the mouse is on.
117 The dialog box appears in the middle of the specified frame.
119 CONTENTS specifies the alternatives to display in the dialog box.
120 It is a list of the form (TITLE ITEM1 ITEM2...).
121 Each ITEM is a cons cell (STRING . VALUE).
122 The return value is VALUE from the chosen item.
124 An ITEM may also be just a string--that makes a nonselectable item.
125 An ITEM may also be nil--that means to put all preceding items
126 on the left of the dialog box and all following items on the right.
127 \(By default, approximately half appear on each side.)
129 If HEADER is non-nil, the frame title for the box is "Information",
130 otherwise it is "Question". */)
131 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
133 FRAME_PTR f = NULL;
134 Lisp_Object window;
136 check_w32 ();
138 /* Decode the first argument: find the window or frame to use. */
139 if (EQ (position, Qt)
140 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
141 || EQ (XCAR (position), Qtool_bar))))
143 #if 0 /* Using the frame the mouse is on may not be right. */
144 /* Use the mouse's current position. */
145 FRAME_PTR new_f = SELECTED_FRAME ();
146 Lisp_Object bar_window;
147 enum scroll_bar_part part;
148 Time time;
149 Lisp_Object x, y;
151 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
153 if (new_f != 0)
154 XSETFRAME (window, new_f);
155 else
156 window = selected_window;
157 #endif
158 window = selected_window;
160 else if (CONSP (position))
162 Lisp_Object tem;
163 tem = Fcar (position);
164 if (CONSP (tem))
165 window = Fcar (Fcdr (position));
166 else
168 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
169 window = Fcar (tem); /* POSN_WINDOW (tem) */
172 else if (WINDOWP (position) || FRAMEP (position))
173 window = position;
174 else
175 window = Qnil;
177 /* Decode where to put the menu. */
179 if (FRAMEP (window))
180 f = XFRAME (window);
181 else if (WINDOWP (window))
183 CHECK_LIVE_WINDOW (window);
184 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
186 else
187 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
188 but I don't want to make one now. */
189 CHECK_WINDOW (window);
191 #ifndef HAVE_DIALOGS
194 /* Handle simple Yes/No choices as MessageBox popups. */
195 if (is_simple_dialog (contents))
196 return simple_dialog_show (f, contents, header);
197 else
199 /* Display a menu with these alternatives
200 in the middle of frame F. */
201 Lisp_Object x, y, frame, newpos;
202 XSETFRAME (frame, f);
203 XSETINT (x, x_pixel_width (f) / 2);
204 XSETINT (y, x_pixel_height (f) / 2);
205 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
206 return Fx_popup_menu (newpos,
207 Fcons (Fcar (contents), Fcons (contents, Qnil)));
210 #else /* HAVE_DIALOGS */
212 Lisp_Object title;
213 char *error_name;
214 Lisp_Object selection;
216 /* Decode the dialog items from what was specified. */
217 title = Fcar (contents);
218 CHECK_STRING (title);
220 list_of_panes (Fcons (contents, Qnil));
222 /* Display them in a dialog box. */
223 BLOCK_INPUT;
224 selection = w32_dialog_show (f, 0, title, header, &error_name);
225 UNBLOCK_INPUT;
227 discard_menu_items ();
228 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
230 if (error_name) error (error_name);
231 return selection;
233 #endif /* HAVE_DIALOGS */
236 /* Activate the menu bar of frame F.
237 This is called from keyboard.c when it gets the
238 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
240 To activate the menu bar, we signal to the input thread that it can
241 return from the WM_INITMENU message, allowing the normal Windows
242 processing of the menus.
244 But first we recompute the menu bar contents (the whole tree).
246 This way we can safely execute Lisp code. */
248 void
249 x_activate_menubar (FRAME_PTR f)
251 set_frame_menubar (f, 0, 1);
253 /* Lock out further menubar changes while active. */
254 f->output_data.w32->menubar_active = 1;
256 /* Signal input thread to return from WM_INITMENU. */
257 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
260 /* This callback is called from the menu bar pulldown menu
261 when the user makes a selection.
262 Figure out what the user chose
263 and put the appropriate events into the keyboard buffer. */
265 void
266 menubar_selection_callback (FRAME_PTR f, void * client_data)
268 Lisp_Object prefix, entry;
269 Lisp_Object vector;
270 Lisp_Object *subprefix_stack;
271 int submenu_depth = 0;
272 int i;
274 if (!f)
275 return;
276 entry = Qnil;
277 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
278 vector = f->menu_bar_vector;
279 prefix = Qnil;
280 i = 0;
281 while (i < f->menu_bar_items_used)
283 if (EQ (AREF (vector, i), Qnil))
285 subprefix_stack[submenu_depth++] = prefix;
286 prefix = entry;
287 i++;
289 else if (EQ (AREF (vector, i), Qlambda))
291 prefix = subprefix_stack[--submenu_depth];
292 i++;
294 else if (EQ (AREF (vector, i), Qt))
296 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
297 i += MENU_ITEMS_PANE_LENGTH;
299 else
301 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
302 /* The EMACS_INT cast avoids a warning. There's no problem
303 as long as pointers have enough bits to hold small integers. */
304 if ((int) (EMACS_INT) client_data == i)
306 int j;
307 struct input_event buf;
308 Lisp_Object frame;
309 EVENT_INIT (buf);
311 XSETFRAME (frame, f);
312 buf.kind = MENU_BAR_EVENT;
313 buf.frame_or_window = frame;
314 buf.arg = frame;
315 kbd_buffer_store_event (&buf);
317 for (j = 0; j < submenu_depth; j++)
318 if (!NILP (subprefix_stack[j]))
320 buf.kind = MENU_BAR_EVENT;
321 buf.frame_or_window = frame;
322 buf.arg = subprefix_stack[j];
323 kbd_buffer_store_event (&buf);
326 if (!NILP (prefix))
328 buf.kind = MENU_BAR_EVENT;
329 buf.frame_or_window = frame;
330 buf.arg = prefix;
331 kbd_buffer_store_event (&buf);
334 buf.kind = MENU_BAR_EVENT;
335 buf.frame_or_window = frame;
336 buf.arg = entry;
337 /* Free memory used by owner-drawn and help-echo strings. */
338 w32_free_menu_strings (FRAME_W32_WINDOW (f));
339 kbd_buffer_store_event (&buf);
341 f->output_data.w32->menubar_active = 0;
342 return;
344 i += MENU_ITEMS_ITEM_LENGTH;
347 /* Free memory used by owner-drawn and help-echo strings. */
348 w32_free_menu_strings (FRAME_W32_WINDOW (f));
349 f->output_data.w32->menubar_active = 0;
353 /* Set the contents of the menubar widgets of frame F.
354 The argument FIRST_TIME is currently ignored;
355 it is set the first time this is called, from initialize_frame_menubar. */
357 void
358 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
360 HMENU menubar_widget = f->output_data.w32->menubar_widget;
361 Lisp_Object items;
362 widget_value *wv, *first_wv, *prev_wv = 0;
363 int i, last_i;
364 int *submenu_start, *submenu_end;
365 int *submenu_top_level_items, *submenu_n_panes;
367 /* We must not change the menubar when actually in use. */
368 if (f->output_data.w32->menubar_active)
369 return;
371 XSETFRAME (Vmenu_updating_frame, f);
373 if (! menubar_widget)
374 deep_p = 1;
375 else if (pending_menu_activation && !deep_p)
376 deep_p = 1;
378 if (deep_p)
380 /* Make a widget-value tree representing the entire menu trees. */
382 struct buffer *prev = current_buffer;
383 Lisp_Object buffer;
384 int specpdl_count = SPECPDL_INDEX ();
385 int previous_menu_items_used = f->menu_bar_items_used;
386 Lisp_Object *previous_items
387 = (Lisp_Object *) alloca (previous_menu_items_used
388 * sizeof (Lisp_Object));
390 /* If we are making a new widget, its contents are empty,
391 do always reinitialize them. */
392 if (! menubar_widget)
393 previous_menu_items_used = 0;
395 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
396 specbind (Qinhibit_quit, Qt);
397 /* Don't let the debugger step into this code
398 because it is not reentrant. */
399 specbind (Qdebug_on_next_call, Qnil);
401 record_unwind_save_match_data ();
403 if (NILP (Voverriding_local_map_menu_flag))
405 specbind (Qoverriding_terminal_local_map, Qnil);
406 specbind (Qoverriding_local_map, Qnil);
409 set_buffer_internal_1 (XBUFFER (buffer));
411 /* Run the hooks. */
412 safe_run_hooks (Qactivate_menubar_hook);
413 safe_run_hooks (Qmenu_bar_update_hook);
414 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
416 items = FRAME_MENU_BAR_ITEMS (f);
418 /* Save the frame's previous menu bar contents data. */
419 if (previous_menu_items_used)
420 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
421 previous_menu_items_used * sizeof (Lisp_Object));
423 /* Fill in menu_items with the current menu bar contents.
424 This can evaluate Lisp code. */
425 save_menu_items ();
427 menu_items = f->menu_bar_vector;
428 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
429 submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
430 submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
431 submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
432 submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
433 init_menu_items ();
434 for (i = 0; i < ASIZE (items); i += 4)
436 Lisp_Object key, string, maps;
438 last_i = i;
440 key = AREF (items, i);
441 string = AREF (items, i + 1);
442 maps = AREF (items, i + 2);
443 if (NILP (string))
444 break;
446 submenu_start[i] = menu_items_used;
448 menu_items_n_panes = 0;
449 submenu_top_level_items[i]
450 = parse_single_submenu (key, string, maps);
451 submenu_n_panes[i] = menu_items_n_panes;
453 submenu_end[i] = menu_items_used;
456 finish_menu_items ();
458 /* Convert menu_items into widget_value trees
459 to display the menu. This cannot evaluate Lisp code. */
461 wv = xmalloc_widget_value ();
462 wv->name = "menubar";
463 wv->value = 0;
464 wv->enabled = 1;
465 wv->button_type = BUTTON_TYPE_NONE;
466 wv->help = Qnil;
467 first_wv = wv;
469 for (i = 0; i < last_i; i += 4)
471 menu_items_n_panes = submenu_n_panes[i];
472 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
473 submenu_top_level_items[i]);
474 if (prev_wv)
475 prev_wv->next = wv;
476 else
477 first_wv->contents = wv;
478 /* Don't set wv->name here; GC during the loop might relocate it. */
479 wv->enabled = 1;
480 wv->button_type = BUTTON_TYPE_NONE;
481 prev_wv = wv;
484 set_buffer_internal_1 (prev);
486 /* If there has been no change in the Lisp-level contents
487 of the menu bar, skip redisplaying it. Just exit. */
489 for (i = 0; i < previous_menu_items_used; i++)
490 if (menu_items_used == i
491 || (!EQ (previous_items[i], AREF (menu_items, i))))
492 break;
493 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
495 free_menubar_widget_value_tree (first_wv);
496 discard_menu_items ();
497 unbind_to (specpdl_count, Qnil);
498 return;
501 f->menu_bar_vector = menu_items;
502 f->menu_bar_items_used = menu_items_used;
504 /* This undoes save_menu_items. */
505 unbind_to (specpdl_count, Qnil);
507 /* Now GC cannot happen during the lifetime of the widget_value,
508 so it's safe to store data from a Lisp_String, as long as
509 local copies are made when the actual menu is created.
510 Windows takes care of this for normal string items, but
511 not for owner-drawn items or additional item-info. */
512 wv = first_wv->contents;
513 for (i = 0; i < ASIZE (items); i += 4)
515 Lisp_Object string;
516 string = AREF (items, i + 1);
517 if (NILP (string))
518 break;
519 wv->name = SSDATA (string);
520 update_submenu_strings (wv->contents);
521 wv = wv->next;
524 else
526 /* Make a widget-value tree containing
527 just the top level menu bar strings. */
529 wv = xmalloc_widget_value ();
530 wv->name = "menubar";
531 wv->value = 0;
532 wv->enabled = 1;
533 wv->button_type = BUTTON_TYPE_NONE;
534 wv->help = Qnil;
535 first_wv = wv;
537 items = FRAME_MENU_BAR_ITEMS (f);
538 for (i = 0; i < ASIZE (items); i += 4)
540 Lisp_Object string;
542 string = AREF (items, i + 1);
543 if (NILP (string))
544 break;
546 wv = xmalloc_widget_value ();
547 wv->name = SSDATA (string);
548 wv->value = 0;
549 wv->enabled = 1;
550 wv->button_type = BUTTON_TYPE_NONE;
551 wv->help = Qnil;
552 /* This prevents lwlib from assuming this
553 menu item is really supposed to be empty. */
554 /* The EMACS_INT cast avoids a warning.
555 This value just has to be different from small integers. */
556 wv->call_data = (void *) (EMACS_INT) (-1);
558 if (prev_wv)
559 prev_wv->next = wv;
560 else
561 first_wv->contents = wv;
562 prev_wv = wv;
565 /* Forget what we thought we knew about what is in the
566 detailed contents of the menu bar menus.
567 Changing the top level always destroys the contents. */
568 f->menu_bar_items_used = 0;
571 /* Create or update the menu bar widget. */
573 BLOCK_INPUT;
575 if (menubar_widget)
577 /* Empty current menubar, rather than creating a fresh one. */
578 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
581 else
583 menubar_widget = CreateMenu ();
585 fill_in_menu (menubar_widget, first_wv->contents);
587 free_menubar_widget_value_tree (first_wv);
590 HMENU old_widget = f->output_data.w32->menubar_widget;
592 f->output_data.w32->menubar_widget = menubar_widget;
593 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
594 /* Causes flicker when menu bar is updated
595 DrawMenuBar (FRAME_W32_WINDOW (f)); */
597 /* Force the window size to be recomputed so that the frame's text
598 area remains the same, if menubar has just been created. */
599 if (old_widget == NULL)
600 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
603 UNBLOCK_INPUT;
606 /* Called from Fx_create_frame to create the initial menubar of a frame
607 before it is mapped, so that the window is mapped with the menubar already
608 there instead of us tacking it on later and thrashing the window after it
609 is visible. */
611 void
612 initialize_frame_menubar (FRAME_PTR f)
614 /* This function is called before the first chance to redisplay
615 the frame. It has to be, so the frame will have the right size. */
616 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
617 set_frame_menubar (f, 1, 1);
620 /* Get rid of the menu bar of frame F, and free its storage.
621 This is used when deleting a frame, and when turning off the menu bar. */
623 void
624 free_frame_menubar (FRAME_PTR f)
626 BLOCK_INPUT;
629 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
630 SetMenu (FRAME_W32_WINDOW (f), NULL);
631 f->output_data.w32->menubar_widget = NULL;
632 DestroyMenu (old);
635 UNBLOCK_INPUT;
639 /* w32_menu_show actually displays a menu using the panes and items in
640 menu_items and returns the value selected from it; we assume input
641 is blocked by the caller. */
643 /* F is the frame the menu is for.
644 X and Y are the frame-relative specified position,
645 relative to the inside upper left corner of the frame F.
646 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
647 KEYMAPS is 1 if this menu was specified with keymaps;
648 in that case, we return a list containing the chosen item's value
649 and perhaps also the pane's prefix.
650 TITLE is the specified menu title.
651 ERROR is a place to store an error message string in case of failure.
652 (We return nil on failure, but the value doesn't actually matter.) */
654 Lisp_Object
655 w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
656 Lisp_Object title, const char **error)
658 int i;
659 int menu_item_selection;
660 HMENU menu;
661 POINT pos;
662 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
663 widget_value **submenu_stack
664 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
665 Lisp_Object *subprefix_stack
666 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
667 int submenu_depth = 0;
668 int first_pane;
670 *error = NULL;
672 if (menu_items_n_panes == 0)
673 return Qnil;
675 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
677 *error = "Empty menu";
678 return Qnil;
681 /* Create a tree of widget_value objects
682 representing the panes and their items. */
683 wv = xmalloc_widget_value ();
684 wv->name = "menu";
685 wv->value = 0;
686 wv->enabled = 1;
687 wv->button_type = BUTTON_TYPE_NONE;
688 wv->help = Qnil;
689 first_wv = wv;
690 first_pane = 1;
692 /* Loop over all panes and items, filling in the tree. */
693 i = 0;
694 while (i < menu_items_used)
696 if (EQ (AREF (menu_items, i), Qnil))
698 submenu_stack[submenu_depth++] = save_wv;
699 save_wv = prev_wv;
700 prev_wv = 0;
701 first_pane = 1;
702 i++;
704 else if (EQ (AREF (menu_items, i), Qlambda))
706 prev_wv = save_wv;
707 save_wv = submenu_stack[--submenu_depth];
708 first_pane = 0;
709 i++;
711 else if (EQ (AREF (menu_items, i), Qt)
712 && submenu_depth != 0)
713 i += MENU_ITEMS_PANE_LENGTH;
714 /* Ignore a nil in the item list.
715 It's meaningful only for dialog boxes. */
716 else if (EQ (AREF (menu_items, i), Qquote))
717 i += 1;
718 else if (EQ (AREF (menu_items, i), Qt))
720 /* Create a new pane. */
721 Lisp_Object pane_name, prefix;
722 char *pane_string;
723 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
724 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
726 if (STRINGP (pane_name))
728 if (unicode_append_menu)
729 pane_name = ENCODE_UTF_8 (pane_name);
730 else if (STRING_MULTIBYTE (pane_name))
731 pane_name = ENCODE_SYSTEM (pane_name);
733 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
736 pane_string = (NILP (pane_name)
737 ? "" : SSDATA (pane_name));
738 /* If there is just one top-level pane, put all its items directly
739 under the top-level menu. */
740 if (menu_items_n_panes == 1)
741 pane_string = "";
743 /* If the pane has a meaningful name,
744 make the pane a top-level menu item
745 with its items as a submenu beneath it. */
746 if (!keymaps && strcmp (pane_string, ""))
748 wv = xmalloc_widget_value ();
749 if (save_wv)
750 save_wv->next = wv;
751 else
752 first_wv->contents = wv;
753 wv->name = pane_string;
754 if (keymaps && !NILP (prefix))
755 wv->name++;
756 wv->value = 0;
757 wv->enabled = 1;
758 wv->button_type = BUTTON_TYPE_NONE;
759 wv->help = Qnil;
760 save_wv = wv;
761 prev_wv = 0;
763 else if (first_pane)
765 save_wv = wv;
766 prev_wv = 0;
768 first_pane = 0;
769 i += MENU_ITEMS_PANE_LENGTH;
771 else
773 /* Create a new item within current pane. */
774 Lisp_Object item_name, enable, descrip, def, type, selected, help;
776 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
777 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
778 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
779 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
780 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
781 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
782 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
784 if (STRINGP (item_name))
786 if (unicode_append_menu)
787 item_name = ENCODE_UTF_8 (item_name);
788 else if (STRING_MULTIBYTE (item_name))
789 item_name = ENCODE_SYSTEM (item_name);
791 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
794 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
796 descrip = ENCODE_SYSTEM (descrip);
797 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
800 wv = xmalloc_widget_value ();
801 if (prev_wv)
802 prev_wv->next = wv;
803 else
804 save_wv->contents = wv;
805 wv->name = SSDATA (item_name);
806 if (!NILP (descrip))
807 wv->key = SSDATA (descrip);
808 wv->value = 0;
809 /* Use the contents index as call_data, since we are
810 restricted to 16-bits. */
811 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
812 wv->enabled = !NILP (enable);
814 if (NILP (type))
815 wv->button_type = BUTTON_TYPE_NONE;
816 else if (EQ (type, QCtoggle))
817 wv->button_type = BUTTON_TYPE_TOGGLE;
818 else if (EQ (type, QCradio))
819 wv->button_type = BUTTON_TYPE_RADIO;
820 else
821 abort ();
823 wv->selected = !NILP (selected);
825 if (!STRINGP (help))
826 help = Qnil;
828 wv->help = help;
830 prev_wv = wv;
832 i += MENU_ITEMS_ITEM_LENGTH;
836 /* Deal with the title, if it is non-nil. */
837 if (!NILP (title))
839 widget_value *wv_title = xmalloc_widget_value ();
840 widget_value *wv_sep = xmalloc_widget_value ();
842 /* Maybe replace this separator with a bitmap or owner-draw item
843 so that it looks better. Having two separators looks odd. */
844 wv_sep->name = "--";
845 wv_sep->next = first_wv->contents;
846 wv_sep->help = Qnil;
848 if (unicode_append_menu)
849 title = ENCODE_UTF_8 (title);
850 else if (STRING_MULTIBYTE (title))
851 title = ENCODE_SYSTEM (title);
853 wv_title->name = SSDATA (title);
854 wv_title->enabled = TRUE;
855 wv_title->title = TRUE;
856 wv_title->button_type = BUTTON_TYPE_NONE;
857 wv_title->help = Qnil;
858 wv_title->next = wv_sep;
859 first_wv->contents = wv_title;
862 /* No selection has been chosen yet. */
863 menu_item_selection = 0;
865 /* Actually create the menu. */
866 current_popup_menu = menu = CreatePopupMenu ();
867 fill_in_menu (menu, first_wv->contents);
869 /* Adjust coordinates to be root-window-relative. */
870 pos.x = x;
871 pos.y = y;
872 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
874 /* Display the menu. */
875 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
876 WM_EMACS_TRACKPOPUPMENU,
877 (WPARAM)menu, (LPARAM)&pos);
879 /* Clean up extraneous mouse events which might have been generated
880 during the call. */
881 discard_mouse_events ();
882 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
884 /* Free the widget_value objects we used to specify the contents. */
885 free_menubar_widget_value_tree (first_wv);
887 DestroyMenu (menu);
889 /* Free the owner-drawn and help-echo menu strings. */
890 w32_free_menu_strings (FRAME_W32_WINDOW (f));
891 f->output_data.w32->menubar_active = 0;
893 /* Find the selected item, and its pane, to return
894 the proper value. */
895 if (menu_item_selection != 0)
897 Lisp_Object prefix, entry;
899 prefix = entry = Qnil;
900 i = 0;
901 while (i < menu_items_used)
903 if (EQ (AREF (menu_items, i), Qnil))
905 subprefix_stack[submenu_depth++] = prefix;
906 prefix = entry;
907 i++;
909 else if (EQ (AREF (menu_items, i), Qlambda))
911 prefix = subprefix_stack[--submenu_depth];
912 i++;
914 else if (EQ (AREF (menu_items, i), Qt))
916 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
917 i += MENU_ITEMS_PANE_LENGTH;
919 /* Ignore a nil in the item list.
920 It's meaningful only for dialog boxes. */
921 else if (EQ (AREF (menu_items, i), Qquote))
922 i += 1;
923 else
925 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
926 if (menu_item_selection == i)
928 if (keymaps != 0)
930 int j;
932 entry = Fcons (entry, Qnil);
933 if (!NILP (prefix))
934 entry = Fcons (prefix, entry);
935 for (j = submenu_depth - 1; j >= 0; j--)
936 if (!NILP (subprefix_stack[j]))
937 entry = Fcons (subprefix_stack[j], entry);
939 return entry;
941 i += MENU_ITEMS_ITEM_LENGTH;
945 else if (!for_click)
946 /* Make "Cancel" equivalent to C-g. */
947 Fsignal (Qquit, Qnil);
949 return Qnil;
953 #ifdef HAVE_DIALOGS
954 /* TODO: On Windows, there are two ways of defining a dialog.
956 1. Create a predefined dialog resource and include it in nt/emacs.rc.
957 Using this method, we could then set the titles and make unneeded
958 buttons invisible before displaying the dialog. Everything would
959 be a fixed size though, so there is a risk that text does not
960 fit on a button.
961 2. Create the dialog template in memory on the fly. This allows us
962 to size the dialog and buttons dynamically, probably giving more
963 natural looking results for dialogs with few buttons, and eliminating
964 the problem of text overflowing the buttons. But the API for this is
965 quite complex - structures have to be allocated in particular ways,
966 text content is tacked onto the end of structures in variable length
967 arrays with further structures tacked on after these, there are
968 certain alignment requirements for all this, and we have to
969 measure all the text and convert to "dialog coordinates" to figure
970 out how big to make everything.
972 For now, we'll just stick with menus for dialogs that are more
973 complicated than simple yes/no type questions for which we can use
974 the MessageBox function.
977 static char * button_names [] = {
978 "button1", "button2", "button3", "button4", "button5",
979 "button6", "button7", "button8", "button9", "button10" };
981 static Lisp_Object
982 w32_dialog_show (FRAME_PTR f, int keymaps,
983 Lisp_Object title, Lisp_Object header,
984 char **error)
986 int i, nb_buttons = 0;
987 char dialog_name[6];
988 int menu_item_selection;
990 widget_value *wv, *first_wv = 0, *prev_wv = 0;
992 /* Number of elements seen so far, before boundary. */
993 int left_count = 0;
994 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
995 int boundary_seen = 0;
997 *error = NULL;
999 if (menu_items_n_panes > 1)
1001 *error = "Multiple panes in dialog box";
1002 return Qnil;
1005 /* Create a tree of widget_value objects
1006 representing the text label and buttons. */
1008 Lisp_Object pane_name, prefix;
1009 char *pane_string;
1010 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1011 prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
1012 pane_string = (NILP (pane_name)
1013 ? "" : SSDATA (pane_name));
1014 prev_wv = xmalloc_widget_value ();
1015 prev_wv->value = pane_string;
1016 if (keymaps && !NILP (prefix))
1017 prev_wv->name++;
1018 prev_wv->enabled = 1;
1019 prev_wv->name = "message";
1020 prev_wv->help = Qnil;
1021 first_wv = prev_wv;
1023 /* Loop over all panes and items, filling in the tree. */
1024 i = MENU_ITEMS_PANE_LENGTH;
1025 while (i < menu_items_used)
1028 /* Create a new item within current pane. */
1029 Lisp_Object item_name, enable, descrip, help;
1031 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1032 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1033 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1034 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1036 if (NILP (item_name))
1038 free_menubar_widget_value_tree (first_wv);
1039 *error = "Submenu in dialog items";
1040 return Qnil;
1042 if (EQ (item_name, Qquote))
1044 /* This is the boundary between left-side elts
1045 and right-side elts. Stop incrementing right_count. */
1046 boundary_seen = 1;
1047 i++;
1048 continue;
1050 if (nb_buttons >= 9)
1052 free_menubar_widget_value_tree (first_wv);
1053 *error = "Too many dialog items";
1054 return Qnil;
1057 wv = xmalloc_widget_value ();
1058 prev_wv->next = wv;
1059 wv->name = (char *) button_names[nb_buttons];
1060 if (!NILP (descrip))
1061 wv->key = SSDATA (descrip);
1062 wv->value = SSDATA (item_name);
1063 wv->call_data = (void *) &AREF (menu_items, i);
1064 wv->enabled = !NILP (enable);
1065 wv->help = Qnil;
1066 prev_wv = wv;
1068 if (! boundary_seen)
1069 left_count++;
1071 nb_buttons++;
1072 i += MENU_ITEMS_ITEM_LENGTH;
1075 /* If the boundary was not specified,
1076 by default put half on the left and half on the right. */
1077 if (! boundary_seen)
1078 left_count = nb_buttons - nb_buttons / 2;
1080 wv = xmalloc_widget_value ();
1081 wv->name = dialog_name;
1082 wv->help = Qnil;
1084 /* Frame title: 'Q' = Question, 'I' = Information.
1085 Can also have 'E' = Error if, one day, we want
1086 a popup for errors. */
1087 if (NILP (header))
1088 dialog_name[0] = 'Q';
1089 else
1090 dialog_name[0] = 'I';
1092 /* Dialog boxes use a really stupid name encoding
1093 which specifies how many buttons to use
1094 and how many buttons are on the right. */
1095 dialog_name[1] = '0' + nb_buttons;
1096 dialog_name[2] = 'B';
1097 dialog_name[3] = 'R';
1098 /* Number of buttons to put on the right. */
1099 dialog_name[4] = '0' + nb_buttons - left_count;
1100 dialog_name[5] = 0;
1101 wv->contents = first_wv;
1102 first_wv = wv;
1105 /* Actually create the dialog. */
1106 dialog_id = widget_id_tick++;
1107 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1108 f->output_data.w32->widget, 1, 0,
1109 dialog_selection_callback, 0);
1110 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
1112 /* Free the widget_value objects we used to specify the contents. */
1113 free_menubar_widget_value_tree (first_wv);
1115 /* No selection has been chosen yet. */
1116 menu_item_selection = 0;
1118 /* Display the menu. */
1119 lw_pop_up_all_widgets (dialog_id);
1121 /* Process events that apply to the menu. */
1122 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
1124 lw_destroy_all_widgets (dialog_id);
1126 /* Find the selected item, and its pane, to return
1127 the proper value. */
1128 if (menu_item_selection != 0)
1130 Lisp_Object prefix;
1132 prefix = Qnil;
1133 i = 0;
1134 while (i < menu_items_used)
1136 Lisp_Object entry;
1138 if (EQ (AREF (menu_items, i), Qt))
1140 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1141 i += MENU_ITEMS_PANE_LENGTH;
1143 else
1145 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1146 if (menu_item_selection == i)
1148 if (keymaps != 0)
1150 entry = Fcons (entry, Qnil);
1151 if (!NILP (prefix))
1152 entry = Fcons (prefix, entry);
1154 return entry;
1156 i += MENU_ITEMS_ITEM_LENGTH;
1160 else
1161 /* Make "Cancel" equivalent to C-g. */
1162 Fsignal (Qquit, Qnil);
1164 return Qnil;
1166 #else /* !HAVE_DIALOGS */
1168 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1169 simple dialogs. We could handle a few more, but I'm not aware of
1170 anywhere in Emacs that uses the other specific dialog choices that
1171 MessageBox provides. */
1173 static int
1174 is_simple_dialog (Lisp_Object contents)
1176 Lisp_Object options;
1177 Lisp_Object name, yes, no, other;
1179 if (!CONSP (contents))
1180 return 0;
1181 options = XCDR (contents);
1183 yes = build_string ("Yes");
1184 no = build_string ("No");
1186 if (!CONSP (options))
1187 return 0;
1189 name = XCAR (options);
1190 if (!CONSP (name))
1191 return 0;
1192 name = XCAR (name);
1194 if (!NILP (Fstring_equal (name, yes)))
1195 other = no;
1196 else if (!NILP (Fstring_equal (name, no)))
1197 other = yes;
1198 else
1199 return 0;
1201 options = XCDR (options);
1202 if (!CONSP (options))
1203 return 0;
1205 name = XCAR (options);
1206 if (!CONSP (name))
1207 return 0;
1208 name = XCAR (name);
1209 if (NILP (Fstring_equal (name, other)))
1210 return 0;
1212 /* Check there are no more options. */
1213 options = XCDR (options);
1214 return !(CONSP (options));
1217 static Lisp_Object
1218 simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
1220 int answer;
1221 UINT type;
1222 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1224 type = MB_YESNO;
1226 /* Since we only handle Yes/No dialogs, and we already checked
1227 is_simple_dialog, we don't need to worry about checking contents
1228 to see what type of dialog to use. */
1230 /* Use Unicode if possible, so any language can be displayed. */
1231 if (unicode_message_box)
1233 WCHAR *text, *title;
1234 USE_SAFE_ALLOCA;
1236 if (STRINGP (temp))
1238 char *utf8_text = SDATA (ENCODE_UTF_8 (temp));
1239 /* Be pessimistic about the number of characters needed.
1240 Remember characters outside the BMP will take more than
1241 one utf16 word, so we cannot simply use the character
1242 length of temp. */
1243 int utf8_len = strlen (utf8_text);
1244 SAFE_ALLOCA (text, WCHAR *, (utf8_len + 1) * sizeof (WCHAR));
1245 utf8to16 (utf8_text, utf8_len, text);
1247 else
1249 text = L"";
1252 if (NILP (header))
1254 title = L"Question";
1255 type |= MB_ICONQUESTION;
1257 else
1259 title = L"Information";
1260 type |= MB_ICONINFORMATION;
1263 answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
1264 SAFE_FREE ();
1266 else
1268 char *text, *title;
1270 /* Fall back on ANSI message box, but at least use system
1271 encoding so questions representable by the system codepage
1272 are encoded properly. */
1273 if (STRINGP (temp))
1274 text = SDATA (ENCODE_SYSTEM (temp));
1275 else
1276 text = "";
1278 if (NILP (header))
1280 title = "Question";
1281 type |= MB_ICONQUESTION;
1283 else
1285 title = "Information";
1286 type |= MB_ICONINFORMATION;
1289 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1292 if (answer == IDYES)
1293 lispy_answer = build_string ("Yes");
1294 else if (answer == IDNO)
1295 lispy_answer = build_string ("No");
1296 else
1297 Fsignal (Qquit, Qnil);
1299 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1301 Lisp_Object item, name, value;
1302 item = XCAR (temp);
1303 if (CONSP (item))
1305 name = XCAR (item);
1306 value = XCDR (item);
1308 else
1310 name = item;
1311 value = Qnil;
1314 if (!NILP (Fstring_equal (name, lispy_answer)))
1316 return value;
1319 Fsignal (Qquit, Qnil);
1320 return Qnil;
1322 #endif /* !HAVE_DIALOGS */
1325 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1326 static void
1327 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1329 while (len > 0)
1331 if (*src < 0x80)
1333 *dest = (WCHAR) *src;
1334 dest++; src++; len--;
1336 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1337 else if (*src < 0xC0)
1339 src++; len--;
1341 /* 2 char UTF-8 sequence. */
1342 else if (*src < 0xE0)
1344 *dest = (WCHAR) (((*src & 0x1f) << 6)
1345 | (*(src + 1) & 0x3f));
1346 src += 2; len -= 2; dest++;
1348 else if (*src < 0xF0)
1350 *dest = (WCHAR) (((*src & 0x0f) << 12)
1351 | ((*(src + 1) & 0x3f) << 6)
1352 | (*(src + 2) & 0x3f));
1353 src += 3; len -= 3; dest++;
1355 else /* Not encodable. Insert Unicode Substitution char. */
1357 *dest = (WCHAR) 0xfffd;
1358 src++; len--; dest++;
1361 *dest = 0;
1364 static int
1365 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1367 UINT fuFlags;
1368 char *out_string, *p, *q;
1369 int return_value;
1370 size_t nlen, orig_len;
1371 USE_SAFE_ALLOCA;
1373 if (menu_separator_name_p (wv->name))
1375 fuFlags = MF_SEPARATOR;
1376 out_string = NULL;
1378 else
1380 if (wv->enabled)
1381 fuFlags = MF_STRING;
1382 else
1383 fuFlags = MF_STRING | MF_GRAYED;
1385 if (wv->key != NULL)
1387 SAFE_ALLOCA (out_string, char *,
1388 strlen (wv->name) + strlen (wv->key) + 2);
1389 strcpy (out_string, wv->name);
1390 strcat (out_string, "\t");
1391 strcat (out_string, wv->key);
1393 else
1394 out_string = (char *)wv->name;
1396 /* Quote any special characters within the menu item's text and
1397 key binding. */
1398 nlen = orig_len = strlen (out_string);
1399 if (unicode_append_menu)
1401 /* With UTF-8, & cannot be part of a multibyte character. */
1402 for (p = out_string; *p; p++)
1404 if (*p == '&')
1405 nlen++;
1408 else
1410 /* If encoded with the system codepage, use multibyte string
1411 functions in case of multibyte characters that contain '&'. */
1412 for (p = out_string; *p; p = _mbsinc (p))
1414 if (_mbsnextc (p) == '&')
1415 nlen++;
1419 if (nlen > orig_len)
1421 p = out_string;
1422 SAFE_ALLOCA (out_string, char *, nlen + 1);
1423 q = out_string;
1424 while (*p)
1426 if (unicode_append_menu)
1428 if (*p == '&')
1429 *q++ = *p;
1430 *q++ = *p++;
1432 else
1434 if (_mbsnextc (p) == '&')
1436 _mbsncpy (q, p, 1);
1437 q = _mbsinc (q);
1439 _mbsncpy (q, p, 1);
1440 p = _mbsinc (p);
1441 q = _mbsinc (q);
1444 *q = '\0';
1447 if (item != NULL)
1448 fuFlags = MF_POPUP;
1449 else if (wv->title || wv->call_data == 0)
1451 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1452 we can't deallocate the memory otherwise. */
1453 if (get_menu_item_info)
1455 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1456 strcpy (out_string, wv->name);
1457 #ifdef MENU_DEBUG
1458 DebPrint ("Menu: allocating %ld for owner-draw", out_string);
1459 #endif
1460 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1462 else
1463 fuFlags = MF_DISABLED;
1466 /* Draw radio buttons and tickboxes. */
1467 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1468 wv->button_type == BUTTON_TYPE_RADIO))
1469 fuFlags |= MF_CHECKED;
1470 else
1471 fuFlags |= MF_UNCHECKED;
1474 if (unicode_append_menu && out_string)
1476 /* Convert out_string from UTF-8 to UTF-16-LE. */
1477 int utf8_len = strlen (out_string);
1478 WCHAR * utf16_string;
1479 if (fuFlags & MF_OWNERDRAW)
1480 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1481 else
1482 SAFE_ALLOCA (utf16_string, WCHAR *, (utf8_len + 1) * sizeof (WCHAR));
1484 utf8to16 (out_string, utf8_len, utf16_string);
1485 return_value = unicode_append_menu (menu, fuFlags,
1486 item != NULL ? (UINT) item
1487 : (UINT) wv->call_data,
1488 utf16_string);
1489 if (!return_value)
1491 /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
1492 apparently does exist at least in some cases and appears to be
1493 stubbed out to do nothing. out_string is UTF-8, but since
1494 our standard menus are in English and this is only going to
1495 happen the first time a menu is used, the encoding is
1496 of minor importance compared with menus not working at all. */
1497 return_value =
1498 AppendMenu (menu, fuFlags,
1499 item != NULL ? (UINT) item: (UINT) wv->call_data,
1500 out_string);
1501 /* Don't use Unicode menus in future. */
1502 unicode_append_menu = NULL;
1505 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1506 local_free (out_string);
1508 else
1510 return_value =
1511 AppendMenu (menu,
1512 fuFlags,
1513 item != NULL ? (UINT) item : (UINT) wv->call_data,
1514 out_string );
1517 /* This must be done after the menu item is created. */
1518 if (!wv->title && wv->call_data != 0)
1520 if (set_menu_item_info)
1522 MENUITEMINFO info;
1523 memset (&info, 0, sizeof (info));
1524 info.cbSize = sizeof (info);
1525 info.fMask = MIIM_DATA;
1527 /* Set help string for menu item. Leave it as a Lisp_Object
1528 until it is ready to be displayed, since GC can happen while
1529 menus are active. */
1530 if (!NILP (wv->help))
1531 #ifdef USE_LISP_UNION_TYPE
1532 info.dwItemData = (DWORD) (wv->help).i;
1533 #else
1534 info.dwItemData = (DWORD) (wv->help);
1535 #endif
1536 if (wv->button_type == BUTTON_TYPE_RADIO)
1538 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1539 RADIO items, but is not available on NT 3.51 and earlier. */
1540 info.fMask |= MIIM_TYPE | MIIM_STATE;
1541 info.fType = MFT_RADIOCHECK | MFT_STRING;
1542 info.dwTypeData = out_string;
1543 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1546 set_menu_item_info (menu,
1547 item != NULL ? (UINT) item : (UINT) wv->call_data,
1548 FALSE, &info);
1551 SAFE_FREE ();
1552 return return_value;
1555 /* Construct native Windows menu(bar) based on widget_value tree. */
1556 static int
1557 fill_in_menu (HMENU menu, widget_value *wv)
1559 for ( ; wv != NULL; wv = wv->next)
1561 if (wv->contents)
1563 HMENU sub_menu = CreatePopupMenu ();
1565 if (sub_menu == NULL)
1566 return 0;
1568 if (!fill_in_menu (sub_menu, wv->contents) ||
1569 !add_menu_item (menu, wv, sub_menu))
1571 DestroyMenu (sub_menu);
1572 return 0;
1575 else
1577 if (!add_menu_item (menu, wv, NULL))
1578 return 0;
1581 return 1;
1584 /* Display help string for currently pointed to menu item. Not
1585 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1586 available. */
1587 void
1588 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
1590 if (get_menu_item_info)
1592 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
1593 Lisp_Object frame, help;
1595 /* No help echo on owner-draw menu items, or when the keyboard is used
1596 to navigate the menus, since tooltips are distracting if they pop
1597 up elsewhere. */
1598 if (flags & MF_OWNERDRAW || flags & MF_POPUP
1599 || !(flags & MF_MOUSESELECT))
1600 help = Qnil;
1601 else
1603 MENUITEMINFO info;
1605 memset (&info, 0, sizeof (info));
1606 info.cbSize = sizeof (info);
1607 info.fMask = MIIM_DATA;
1608 get_menu_item_info (menu, item, FALSE, &info);
1610 #ifdef USE_LISP_UNION_TYPE
1611 help = info.dwItemData ? (Lisp_Object) ((EMACS_INT) info.dwItemData)
1612 : Qnil;
1613 #else
1614 help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
1615 #endif
1618 /* Store the help echo in the keyboard buffer as the X toolkit
1619 version does, rather than directly showing it. This seems to
1620 solve the GC problems that were present when we based the
1621 Windows code on the non-toolkit version. */
1622 if (f)
1624 XSETFRAME (frame, f);
1625 kbd_buffer_store_help_event (frame, help);
1627 else
1628 /* X version has a loop through frames here, which doesn't
1629 appear to do anything, unless it has some side effect. */
1630 show_help_echo (help, Qnil, Qnil, Qnil);
1634 /* Free memory used by owner-drawn strings. */
1635 static void
1636 w32_free_submenu_strings (HMENU menu)
1638 int i, num = GetMenuItemCount (menu);
1639 for (i = 0; i < num; i++)
1641 MENUITEMINFO info;
1642 memset (&info, 0, sizeof (info));
1643 info.cbSize = sizeof (info);
1644 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1646 get_menu_item_info (menu, i, TRUE, &info);
1648 /* Owner-drawn names are held in dwItemData. */
1649 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1651 #ifdef MENU_DEBUG
1652 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1653 #endif
1654 local_free (info.dwItemData);
1657 /* Recurse down submenus. */
1658 if (info.hSubMenu)
1659 w32_free_submenu_strings (info.hSubMenu);
1663 void
1664 w32_free_menu_strings (HWND hwnd)
1666 HMENU menu = current_popup_menu;
1668 if (get_menu_item_info)
1670 /* If there is no popup menu active, free the strings from the frame's
1671 menubar. */
1672 if (!menu)
1673 menu = GetMenu (hwnd);
1675 if (menu)
1676 w32_free_submenu_strings (menu);
1679 current_popup_menu = NULL;
1682 #endif /* HAVE_MENUS */
1684 /* The following is used by delayed window autoselection. */
1686 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1687 doc: /* Return t if a menu or popup dialog is active on selected frame. */)
1688 (void)
1690 #ifdef HAVE_MENUS
1691 FRAME_PTR f;
1692 f = SELECTED_FRAME ();
1693 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1694 #else
1695 return Qnil;
1696 #endif /* HAVE_MENUS */
1699 void
1700 syms_of_w32menu (void)
1702 globals_of_w32menu ();
1704 current_popup_menu = NULL;
1706 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1708 defsubr (&Smenu_or_popup_active_p);
1709 #ifdef HAVE_MENUS
1710 defsubr (&Sx_popup_dialog);
1711 #endif
1715 globals_of_w32menu is used to initialize those global variables that
1716 must always be initialized on startup even when the global variable
1717 initialized is non zero (see the function main in emacs.c).
1718 globals_of_w32menu is called from syms_of_w32menu when the global
1719 variable initialized is 0 and directly from main when initialized
1720 is non zero.
1722 void
1723 globals_of_w32menu (void)
1725 /* See if Get/SetMenuItemInfo functions are available. */
1726 HMODULE user32 = GetModuleHandle ("user32.dll");
1727 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
1728 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
1729 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
1730 unicode_message_box = (MessageBoxW_Proc) GetProcAddress (user32, "MessageBoxW");