gnus-ems.el: Provide compatibility functions for gnus-set-process-plist by Katsumi...
[emacs.git] / src / w32menu.c
blob0ed9bffe70c888e1534a8def969fffbfd01f418f
1 /* Menu support for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1998, 1999, 2001, 2002,
3 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <mbstring.h>
26 #include <setjmp.h>
28 #include "lisp.h"
29 #include "keyboard.h"
30 #include "keymap.h"
31 #include "frame.h"
32 #include "termhooks.h"
33 #include "window.h"
34 #include "blockinput.h"
35 #include "buffer.h"
36 #include "charset.h"
37 #include "character.h"
38 #include "coding.h"
39 #include "menu.h"
41 /* This may include sys/types.h, and that somehow loses
42 if this is not done before the other system files. */
43 #include "w32term.h"
45 /* Load sys/types.h if not already loaded.
46 In some systems loading it twice is suicidal. */
47 #ifndef makedev
48 #include <sys/types.h>
49 #endif
51 #include "dispextern.h"
53 #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
55 #ifndef TRUE
56 #define TRUE 1
57 #define FALSE 0
58 #endif /* no TRUE */
60 HMENU current_popup_menu;
62 void syms_of_w32menu (void);
63 void globals_of_w32menu (void);
65 typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
66 IN HMENU,
67 IN UINT,
68 IN BOOL,
69 IN OUT LPMENUITEMINFOA);
70 typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
71 IN HMENU,
72 IN UINT,
73 IN BOOL,
74 IN LPCMENUITEMINFOA);
75 typedef int (WINAPI * MessageBoxW_Proc) (
76 IN HWND window,
77 IN WCHAR *text,
78 IN WCHAR *caption,
79 IN UINT type);
81 GetMenuItemInfoA_Proc get_menu_item_info = NULL;
82 SetMenuItemInfoA_Proc set_menu_item_info = NULL;
83 AppendMenuW_Proc unicode_append_menu = NULL;
84 MessageBoxW_Proc unicode_message_box = NULL;
86 Lisp_Object Qdebug_on_next_call;
88 extern Lisp_Object Qmenu_bar;
90 extern Lisp_Object QCtoggle, QCradio;
92 extern Lisp_Object Voverriding_local_map;
93 extern Lisp_Object Voverriding_local_map_menu_flag;
95 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
97 extern Lisp_Object Qmenu_bar_update_hook;
99 void set_frame_menubar (FRAME_PTR, int, int);
101 #ifdef HAVE_DIALOGS
102 static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**);
103 #else
104 static int is_simple_dialog (Lisp_Object);
105 static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object);
106 #endif
108 static void utf8to16 (unsigned char *, int, WCHAR *);
110 void w32_free_menu_strings (HWND);
113 /* This is set nonzero after the user activates the menu bar, and set
114 to zero again after the menu bars are redisplayed by prepare_menu_bar.
115 While it is nonzero, all calls to set_frame_menubar go deep.
117 I don't understand why this is needed, but it does seem to be
118 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
120 int pending_menu_activation;
122 #ifdef HAVE_MENUS
124 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
125 doc: /* Pop up a dialog box and return user's selection.
126 POSITION specifies which frame to use.
127 This is normally a mouse button event or a window or frame.
128 If POSITION is t, it means to use the frame the mouse is on.
129 The dialog box appears in the middle of the specified frame.
131 CONTENTS specifies the alternatives to display in the dialog box.
132 It is a list of the form (TITLE ITEM1 ITEM2...).
133 Each ITEM is a cons cell (STRING . VALUE).
134 The return value is VALUE from the chosen item.
136 An ITEM may also be just a string--that makes a nonselectable item.
137 An ITEM may also be nil--that means to put all preceding items
138 on the left of the dialog box and all following items on the right.
139 \(By default, approximately half appear on each side.)
141 If HEADER is non-nil, the frame title for the box is "Information",
142 otherwise it is "Question". */)
143 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
145 FRAME_PTR f = NULL;
146 Lisp_Object window;
148 check_w32 ();
150 /* Decode the first argument: find the window or frame to use. */
151 if (EQ (position, Qt)
152 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
153 || EQ (XCAR (position), Qtool_bar))))
155 #if 0 /* Using the frame the mouse is on may not be right. */
156 /* Use the mouse's current position. */
157 FRAME_PTR new_f = SELECTED_FRAME ();
158 Lisp_Object bar_window;
159 enum scroll_bar_part part;
160 unsigned long time;
161 Lisp_Object x, y;
163 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
165 if (new_f != 0)
166 XSETFRAME (window, new_f);
167 else
168 window = selected_window;
169 #endif
170 window = selected_window;
172 else if (CONSP (position))
174 Lisp_Object tem;
175 tem = Fcar (position);
176 if (CONSP (tem))
177 window = Fcar (Fcdr (position));
178 else
180 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
181 window = Fcar (tem); /* POSN_WINDOW (tem) */
184 else if (WINDOWP (position) || FRAMEP (position))
185 window = position;
186 else
187 window = Qnil;
189 /* Decode where to put the menu. */
191 if (FRAMEP (window))
192 f = XFRAME (window);
193 else if (WINDOWP (window))
195 CHECK_LIVE_WINDOW (window);
196 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
198 else
199 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
200 but I don't want to make one now. */
201 CHECK_WINDOW (window);
203 #ifndef HAVE_DIALOGS
206 /* Handle simple Yes/No choices as MessageBox popups. */
207 if (is_simple_dialog (contents))
208 return simple_dialog_show (f, contents, header);
209 else
211 /* Display a menu with these alternatives
212 in the middle of frame F. */
213 Lisp_Object x, y, frame, newpos;
214 XSETFRAME (frame, f);
215 XSETINT (x, x_pixel_width (f) / 2);
216 XSETINT (y, x_pixel_height (f) / 2);
217 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
218 return Fx_popup_menu (newpos,
219 Fcons (Fcar (contents), Fcons (contents, Qnil)));
222 #else /* HAVE_DIALOGS */
224 Lisp_Object title;
225 char *error_name;
226 Lisp_Object selection;
228 /* Decode the dialog items from what was specified. */
229 title = Fcar (contents);
230 CHECK_STRING (title);
232 list_of_panes (Fcons (contents, Qnil));
234 /* Display them in a dialog box. */
235 BLOCK_INPUT;
236 selection = w32_dialog_show (f, 0, title, header, &error_name);
237 UNBLOCK_INPUT;
239 discard_menu_items ();
240 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
242 if (error_name) error (error_name);
243 return selection;
245 #endif /* HAVE_DIALOGS */
248 /* Activate the menu bar of frame F.
249 This is called from keyboard.c when it gets the
250 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
252 To activate the menu bar, we signal to the input thread that it can
253 return from the WM_INITMENU message, allowing the normal Windows
254 processing of the menus.
256 But first we recompute the menu bar contents (the whole tree).
258 This way we can safely execute Lisp code. */
260 void
261 x_activate_menubar (FRAME_PTR f)
263 set_frame_menubar (f, 0, 1);
265 /* Lock out further menubar changes while active. */
266 f->output_data.w32->menubar_active = 1;
268 /* Signal input thread to return from WM_INITMENU. */
269 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
272 /* This callback is called from the menu bar pulldown menu
273 when the user makes a selection.
274 Figure out what the user chose
275 and put the appropriate events into the keyboard buffer. */
277 void
278 menubar_selection_callback (FRAME_PTR f, void * client_data)
280 Lisp_Object prefix, entry;
281 Lisp_Object vector;
282 Lisp_Object *subprefix_stack;
283 int submenu_depth = 0;
284 int i;
286 if (!f)
287 return;
288 entry = Qnil;
289 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
290 vector = f->menu_bar_vector;
291 prefix = Qnil;
292 i = 0;
293 while (i < f->menu_bar_items_used)
295 if (EQ (AREF (vector, i), Qnil))
297 subprefix_stack[submenu_depth++] = prefix;
298 prefix = entry;
299 i++;
301 else if (EQ (AREF (vector, i), Qlambda))
303 prefix = subprefix_stack[--submenu_depth];
304 i++;
306 else if (EQ (AREF (vector, i), Qt))
308 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
309 i += MENU_ITEMS_PANE_LENGTH;
311 else
313 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
314 /* The EMACS_INT cast avoids a warning. There's no problem
315 as long as pointers have enough bits to hold small integers. */
316 if ((int) (EMACS_INT) client_data == i)
318 int j;
319 struct input_event buf;
320 Lisp_Object frame;
321 EVENT_INIT (buf);
323 XSETFRAME (frame, f);
324 buf.kind = MENU_BAR_EVENT;
325 buf.frame_or_window = frame;
326 buf.arg = frame;
327 kbd_buffer_store_event (&buf);
329 for (j = 0; j < submenu_depth; j++)
330 if (!NILP (subprefix_stack[j]))
332 buf.kind = MENU_BAR_EVENT;
333 buf.frame_or_window = frame;
334 buf.arg = subprefix_stack[j];
335 kbd_buffer_store_event (&buf);
338 if (!NILP (prefix))
340 buf.kind = MENU_BAR_EVENT;
341 buf.frame_or_window = frame;
342 buf.arg = prefix;
343 kbd_buffer_store_event (&buf);
346 buf.kind = MENU_BAR_EVENT;
347 buf.frame_or_window = frame;
348 buf.arg = entry;
349 /* Free memory used by owner-drawn and help-echo strings. */
350 w32_free_menu_strings (FRAME_W32_WINDOW (f));
351 kbd_buffer_store_event (&buf);
353 f->output_data.w32->menubar_active = 0;
354 return;
356 i += MENU_ITEMS_ITEM_LENGTH;
359 /* Free memory used by owner-drawn and help-echo strings. */
360 w32_free_menu_strings (FRAME_W32_WINDOW (f));
361 f->output_data.w32->menubar_active = 0;
365 /* Set the contents of the menubar widgets of frame F.
366 The argument FIRST_TIME is currently ignored;
367 it is set the first time this is called, from initialize_frame_menubar. */
369 void
370 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
372 HMENU menubar_widget = f->output_data.w32->menubar_widget;
373 Lisp_Object items;
374 widget_value *wv, *first_wv, *prev_wv = 0;
375 int i, last_i;
376 int *submenu_start, *submenu_end;
377 int *submenu_top_level_items, *submenu_n_panes;
379 /* We must not change the menubar when actually in use. */
380 if (f->output_data.w32->menubar_active)
381 return;
383 XSETFRAME (Vmenu_updating_frame, f);
385 if (! menubar_widget)
386 deep_p = 1;
387 else if (pending_menu_activation && !deep_p)
388 deep_p = 1;
390 if (deep_p)
392 /* Make a widget-value tree representing the entire menu trees. */
394 struct buffer *prev = current_buffer;
395 Lisp_Object buffer;
396 int specpdl_count = SPECPDL_INDEX ();
397 int previous_menu_items_used = f->menu_bar_items_used;
398 Lisp_Object *previous_items
399 = (Lisp_Object *) alloca (previous_menu_items_used
400 * sizeof (Lisp_Object));
402 /* If we are making a new widget, its contents are empty,
403 do always reinitialize them. */
404 if (! menubar_widget)
405 previous_menu_items_used = 0;
407 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
408 specbind (Qinhibit_quit, Qt);
409 /* Don't let the debugger step into this code
410 because it is not reentrant. */
411 specbind (Qdebug_on_next_call, Qnil);
413 record_unwind_save_match_data ();
415 if (NILP (Voverriding_local_map_menu_flag))
417 specbind (Qoverriding_terminal_local_map, Qnil);
418 specbind (Qoverriding_local_map, Qnil);
421 set_buffer_internal_1 (XBUFFER (buffer));
423 /* Run the hooks. */
424 safe_run_hooks (Qactivate_menubar_hook);
425 safe_run_hooks (Qmenu_bar_update_hook);
426 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
428 items = FRAME_MENU_BAR_ITEMS (f);
430 /* Save the frame's previous menu bar contents data. */
431 if (previous_menu_items_used)
432 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
433 previous_menu_items_used * sizeof (Lisp_Object));
435 /* Fill in menu_items with the current menu bar contents.
436 This can evaluate Lisp code. */
437 save_menu_items ();
439 menu_items = f->menu_bar_vector;
440 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
441 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
442 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
443 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
444 submenu_top_level_items
445 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
446 init_menu_items ();
447 for (i = 0; i < ASIZE (items); i += 4)
449 Lisp_Object key, string, maps;
451 last_i = i;
453 key = AREF (items, i);
454 string = AREF (items, i + 1);
455 maps = AREF (items, i + 2);
456 if (NILP (string))
457 break;
459 submenu_start[i] = menu_items_used;
461 menu_items_n_panes = 0;
462 submenu_top_level_items[i]
463 = parse_single_submenu (key, string, maps);
464 submenu_n_panes[i] = menu_items_n_panes;
466 submenu_end[i] = menu_items_used;
469 finish_menu_items ();
471 /* Convert menu_items into widget_value trees
472 to display the menu. This cannot evaluate Lisp code. */
474 wv = xmalloc_widget_value ();
475 wv->name = "menubar";
476 wv->value = 0;
477 wv->enabled = 1;
478 wv->button_type = BUTTON_TYPE_NONE;
479 wv->help = Qnil;
480 first_wv = wv;
482 for (i = 0; i < last_i; i += 4)
484 menu_items_n_panes = submenu_n_panes[i];
485 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
486 submenu_top_level_items[i]);
487 if (prev_wv)
488 prev_wv->next = wv;
489 else
490 first_wv->contents = wv;
491 /* Don't set wv->name here; GC during the loop might relocate it. */
492 wv->enabled = 1;
493 wv->button_type = BUTTON_TYPE_NONE;
494 prev_wv = wv;
497 set_buffer_internal_1 (prev);
499 /* If there has been no change in the Lisp-level contents
500 of the menu bar, skip redisplaying it. Just exit. */
502 for (i = 0; i < previous_menu_items_used; i++)
503 if (menu_items_used == i
504 || (!EQ (previous_items[i], AREF (menu_items, i))))
505 break;
506 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
508 free_menubar_widget_value_tree (first_wv);
509 discard_menu_items ();
510 unbind_to (specpdl_count, Qnil);
511 return;
514 f->menu_bar_vector = menu_items;
515 f->menu_bar_items_used = menu_items_used;
517 /* This undoes save_menu_items. */
518 unbind_to (specpdl_count, Qnil);
520 /* Now GC cannot happen during the lifetime of the widget_value,
521 so it's safe to store data from a Lisp_String, as long as
522 local copies are made when the actual menu is created.
523 Windows takes care of this for normal string items, but
524 not for owner-drawn items or additional item-info. */
525 wv = first_wv->contents;
526 for (i = 0; i < ASIZE (items); i += 4)
528 Lisp_Object string;
529 string = AREF (items, i + 1);
530 if (NILP (string))
531 break;
532 wv->name = (char *) SDATA (string);
533 update_submenu_strings (wv->contents);
534 wv = wv->next;
537 else
539 /* Make a widget-value tree containing
540 just the top level menu bar strings. */
542 wv = xmalloc_widget_value ();
543 wv->name = "menubar";
544 wv->value = 0;
545 wv->enabled = 1;
546 wv->button_type = BUTTON_TYPE_NONE;
547 wv->help = Qnil;
548 first_wv = wv;
550 items = FRAME_MENU_BAR_ITEMS (f);
551 for (i = 0; i < ASIZE (items); i += 4)
553 Lisp_Object string;
555 string = AREF (items, i + 1);
556 if (NILP (string))
557 break;
559 wv = xmalloc_widget_value ();
560 wv->name = (char *) SDATA (string);
561 wv->value = 0;
562 wv->enabled = 1;
563 wv->button_type = BUTTON_TYPE_NONE;
564 wv->help = Qnil;
565 /* This prevents lwlib from assuming this
566 menu item is really supposed to be empty. */
567 /* The EMACS_INT cast avoids a warning.
568 This value just has to be different from small integers. */
569 wv->call_data = (void *) (EMACS_INT) (-1);
571 if (prev_wv)
572 prev_wv->next = wv;
573 else
574 first_wv->contents = wv;
575 prev_wv = wv;
578 /* Forget what we thought we knew about what is in the
579 detailed contents of the menu bar menus.
580 Changing the top level always destroys the contents. */
581 f->menu_bar_items_used = 0;
584 /* Create or update the menu bar widget. */
586 BLOCK_INPUT;
588 if (menubar_widget)
590 /* Empty current menubar, rather than creating a fresh one. */
591 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
594 else
596 menubar_widget = CreateMenu ();
598 fill_in_menu (menubar_widget, first_wv->contents);
600 free_menubar_widget_value_tree (first_wv);
603 HMENU old_widget = f->output_data.w32->menubar_widget;
605 f->output_data.w32->menubar_widget = menubar_widget;
606 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
607 /* Causes flicker when menu bar is updated
608 DrawMenuBar (FRAME_W32_WINDOW (f)); */
610 /* Force the window size to be recomputed so that the frame's text
611 area remains the same, if menubar has just been created. */
612 if (old_widget == NULL)
613 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
616 UNBLOCK_INPUT;
619 /* Called from Fx_create_frame to create the initial menubar of a frame
620 before it is mapped, so that the window is mapped with the menubar already
621 there instead of us tacking it on later and thrashing the window after it
622 is visible. */
624 void
625 initialize_frame_menubar (FRAME_PTR f)
627 /* This function is called before the first chance to redisplay
628 the frame. It has to be, so the frame will have the right size. */
629 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
630 set_frame_menubar (f, 1, 1);
633 /* Get rid of the menu bar of frame F, and free its storage.
634 This is used when deleting a frame, and when turning off the menu bar. */
636 void
637 free_frame_menubar (FRAME_PTR f)
639 BLOCK_INPUT;
642 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
643 SetMenu (FRAME_W32_WINDOW (f), NULL);
644 f->output_data.w32->menubar_widget = NULL;
645 DestroyMenu (old);
648 UNBLOCK_INPUT;
652 /* w32_menu_show actually displays a menu using the panes and items in
653 menu_items and returns the value selected from it; we assume input
654 is blocked by the caller. */
656 /* F is the frame the menu is for.
657 X and Y are the frame-relative specified position,
658 relative to the inside upper left corner of the frame F.
659 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
660 KEYMAPS is 1 if this menu was specified with keymaps;
661 in that case, we return a list containing the chosen item's value
662 and perhaps also the pane's prefix.
663 TITLE is the specified menu title.
664 ERROR is a place to store an error message string in case of failure.
665 (We return nil on failure, but the value doesn't actually matter.) */
667 Lisp_Object
668 w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
669 Lisp_Object title, const char **error)
671 int i;
672 int menu_item_selection;
673 HMENU menu;
674 POINT pos;
675 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
676 widget_value **submenu_stack
677 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
678 Lisp_Object *subprefix_stack
679 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
680 int submenu_depth = 0;
681 int first_pane;
683 *error = NULL;
685 if (menu_items_n_panes == 0)
686 return Qnil;
688 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
690 *error = "Empty menu";
691 return Qnil;
694 /* Create a tree of widget_value objects
695 representing the panes and their items. */
696 wv = xmalloc_widget_value ();
697 wv->name = "menu";
698 wv->value = 0;
699 wv->enabled = 1;
700 wv->button_type = BUTTON_TYPE_NONE;
701 wv->help = Qnil;
702 first_wv = wv;
703 first_pane = 1;
705 /* Loop over all panes and items, filling in the tree. */
706 i = 0;
707 while (i < menu_items_used)
709 if (EQ (AREF (menu_items, i), Qnil))
711 submenu_stack[submenu_depth++] = save_wv;
712 save_wv = prev_wv;
713 prev_wv = 0;
714 first_pane = 1;
715 i++;
717 else if (EQ (AREF (menu_items, i), Qlambda))
719 prev_wv = save_wv;
720 save_wv = submenu_stack[--submenu_depth];
721 first_pane = 0;
722 i++;
724 else if (EQ (AREF (menu_items, i), Qt)
725 && submenu_depth != 0)
726 i += MENU_ITEMS_PANE_LENGTH;
727 /* Ignore a nil in the item list.
728 It's meaningful only for dialog boxes. */
729 else if (EQ (AREF (menu_items, i), Qquote))
730 i += 1;
731 else if (EQ (AREF (menu_items, i), Qt))
733 /* Create a new pane. */
734 Lisp_Object pane_name, prefix;
735 char *pane_string;
736 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
737 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
739 if (STRINGP (pane_name))
741 if (unicode_append_menu)
742 pane_name = ENCODE_UTF_8 (pane_name);
743 else if (STRING_MULTIBYTE (pane_name))
744 pane_name = ENCODE_SYSTEM (pane_name);
746 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
749 pane_string = (NILP (pane_name)
750 ? "" : (char *) SDATA (pane_name));
751 /* If there is just one top-level pane, put all its items directly
752 under the top-level menu. */
753 if (menu_items_n_panes == 1)
754 pane_string = "";
756 /* If the pane has a meaningful name,
757 make the pane a top-level menu item
758 with its items as a submenu beneath it. */
759 if (!keymaps && strcmp (pane_string, ""))
761 wv = xmalloc_widget_value ();
762 if (save_wv)
763 save_wv->next = wv;
764 else
765 first_wv->contents = wv;
766 wv->name = pane_string;
767 if (keymaps && !NILP (prefix))
768 wv->name++;
769 wv->value = 0;
770 wv->enabled = 1;
771 wv->button_type = BUTTON_TYPE_NONE;
772 wv->help = Qnil;
773 save_wv = wv;
774 prev_wv = 0;
776 else if (first_pane)
778 save_wv = wv;
779 prev_wv = 0;
781 first_pane = 0;
782 i += MENU_ITEMS_PANE_LENGTH;
784 else
786 /* Create a new item within current pane. */
787 Lisp_Object item_name, enable, descrip, def, type, selected, help;
789 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
790 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
791 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
792 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
793 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
794 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
795 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
797 if (STRINGP (item_name))
799 if (unicode_append_menu)
800 item_name = ENCODE_UTF_8 (item_name);
801 else if (STRING_MULTIBYTE (item_name))
802 item_name = ENCODE_SYSTEM (item_name);
804 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
807 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
809 descrip = ENCODE_SYSTEM (descrip);
810 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
813 wv = xmalloc_widget_value ();
814 if (prev_wv)
815 prev_wv->next = wv;
816 else
817 save_wv->contents = wv;
818 wv->name = (char *) SDATA (item_name);
819 if (!NILP (descrip))
820 wv->key = (char *) SDATA (descrip);
821 wv->value = 0;
822 /* Use the contents index as call_data, since we are
823 restricted to 16-bits. */
824 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
825 wv->enabled = !NILP (enable);
827 if (NILP (type))
828 wv->button_type = BUTTON_TYPE_NONE;
829 else if (EQ (type, QCtoggle))
830 wv->button_type = BUTTON_TYPE_TOGGLE;
831 else if (EQ (type, QCradio))
832 wv->button_type = BUTTON_TYPE_RADIO;
833 else
834 abort ();
836 wv->selected = !NILP (selected);
838 if (!STRINGP (help))
839 help = Qnil;
841 wv->help = help;
843 prev_wv = wv;
845 i += MENU_ITEMS_ITEM_LENGTH;
849 /* Deal with the title, if it is non-nil. */
850 if (!NILP (title))
852 widget_value *wv_title = xmalloc_widget_value ();
853 widget_value *wv_sep = xmalloc_widget_value ();
855 /* Maybe replace this separator with a bitmap or owner-draw item
856 so that it looks better. Having two separators looks odd. */
857 wv_sep->name = "--";
858 wv_sep->next = first_wv->contents;
859 wv_sep->help = Qnil;
861 if (unicode_append_menu)
862 title = ENCODE_UTF_8 (title);
863 else if (STRING_MULTIBYTE (title))
864 title = ENCODE_SYSTEM (title);
866 wv_title->name = (char *) SDATA (title);
867 wv_title->enabled = TRUE;
868 wv_title->title = TRUE;
869 wv_title->button_type = BUTTON_TYPE_NONE;
870 wv_title->help = Qnil;
871 wv_title->next = wv_sep;
872 first_wv->contents = wv_title;
875 /* No selection has been chosen yet. */
876 menu_item_selection = 0;
878 /* Actually create the menu. */
879 current_popup_menu = menu = CreatePopupMenu ();
880 fill_in_menu (menu, first_wv->contents);
882 /* Adjust coordinates to be root-window-relative. */
883 pos.x = x;
884 pos.y = y;
885 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
887 /* Display the menu. */
888 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
889 WM_EMACS_TRACKPOPUPMENU,
890 (WPARAM)menu, (LPARAM)&pos);
892 /* Clean up extraneous mouse events which might have been generated
893 during the call. */
894 discard_mouse_events ();
895 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
897 /* Free the widget_value objects we used to specify the contents. */
898 free_menubar_widget_value_tree (first_wv);
900 DestroyMenu (menu);
902 /* Free the owner-drawn and help-echo menu strings. */
903 w32_free_menu_strings (FRAME_W32_WINDOW (f));
904 f->output_data.w32->menubar_active = 0;
906 /* Find the selected item, and its pane, to return
907 the proper value. */
908 if (menu_item_selection != 0)
910 Lisp_Object prefix, entry;
912 prefix = entry = Qnil;
913 i = 0;
914 while (i < menu_items_used)
916 if (EQ (AREF (menu_items, i), Qnil))
918 subprefix_stack[submenu_depth++] = prefix;
919 prefix = entry;
920 i++;
922 else if (EQ (AREF (menu_items, i), Qlambda))
924 prefix = subprefix_stack[--submenu_depth];
925 i++;
927 else if (EQ (AREF (menu_items, i), Qt))
929 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
930 i += MENU_ITEMS_PANE_LENGTH;
932 /* Ignore a nil in the item list.
933 It's meaningful only for dialog boxes. */
934 else if (EQ (AREF (menu_items, i), Qquote))
935 i += 1;
936 else
938 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
939 if (menu_item_selection == i)
941 if (keymaps != 0)
943 int j;
945 entry = Fcons (entry, Qnil);
946 if (!NILP (prefix))
947 entry = Fcons (prefix, entry);
948 for (j = submenu_depth - 1; j >= 0; j--)
949 if (!NILP (subprefix_stack[j]))
950 entry = Fcons (subprefix_stack[j], entry);
952 return entry;
954 i += MENU_ITEMS_ITEM_LENGTH;
958 else if (!for_click)
959 /* Make "Cancel" equivalent to C-g. */
960 Fsignal (Qquit, Qnil);
962 return Qnil;
966 #ifdef HAVE_DIALOGS
967 /* TODO: On Windows, there are two ways of defining a dialog.
969 1. Create a predefined dialog resource and include it in nt/emacs.rc.
970 Using this method, we could then set the titles and make unneeded
971 buttons invisible before displaying the dialog. Everything would
972 be a fixed size though, so there is a risk that text does not
973 fit on a button.
974 2. Create the dialog template in memory on the fly. This allows us
975 to size the dialog and buttons dynamically, probably giving more
976 natural looking results for dialogs with few buttons, and eliminating
977 the problem of text overflowing the buttons. But the API for this is
978 quite complex - structures have to be allocated in particular ways,
979 text content is tacked onto the end of structures in variable length
980 arrays with further structures tacked on after these, there are
981 certain alignment requirements for all this, and we have to
982 measure all the text and convert to "dialog coordinates" to figure
983 out how big to make everything.
985 For now, we'll just stick with menus for dialogs that are more
986 complicated than simple yes/no type questions for which we can use
987 the MessageBox function.
990 static char * button_names [] = {
991 "button1", "button2", "button3", "button4", "button5",
992 "button6", "button7", "button8", "button9", "button10" };
994 static Lisp_Object
995 w32_dialog_show (FRAME_PTR f, int keymaps,
996 Lisp_Object title, Lisp_Object header,
997 char **error)
999 int i, nb_buttons=0;
1000 char dialog_name[6];
1001 int menu_item_selection;
1003 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1005 /* Number of elements seen so far, before boundary. */
1006 int left_count = 0;
1007 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1008 int boundary_seen = 0;
1010 *error = NULL;
1012 if (menu_items_n_panes > 1)
1014 *error = "Multiple panes in dialog box";
1015 return Qnil;
1018 /* Create a tree of widget_value objects
1019 representing the text label and buttons. */
1021 Lisp_Object pane_name, prefix;
1022 char *pane_string;
1023 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1024 prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
1025 pane_string = (NILP (pane_name)
1026 ? "" : (char *) SDATA (pane_name));
1027 prev_wv = xmalloc_widget_value ();
1028 prev_wv->value = pane_string;
1029 if (keymaps && !NILP (prefix))
1030 prev_wv->name++;
1031 prev_wv->enabled = 1;
1032 prev_wv->name = "message";
1033 prev_wv->help = Qnil;
1034 first_wv = prev_wv;
1036 /* Loop over all panes and items, filling in the tree. */
1037 i = MENU_ITEMS_PANE_LENGTH;
1038 while (i < menu_items_used)
1041 /* Create a new item within current pane. */
1042 Lisp_Object item_name, enable, descrip, help;
1044 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1045 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1046 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1047 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1049 if (NILP (item_name))
1051 free_menubar_widget_value_tree (first_wv);
1052 *error = "Submenu in dialog items";
1053 return Qnil;
1055 if (EQ (item_name, Qquote))
1057 /* This is the boundary between left-side elts
1058 and right-side elts. Stop incrementing right_count. */
1059 boundary_seen = 1;
1060 i++;
1061 continue;
1063 if (nb_buttons >= 9)
1065 free_menubar_widget_value_tree (first_wv);
1066 *error = "Too many dialog items";
1067 return Qnil;
1070 wv = xmalloc_widget_value ();
1071 prev_wv->next = wv;
1072 wv->name = (char *) button_names[nb_buttons];
1073 if (!NILP (descrip))
1074 wv->key = (char *) SDATA (descrip);
1075 wv->value = (char *) SDATA (item_name);
1076 wv->call_data = (void *) &AREF (menu_items, i);
1077 wv->enabled = !NILP (enable);
1078 wv->help = Qnil;
1079 prev_wv = wv;
1081 if (! boundary_seen)
1082 left_count++;
1084 nb_buttons++;
1085 i += MENU_ITEMS_ITEM_LENGTH;
1088 /* If the boundary was not specified,
1089 by default put half on the left and half on the right. */
1090 if (! boundary_seen)
1091 left_count = nb_buttons - nb_buttons / 2;
1093 wv = xmalloc_widget_value ();
1094 wv->name = dialog_name;
1095 wv->help = Qnil;
1097 /* Frame title: 'Q' = Question, 'I' = Information.
1098 Can also have 'E' = Error if, one day, we want
1099 a popup for errors. */
1100 if (NILP (header))
1101 dialog_name[0] = 'Q';
1102 else
1103 dialog_name[0] = 'I';
1105 /* Dialog boxes use a really stupid name encoding
1106 which specifies how many buttons to use
1107 and how many buttons are on the right. */
1108 dialog_name[1] = '0' + nb_buttons;
1109 dialog_name[2] = 'B';
1110 dialog_name[3] = 'R';
1111 /* Number of buttons to put on the right. */
1112 dialog_name[4] = '0' + nb_buttons - left_count;
1113 dialog_name[5] = 0;
1114 wv->contents = first_wv;
1115 first_wv = wv;
1118 /* Actually create the dialog. */
1119 dialog_id = widget_id_tick++;
1120 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1121 f->output_data.w32->widget, 1, 0,
1122 dialog_selection_callback, 0);
1123 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
1125 /* Free the widget_value objects we used to specify the contents. */
1126 free_menubar_widget_value_tree (first_wv);
1128 /* No selection has been chosen yet. */
1129 menu_item_selection = 0;
1131 /* Display the menu. */
1132 lw_pop_up_all_widgets (dialog_id);
1134 /* Process events that apply to the menu. */
1135 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
1137 lw_destroy_all_widgets (dialog_id);
1139 /* Find the selected item, and its pane, to return
1140 the proper value. */
1141 if (menu_item_selection != 0)
1143 Lisp_Object prefix;
1145 prefix = Qnil;
1146 i = 0;
1147 while (i < menu_items_used)
1149 Lisp_Object entry;
1151 if (EQ (AREF (menu_items, i), Qt))
1153 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1154 i += MENU_ITEMS_PANE_LENGTH;
1156 else
1158 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1159 if (menu_item_selection == i)
1161 if (keymaps != 0)
1163 entry = Fcons (entry, Qnil);
1164 if (!NILP (prefix))
1165 entry = Fcons (prefix, entry);
1167 return entry;
1169 i += MENU_ITEMS_ITEM_LENGTH;
1173 else
1174 /* Make "Cancel" equivalent to C-g. */
1175 Fsignal (Qquit, Qnil);
1177 return Qnil;
1179 #else /* !HAVE_DIALOGS */
1181 /* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1182 simple dialogs. We could handle a few more, but I'm not aware of
1183 anywhere in Emacs that uses the other specific dialog choices that
1184 MessageBox provides. */
1186 static int
1187 is_simple_dialog (Lisp_Object contents)
1189 Lisp_Object options = XCDR (contents);
1190 Lisp_Object name, yes, no, other;
1192 yes = build_string ("Yes");
1193 no = build_string ("No");
1195 if (!CONSP (options))
1196 return 0;
1198 name = XCAR (XCAR (options));
1199 if (!CONSP (options))
1200 return 0;
1202 if (!NILP (Fstring_equal (name, yes)))
1203 other = no;
1204 else if (!NILP (Fstring_equal (name, no)))
1205 other = yes;
1206 else
1207 return 0;
1209 options = XCDR (options);
1210 if (!CONSP (options))
1211 return 0;
1213 name = XCAR (XCAR (options));
1214 if (NILP (Fstring_equal (name, other)))
1215 return 0;
1217 /* Check there are no more options. */
1218 options = XCDR (options);
1219 return !(CONSP (options));
1222 static Lisp_Object
1223 simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
1225 int answer;
1226 UINT type;
1227 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1229 type = MB_YESNO;
1231 /* Since we only handle Yes/No dialogs, and we already checked
1232 is_simple_dialog, we don't need to worry about checking contents
1233 to see what type of dialog to use. */
1235 /* Use unicode if possible, so any language can be displayed. */
1236 if (unicode_message_box)
1238 WCHAR *text, *title;
1240 if (STRINGP (temp))
1242 char *utf8_text = SDATA (ENCODE_UTF_8 (temp));
1243 /* Be pessimistic about the number of characters needed.
1244 Remember characters outside the BMP will take more than
1245 one utf16 word, so we cannot simply use the character
1246 length of temp. */
1247 int utf8_len = strlen (utf8_text);
1248 text = alloca ((utf8_len + 1) * sizeof (WCHAR));
1249 utf8to16 (utf8_text, utf8_len, text);
1251 else
1253 text = L"";
1256 if (NILP (header))
1258 title = L"Question";
1259 type |= MB_ICONQUESTION;
1261 else
1263 title = L"Information";
1264 type |= MB_ICONINFORMATION;
1267 answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
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 /* Is this item a separator? */
1329 static int
1330 name_is_separator (const char *name)
1332 const char *start = name;
1334 /* Check if name string consists of only dashes ('-'). */
1335 while (*name == '-') name++;
1336 /* Separators can also be of the form "--:TripleSuperMegaEtched"
1337 or "--deep-shadow". We don't implement them yet, se we just treat
1338 them like normal separators. */
1339 return (*name == '\0' || start + 2 == name);
1342 /* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1343 static void
1344 utf8to16 (unsigned char * src, int len, WCHAR * dest)
1346 while (len > 0)
1348 int utf16;
1349 if (*src < 0x80)
1351 *dest = (WCHAR) *src;
1352 dest++; src++; len--;
1354 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1355 else if (*src < 0xC0)
1357 src++; len--;
1359 /* 2 char UTF-8 sequence. */
1360 else if (*src < 0xE0)
1362 *dest = (WCHAR) (((*src & 0x1f) << 6)
1363 | (*(src + 1) & 0x3f));
1364 src += 2; len -= 2; dest++;
1366 else if (*src < 0xF0)
1368 *dest = (WCHAR) (((*src & 0x0f) << 12)
1369 | ((*(src + 1) & 0x3f) << 6)
1370 | (*(src + 2) & 0x3f));
1371 src += 3; len -= 3; dest++;
1373 else /* Not encodable. Insert Unicode Substitution char. */
1375 *dest = (WCHAR) 0xfffd;
1376 src++; len--; dest++;
1379 *dest = 0;
1382 static int
1383 add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1385 UINT fuFlags;
1386 char *out_string, *p, *q;
1387 int return_value;
1388 size_t nlen, orig_len;
1390 if (name_is_separator (wv->name))
1392 fuFlags = MF_SEPARATOR;
1393 out_string = NULL;
1395 else
1397 if (wv->enabled)
1398 fuFlags = MF_STRING;
1399 else
1400 fuFlags = MF_STRING | MF_GRAYED;
1402 if (wv->key != NULL)
1404 out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2);
1405 strcpy (out_string, wv->name);
1406 strcat (out_string, "\t");
1407 strcat (out_string, wv->key);
1409 else
1410 out_string = (char *)wv->name;
1412 /* Quote any special characters within the menu item's text and
1413 key binding. */
1414 nlen = orig_len = strlen (out_string);
1415 if (unicode_append_menu)
1417 /* With UTF-8, & cannot be part of a multibyte character. */
1418 for (p = out_string; *p; p++)
1420 if (*p == '&')
1421 nlen++;
1424 else
1426 /* If encoded with the system codepage, use multibyte string
1427 functions in case of multibyte characters that contain '&'. */
1428 for (p = out_string; *p; p = _mbsinc (p))
1430 if (_mbsnextc (p) == '&')
1431 nlen++;
1435 if (nlen > orig_len)
1437 p = out_string;
1438 out_string = alloca (nlen + 1);
1439 q = out_string;
1440 while (*p)
1442 if (unicode_append_menu)
1444 if (*p == '&')
1445 *q++ = *p;
1446 *q++ = *p++;
1448 else
1450 if (_mbsnextc (p) == '&')
1452 _mbsncpy (q, p, 1);
1453 q = _mbsinc (q);
1455 _mbsncpy (q, p, 1);
1456 p = _mbsinc (p);
1457 q = _mbsinc (q);
1460 *q = '\0';
1463 if (item != NULL)
1464 fuFlags = MF_POPUP;
1465 else if (wv->title || wv->call_data == 0)
1467 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1468 we can't deallocate the memory otherwise. */
1469 if (get_menu_item_info)
1471 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1472 strcpy (out_string, wv->name);
1473 #ifdef MENU_DEBUG
1474 DebPrint ("Menu: allocing %ld for owner-draw", out_string);
1475 #endif
1476 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1478 else
1479 fuFlags = MF_DISABLED;
1482 /* Draw radio buttons and tickboxes. */
1483 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
1484 wv->button_type == BUTTON_TYPE_RADIO))
1485 fuFlags |= MF_CHECKED;
1486 else
1487 fuFlags |= MF_UNCHECKED;
1490 if (unicode_append_menu && out_string)
1492 /* Convert out_string from UTF-8 to UTF-16-LE. */
1493 int utf8_len = strlen (out_string);
1494 WCHAR * utf16_string;
1495 if (fuFlags & MF_OWNERDRAW)
1496 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1497 else
1498 utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR));
1500 utf8to16 (out_string, utf8_len, utf16_string);
1501 return_value = unicode_append_menu (menu, fuFlags,
1502 item != NULL ? (UINT) item
1503 : (UINT) wv->call_data,
1504 utf16_string);
1505 if (!return_value)
1507 /* On W9x/ME, unicode menus are not supported, though AppendMenuW
1508 apparently does exist at least in some cases and appears to be
1509 stubbed out to do nothing. out_string is UTF-8, but since
1510 our standard menus are in English and this is only going to
1511 happen the first time a menu is used, the encoding is
1512 of minor importance compared with menus not working at all. */
1513 return_value =
1514 AppendMenu (menu, fuFlags,
1515 item != NULL ? (UINT) item: (UINT) wv->call_data,
1516 out_string);
1517 /* Don't use unicode menus in future. */
1518 unicode_append_menu = NULL;
1521 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1522 local_free (out_string);
1524 else
1526 return_value =
1527 AppendMenu (menu,
1528 fuFlags,
1529 item != NULL ? (UINT) item : (UINT) wv->call_data,
1530 out_string );
1533 /* This must be done after the menu item is created. */
1534 if (!wv->title && wv->call_data != 0)
1536 if (set_menu_item_info)
1538 MENUITEMINFO info;
1539 memset (&info, 0, sizeof (info));
1540 info.cbSize = sizeof (info);
1541 info.fMask = MIIM_DATA;
1543 /* Set help string for menu item. Leave it as a Lisp_Object
1544 until it is ready to be displayed, since GC can happen while
1545 menus are active. */
1546 if (!NILP (wv->help))
1547 #ifdef USE_LISP_UNION_TYPE
1548 info.dwItemData = (DWORD) (wv->help).i;
1549 #else
1550 info.dwItemData = (DWORD) (wv->help);
1551 #endif
1552 if (wv->button_type == BUTTON_TYPE_RADIO)
1554 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1555 RADIO items, but is not available on NT 3.51 and earlier. */
1556 info.fMask |= MIIM_TYPE | MIIM_STATE;
1557 info.fType = MFT_RADIOCHECK | MFT_STRING;
1558 info.dwTypeData = out_string;
1559 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1562 set_menu_item_info (menu,
1563 item != NULL ? (UINT) item : (UINT) wv->call_data,
1564 FALSE, &info);
1567 return return_value;
1570 /* Construct native Windows menu(bar) based on widget_value tree. */
1572 fill_in_menu (HMENU menu, widget_value *wv)
1574 int items_added = 0;
1576 for ( ; wv != NULL; wv = wv->next)
1578 if (wv->contents)
1580 HMENU sub_menu = CreatePopupMenu ();
1582 if (sub_menu == NULL)
1583 return 0;
1585 if (!fill_in_menu (sub_menu, wv->contents) ||
1586 !add_menu_item (menu, wv, sub_menu))
1588 DestroyMenu (sub_menu);
1589 return 0;
1592 else
1594 if (!add_menu_item (menu, wv, NULL))
1595 return 0;
1598 return 1;
1601 /* Display help string for currently pointed to menu item. Not
1602 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1603 available. */
1604 void
1605 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
1607 if (get_menu_item_info)
1609 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
1610 Lisp_Object frame, help;
1612 /* No help echo on owner-draw menu items, or when the keyboard is used
1613 to navigate the menus, since tooltips are distracting if they pop
1614 up elsewhere. */
1615 if (flags & MF_OWNERDRAW || flags & MF_POPUP
1616 || !(flags & MF_MOUSESELECT))
1617 help = Qnil;
1618 else
1620 MENUITEMINFO info;
1622 memset (&info, 0, sizeof (info));
1623 info.cbSize = sizeof (info);
1624 info.fMask = MIIM_DATA;
1625 get_menu_item_info (menu, item, FALSE, &info);
1627 #ifdef USE_LISP_UNION_TYPE
1628 help = info.dwItemData ? (Lisp_Object) ((EMACS_INT) info.dwItemData)
1629 : Qnil;
1630 #else
1631 help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
1632 #endif
1635 /* Store the help echo in the keyboard buffer as the X toolkit
1636 version does, rather than directly showing it. This seems to
1637 solve the GC problems that were present when we based the
1638 Windows code on the non-toolkit version. */
1639 if (f)
1641 XSETFRAME (frame, f);
1642 kbd_buffer_store_help_event (frame, help);
1644 else
1645 /* X version has a loop through frames here, which doesn't
1646 appear to do anything, unless it has some side effect. */
1647 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1651 /* Free memory used by owner-drawn strings. */
1652 static void
1653 w32_free_submenu_strings (HMENU menu)
1655 int i, num = GetMenuItemCount (menu);
1656 for (i = 0; i < num; i++)
1658 MENUITEMINFO info;
1659 memset (&info, 0, sizeof (info));
1660 info.cbSize = sizeof (info);
1661 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
1663 get_menu_item_info (menu, i, TRUE, &info);
1665 /* Owner-drawn names are held in dwItemData. */
1666 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1668 #ifdef MENU_DEBUG
1669 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1670 #endif
1671 local_free (info.dwItemData);
1674 /* Recurse down submenus. */
1675 if (info.hSubMenu)
1676 w32_free_submenu_strings (info.hSubMenu);
1680 void
1681 w32_free_menu_strings (HWND hwnd)
1683 HMENU menu = current_popup_menu;
1685 if (get_menu_item_info)
1687 /* If there is no popup menu active, free the strings from the frame's
1688 menubar. */
1689 if (!menu)
1690 menu = GetMenu (hwnd);
1692 if (menu)
1693 w32_free_submenu_strings (menu);
1696 current_popup_menu = NULL;
1699 #endif /* HAVE_MENUS */
1701 /* The following is used by delayed window autoselection. */
1703 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1704 doc: /* Return t if a menu or popup dialog is active on selected frame. */)
1705 (void)
1707 #ifdef HAVE_MENUS
1708 FRAME_PTR f;
1709 f = SELECTED_FRAME ();
1710 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1711 #else
1712 return Qnil;
1713 #endif /* HAVE_MENUS */
1716 void
1717 syms_of_w32menu (void)
1719 globals_of_w32menu ();
1721 current_popup_menu = NULL;
1723 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
1725 defsubr (&Smenu_or_popup_active_p);
1726 #ifdef HAVE_MENUS
1727 defsubr (&Sx_popup_dialog);
1728 #endif
1732 globals_of_w32menu is used to initialize those global variables that
1733 must always be initialized on startup even when the global variable
1734 initialized is non zero (see the function main in emacs.c).
1735 globals_of_w32menu is called from syms_of_w32menu when the global
1736 variable initialized is 0 and directly from main when initialized
1737 is non zero.
1739 void
1740 globals_of_w32menu (void)
1742 /* See if Get/SetMenuItemInfo functions are available. */
1743 HMODULE user32 = GetModuleHandle ("user32.dll");
1744 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
1745 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
1746 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
1747 unicode_message_box = (MessageBoxW_Proc) GetProcAddress (user32, "MessageBoxW");
1750 /* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0
1751 (do not change this comment) */