* buffer.h (FETCH_MULTIBYTE_CHAR): Define as inline.
[emacs.git] / src / w32menu.c
blobb957da67567acd1bb41f1e48e91d63b8e7c1d535
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 "character.h"
35 #include "buffer.h"
36 #include "charset.h"
37 #include "coding.h"
38 #include "menu.h"
40 /* This may include sys/types.h, and that somehow loses
41 if this is not done before the other system files. */
42 #include "w32term.h"
44 /* Load sys/types.h if not already loaded.
45 In some systems loading it twice is suicidal. */
46 #ifndef makedev
47 #include <sys/types.h>
48 #endif
50 #include "dispextern.h"
52 #include "w32heap.h" /* for osinfo_cache */
54 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
56 #ifndef TRUE
57 #define TRUE 1
58 #define FALSE 0
59 #endif /* no TRUE */
61 HMENU current_popup_menu;
63 void syms_of_w32menu (void);
64 void globals_of_w32menu (void);
66 typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
67 IN HMENU,
68 IN UINT,
69 IN BOOL,
70 IN OUT LPMENUITEMINFOA);
71 typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
72 IN HMENU,
73 IN UINT,
74 IN BOOL,
75 IN LPCMENUITEMINFOA);
76 typedef int (WINAPI * MessageBoxW_Proc) (
77 IN HWND window,
78 IN WCHAR *text,
79 IN WCHAR *caption,
80 IN UINT type);
82 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
83 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
84 AppendMenuW_Proc unicode_append_menu = NULL;
85 MessageBoxW_Proc unicode_message_box = NULL;
87 Lisp_Object Qdebug_on_next_call;
89 void set_frame_menubar (FRAME_PTR, int, int);
91 #ifdef HAVE_DIALOGS
92 static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**);
93 #else
94 static int is_simple_dialog (Lisp_Object);
95 static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object);
96 #endif
98 static void utf8to16 (unsigned char *, int, WCHAR *);
99 static int fill_in_menu (HMENU, widget_value *);
101 void w32_free_menu_strings (HWND);
104 /* This is set nonzero after the user activates the menu bar, and set
105 to zero again after the menu bars are redisplayed by prepare_menu_bar.
106 While it is nonzero, all calls to set_frame_menubar go deep.
108 I don't understand why this is needed, but it does seem to be
109 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
111 int pending_menu_activation;
113 #ifdef HAVE_MENUS
115 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
116 doc: /* Pop up a dialog box and return user's selection.
117 POSITION specifies which frame to use.
118 This is normally a mouse button event or a window or frame.
119 If POSITION is t, it means to use the frame the mouse is on.
120 The dialog box appears in the middle of the specified frame.
122 CONTENTS specifies the alternatives to display in the dialog box.
123 It is a list of the form (TITLE ITEM1 ITEM2...).
124 Each ITEM is a cons cell (STRING . VALUE).
125 The return value is VALUE from the chosen item.
127 An ITEM may also be just a string--that makes a nonselectable item.
128 An ITEM may also be nil--that means to put all preceding items
129 on the left of the dialog box and all following items on the right.
130 \(By default, approximately half appear on each side.)
132 If HEADER is non-nil, the frame title for the box is "Information",
133 otherwise it is "Question". */)
134 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
136 FRAME_PTR f = NULL;
137 Lisp_Object window;
139 check_w32 ();
141 /* Decode the first argument: find the window or frame to use. */
142 if (EQ (position, Qt)
143 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
144 || EQ (XCAR (position), Qtool_bar))))
146 #if 0 /* Using the frame the mouse is on may not be right. */
147 /* Use the mouse's current position. */
148 FRAME_PTR new_f = SELECTED_FRAME ();
149 Lisp_Object bar_window;
150 enum scroll_bar_part part;
151 Time time;
152 Lisp_Object x, y;
154 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
156 if (new_f != 0)
157 XSETFRAME (window, new_f);
158 else
159 window = selected_window;
160 #endif
161 window = selected_window;
163 else if (CONSP (position))
165 Lisp_Object tem;
166 tem = Fcar (position);
167 if (CONSP (tem))
168 window = Fcar (Fcdr (position));
169 else
171 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
172 window = Fcar (tem); /* POSN_WINDOW (tem) */
175 else if (WINDOWP (position) || FRAMEP (position))
176 window = position;
177 else
178 window = Qnil;
180 /* Decode where to put the menu. */
182 if (FRAMEP (window))
183 f = XFRAME (window);
184 else if (WINDOWP (window))
186 CHECK_LIVE_WINDOW (window);
187 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
189 else
190 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
191 but I don't want to make one now. */
192 CHECK_WINDOW (window);
194 #ifndef HAVE_DIALOGS
197 /* Handle simple Yes/No choices as MessageBox popups. */
198 if (is_simple_dialog (contents))
199 return simple_dialog_show (f, contents, header);
200 else
202 /* Display a menu with these alternatives
203 in the middle of frame F. */
204 Lisp_Object x, y, frame, newpos;
205 XSETFRAME (frame, f);
206 XSETINT (x, x_pixel_width (f) / 2);
207 XSETINT (y, x_pixel_height (f) / 2);
208 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
209 return Fx_popup_menu (newpos,
210 Fcons (Fcar (contents), Fcons (contents, Qnil)));
213 #else /* HAVE_DIALOGS */
215 Lisp_Object title;
216 char *error_name;
217 Lisp_Object selection;
219 /* Decode the dialog items from what was specified. */
220 title = Fcar (contents);
221 CHECK_STRING (title);
223 list_of_panes (Fcons (contents, Qnil));
225 /* Display them in a dialog box. */
226 BLOCK_INPUT;
227 selection = w32_dialog_show (f, 0, title, header, &error_name);
228 UNBLOCK_INPUT;
230 discard_menu_items ();
231 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
233 if (error_name) error (error_name);
234 return selection;
236 #endif /* HAVE_DIALOGS */
239 /* Activate the menu bar of frame F.
240 This is called from keyboard.c when it gets the
241 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
243 To activate the menu bar, we signal to the input thread that it can
244 return from the WM_INITMENU message, allowing the normal Windows
245 processing of the menus.
247 But first we recompute the menu bar contents (the whole tree).
249 This way we can safely execute Lisp code. */
251 void
252 x_activate_menubar (FRAME_PTR f)
254 set_frame_menubar (f, 0, 1);
256 /* Lock out further menubar changes while active. */
257 f->output_data.w32->menubar_active = 1;
259 /* Signal input thread to return from WM_INITMENU. */
260 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
263 /* This callback is called from the menu bar pulldown menu
264 when the user makes a selection.
265 Figure out what the user chose
266 and put the appropriate events into the keyboard buffer. */
268 void
269 menubar_selection_callback (FRAME_PTR f, void * client_data)
271 Lisp_Object prefix, entry;
272 Lisp_Object vector;
273 Lisp_Object *subprefix_stack;
274 int submenu_depth = 0;
275 int i;
277 if (!f)
278 return;
279 entry = Qnil;
280 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
281 vector = f->menu_bar_vector;
282 prefix = Qnil;
283 i = 0;
284 while (i < f->menu_bar_items_used)
286 if (EQ (AREF (vector, i), Qnil))
288 subprefix_stack[submenu_depth++] = prefix;
289 prefix = entry;
290 i++;
292 else if (EQ (AREF (vector, i), Qlambda))
294 prefix = subprefix_stack[--submenu_depth];
295 i++;
297 else if (EQ (AREF (vector, i), Qt))
299 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
300 i += MENU_ITEMS_PANE_LENGTH;
302 else
304 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
305 /* The EMACS_INT cast avoids a warning. There's no problem
306 as long as pointers have enough bits to hold small integers. */
307 if ((int) (EMACS_INT) client_data == i)
309 int j;
310 struct input_event buf;
311 Lisp_Object frame;
312 EVENT_INIT (buf);
314 XSETFRAME (frame, f);
315 buf.kind = MENU_BAR_EVENT;
316 buf.frame_or_window = frame;
317 buf.arg = frame;
318 kbd_buffer_store_event (&buf);
320 for (j = 0; j < submenu_depth; j++)
321 if (!NILP (subprefix_stack[j]))
323 buf.kind = MENU_BAR_EVENT;
324 buf.frame_or_window = frame;
325 buf.arg = subprefix_stack[j];
326 kbd_buffer_store_event (&buf);
329 if (!NILP (prefix))
331 buf.kind = MENU_BAR_EVENT;
332 buf.frame_or_window = frame;
333 buf.arg = prefix;
334 kbd_buffer_store_event (&buf);
337 buf.kind = MENU_BAR_EVENT;
338 buf.frame_or_window = frame;
339 buf.arg = entry;
340 /* Free memory used by owner-drawn and help-echo strings. */
341 w32_free_menu_strings (FRAME_W32_WINDOW (f));
342 kbd_buffer_store_event (&buf);
344 f->output_data.w32->menubar_active = 0;
345 return;
347 i += MENU_ITEMS_ITEM_LENGTH;
350 /* Free memory used by owner-drawn and help-echo strings. */
351 w32_free_menu_strings (FRAME_W32_WINDOW (f));
352 f->output_data.w32->menubar_active = 0;
356 /* Set the contents of the menubar widgets of frame F.
357 The argument FIRST_TIME is currently ignored;
358 it is set the first time this is called, from initialize_frame_menubar. */
360 void
361 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
363 HMENU menubar_widget = f->output_data.w32->menubar_widget;
364 Lisp_Object items;
365 widget_value *wv, *first_wv, *prev_wv = 0;
366 int i, last_i;
367 int *submenu_start, *submenu_end;
368 int *submenu_top_level_items, *submenu_n_panes;
370 /* We must not change the menubar when actually in use. */
371 if (f->output_data.w32->menubar_active)
372 return;
374 XSETFRAME (Vmenu_updating_frame, f);
376 if (! menubar_widget)
377 deep_p = 1;
378 else if (pending_menu_activation && !deep_p)
379 deep_p = 1;
381 if (deep_p)
383 /* Make a widget-value tree representing the entire menu trees. */
385 struct buffer *prev = current_buffer;
386 Lisp_Object buffer;
387 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
388 int previous_menu_items_used = f->menu_bar_items_used;
389 Lisp_Object *previous_items
390 = (Lisp_Object *) alloca (previous_menu_items_used
391 * sizeof (Lisp_Object));
393 /* If we are making a new widget, its contents are empty,
394 do always reinitialize them. */
395 if (! menubar_widget)
396 previous_menu_items_used = 0;
398 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
399 specbind (Qinhibit_quit, Qt);
400 /* Don't let the debugger step into this code
401 because it is not reentrant. */
402 specbind (Qdebug_on_next_call, Qnil);
404 record_unwind_save_match_data ();
406 if (NILP (Voverriding_local_map_menu_flag))
408 specbind (Qoverriding_terminal_local_map, Qnil);
409 specbind (Qoverriding_local_map, Qnil);
412 set_buffer_internal_1 (XBUFFER (buffer));
414 /* Run the hooks. */
415 safe_run_hooks (Qactivate_menubar_hook);
416 safe_run_hooks (Qmenu_bar_update_hook);
417 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
419 items = FRAME_MENU_BAR_ITEMS (f);
421 /* Save the frame's previous menu bar contents data. */
422 if (previous_menu_items_used)
423 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
424 previous_menu_items_used * sizeof (Lisp_Object));
426 /* Fill in menu_items with the current menu bar contents.
427 This can evaluate Lisp code. */
428 save_menu_items ();
430 menu_items = f->menu_bar_vector;
431 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
432 submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
433 submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
434 submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
435 submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
436 init_menu_items ();
437 for (i = 0; i < ASIZE (items); i += 4)
439 Lisp_Object key, string, maps;
441 last_i = i;
443 key = AREF (items, i);
444 string = AREF (items, i + 1);
445 maps = AREF (items, i + 2);
446 if (NILP (string))
447 break;
449 submenu_start[i] = menu_items_used;
451 menu_items_n_panes = 0;
452 submenu_top_level_items[i]
453 = parse_single_submenu (key, string, maps);
454 submenu_n_panes[i] = menu_items_n_panes;
456 submenu_end[i] = menu_items_used;
459 finish_menu_items ();
461 /* Convert menu_items into widget_value trees
462 to display the menu. This cannot evaluate Lisp code. */
464 wv = xmalloc_widget_value ();
465 wv->name = "menubar";
466 wv->value = 0;
467 wv->enabled = 1;
468 wv->button_type = BUTTON_TYPE_NONE;
469 wv->help = Qnil;
470 first_wv = wv;
472 for (i = 0; i < last_i; i += 4)
474 menu_items_n_panes = submenu_n_panes[i];
475 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
476 submenu_top_level_items[i]);
477 if (prev_wv)
478 prev_wv->next = wv;
479 else
480 first_wv->contents = wv;
481 /* Don't set wv->name here; GC during the loop might relocate it. */
482 wv->enabled = 1;
483 wv->button_type = BUTTON_TYPE_NONE;
484 prev_wv = wv;
487 set_buffer_internal_1 (prev);
489 /* If there has been no change in the Lisp-level contents
490 of the menu bar, skip redisplaying it. Just exit. */
492 for (i = 0; i < previous_menu_items_used; i++)
493 if (menu_items_used == i
494 || (!EQ (previous_items[i], AREF (menu_items, i))))
495 break;
496 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
498 free_menubar_widget_value_tree (first_wv);
499 discard_menu_items ();
500 unbind_to (specpdl_count, Qnil);
501 return;
504 f->menu_bar_vector = menu_items;
505 f->menu_bar_items_used = menu_items_used;
507 /* This undoes save_menu_items. */
508 unbind_to (specpdl_count, Qnil);
510 /* Now GC cannot happen during the lifetime of the widget_value,
511 so it's safe to store data from a Lisp_String, as long as
512 local copies are made when the actual menu is created.
513 Windows takes care of this for normal string items, but
514 not for owner-drawn items or additional item-info. */
515 wv = first_wv->contents;
516 for (i = 0; i < ASIZE (items); i += 4)
518 Lisp_Object string;
519 string = AREF (items, i + 1);
520 if (NILP (string))
521 break;
522 wv->name = SSDATA (string);
523 update_submenu_strings (wv->contents);
524 wv = wv->next;
527 else
529 /* Make a widget-value tree containing
530 just the top level menu bar strings. */
532 wv = xmalloc_widget_value ();
533 wv->name = "menubar";
534 wv->value = 0;
535 wv->enabled = 1;
536 wv->button_type = BUTTON_TYPE_NONE;
537 wv->help = Qnil;
538 first_wv = wv;
540 items = FRAME_MENU_BAR_ITEMS (f);
541 for (i = 0; i < ASIZE (items); i += 4)
543 Lisp_Object string;
545 string = AREF (items, i + 1);
546 if (NILP (string))
547 break;
549 wv = xmalloc_widget_value ();
550 wv->name = SSDATA (string);
551 wv->value = 0;
552 wv->enabled = 1;
553 wv->button_type = BUTTON_TYPE_NONE;
554 wv->help = Qnil;
555 /* This prevents lwlib from assuming this
556 menu item is really supposed to be empty. */
557 /* The EMACS_INT cast avoids a warning.
558 This value just has to be different from small integers. */
559 wv->call_data = (void *) (EMACS_INT) (-1);
561 if (prev_wv)
562 prev_wv->next = wv;
563 else
564 first_wv->contents = wv;
565 prev_wv = wv;
568 /* Forget what we thought we knew about what is in the
569 detailed contents of the menu bar menus.
570 Changing the top level always destroys the contents. */
571 f->menu_bar_items_used = 0;
574 /* Create or update the menu bar widget. */
576 BLOCK_INPUT;
578 if (menubar_widget)
580 /* Empty current menubar, rather than creating a fresh one. */
581 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
584 else
586 menubar_widget = CreateMenu ();
588 fill_in_menu (menubar_widget, first_wv->contents);
590 free_menubar_widget_value_tree (first_wv);
593 HMENU old_widget = f->output_data.w32->menubar_widget;
595 f->output_data.w32->menubar_widget = menubar_widget;
596 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
597 /* Causes flicker when menu bar is updated
598 DrawMenuBar (FRAME_W32_WINDOW (f)); */
600 /* Force the window size to be recomputed so that the frame's text
601 area remains the same, if menubar has just been created. */
602 if (old_widget == NULL)
603 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
606 UNBLOCK_INPUT;
609 /* Called from Fx_create_frame to create the initial menubar of a frame
610 before it is mapped, so that the window is mapped with the menubar already
611 there instead of us tacking it on later and thrashing the window after it
612 is visible. */
614 void
615 initialize_frame_menubar (FRAME_PTR f)
617 /* This function is called before the first chance to redisplay
618 the frame. It has to be, so the frame will have the right size. */
619 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
620 set_frame_menubar (f, 1, 1);
623 /* Get rid of the menu bar of frame F, and free its storage.
624 This is used when deleting a frame, and when turning off the menu bar. */
626 void
627 free_frame_menubar (FRAME_PTR f)
629 BLOCK_INPUT;
632 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
633 SetMenu (FRAME_W32_WINDOW (f), NULL);
634 f->output_data.w32->menubar_widget = NULL;
635 DestroyMenu (old);
638 UNBLOCK_INPUT;
642 /* w32_menu_show actually displays a menu using the panes and items in
643 menu_items and returns the value selected from it; we assume input
644 is blocked by the caller. */
646 /* F is the frame the menu is for.
647 X and Y are the frame-relative specified position,
648 relative to the inside upper left corner of the frame F.
649 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
650 KEYMAPS is 1 if this menu was specified with keymaps;
651 in that case, we return a list containing the chosen item's value
652 and perhaps also the pane's prefix.
653 TITLE is the specified menu title.
654 ERROR is a place to store an error message string in case of failure.
655 (We return nil on failure, but the value doesn't actually matter.) */
657 Lisp_Object
658 w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
659 Lisp_Object title, const char **error)
661 int i;
662 int menu_item_selection;
663 HMENU menu;
664 POINT pos;
665 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
666 widget_value **submenu_stack
667 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
668 Lisp_Object *subprefix_stack
669 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
670 int submenu_depth = 0;
671 int first_pane;
673 *error = NULL;
675 if (menu_items_n_panes == 0)
676 return Qnil;
678 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
680 *error = "Empty menu";
681 return Qnil;
684 /* Create a tree of widget_value objects
685 representing the panes and their items. */
686 wv = xmalloc_widget_value ();
687 wv->name = "menu";
688 wv->value = 0;
689 wv->enabled = 1;
690 wv->button_type = BUTTON_TYPE_NONE;
691 wv->help = Qnil;
692 first_wv = wv;
693 first_pane = 1;
695 /* Loop over all panes and items, filling in the tree. */
696 i = 0;
697 while (i < menu_items_used)
699 if (EQ (AREF (menu_items, i), Qnil))
701 submenu_stack[submenu_depth++] = save_wv;
702 save_wv = prev_wv;
703 prev_wv = 0;
704 first_pane = 1;
705 i++;
707 else if (EQ (AREF (menu_items, i), Qlambda))
709 prev_wv = save_wv;
710 save_wv = submenu_stack[--submenu_depth];
711 first_pane = 0;
712 i++;
714 else if (EQ (AREF (menu_items, i), Qt)
715 && submenu_depth != 0)
716 i += MENU_ITEMS_PANE_LENGTH;
717 /* Ignore a nil in the item list.
718 It's meaningful only for dialog boxes. */
719 else if (EQ (AREF (menu_items, i), Qquote))
720 i += 1;
721 else if (EQ (AREF (menu_items, i), Qt))
723 /* Create a new pane. */
724 Lisp_Object pane_name, prefix;
725 char *pane_string;
726 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
727 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
729 if (STRINGP (pane_name))
731 if (unicode_append_menu)
732 pane_name = ENCODE_UTF_8 (pane_name);
733 else if (STRING_MULTIBYTE (pane_name))
734 pane_name = ENCODE_SYSTEM (pane_name);
736 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
739 pane_string = (NILP (pane_name)
740 ? "" : SSDATA (pane_name));
741 /* If there is just one top-level pane, put all its items directly
742 under the top-level menu. */
743 if (menu_items_n_panes == 1)
744 pane_string = "";
746 /* If the pane has a meaningful name,
747 make the pane a top-level menu item
748 with its items as a submenu beneath it. */
749 if (!keymaps && strcmp (pane_string, ""))
751 wv = xmalloc_widget_value ();
752 if (save_wv)
753 save_wv->next = wv;
754 else
755 first_wv->contents = wv;
756 wv->name = pane_string;
757 if (keymaps && !NILP (prefix))
758 wv->name++;
759 wv->value = 0;
760 wv->enabled = 1;
761 wv->button_type = BUTTON_TYPE_NONE;
762 wv->help = Qnil;
763 save_wv = wv;
764 prev_wv = 0;
766 else if (first_pane)
768 save_wv = wv;
769 prev_wv = 0;
771 first_pane = 0;
772 i += MENU_ITEMS_PANE_LENGTH;
774 else
776 /* Create a new item within current pane. */
777 Lisp_Object item_name, enable, descrip, def, type, selected, help;
779 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
780 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
781 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
782 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
783 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
784 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
785 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
787 if (STRINGP (item_name))
789 if (unicode_append_menu)
790 item_name = ENCODE_UTF_8 (item_name);
791 else if (STRING_MULTIBYTE (item_name))
792 item_name = ENCODE_SYSTEM (item_name);
794 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
797 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
799 descrip = ENCODE_SYSTEM (descrip);
800 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
803 wv = xmalloc_widget_value ();
804 if (prev_wv)
805 prev_wv->next = wv;
806 else
807 save_wv->contents = wv;
808 wv->name = SSDATA (item_name);
809 if (!NILP (descrip))
810 wv->key = SSDATA (descrip);
811 wv->value = 0;
812 /* Use the contents index as call_data, since we are
813 restricted to 16-bits. */
814 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
815 wv->enabled = !NILP (enable);
817 if (NILP (type))
818 wv->button_type = BUTTON_TYPE_NONE;
819 else if (EQ (type, QCtoggle))
820 wv->button_type = BUTTON_TYPE_TOGGLE;
821 else if (EQ (type, QCradio))
822 wv->button_type = BUTTON_TYPE_RADIO;
823 else
824 abort ();
826 wv->selected = !NILP (selected);
828 if (!STRINGP (help))
829 help = Qnil;
831 wv->help = help;
833 prev_wv = wv;
835 i += MENU_ITEMS_ITEM_LENGTH;
839 /* Deal with the title, if it is non-nil. */
840 if (!NILP (title))
842 widget_value *wv_title = xmalloc_widget_value ();
843 widget_value *wv_sep = xmalloc_widget_value ();
845 /* Maybe replace this separator with a bitmap or owner-draw item
846 so that it looks better. Having two separators looks odd. */
847 wv_sep->name = "--";
848 wv_sep->next = first_wv->contents;
849 wv_sep->help = Qnil;
851 if (unicode_append_menu)
852 title = ENCODE_UTF_8 (title);
853 else if (STRING_MULTIBYTE (title))
854 title = ENCODE_SYSTEM (title);
856 wv_title->name = SSDATA (title);
857 wv_title->enabled = TRUE;
858 wv_title->title = TRUE;
859 wv_title->button_type = BUTTON_TYPE_NONE;
860 wv_title->help = Qnil;
861 wv_title->next = wv_sep;
862 first_wv->contents = wv_title;
865 /* No selection has been chosen yet. */
866 menu_item_selection = 0;
868 /* Actually create the menu. */
869 current_popup_menu = menu = CreatePopupMenu ();
870 fill_in_menu (menu, first_wv->contents);
872 /* Adjust coordinates to be root-window-relative. */
873 pos.x = x;
874 pos.y = y;
875 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
877 /* Display the menu. */
878 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
879 WM_EMACS_TRACKPOPUPMENU,
880 (WPARAM)menu, (LPARAM)&pos);
882 /* Clean up extraneous mouse events which might have been generated
883 during the call. */
884 discard_mouse_events ();
885 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
887 /* Free the widget_value objects we used to specify the contents. */
888 free_menubar_widget_value_tree (first_wv);
890 DestroyMenu (menu);
892 /* Free the owner-drawn and help-echo menu strings. */
893 w32_free_menu_strings (FRAME_W32_WINDOW (f));
894 f->output_data.w32->menubar_active = 0;
896 /* Find the selected item, and its pane, to return
897 the proper value. */
898 if (menu_item_selection != 0)
900 Lisp_Object prefix, entry;
902 prefix = entry = Qnil;
903 i = 0;
904 while (i < menu_items_used)
906 if (EQ (AREF (menu_items, i), Qnil))
908 subprefix_stack[submenu_depth++] = prefix;
909 prefix = entry;
910 i++;
912 else if (EQ (AREF (menu_items, i), Qlambda))
914 prefix = subprefix_stack[--submenu_depth];
915 i++;
917 else if (EQ (AREF (menu_items, i), Qt))
919 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
920 i += MENU_ITEMS_PANE_LENGTH;
922 /* Ignore a nil in the item list.
923 It's meaningful only for dialog boxes. */
924 else if (EQ (AREF (menu_items, i), Qquote))
925 i += 1;
926 else
928 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
929 if (menu_item_selection == i)
931 if (keymaps != 0)
933 int j;
935 entry = Fcons (entry, Qnil);
936 if (!NILP (prefix))
937 entry = Fcons (prefix, entry);
938 for (j = submenu_depth - 1; j >= 0; j--)
939 if (!NILP (subprefix_stack[j]))
940 entry = Fcons (subprefix_stack[j], entry);
942 return entry;
944 i += MENU_ITEMS_ITEM_LENGTH;
948 else if (!for_click)
949 /* Make "Cancel" equivalent to C-g. */
950 Fsignal (Qquit, Qnil);
952 return Qnil;
956 #ifdef HAVE_DIALOGS
957 /* TODO: On Windows, there are two ways of defining a dialog.
959 1. Create a predefined dialog resource and include it in nt/emacs.rc.
960 Using this method, we could then set the titles and make unneeded
961 buttons invisible before displaying the dialog. Everything would
962 be a fixed size though, so there is a risk that text does not
963 fit on a button.
964 2. Create the dialog template in memory on the fly. This allows us
965 to size the dialog and buttons dynamically, probably giving more
966 natural looking results for dialogs with few buttons, and eliminating
967 the problem of text overflowing the buttons. But the API for this is
968 quite complex - structures have to be allocated in particular ways,
969 text content is tacked onto the end of structures in variable length
970 arrays with further structures tacked on after these, there are
971 certain alignment requirements for all this, and we have to
972 measure all the text and convert to "dialog coordinates" to figure
973 out how big to make everything.
975 For now, we'll just stick with menus for dialogs that are more
976 complicated than simple yes/no type questions for which we can use
977 the MessageBox function.
980 static char * button_names [] = {
981 "button1", "button2", "button3", "button4", "button5",
982 "button6", "button7", "button8", "button9", "button10" };
984 static Lisp_Object
985 w32_dialog_show (FRAME_PTR f, int keymaps,
986 Lisp_Object title, Lisp_Object header,
987 char **error)
989 int i, nb_buttons = 0;
990 char dialog_name[6];
991 int menu_item_selection;
993 widget_value *wv, *first_wv = 0, *prev_wv = 0;
995 /* Number of elements seen so far, before boundary. */
996 int left_count = 0;
997 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
998 int boundary_seen = 0;
1000 *error = NULL;
1002 if (menu_items_n_panes > 1)
1004 *error = "Multiple panes in dialog box";
1005 return Qnil;
1008 /* Create a tree of widget_value objects
1009 representing the text label and buttons. */
1011 Lisp_Object pane_name, prefix;
1012 char *pane_string;
1013 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1014 prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
1015 pane_string = (NILP (pane_name)
1016 ? "" : SSDATA (pane_name));
1017 prev_wv = xmalloc_widget_value ();
1018 prev_wv->value = pane_string;
1019 if (keymaps && !NILP (prefix))
1020 prev_wv->name++;
1021 prev_wv->enabled = 1;
1022 prev_wv->name = "message";
1023 prev_wv->help = Qnil;
1024 first_wv = prev_wv;
1026 /* Loop over all panes and items, filling in the tree. */
1027 i = MENU_ITEMS_PANE_LENGTH;
1028 while (i < menu_items_used)
1031 /* Create a new item within current pane. */
1032 Lisp_Object item_name, enable, descrip, help;
1034 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1035 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1036 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1037 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1039 if (NILP (item_name))
1041 free_menubar_widget_value_tree (first_wv);
1042 *error = "Submenu in dialog items";
1043 return Qnil;
1045 if (EQ (item_name, Qquote))
1047 /* This is the boundary between left-side elts
1048 and right-side elts. Stop incrementing right_count. */
1049 boundary_seen = 1;
1050 i++;
1051 continue;
1053 if (nb_buttons >= 9)
1055 free_menubar_widget_value_tree (first_wv);
1056 *error = "Too many dialog items";
1057 return Qnil;
1060 wv = xmalloc_widget_value ();
1061 prev_wv->next = wv;
1062 wv->name = (char *) button_names[nb_buttons];
1063 if (!NILP (descrip))
1064 wv->key = SSDATA (descrip);
1065 wv->value = SSDATA (item_name);
1066 wv->call_data = (void *) &AREF (menu_items, i);
1067 wv->enabled = !NILP (enable);
1068 wv->help = Qnil;
1069 prev_wv = wv;
1071 if (! boundary_seen)
1072 left_count++;
1074 nb_buttons++;
1075 i += MENU_ITEMS_ITEM_LENGTH;
1078 /* If the boundary was not specified,
1079 by default put half on the left and half on the right. */
1080 if (! boundary_seen)
1081 left_count = nb_buttons - nb_buttons / 2;
1083 wv = xmalloc_widget_value ();
1084 wv->name = dialog_name;
1085 wv->help = Qnil;
1087 /* Frame title: 'Q' = Question, 'I' = Information.
1088 Can also have 'E' = Error if, one day, we want
1089 a popup for errors. */
1090 if (NILP (header))
1091 dialog_name[0] = 'Q';
1092 else
1093 dialog_name[0] = 'I';
1095 /* Dialog boxes use a really stupid name encoding
1096 which specifies how many buttons to use
1097 and how many buttons are on the right. */
1098 dialog_name[1] = '0' + nb_buttons;
1099 dialog_name[2] = 'B';
1100 dialog_name[3] = 'R';
1101 /* Number of buttons to put on the right. */
1102 dialog_name[4] = '0' + nb_buttons - left_count;
1103 dialog_name[5] = 0;
1104 wv->contents = first_wv;
1105 first_wv = wv;
1108 /* Actually create the dialog. */
1109 dialog_id = widget_id_tick++;
1110 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1111 f->output_data.w32->widget, 1, 0,
1112 dialog_selection_callback, 0);
1113 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
1115 /* Free the widget_value objects we used to specify the contents. */
1116 free_menubar_widget_value_tree (first_wv);
1118 /* No selection has been chosen yet. */
1119 menu_item_selection = 0;
1121 /* Display the menu. */
1122 lw_pop_up_all_widgets (dialog_id);
1124 /* Process events that apply to the menu. */
1125 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
1127 lw_destroy_all_widgets (dialog_id);
1129 /* Find the selected item, and its pane, to return
1130 the proper value. */
1131 if (menu_item_selection != 0)
1133 Lisp_Object prefix;
1135 prefix = Qnil;
1136 i = 0;
1137 while (i < menu_items_used)
1139 Lisp_Object entry;
1141 if (EQ (AREF (menu_items, i), Qt))
1143 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1144 i += MENU_ITEMS_PANE_LENGTH;
1146 else
1148 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1149 if (menu_item_selection == i)
1151 if (keymaps != 0)
1153 entry = Fcons (entry, Qnil);
1154 if (!NILP (prefix))
1155 entry = Fcons (prefix, entry);
1157 return entry;
1159 i += MENU_ITEMS_ITEM_LENGTH;
1163 else
1164 /* Make "Cancel" equivalent to C-g. */
1165 Fsignal (Qquit, Qnil);
1167 return Qnil;
1169 #else /* !HAVE_DIALOGS */
1171 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1172 simple dialogs. We could handle a few more, but I'm not aware of
1173 anywhere in Emacs that uses the other specific dialog choices that
1174 MessageBox provides. */
1176 static int
1177 is_simple_dialog (Lisp_Object contents)
1179 Lisp_Object options;
1180 Lisp_Object name, yes, no, other;
1182 if (!CONSP (contents))
1183 return 0;
1184 options = XCDR (contents);
1186 yes = build_string ("Yes");
1187 no = build_string ("No");
1189 if (!CONSP (options))
1190 return 0;
1192 name = XCAR (options);
1193 if (!CONSP (name))
1194 return 0;
1195 name = XCAR (name);
1197 if (!NILP (Fstring_equal (name, yes)))
1198 other = no;
1199 else if (!NILP (Fstring_equal (name, no)))
1200 other = yes;
1201 else
1202 return 0;
1204 options = XCDR (options);
1205 if (!CONSP (options))
1206 return 0;
1208 name = XCAR (options);
1209 if (!CONSP (name))
1210 return 0;
1211 name = XCAR (name);
1212 if (NILP (Fstring_equal (name, other)))
1213 return 0;
1215 /* Check there are no more options. */
1216 options = XCDR (options);
1217 return !(CONSP (options));
1220 static Lisp_Object
1221 simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
1223 int answer;
1224 UINT type;
1225 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1227 type = MB_YESNO;
1229 /* Since we only handle Yes/No dialogs, and we already checked
1230 is_simple_dialog, we don't need to worry about checking contents
1231 to see what type of dialog to use. */
1233 /* Use Unicode if possible, so any language can be displayed. */
1234 if (unicode_message_box)
1236 WCHAR *text, *title;
1237 USE_SAFE_ALLOCA;
1239 if (STRINGP (temp))
1241 char *utf8_text = SDATA (ENCODE_UTF_8 (temp));
1242 /* Be pessimistic about the number of characters needed.
1243 Remember characters outside the BMP will take more than
1244 one utf16 word, so we cannot simply use the character
1245 length of temp. */
1246 int utf8_len = strlen (utf8_text);
1247 SAFE_ALLOCA (text, WCHAR *, (utf8_len + 1) * sizeof (WCHAR));
1248 utf8to16 (utf8_text, utf8_len, text);
1250 else
1252 text = L"";
1255 if (NILP (header))
1257 title = L"Question";
1258 type |= MB_ICONQUESTION;
1260 else
1262 title = L"Information";
1263 type |= MB_ICONINFORMATION;
1266 answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
1267 SAFE_FREE ();
1269 else
1271 char *text, *title;
1273 /* Fall back on ANSI message box, but at least use system
1274 encoding so questions representable by the system codepage
1275 are encoded properly. */
1276 if (STRINGP (temp))
1277 text = SDATA (ENCODE_SYSTEM (temp));
1278 else
1279 text = "";
1281 if (NILP (header))
1283 title = "Question";
1284 type |= MB_ICONQUESTION;
1286 else
1288 title = "Information";
1289 type |= MB_ICONINFORMATION;
1292 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1295 if (answer == IDYES)
1296 lispy_answer = build_string ("Yes");
1297 else if (answer == IDNO)
1298 lispy_answer = build_string ("No");
1299 else
1300 Fsignal (Qquit, Qnil);
1302 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1304 Lisp_Object item, name, value;
1305 item = XCAR (temp);
1306 if (CONSP (item))
1308 name = XCAR (item);
1309 value = XCDR (item);
1311 else
1313 name = item;
1314 value = Qnil;
1317 if (!NILP (Fstring_equal (name, lispy_answer)))
1319 return value;
1322 Fsignal (Qquit, Qnil);
1323 return Qnil;
1325 #endif /* !HAVE_DIALOGS */
1328 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1329 static void
1330 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1332 while (len > 0)
1334 if (*src < 0x80)
1336 *dest = (WCHAR) *src;
1337 dest++; src++; len--;
1339 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1340 else if (*src < 0xC0)
1342 src++; len--;
1344 /* 2 char UTF-8 sequence. */
1345 else if (*src < 0xE0)
1347 *dest = (WCHAR) (((*src & 0x1f) << 6)
1348 | (*(src + 1) & 0x3f));
1349 src += 2; len -= 2; dest++;
1351 else if (*src < 0xF0)
1353 *dest = (WCHAR) (((*src & 0x0f) << 12)
1354 | ((*(src + 1) & 0x3f) << 6)
1355 | (*(src + 2) & 0x3f));
1356 src += 3; len -= 3; dest++;
1358 else /* Not encodable. Insert Unicode Substitution char. */
1360 *dest = (WCHAR) 0xfffd;
1361 src++; len--; dest++;
1364 *dest = 0;
1367 static int
1368 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1370 UINT fuFlags;
1371 char *out_string, *p, *q;
1372 int return_value;
1373 size_t nlen, orig_len;
1374 USE_SAFE_ALLOCA;
1376 if (menu_separator_name_p (wv->name))
1378 fuFlags = MF_SEPARATOR;
1379 out_string = NULL;
1381 else
1383 if (wv->enabled)
1384 fuFlags = MF_STRING;
1385 else
1386 fuFlags = MF_STRING | MF_GRAYED;
1388 if (wv->key != NULL)
1390 SAFE_ALLOCA (out_string, char *,
1391 strlen (wv->name) + strlen (wv->key) + 2);
1392 strcpy (out_string, wv->name);
1393 strcat (out_string, "\t");
1394 strcat (out_string, wv->key);
1396 else
1397 out_string = (char *)wv->name;
1399 /* Quote any special characters within the menu item's text and
1400 key binding. */
1401 nlen = orig_len = strlen (out_string);
1402 if (unicode_append_menu)
1404 /* With UTF-8, & cannot be part of a multibyte character. */
1405 for (p = out_string; *p; p++)
1407 if (*p == '&')
1408 nlen++;
1411 else
1413 /* If encoded with the system codepage, use multibyte string
1414 functions in case of multibyte characters that contain '&'. */
1415 for (p = out_string; *p; p = _mbsinc (p))
1417 if (_mbsnextc (p) == '&')
1418 nlen++;
1422 if (nlen > orig_len)
1424 p = out_string;
1425 SAFE_ALLOCA (out_string, char *, nlen + 1);
1426 q = out_string;
1427 while (*p)
1429 if (unicode_append_menu)
1431 if (*p == '&')
1432 *q++ = *p;
1433 *q++ = *p++;
1435 else
1437 if (_mbsnextc (p) == '&')
1439 _mbsncpy (q, p, 1);
1440 q = _mbsinc (q);
1442 _mbsncpy (q, p, 1);
1443 p = _mbsinc (p);
1444 q = _mbsinc (q);
1447 *q = '\0';
1450 if (item != NULL)
1451 fuFlags = MF_POPUP;
1452 else if (wv->title || wv->call_data == 0)
1454 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1455 we can't deallocate the memory otherwise. */
1456 if (get_menu_item_info)
1458 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1459 strcpy (out_string, wv->name);
1460 #ifdef MENU_DEBUG
1461 DebPrint ("Menu: allocating %ld for owner-draw", out_string);
1462 #endif
1463 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1465 else
1466 fuFlags = MF_DISABLED;
1469 /* Draw radio buttons and tickboxes. */
1470 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1471 wv->button_type == BUTTON_TYPE_RADIO))
1472 fuFlags |= MF_CHECKED;
1473 else
1474 fuFlags |= MF_UNCHECKED;
1477 if (unicode_append_menu && out_string)
1479 /* Convert out_string from UTF-8 to UTF-16-LE. */
1480 int utf8_len = strlen (out_string);
1481 WCHAR * utf16_string;
1482 if (fuFlags & MF_OWNERDRAW)
1483 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1484 else
1485 SAFE_ALLOCA (utf16_string, WCHAR *, (utf8_len + 1) * sizeof (WCHAR));
1487 utf8to16 (out_string, utf8_len, utf16_string);
1488 return_value = unicode_append_menu (menu, fuFlags,
1489 item != NULL ? (UINT) item
1490 : (UINT) wv->call_data,
1491 utf16_string);
1492 if (!return_value)
1494 /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
1495 apparently does exist at least in some cases and appears to be
1496 stubbed out to do nothing. out_string is UTF-8, but since
1497 our standard menus are in English and this is only going to
1498 happen the first time a menu is used, the encoding is
1499 of minor importance compared with menus not working at all. */
1500 return_value =
1501 AppendMenu (menu, fuFlags,
1502 item != NULL ? (UINT) item: (UINT) wv->call_data,
1503 out_string);
1504 /* Don't use Unicode menus in future, unless this is Windows
1505 NT or later, where a failure of AppendMenuW does NOT mean
1506 Unicode menus are unsupported. */
1507 if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT)
1508 unicode_append_menu = NULL;
1511 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1512 local_free (out_string);
1514 else
1516 return_value =
1517 AppendMenu (menu,
1518 fuFlags,
1519 item != NULL ? (UINT) item : (UINT) wv->call_data,
1520 out_string );
1523 /* This must be done after the menu item is created. */
1524 if (!wv->title && wv->call_data != 0)
1526 if (set_menu_item_info)
1528 MENUITEMINFO info;
1529 memset (&info, 0, sizeof (info));
1530 info.cbSize = sizeof (info);
1531 info.fMask = MIIM_DATA;
1533 /* Set help string for menu item. Leave it as a Lisp_Object
1534 until it is ready to be displayed, since GC can happen while
1535 menus are active. */
1536 if (!NILP (wv->help))
1537 info.dwItemData = (DWORD) XLI (wv->help);
1538 if (wv->button_type == BUTTON_TYPE_RADIO)
1540 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1541 RADIO items, but is not available on NT 3.51 and earlier. */
1542 info.fMask |= MIIM_TYPE | MIIM_STATE;
1543 info.fType = MFT_RADIOCHECK | MFT_STRING;
1544 info.dwTypeData = out_string;
1545 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1548 set_menu_item_info (menu,
1549 item != NULL ? (UINT) item : (UINT) wv->call_data,
1550 FALSE, &info);
1553 SAFE_FREE ();
1554 return return_value;
1557 /* Construct native Windows menu(bar) based on widget_value tree. */
1558 static int
1559 fill_in_menu (HMENU menu, widget_value *wv)
1561 for ( ; wv != NULL; wv = wv->next)
1563 if (wv->contents)
1565 HMENU sub_menu = CreatePopupMenu ();
1567 if (sub_menu == NULL)
1568 return 0;
1570 if (!fill_in_menu (sub_menu, wv->contents) ||
1571 !add_menu_item (menu, wv, sub_menu))
1573 DestroyMenu (sub_menu);
1574 return 0;
1577 else
1579 if (!add_menu_item (menu, wv, NULL))
1580 return 0;
1583 return 1;
1586 /* Display help string for currently pointed to menu item. Not
1587 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1588 available. */
1589 void
1590 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
1592 if (get_menu_item_info)
1594 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
1595 Lisp_Object frame, help;
1597 /* No help echo on owner-draw menu items, or when the keyboard is used
1598 to navigate the menus, since tooltips are distracting if they pop
1599 up elsewhere. */
1600 if (flags & MF_OWNERDRAW || flags & MF_POPUP
1601 || !(flags & MF_MOUSESELECT))
1602 help = Qnil;
1603 else
1605 MENUITEMINFO info;
1607 memset (&info, 0, sizeof (info));
1608 info.cbSize = sizeof (info);
1609 info.fMask = MIIM_DATA;
1610 get_menu_item_info (menu, item, FALSE, &info);
1612 help = info.dwItemData ? XIL (info.dwItemData) : Qnil;
1615 /* Store the help echo in the keyboard buffer as the X toolkit
1616 version does, rather than directly showing it. This seems to
1617 solve the GC problems that were present when we based the
1618 Windows code on the non-toolkit version. */
1619 if (f)
1621 XSETFRAME (frame, f);
1622 kbd_buffer_store_help_event (frame, help);
1624 else
1625 /* X version has a loop through frames here, which doesn't
1626 appear to do anything, unless it has some side effect. */
1627 show_help_echo (help, Qnil, Qnil, Qnil);
1631 /* Free memory used by owner-drawn strings. */
1632 static void
1633 w32_free_submenu_strings (HMENU menu)
1635 int i, num = GetMenuItemCount (menu);
1636 for (i = 0; i < num; i++)
1638 MENUITEMINFO info;
1639 memset (&info, 0, sizeof (info));
1640 info.cbSize = sizeof (info);
1641 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1643 get_menu_item_info (menu, i, TRUE, &info);
1645 /* Owner-drawn names are held in dwItemData. */
1646 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1648 #ifdef MENU_DEBUG
1649 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1650 #endif
1651 local_free (info.dwItemData);
1654 /* Recurse down submenus. */
1655 if (info.hSubMenu)
1656 w32_free_submenu_strings (info.hSubMenu);
1660 void
1661 w32_free_menu_strings (HWND hwnd)
1663 HMENU menu = current_popup_menu;
1665 if (get_menu_item_info)
1667 /* If there is no popup menu active, free the strings from the frame's
1668 menubar. */
1669 if (!menu)
1670 menu = GetMenu (hwnd);
1672 if (menu)
1673 w32_free_submenu_strings (menu);
1676 current_popup_menu = NULL;
1679 #endif /* HAVE_MENUS */
1681 /* The following is used by delayed window autoselection. */
1683 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1684 doc: /* Return t if a menu or popup dialog is active on selected frame. */)
1685 (void)
1687 #ifdef HAVE_MENUS
1688 FRAME_PTR f;
1689 f = SELECTED_FRAME ();
1690 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1691 #else
1692 return Qnil;
1693 #endif /* HAVE_MENUS */
1696 void
1697 syms_of_w32menu (void)
1699 globals_of_w32menu ();
1701 current_popup_menu = NULL;
1703 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1705 defsubr (&Smenu_or_popup_active_p);
1706 #ifdef HAVE_MENUS
1707 defsubr (&Sx_popup_dialog);
1708 #endif
1712 globals_of_w32menu is used to initialize those global variables that
1713 must always be initialized on startup even when the global variable
1714 initialized is non zero (see the function main in emacs.c).
1715 globals_of_w32menu is called from syms_of_w32menu when the global
1716 variable initialized is 0 and directly from main when initialized
1717 is non zero.
1719 void
1720 globals_of_w32menu (void)
1722 /* See if Get/SetMenuItemInfo functions are available. */
1723 HMODULE user32 = GetModuleHandle ("user32.dll");
1724 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
1725 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
1726 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
1727 unicode_message_box = (MessageBoxW_Proc) GetProcAddress (user32, "MessageBoxW");