A few more naming-convention fixes for getters and setters.
[bpt/emacs.git] / src / w32menu.c
CommitLineData
b46a6a83 1/* Menu support for GNU Emacs on the Microsoft Windows API.
acaf905b 2 Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2012
8cabe764 3 Free Software Foundation, Inc.
ee78dc32
GV
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
ee78dc32 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
ee78dc32
GV
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
ee78dc32 19
ee78dc32 20#include <config.h>
162d2499 21
7ab7006c 22#include <signal.h>
ee78dc32 23#include <stdio.h>
af41f8a8 24#include <mbstring.h>
d7306fe6 25#include <setjmp.h>
7ab7006c 26
ee78dc32 27#include "lisp.h"
15d36dee 28#include "keyboard.h"
5ee707b8 29#include "keymap.h"
ee78dc32 30#include "frame.h"
7ab7006c 31#include "termhooks.h"
ee78dc32 32#include "window.h"
ee78dc32 33#include "blockinput.h"
e5560ff7 34#include "character.h"
fdc12c4d 35#include "buffer.h"
6915ded0
JR
36#include "charset.h"
37#include "coding.h"
ef7417fd 38#include "menu.h"
ee78dc32
GV
39
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"
43
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
49
50#include "dispextern.h"
51
1c6900d9
EZ
52#include "w32heap.h" /* for osinfo_cache */
53
222456a1 54#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
162d2499 55
485015ca
GV
56#ifndef TRUE
57#define TRUE 1
58#define FALSE 0
59#endif /* no TRUE */
60
b2a916a0 61HMENU current_popup_menu;
ace9b298 62
b56ceb92
JB
63void syms_of_w32menu (void);
64void globals_of_w32menu (void);
f60ae425
BK
65
66typedef BOOL (WINAPI * GetMenuItemInfoA_Proc) (
67 IN HMENU,
68 IN UINT,
69 IN BOOL,
1f06d367 70 IN OUT LPMENUITEMINFOA);
f60ae425
BK
71typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
72 IN HMENU,
73 IN UINT,
74 IN BOOL,
1f06d367 75 IN LPCMENUITEMINFOA);
1c9b4129
JR
76typedef int (WINAPI * MessageBoxW_Proc) (
77 IN HWND window,
78 IN WCHAR *text,
79 IN WCHAR *caption,
80 IN UINT type);
f60ae425 81
1f06d367
JR
82GetMenuItemInfoA_Proc get_menu_item_info = NULL;
83SetMenuItemInfoA_Proc set_menu_item_info = NULL;
84AppendMenuW_Proc unicode_append_menu = NULL;
1c9b4129 85MessageBoxW_Proc unicode_message_box = NULL;
ace9b298 86
fdc12c4d
RS
87Lisp_Object Qdebug_on_next_call;
88
f57e2426 89void set_frame_menubar (FRAME_PTR, int, int);
014510b0 90
1c5acb8c 91#ifdef HAVE_DIALOGS
f57e2426 92static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**);
31403b24 93#else
f57e2426
J
94static int is_simple_dialog (Lisp_Object);
95static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object);
1c5acb8c 96#endif
31403b24 97
1c9b4129 98static void utf8to16 (unsigned char *, int, WCHAR *);
24f981c9 99static int fill_in_menu (HMENU, widget_value *);
1c9b4129 100
f57e2426 101void w32_free_menu_strings (HWND);
485015ca 102\f
6fc032ed 103
485015ca
GV
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.
107
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>. */
ee78dc32 110
485015ca
GV
111int pending_menu_activation;
112\f
485015ca
GV
113#ifdef HAVE_MENUS
114
16b12668 115DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
33f09670
JR
116 doc: /* Pop up a dialog box and return user's selection.
117POSITION specifies which frame to use.
118This is normally a mouse button event or a window or frame.
119If POSITION is t, it means to use the frame the mouse is on.
120The dialog box appears in the middle of the specified frame.
121
122CONTENTS specifies the alternatives to display in the dialog box.
123It is a list of the form (TITLE ITEM1 ITEM2...).
124Each ITEM is a cons cell (STRING . VALUE).
125The return value is VALUE from the chosen item.
126
127An ITEM may also be just a string--that makes a nonselectable item.
128An ITEM may also be nil--that means to put all preceding items
129on the left of the dialog box and all following items on the right.
d23928c7
NR
130\(By default, approximately half appear on each side.)
131
132If HEADER is non-nil, the frame title for the box is "Information",
133otherwise it is "Question". */)
5842a27b 134 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
ee78dc32 135{
b2123f81 136 FRAME_PTR f = NULL;
ee78dc32 137 Lisp_Object window;
485015ca
GV
138
139 check_w32 ();
140
ee78dc32 141 /* Decode the first argument: find the window or frame to use. */
485015ca 142 if (EQ (position, Qt)
0b6bb670
JR
143 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
144 || EQ (XCAR (position), Qtool_bar))))
ee78dc32 145 {
485015ca
GV
146#if 0 /* Using the frame the mouse is on may not be right. */
147 /* Use the mouse's current position. */
162d2499 148 FRAME_PTR new_f = SELECTED_FRAME ();
485015ca 149 Lisp_Object bar_window;
15d36dee 150 enum scroll_bar_part part;
07156b35 151 Time time;
485015ca
GV
152 Lisp_Object x, y;
153
154 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
155
156 if (new_f != 0)
157 XSETFRAME (window, new_f);
158 else
ee78dc32 159 window = selected_window;
485015ca
GV
160#endif
161 window = selected_window;
ee78dc32
GV
162 }
163 else if (CONSP (position))
164 {
7d7bbefd 165 Lisp_Object tem = XCAR (position);
485015ca 166 if (CONSP (tem))
34348bd4 167 window = Fcar (XCDR (position));
ee78dc32
GV
168 else
169 {
34348bd4 170 tem = Fcar (XCDR (position)); /* EVENT_START (position) */
485015ca 171 window = Fcar (tem); /* POSN_WINDOW (tem) */
ee78dc32
GV
172 }
173 }
174 else if (WINDOWP (position) || FRAMEP (position))
175 window = position;
485015ca
GV
176 else
177 window = Qnil;
178
ee78dc32 179 /* Decode where to put the menu. */
485015ca 180
ee78dc32
GV
181 if (FRAMEP (window))
182 f = XFRAME (window);
183 else if (WINDOWP (window))
184 {
b7826503 185 CHECK_LIVE_WINDOW (window);
ee78dc32
GV
186 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
187 }
188 else
189 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
190 but I don't want to make one now. */
b7826503 191 CHECK_WINDOW (window);
485015ca 192
162d2499 193#ifndef HAVE_DIALOGS
31403b24 194
ee78dc32 195 {
31403b24
JR
196 /* Handle simple Yes/No choices as MessageBox popups. */
197 if (is_simple_dialog (contents))
198 return simple_dialog_show (f, contents, header);
199 else
200 {
201 /* Display a menu with these alternatives
202 in the middle of frame F. */
203 Lisp_Object x, y, frame, newpos;
204 XSETFRAME (frame, f);
205 XSETINT (x, x_pixel_width (f) / 2);
206 XSETINT (y, x_pixel_height (f) / 2);
207 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
208 return Fx_popup_menu (newpos,
209 Fcons (Fcar (contents), Fcons (contents, Qnil)));
210 }
ee78dc32 211 }
162d2499 212#else /* HAVE_DIALOGS */
ee78dc32
GV
213 {
214 Lisp_Object title;
215 char *error_name;
216 Lisp_Object selection;
217
218 /* Decode the dialog items from what was specified. */
219 title = Fcar (contents);
b7826503 220 CHECK_STRING (title);
ee78dc32
GV
221
222 list_of_panes (Fcons (contents, Qnil));
223
224 /* Display them in a dialog box. */
225 BLOCK_INPUT;
d23928c7 226 selection = w32_dialog_show (f, 0, title, header, &error_name);
ee78dc32
GV
227 UNBLOCK_INPUT;
228
229 discard_menu_items ();
38f2b112 230 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
ee78dc32
GV
231
232 if (error_name) error (error_name);
233 return selection;
234 }
162d2499 235#endif /* HAVE_DIALOGS */
ee78dc32
GV
236}
237
014510b0
GV
238/* Activate the menu bar of frame F.
239 This is called from keyboard.c when it gets the
3b8f9651 240 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
014510b0
GV
241
242 To activate the menu bar, we signal to the input thread that it can
243 return from the WM_INITMENU message, allowing the normal Windows
244 processing of the menus.
245
246 But first we recompute the menu bar contents (the whole tree).
247
248 This way we can safely execute Lisp code. */
177c0ea7 249
162d2499 250void
b56ceb92 251x_activate_menubar (FRAME_PTR f)
014510b0
GV
252{
253 set_frame_menubar (f, 0, 1);
254
255 /* Lock out further menubar changes while active. */
256 f->output_data.w32->menubar_active = 1;
257
258 /* Signal input thread to return from WM_INITMENU. */
259 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
260}
261
485015ca
GV
262/* This callback is called from the menu bar pulldown menu
263 when the user makes a selection.
264 Figure out what the user chose
265 and put the appropriate events into the keyboard buffer. */
266
267void
268menubar_selection_callback (FRAME_PTR f, void * client_data)
ee78dc32 269{
485015ca
GV
270 Lisp_Object prefix, entry;
271 Lisp_Object vector;
272 Lisp_Object *subprefix_stack;
273 int submenu_depth = 0;
ee78dc32 274 int i;
fdc12c4d 275
485015ca 276 if (!f)
014510b0 277 return;
fe5a0162 278 entry = Qnil;
663e2b3f 279 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
e69b0960 280 vector = f->menu_bar_vector;
485015ca
GV
281 prefix = Qnil;
282 i = 0;
283 while (i < f->menu_bar_items_used)
284 {
6ed09cf0 285 if (EQ (AREF (vector, i), Qnil))
485015ca
GV
286 {
287 subprefix_stack[submenu_depth++] = prefix;
288 prefix = entry;
289 i++;
290 }
6ed09cf0 291 else if (EQ (AREF (vector, i), Qlambda))
485015ca
GV
292 {
293 prefix = subprefix_stack[--submenu_depth];
294 i++;
295 }
6ed09cf0 296 else if (EQ (AREF (vector, i), Qt))
485015ca 297 {
6ed09cf0 298 prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
485015ca
GV
299 i += MENU_ITEMS_PANE_LENGTH;
300 }
301 else
302 {
6ed09cf0 303 entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
485015ca
GV
304 /* The EMACS_INT cast avoids a warning. There's no problem
305 as long as pointers have enough bits to hold small integers. */
306 if ((int) (EMACS_INT) client_data == i)
307 {
308 int j;
309 struct input_event buf;
310 Lisp_Object frame;
f456401b 311 EVENT_INIT (buf);
014510b0 312
485015ca 313 XSETFRAME (frame, f);
20501278
GM
314 buf.kind = MENU_BAR_EVENT;
315 buf.frame_or_window = frame;
316 buf.arg = frame;
485015ca 317 kbd_buffer_store_event (&buf);
014510b0 318
485015ca
GV
319 for (j = 0; j < submenu_depth; j++)
320 if (!NILP (subprefix_stack[j]))
321 {
20501278
GM
322 buf.kind = MENU_BAR_EVENT;
323 buf.frame_or_window = frame;
324 buf.arg = subprefix_stack[j];
485015ca
GV
325 kbd_buffer_store_event (&buf);
326 }
fdc12c4d 327
485015ca
GV
328 if (!NILP (prefix))
329 {
20501278
GM
330 buf.kind = MENU_BAR_EVENT;
331 buf.frame_or_window = frame;
332 buf.arg = prefix;
485015ca
GV
333 kbd_buffer_store_event (&buf);
334 }
fdc12c4d 335
20501278
GM
336 buf.kind = MENU_BAR_EVENT;
337 buf.frame_or_window = frame;
338 buf.arg = entry;
71f6b295
JR
339 /* Free memory used by owner-drawn and help-echo strings. */
340 w32_free_menu_strings (FRAME_W32_WINDOW (f));
b2a916a0
JR
341 kbd_buffer_store_event (&buf);
342
71f6b295 343 f->output_data.w32->menubar_active = 0;
485015ca
GV
344 return;
345 }
346 i += MENU_ITEMS_ITEM_LENGTH;
347 }
014510b0 348 }
71f6b295
JR
349 /* Free memory used by owner-drawn and help-echo strings. */
350 w32_free_menu_strings (FRAME_W32_WINDOW (f));
71f6b295 351 f->output_data.w32->menubar_active = 0;
485015ca 352}
014510b0 353
ee78dc32 354\f
485015ca
GV
355/* Set the contents of the menubar widgets of frame F.
356 The argument FIRST_TIME is currently ignored;
357 it is set the first time this is called, from initialize_frame_menubar. */
358
359void
b56ceb92 360set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
485015ca
GV
361{
362 HMENU menubar_widget = f->output_data.w32->menubar_widget;
162d2499 363 Lisp_Object items;
485015ca 364 widget_value *wv, *first_wv, *prev_wv = 0;
6ed09cf0
RS
365 int i, last_i;
366 int *submenu_start, *submenu_end;
fe04b8c8 367 int *submenu_top_level_items, *submenu_n_panes;
485015ca
GV
368
369 /* We must not change the menubar when actually in use. */
370 if (f->output_data.w32->menubar_active)
371 return;
372
373 XSETFRAME (Vmenu_updating_frame, f);
374
375 if (! menubar_widget)
376 deep_p = 1;
377 else if (pending_menu_activation && !deep_p)
378 deep_p = 1;
379
485015ca
GV
380 if (deep_p)
381 {
382 /* Make a widget-value tree representing the entire menu trees. */
383
384 struct buffer *prev = current_buffer;
385 Lisp_Object buffer;
d311d28c 386 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
485015ca
GV
387 int previous_menu_items_used = f->menu_bar_items_used;
388 Lisp_Object *previous_items
389 = (Lisp_Object *) alloca (previous_menu_items_used
663e2b3f 390 * word_size);
485015ca
GV
391
392 /* If we are making a new widget, its contents are empty,
393 do always reinitialize them. */
394 if (! menubar_widget)
395 previous_menu_items_used = 0;
396
d3d50620 397 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
485015ca
GV
398 specbind (Qinhibit_quit, Qt);
399 /* Don't let the debugger step into this code
400 because it is not reentrant. */
401 specbind (Qdebug_on_next_call, Qnil);
402
89f2614d
KS
403 record_unwind_save_match_data ();
404
485015ca
GV
405 if (NILP (Voverriding_local_map_menu_flag))
406 {
407 specbind (Qoverriding_terminal_local_map, Qnil);
408 specbind (Qoverriding_local_map, Qnil);
409 }
410
411 set_buffer_internal_1 (XBUFFER (buffer));
412
cc477da7 413 /* Run the hooks. */
c53b6500 414 safe_run_hooks (Qactivate_menubar_hook);
485015ca 415 safe_run_hooks (Qmenu_bar_update_hook);
5f50daf2 416 FSET (f, menu_bar_items, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
485015ca
GV
417
418 items = FRAME_MENU_BAR_ITEMS (f);
419
485015ca 420 /* Save the frame's previous menu bar contents data. */
c30dce3d 421 if (previous_menu_items_used)
e69b0960 422 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
663e2b3f 423 previous_menu_items_used * word_size);
485015ca 424
6ed09cf0
RS
425 /* Fill in menu_items with the current menu bar contents.
426 This can evaluate Lisp code. */
df80fd9d
JR
427 save_menu_items ();
428
e69b0960 429 menu_items = f->menu_bar_vector;
c30dce3d 430 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
57679c86
AS
431 submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
432 submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
77b37c05 433 submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
57679c86 434 submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
485015ca 435 init_menu_items ();
6ed09cf0 436 for (i = 0; i < ASIZE (items); i += 4)
485015ca
GV
437 {
438 Lisp_Object key, string, maps;
439
6ed09cf0
RS
440 last_i = i;
441
442 key = AREF (items, i);
443 string = AREF (items, i + 1);
444 maps = AREF (items, i + 2);
485015ca
GV
445 if (NILP (string))
446 break;
447
6ed09cf0
RS
448 submenu_start[i] = menu_items_used;
449
450 menu_items_n_panes = 0;
451 submenu_top_level_items[i]
452 = parse_single_submenu (key, string, maps);
fe04b8c8 453 submenu_n_panes[i] = menu_items_n_panes;
6ed09cf0
RS
454
455 submenu_end[i] = menu_items_used;
456 }
457
458 finish_menu_items ();
459
460 /* Convert menu_items into widget_value trees
461 to display the menu. This cannot evaluate Lisp code. */
462
463 wv = xmalloc_widget_value ();
464 wv->name = "menubar";
465 wv->value = 0;
466 wv->enabled = 1;
467 wv->button_type = BUTTON_TYPE_NONE;
468 wv->help = Qnil;
469 first_wv = wv;
470
471 for (i = 0; i < last_i; i += 4)
472 {
fe04b8c8 473 menu_items_n_panes = submenu_n_panes[i];
6ed09cf0
RS
474 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
475 submenu_top_level_items[i]);
177c0ea7 476 if (prev_wv)
485015ca
GV
477 prev_wv->next = wv;
478 else
479 first_wv->contents = wv;
480 /* Don't set wv->name here; GC during the loop might relocate it. */
481 wv->enabled = 1;
162d2499 482 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
483 prev_wv = wv;
484 }
485
485015ca 486 set_buffer_internal_1 (prev);
485015ca
GV
487
488 /* If there has been no change in the Lisp-level contents
489 of the menu bar, skip redisplaying it. Just exit. */
490
491 for (i = 0; i < previous_menu_items_used; i++)
492 if (menu_items_used == i
6ed09cf0 493 || (!EQ (previous_items[i], AREF (menu_items, i))))
485015ca
GV
494 break;
495 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
496 {
497 free_menubar_widget_value_tree (first_wv);
df80fd9d
JR
498 discard_menu_items ();
499 unbind_to (specpdl_count, Qnil);
485015ca
GV
500 return;
501 }
502
edd74c35 503 FSET (f, menu_bar_vector, menu_items);
df80fd9d
JR
504 f->menu_bar_items_used = menu_items_used;
505
506 /* This undoes save_menu_items. */
507 unbind_to (specpdl_count, Qnil);
508
485015ca 509 /* Now GC cannot happen during the lifetime of the widget_value,
ace9b298
JR
510 so it's safe to store data from a Lisp_String, as long as
511 local copies are made when the actual menu is created.
512 Windows takes care of this for normal string items, but
513 not for owner-drawn items or additional item-info. */
485015ca 514 wv = first_wv->contents;
6ed09cf0 515 for (i = 0; i < ASIZE (items); i += 4)
485015ca
GV
516 {
517 Lisp_Object string;
6ed09cf0 518 string = AREF (items, i + 1);
485015ca
GV
519 if (NILP (string))
520 break;
51b59d79 521 wv->name = SSDATA (string);
1f06d367 522 update_submenu_strings (wv->contents);
485015ca
GV
523 wv = wv->next;
524 }
485015ca
GV
525 }
526 else
527 {
528 /* Make a widget-value tree containing
162d2499 529 just the top level menu bar strings. */
485015ca 530
6ed09cf0
RS
531 wv = xmalloc_widget_value ();
532 wv->name = "menubar";
533 wv->value = 0;
534 wv->enabled = 1;
535 wv->button_type = BUTTON_TYPE_NONE;
536 wv->help = Qnil;
537 first_wv = wv;
538
485015ca 539 items = FRAME_MENU_BAR_ITEMS (f);
6ed09cf0 540 for (i = 0; i < ASIZE (items); i += 4)
485015ca
GV
541 {
542 Lisp_Object string;
543
6ed09cf0 544 string = AREF (items, i + 1);
485015ca
GV
545 if (NILP (string))
546 break;
547
548 wv = xmalloc_widget_value ();
51b59d79 549 wv->name = SSDATA (string);
485015ca
GV
550 wv->value = 0;
551 wv->enabled = 1;
162d2499 552 wv->button_type = BUTTON_TYPE_NONE;
2d10309f 553 wv->help = Qnil;
485015ca
GV
554 /* This prevents lwlib from assuming this
555 menu item is really supposed to be empty. */
556 /* The EMACS_INT cast avoids a warning.
557 This value just has to be different from small integers. */
558 wv->call_data = (void *) (EMACS_INT) (-1);
559
177c0ea7 560 if (prev_wv)
485015ca
GV
561 prev_wv->next = wv;
562 else
563 first_wv->contents = wv;
564 prev_wv = wv;
565 }
566
162d2499
JR
567 /* Forget what we thought we knew about what is in the
568 detailed contents of the menu bar menus.
569 Changing the top level always destroys the contents. */
570 f->menu_bar_items_used = 0;
485015ca
GV
571 }
572
573 /* Create or update the menu bar widget. */
ee78dc32 574
485015ca 575 BLOCK_INPUT;
ee78dc32 576
485015ca
GV
577 if (menubar_widget)
578 {
579 /* Empty current menubar, rather than creating a fresh one. */
580 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
581 ;
582 }
583 else
584 {
585 menubar_widget = CreateMenu ();
586 }
587 fill_in_menu (menubar_widget, first_wv->contents);
ee78dc32 588
485015ca 589 free_menubar_widget_value_tree (first_wv);
ee78dc32 590
485015ca
GV
591 {
592 HMENU old_widget = f->output_data.w32->menubar_widget;
ee78dc32 593
485015ca
GV
594 f->output_data.w32->menubar_widget = menubar_widget;
595 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
177c0ea7 596 /* Causes flicker when menu bar is updated
485015ca 597 DrawMenuBar (FRAME_W32_WINDOW (f)); */
ee78dc32 598
485015ca
GV
599 /* Force the window size to be recomputed so that the frame's text
600 area remains the same, if menubar has just been created. */
601 if (old_widget == NULL)
90022f5a 602 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
ee78dc32 603 }
485015ca
GV
604
605 UNBLOCK_INPUT;
ee78dc32
GV
606}
607
485015ca
GV
608/* Called from Fx_create_frame to create the initial menubar of a frame
609 before it is mapped, so that the window is mapped with the menubar already
610 there instead of us tacking it on later and thrashing the window after it
611 is visible. */
612
613void
b56ceb92 614initialize_frame_menubar (FRAME_PTR f)
485015ca
GV
615{
616 /* This function is called before the first chance to redisplay
617 the frame. It has to be, so the frame will have the right size. */
5f50daf2 618 FSET (f, menu_bar_items, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
485015ca 619 set_frame_menubar (f, 1, 1);
ee78dc32
GV
620}
621
485015ca
GV
622/* Get rid of the menu bar of frame F, and free its storage.
623 This is used when deleting a frame, and when turning off the menu bar. */
624
625void
b56ceb92 626free_frame_menubar (FRAME_PTR f)
485015ca
GV
627{
628 BLOCK_INPUT;
629
630 {
631 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
632 SetMenu (FRAME_W32_WINDOW (f), NULL);
633 f->output_data.w32->menubar_widget = NULL;
634 DestroyMenu (old);
635 }
29250851 636
485015ca
GV
637 UNBLOCK_INPUT;
638}
ee78dc32 639
485015ca
GV
640\f
641/* w32_menu_show actually displays a menu using the panes and items in
642 menu_items and returns the value selected from it; we assume input
643 is blocked by the caller. */
ee78dc32
GV
644
645/* F is the frame the menu is for.
646 X and Y are the frame-relative specified position,
647 relative to the inside upper left corner of the frame F.
485015ca 648 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
ee78dc32 649 KEYMAPS is 1 if this menu was specified with keymaps;
485015ca
GV
650 in that case, we return a list containing the chosen item's value
651 and perhaps also the pane's prefix.
ee78dc32
GV
652 TITLE is the specified menu title.
653 ERROR is a place to store an error message string in case of failure.
654 (We return nil on failure, but the value doesn't actually matter.) */
655
ef7417fd
SM
656Lisp_Object
657w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
42ca4633 658 Lisp_Object title, const char **error)
ee78dc32 659{
485015ca
GV
660 int i;
661 int menu_item_selection;
662 HMENU menu;
ee78dc32 663 POINT pos;
485015ca
GV
664 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
665 widget_value **submenu_stack
666 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
667 Lisp_Object *subprefix_stack
663e2b3f 668 = (Lisp_Object *) alloca (menu_items_used * word_size);
485015ca 669 int submenu_depth = 0;
485015ca 670 int first_pane;
485015ca 671
ee78dc32 672 *error = NULL;
485015ca 673
df80fd9d
JR
674 if (menu_items_n_panes == 0)
675 return Qnil;
676
485015ca 677 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
ee78dc32
GV
678 {
679 *error = "Empty menu";
680 return Qnil;
681 }
485015ca
GV
682
683 /* Create a tree of widget_value objects
684 representing the panes and their items. */
685 wv = xmalloc_widget_value ();
686 wv->name = "menu";
687 wv->value = 0;
688 wv->enabled = 1;
162d2499 689 wv->button_type = BUTTON_TYPE_NONE;
e6bb685b 690 wv->help = Qnil;
485015ca
GV
691 first_wv = wv;
692 first_pane = 1;
177c0ea7 693
485015ca
GV
694 /* Loop over all panes and items, filling in the tree. */
695 i = 0;
696 while (i < menu_items_used)
697 {
6ed09cf0 698 if (EQ (AREF (menu_items, i), Qnil))
485015ca
GV
699 {
700 submenu_stack[submenu_depth++] = save_wv;
701 save_wv = prev_wv;
702 prev_wv = 0;
703 first_pane = 1;
704 i++;
705 }
6ed09cf0 706 else if (EQ (AREF (menu_items, i), Qlambda))
485015ca
GV
707 {
708 prev_wv = save_wv;
709 save_wv = submenu_stack[--submenu_depth];
710 first_pane = 0;
711 i++;
712 }
6ed09cf0 713 else if (EQ (AREF (menu_items, i), Qt)
485015ca
GV
714 && submenu_depth != 0)
715 i += MENU_ITEMS_PANE_LENGTH;
716 /* Ignore a nil in the item list.
717 It's meaningful only for dialog boxes. */
6ed09cf0 718 else if (EQ (AREF (menu_items, i), Qquote))
485015ca 719 i += 1;
6ed09cf0 720 else if (EQ (AREF (menu_items, i), Qt))
485015ca
GV
721 {
722 /* Create a new pane. */
723 Lisp_Object pane_name, prefix;
724 char *pane_string;
29250851
JR
725 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
726 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1f06d367
JR
727
728 if (STRINGP (pane_name))
29250851 729 {
1f06d367
JR
730 if (unicode_append_menu)
731 pane_name = ENCODE_UTF_8 (pane_name);
732 else if (STRING_MULTIBYTE (pane_name))
733 pane_name = ENCODE_SYSTEM (pane_name);
734
6ed09cf0 735 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
29250851 736 }
1f06d367 737
485015ca 738 pane_string = (NILP (pane_name)
51b59d79 739 ? "" : SSDATA (pane_name));
485015ca
GV
740 /* If there is just one top-level pane, put all its items directly
741 under the top-level menu. */
742 if (menu_items_n_panes == 1)
743 pane_string = "";
744
745 /* If the pane has a meaningful name,
746 make the pane a top-level menu item
747 with its items as a submenu beneath it. */
748 if (!keymaps && strcmp (pane_string, ""))
749 {
750 wv = xmalloc_widget_value ();
751 if (save_wv)
752 save_wv->next = wv;
753 else
754 first_wv->contents = wv;
755 wv->name = pane_string;
756 if (keymaps && !NILP (prefix))
757 wv->name++;
758 wv->value = 0;
759 wv->enabled = 1;
162d2499 760 wv->button_type = BUTTON_TYPE_NONE;
2d10309f 761 wv->help = Qnil;
485015ca
GV
762 save_wv = wv;
763 prev_wv = 0;
764 }
765 else if (first_pane)
766 {
767 save_wv = wv;
768 prev_wv = 0;
769 }
770 first_pane = 0;
771 i += MENU_ITEMS_PANE_LENGTH;
772 }
773 else
774 {
775 /* Create a new item within current pane. */
b65a2f83 776 Lisp_Object item_name, enable, descrip, def, type, selected, help;
b65a2f83 777
29250851
JR
778 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
779 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
780 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
781 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
782 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
783 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
784 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
162d2499 785
1f06d367 786 if (STRINGP (item_name))
29250851 787 {
1f06d367
JR
788 if (unicode_append_menu)
789 item_name = ENCODE_UTF_8 (item_name);
790 else if (STRING_MULTIBYTE (item_name))
791 item_name = ENCODE_SYSTEM (item_name);
792
6ed09cf0 793 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
29250851 794 }
1f06d367
JR
795
796 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
29250851
JR
797 {
798 descrip = ENCODE_SYSTEM (descrip);
6ed09cf0 799 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
29250851 800 }
485015ca
GV
801
802 wv = xmalloc_widget_value ();
177c0ea7 803 if (prev_wv)
485015ca 804 prev_wv->next = wv;
177c0ea7 805 else
485015ca 806 save_wv->contents = wv;
51b59d79 807 wv->name = SSDATA (item_name);
485015ca 808 if (!NILP (descrip))
51b59d79 809 wv->key = SSDATA (descrip);
485015ca
GV
810 wv->value = 0;
811 /* Use the contents index as call_data, since we are
2cd23960 812 restricted to 16-bits. */
e59fe83b 813 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
485015ca 814 wv->enabled = !NILP (enable);
162d2499
JR
815
816 if (NILP (type))
817 wv->button_type = BUTTON_TYPE_NONE;
818 else if (EQ (type, QCtoggle))
819 wv->button_type = BUTTON_TYPE_TOGGLE;
820 else if (EQ (type, QCradio))
821 wv->button_type = BUTTON_TYPE_RADIO;
822 else
823 abort ();
824
825 wv->selected = !NILP (selected);
df80fd9d 826
d1fffd1d
JR
827 if (!STRINGP (help))
828 help = Qnil;
829
830 wv->help = help;
7d8e57da 831
485015ca
GV
832 prev_wv = wv;
833
834 i += MENU_ITEMS_ITEM_LENGTH;
835 }
836 }
837
838 /* Deal with the title, if it is non-nil. */
839 if (!NILP (title))
840 {
841 widget_value *wv_title = xmalloc_widget_value ();
842 widget_value *wv_sep = xmalloc_widget_value ();
843
844 /* Maybe replace this separator with a bitmap or owner-draw item
845 so that it looks better. Having two separators looks odd. */
846 wv_sep->name = "--";
847 wv_sep->next = first_wv->contents;
2d10309f 848 wv_sep->help = Qnil;
485015ca 849
1f06d367
JR
850 if (unicode_append_menu)
851 title = ENCODE_UTF_8 (title);
852 else if (STRING_MULTIBYTE (title))
6915ded0 853 title = ENCODE_SYSTEM (title);
1f06d367 854
51b59d79 855 wv_title->name = SSDATA (title);
02067692 856 wv_title->enabled = TRUE;
5b20b3cc 857 wv_title->title = TRUE;
162d2499 858 wv_title->button_type = BUTTON_TYPE_NONE;
2d10309f 859 wv_title->help = Qnil;
485015ca
GV
860 wv_title->next = wv_sep;
861 first_wv->contents = wv_title;
862 }
863
df80fd9d
JR
864 /* No selection has been chosen yet. */
865 menu_item_selection = 0;
866
485015ca 867 /* Actually create the menu. */
ace9b298 868 current_popup_menu = menu = CreatePopupMenu ();
485015ca 869 fill_in_menu (menu, first_wv->contents);
162d2499 870
485015ca 871 /* Adjust coordinates to be root-window-relative. */
ee78dc32
GV
872 pos.x = x;
873 pos.y = y;
fbd6baed 874 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
485015ca 875
ee78dc32 876 /* Display the menu. */
177c0ea7 877 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
485015ca
GV
878 WM_EMACS_TRACKPOPUPMENU,
879 (WPARAM)menu, (LPARAM)&pos);
014510b0
GV
880
881 /* Clean up extraneous mouse events which might have been generated
882 during the call. */
883 discard_mouse_events ();
38f2b112 884 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
014510b0 885
86fb1a79
JR
886 /* Free the widget_value objects we used to specify the contents. */
887 free_menubar_widget_value_tree (first_wv);
888
485015ca
GV
889 DestroyMenu (menu);
890
563cd4c0
JR
891 /* Free the owner-drawn and help-echo menu strings. */
892 w32_free_menu_strings (FRAME_W32_WINDOW (f));
5339f50c 893 f->output_data.w32->menubar_active = 0;
563cd4c0 894
ee78dc32
GV
895 /* Find the selected item, and its pane, to return
896 the proper value. */
485015ca 897 if (menu_item_selection != 0)
ee78dc32 898 {
485015ca
GV
899 Lisp_Object prefix, entry;
900
fe5a0162 901 prefix = entry = Qnil;
485015ca
GV
902 i = 0;
903 while (i < menu_items_used)
904 {
6ed09cf0 905 if (EQ (AREF (menu_items, i), Qnil))
485015ca
GV
906 {
907 subprefix_stack[submenu_depth++] = prefix;
908 prefix = entry;
909 i++;
910 }
6ed09cf0 911 else if (EQ (AREF (menu_items, i), Qlambda))
485015ca
GV
912 {
913 prefix = subprefix_stack[--submenu_depth];
914 i++;
915 }
6ed09cf0 916 else if (EQ (AREF (menu_items, i), Qt))
485015ca 917 {
6ed09cf0 918 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
485015ca
GV
919 i += MENU_ITEMS_PANE_LENGTH;
920 }
921 /* Ignore a nil in the item list.
922 It's meaningful only for dialog boxes. */
6ed09cf0 923 else if (EQ (AREF (menu_items, i), Qquote))
485015ca
GV
924 i += 1;
925 else
926 {
6ed09cf0 927 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
485015ca
GV
928 if (menu_item_selection == i)
929 {
930 if (keymaps != 0)
931 {
932 int j;
933
934 entry = Fcons (entry, Qnil);
935 if (!NILP (prefix))
936 entry = Fcons (prefix, entry);
937 for (j = submenu_depth - 1; j >= 0; j--)
938 if (!NILP (subprefix_stack[j]))
939 entry = Fcons (subprefix_stack[j], entry);
940 }
941 return entry;
942 }
943 i += MENU_ITEMS_ITEM_LENGTH;
944 }
945 }
ee78dc32 946 }
f3e0a6de
JR
947 else if (!for_click)
948 /* Make "Cancel" equivalent to C-g. */
949 Fsignal (Qquit, Qnil);
014510b0 950
ee78dc32
GV
951 return Qnil;
952}
485015ca 953\f
ee78dc32 954
ace9b298 955#ifdef HAVE_DIALOGS
31403b24
JR
956/* TODO: On Windows, there are two ways of defining a dialog.
957
958 1. Create a predefined dialog resource and include it in nt/emacs.rc.
959 Using this method, we could then set the titles and make unneeded
960 buttons invisible before displaying the dialog. Everything would
961 be a fixed size though, so there is a risk that text does not
962 fit on a button.
963 2. Create the dialog template in memory on the fly. This allows us
964 to size the dialog and buttons dynamically, probably giving more
965 natural looking results for dialogs with few buttons, and eliminating
966 the problem of text overflowing the buttons. But the API for this is
967 quite complex - structures have to be allocated in particular ways,
968 text content is tacked onto the end of structures in variable length
969 arrays with further structures tacked on after these, there are
970 certain alignment requirements for all this, and we have to
971 measure all the text and convert to "dialog coordinates" to figure
972 out how big to make everything.
973
974 For now, we'll just stick with menus for dialogs that are more
975 complicated than simple yes/no type questions for which we can use
976 the MessageBox function.
977*/
38fecd52 978
485015ca 979static char * button_names [] = {
ee78dc32 980 "button1", "button2", "button3", "button4", "button5",
485015ca 981 "button6", "button7", "button8", "button9", "button10" };
ee78dc32
GV
982
983static Lisp_Object
b56ceb92
JB
984w32_dialog_show (FRAME_PTR f, int keymaps,
985 Lisp_Object title, Lisp_Object header,
986 char **error)
ee78dc32 987{
9d4f32e8 988 int i, nb_buttons = 0;
ee78dc32 989 char dialog_name[6];
485015ca
GV
990 int menu_item_selection;
991
fe5a0162 992 widget_value *wv, *first_wv = 0, *prev_wv = 0;
485015ca 993
ee78dc32
GV
994 /* Number of elements seen so far, before boundary. */
995 int left_count = 0;
996 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
997 int boundary_seen = 0;
485015ca 998
ee78dc32 999 *error = NULL;
485015ca 1000
ee78dc32
GV
1001 if (menu_items_n_panes > 1)
1002 {
1003 *error = "Multiple panes in dialog box";
1004 return Qnil;
1005 }
485015ca 1006
ee78dc32
GV
1007 /* Create a tree of widget_value objects
1008 representing the text label and buttons. */
1009 {
1010 Lisp_Object pane_name, prefix;
1011 char *pane_string;
6ed09cf0
RS
1012 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1013 prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
ee78dc32 1014 pane_string = (NILP (pane_name)
51b59d79 1015 ? "" : SSDATA (pane_name));
485015ca 1016 prev_wv = xmalloc_widget_value ();
ee78dc32
GV
1017 prev_wv->value = pane_string;
1018 if (keymaps && !NILP (prefix))
1019 prev_wv->name++;
1020 prev_wv->enabled = 1;
1021 prev_wv->name = "message";
2d10309f 1022 prev_wv->help = Qnil;
ee78dc32 1023 first_wv = prev_wv;
177c0ea7 1024
ee78dc32
GV
1025 /* Loop over all panes and items, filling in the tree. */
1026 i = MENU_ITEMS_PANE_LENGTH;
1027 while (i < menu_items_used)
1028 {
177c0ea7 1029
ee78dc32 1030 /* Create a new item within current pane. */
b65a2f83 1031 Lisp_Object item_name, enable, descrip, help;
b65a2f83 1032
6ed09cf0
RS
1033 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1034 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1035 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1036 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
177c0ea7 1037
ee78dc32
GV
1038 if (NILP (item_name))
1039 {
1040 free_menubar_widget_value_tree (first_wv);
1041 *error = "Submenu in dialog items";
1042 return Qnil;
1043 }
1044 if (EQ (item_name, Qquote))
1045 {
1046 /* This is the boundary between left-side elts
1047 and right-side elts. Stop incrementing right_count. */
1048 boundary_seen = 1;
1049 i++;
1050 continue;
1051 }
485015ca 1052 if (nb_buttons >= 9)
ee78dc32
GV
1053 {
1054 free_menubar_widget_value_tree (first_wv);
1055 *error = "Too many dialog items";
1056 return Qnil;
1057 }
485015ca
GV
1058
1059 wv = xmalloc_widget_value ();
ee78dc32
GV
1060 prev_wv->next = wv;
1061 wv->name = (char *) button_names[nb_buttons];
1062 if (!NILP (descrip))
51b59d79
PE
1063 wv->key = SSDATA (descrip);
1064 wv->value = SSDATA (item_name);
4939150c 1065 wv->call_data = aref_addr (menu_items, i);
ee78dc32 1066 wv->enabled = !NILP (enable);
2d10309f 1067 wv->help = Qnil;
ee78dc32 1068 prev_wv = wv;
485015ca 1069
ee78dc32
GV
1070 if (! boundary_seen)
1071 left_count++;
485015ca 1072
ee78dc32
GV
1073 nb_buttons++;
1074 i += MENU_ITEMS_ITEM_LENGTH;
1075 }
485015ca 1076
ee78dc32
GV
1077 /* If the boundary was not specified,
1078 by default put half on the left and half on the right. */
1079 if (! boundary_seen)
1080 left_count = nb_buttons - nb_buttons / 2;
485015ca
GV
1081
1082 wv = xmalloc_widget_value ();
ee78dc32 1083 wv->name = dialog_name;
2d10309f 1084 wv->help = Qnil;
485015ca 1085
d23928c7
NR
1086 /* Frame title: 'Q' = Question, 'I' = Information.
1087 Can also have 'E' = Error if, one day, we want
1088 a popup for errors. */
ed3751c8 1089 if (NILP (header))
d23928c7
NR
1090 dialog_name[0] = 'Q';
1091 else
1092 dialog_name[0] = 'I';
1093
ee78dc32
GV
1094 /* Dialog boxes use a really stupid name encoding
1095 which specifies how many buttons to use
d23928c7 1096 and how many buttons are on the right. */
ee78dc32
GV
1097 dialog_name[1] = '0' + nb_buttons;
1098 dialog_name[2] = 'B';
1099 dialog_name[3] = 'R';
1100 /* Number of buttons to put on the right. */
1101 dialog_name[4] = '0' + nb_buttons - left_count;
1102 dialog_name[5] = 0;
1103 wv->contents = first_wv;
1104 first_wv = wv;
1105 }
485015ca 1106
ee78dc32 1107 /* Actually create the dialog. */
485015ca 1108 dialog_id = widget_id_tick++;
ee78dc32 1109 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
fbd6baed 1110 f->output_data.w32->widget, 1, 0,
ee78dc32 1111 dialog_selection_callback, 0);
02067692 1112 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
485015ca 1113
ee78dc32
GV
1114 /* Free the widget_value objects we used to specify the contents. */
1115 free_menubar_widget_value_tree (first_wv);
485015ca 1116
ee78dc32
GV
1117 /* No selection has been chosen yet. */
1118 menu_item_selection = 0;
485015ca 1119
ee78dc32
GV
1120 /* Display the menu. */
1121 lw_pop_up_all_widgets (dialog_id);
485015ca 1122
ee78dc32 1123 /* Process events that apply to the menu. */
485015ca 1124 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
ee78dc32 1125
177c0ea7 1126 lw_destroy_all_widgets (dialog_id);
ee78dc32 1127
ee78dc32
GV
1128 /* Find the selected item, and its pane, to return
1129 the proper value. */
1130 if (menu_item_selection != 0)
1131 {
1132 Lisp_Object prefix;
485015ca 1133
ee78dc32
GV
1134 prefix = Qnil;
1135 i = 0;
1136 while (i < menu_items_used)
1137 {
1138 Lisp_Object entry;
1139
6ed09cf0 1140 if (EQ (AREF (menu_items, i), Qt))
ee78dc32 1141 {
6ed09cf0 1142 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
ee78dc32
GV
1143 i += MENU_ITEMS_PANE_LENGTH;
1144 }
1145 else
1146 {
6ed09cf0 1147 entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
485015ca 1148 if (menu_item_selection == i)
ee78dc32
GV
1149 {
1150 if (keymaps != 0)
1151 {
1152 entry = Fcons (entry, Qnil);
1153 if (!NILP (prefix))
1154 entry = Fcons (prefix, entry);
1155 }
1156 return entry;
1157 }
1158 i += MENU_ITEMS_ITEM_LENGTH;
1159 }
1160 }
1161 }
f3e0a6de
JR
1162 else
1163 /* Make "Cancel" equivalent to C-g. */
1164 Fsignal (Qquit, Qnil);
485015ca 1165
ee78dc32
GV
1166 return Qnil;
1167}
31403b24
JR
1168#else /* !HAVE_DIALOGS */
1169
1170/* Currently we only handle Yes No dialogs (y-or-n-p and yes-or-no-p) as
1171 simple dialogs. We could handle a few more, but I'm not aware of
1172 anywhere in Emacs that uses the other specific dialog choices that
1173 MessageBox provides. */
1174
b56ceb92
JB
1175static int
1176is_simple_dialog (Lisp_Object contents)
31403b24 1177{
3b0512a3 1178 Lisp_Object options;
31403b24
JR
1179 Lisp_Object name, yes, no, other;
1180
3b0512a3
AS
1181 if (!CONSP (contents))
1182 return 0;
1183 options = XCDR (contents);
1184
31403b24
JR
1185 yes = build_string ("Yes");
1186 no = build_string ("No");
1187
1188 if (!CONSP (options))
1189 return 0;
1190
3b0512a3
AS
1191 name = XCAR (options);
1192 if (!CONSP (name))
31403b24 1193 return 0;
3b0512a3 1194 name = XCAR (name);
31403b24
JR
1195
1196 if (!NILP (Fstring_equal (name, yes)))
1197 other = no;
1198 else if (!NILP (Fstring_equal (name, no)))
1199 other = yes;
1200 else
1201 return 0;
1202
1203 options = XCDR (options);
1204 if (!CONSP (options))
1205 return 0;
1206
3b0512a3
AS
1207 name = XCAR (options);
1208 if (!CONSP (name))
1209 return 0;
1210 name = XCAR (name);
31403b24
JR
1211 if (NILP (Fstring_equal (name, other)))
1212 return 0;
1213
1214 /* Check there are no more options. */
1215 options = XCDR (options);
1216 return !(CONSP (options));
1217}
1218
b56ceb92
JB
1219static Lisp_Object
1220simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header)
31403b24
JR
1221{
1222 int answer;
1223 UINT type;
31403b24
JR
1224 Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);
1225
1c9b4129
JR
1226 type = MB_YESNO;
1227
1228 /* Since we only handle Yes/No dialogs, and we already checked
1229 is_simple_dialog, we don't need to worry about checking contents
1230 to see what type of dialog to use. */
31403b24 1231
fe7a3057 1232 /* Use Unicode if possible, so any language can be displayed. */
1c9b4129 1233 if (unicode_message_box)
31403b24 1234 {
1c9b4129 1235 WCHAR *text, *title;
8bc53d00 1236 USE_SAFE_ALLOCA;
1c9b4129
JR
1237
1238 if (STRINGP (temp))
1239 {
1240 char *utf8_text = SDATA (ENCODE_UTF_8 (temp));
1241 /* Be pessimistic about the number of characters needed.
1242 Remember characters outside the BMP will take more than
1243 one utf16 word, so we cannot simply use the character
1244 length of temp. */
1245 int utf8_len = strlen (utf8_text);
98c6f1e3 1246 text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
1c9b4129
JR
1247 utf8to16 (utf8_text, utf8_len, text);
1248 }
1249 else
1250 {
1251 text = L"";
1252 }
1253
1254 if (NILP (header))
1255 {
1256 title = L"Question";
1257 type |= MB_ICONQUESTION;
1258 }
1259 else
1260 {
1261 title = L"Information";
1262 type |= MB_ICONINFORMATION;
1263 }
1264
1265 answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
8bc53d00 1266 SAFE_FREE ();
31403b24
JR
1267 }
1268 else
1269 {
1c9b4129 1270 char *text, *title;
31403b24 1271
1c9b4129
JR
1272 /* Fall back on ANSI message box, but at least use system
1273 encoding so questions representable by the system codepage
1274 are encoded properly. */
1275 if (STRINGP (temp))
1276 text = SDATA (ENCODE_SYSTEM (temp));
1277 else
1278 text = "";
1279
1280 if (NILP (header))
1281 {
1282 title = "Question";
1283 type |= MB_ICONQUESTION;
1284 }
1285 else
1286 {
1287 title = "Information";
1288 type |= MB_ICONINFORMATION;
1289 }
1290
1291 answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
1292 }
31403b24
JR
1293
1294 if (answer == IDYES)
1295 lispy_answer = build_string ("Yes");
1296 else if (answer == IDNO)
1297 lispy_answer = build_string ("No");
1298 else
1299 Fsignal (Qquit, Qnil);
1300
1301 for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
1302 {
1303 Lisp_Object item, name, value;
1304 item = XCAR (temp);
1305 if (CONSP (item))
1306 {
1307 name = XCAR (item);
1308 value = XCDR (item);
1309 }
1310 else
1311 {
1312 name = item;
1313 value = Qnil;
1314 }
1315
1316 if (!NILP (Fstring_equal (name, lispy_answer)))
1317 {
1318 return value;
1319 }
1320 }
1321 Fsignal (Qquit, Qnil);
1322 return Qnil;
1323}
1324#endif /* !HAVE_DIALOGS */
485015ca
GV
1325\f
1326
1f06d367
JR
1327/* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
1328static void
1329utf8to16 (unsigned char * src, int len, WCHAR * dest)
1330{
1331 while (len > 0)
1332 {
1f06d367
JR
1333 if (*src < 0x80)
1334 {
1335 *dest = (WCHAR) *src;
1336 dest++; src++; len--;
1337 }
1338 /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
1339 else if (*src < 0xC0)
1340 {
1341 src++; len--;
1342 }
1343 /* 2 char UTF-8 sequence. */
1344 else if (*src < 0xE0)
1345 {
1346 *dest = (WCHAR) (((*src & 0x1f) << 6)
1347 | (*(src + 1) & 0x3f));
1348 src += 2; len -= 2; dest++;
1349 }
1350 else if (*src < 0xF0)
1351 {
1352 *dest = (WCHAR) (((*src & 0x0f) << 12)
1353 | ((*(src + 1) & 0x3f) << 6)
1354 | (*(src + 2) & 0x3f));
1355 src += 3; len -= 3; dest++;
1356 }
1357 else /* Not encodable. Insert Unicode Substitution char. */
1358 {
1359 *dest = (WCHAR) 0xfffd;
1360 src++; len--; dest++;
1361 }
1362 }
1363 *dest = 0;
1364}
1365
485015ca
GV
1366static int
1367add_menu_item (HMENU menu, widget_value *wv, HMENU item)
1368{
1369 UINT fuFlags;
af41f8a8 1370 char *out_string, *p, *q;
37ad8b63 1371 int return_value;
af41f8a8 1372 size_t nlen, orig_len;
8bc53d00 1373 USE_SAFE_ALLOCA;
485015ca 1374
4039c786 1375 if (menu_separator_name_p (wv->name))
222456a1
JR
1376 {
1377 fuFlags = MF_SEPARATOR;
1378 out_string = NULL;
1379 }
177c0ea7 1380 else
485015ca 1381 {
070d1949 1382 if (wv->enabled)
485015ca
GV
1383 fuFlags = MF_STRING;
1384 else
1385 fuFlags = MF_STRING | MF_GRAYED;
1386
1387 if (wv->key != NULL)
1388 {
98c6f1e3 1389 out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2);
485015ca
GV
1390 strcpy (out_string, wv->name);
1391 strcat (out_string, "\t");
1392 strcat (out_string, wv->key);
1393 }
1394 else
94c97d85 1395 out_string = (char *)wv->name;
485015ca 1396
af41f8a8
EZ
1397 /* Quote any special characters within the menu item's text and
1398 key binding. */
1399 nlen = orig_len = strlen (out_string);
ff25d115
JR
1400 if (unicode_append_menu)
1401 {
1402 /* With UTF-8, & cannot be part of a multibyte character. */
1403 for (p = out_string; *p; p++)
1404 {
1405 if (*p == '&')
1406 nlen++;
1407 }
1408 }
1409 else
1410 {
1411 /* If encoded with the system codepage, use multibyte string
1412 functions in case of multibyte characters that contain '&'. */
1413 for (p = out_string; *p; p = _mbsinc (p))
1414 {
1415 if (_mbsnextc (p) == '&')
1416 nlen++;
1417 }
1418 }
1419
af41f8a8 1420 if (nlen > orig_len)
ff25d115
JR
1421 {
1422 p = out_string;
98c6f1e3 1423 out_string = SAFE_ALLOCA (nlen + 1);
ff25d115
JR
1424 q = out_string;
1425 while (*p)
1426 {
1427 if (unicode_append_menu)
1428 {
1429 if (*p == '&')
1430 *q++ = *p;
1431 *q++ = *p++;
1432 }
1433 else
1434 {
1435 if (_mbsnextc (p) == '&')
1436 {
1437 _mbsncpy (q, p, 1);
1438 q = _mbsinc (q);
1439 }
1440 _mbsncpy (q, p, 1);
1441 p = _mbsinc (p);
1442 q = _mbsinc (q);
1443 }
1444 }
1445 *q = '\0';
1446 }
af41f8a8 1447
d1fffd1d
JR
1448 if (item != NULL)
1449 fuFlags = MF_POPUP;
1450 else if (wv->title || wv->call_data == 0)
485015ca 1451 {
ace9b298
JR
1452 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
1453 we can't deallocate the memory otherwise. */
1454 if (get_menu_item_info)
1455 {
6ed09cf0
RS
1456 out_string = (char *) local_alloc (strlen (wv->name) + 1);
1457 strcpy (out_string, wv->name);
d1fffd1d 1458#ifdef MENU_DEBUG
91af3942 1459 DebPrint ("Menu: allocating %ld for owner-draw", out_string);
d1fffd1d 1460#endif
ace9b298
JR
1461 fuFlags = MF_OWNERDRAW | MF_DISABLED;
1462 }
1463 else
1464 fuFlags = MF_DISABLED;
485015ca 1465 }
1c5acb8c 1466
162d2499 1467 /* Draw radio buttons and tickboxes. */
4cdf6a6c 1468 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
6f665da9 1469 wv->button_type == BUTTON_TYPE_RADIO))
4cdf6a6c 1470 fuFlags |= MF_CHECKED;
37ad8b63 1471 else
4cdf6a6c 1472 fuFlags |= MF_UNCHECKED;
485015ca 1473 }
4cdf6a6c 1474
1f06d367
JR
1475 if (unicode_append_menu && out_string)
1476 {
1477 /* Convert out_string from UTF-8 to UTF-16-LE. */
1478 int utf8_len = strlen (out_string);
1479 WCHAR * utf16_string;
1480 if (fuFlags & MF_OWNERDRAW)
1481 utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
1482 else
98c6f1e3 1483 utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
1f06d367
JR
1484
1485 utf8to16 (out_string, utf8_len, utf16_string);
1486 return_value = unicode_append_menu (menu, fuFlags,
1487 item != NULL ? (UINT) item
1488 : (UINT) wv->call_data,
1489 utf16_string);
d749b6fa
JR
1490 if (!return_value)
1491 {
fe7a3057 1492 /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
d749b6fa
JR
1493 apparently does exist at least in some cases and appears to be
1494 stubbed out to do nothing. out_string is UTF-8, but since
1495 our standard menus are in English and this is only going to
1496 happen the first time a menu is used, the encoding is
1497 of minor importance compared with menus not working at all. */
1498 return_value =
1499 AppendMenu (menu, fuFlags,
1500 item != NULL ? (UINT) item: (UINT) wv->call_data,
1501 out_string);
1c6900d9
EZ
1502 /* Don't use Unicode menus in future, unless this is Windows
1503 NT or later, where a failure of AppendMenuW does NOT mean
1504 Unicode menus are unsupported. */
1505 if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT)
1506 unicode_append_menu = NULL;
d749b6fa
JR
1507 }
1508
1509 if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
1f06d367
JR
1510 local_free (out_string);
1511 }
1512 else
1513 {
1514 return_value =
1515 AppendMenu (menu,
1516 fuFlags,
1517 item != NULL ? (UINT) item : (UINT) wv->call_data,
1518 out_string );
1519 }
37ad8b63
JR
1520
1521 /* This must be done after the menu item is created. */
6f665da9 1522 if (!wv->title && wv->call_data != 0)
4cdf6a6c 1523 {
4cdf6a6c
AI
1524 if (set_menu_item_info)
1525 {
1526 MENUITEMINFO info;
72af86bd 1527 memset (&info, 0, sizeof (info));
4cdf6a6c
AI
1528 info.cbSize = sizeof (info);
1529 info.fMask = MIIM_DATA;
1530
d1fffd1d
JR
1531 /* Set help string for menu item. Leave it as a Lisp_Object
1532 until it is ready to be displayed, since GC can happen while
1533 menus are active. */
24ee9763 1534 if (!NILP (wv->help))
2d5c5f7d
EZ
1535 {
1536 /* As of Jul-2012, w32api headers say that dwItemData
1537 has DWORD type, but that's a bug: it should actually
37a9eac8 1538 be ULONG_PTR, which is correct for 32-bit and 64-bit
2d5c5f7d
EZ
1539 Windows alike. MSVC headers get it right; hopefully,
1540 MinGW headers will, too. */
37a9eac8 1541 info.dwItemData = (ULONG_PTR) XLI (wv->help);
2d5c5f7d 1542 }
4cdf6a6c
AI
1543 if (wv->button_type == BUTTON_TYPE_RADIO)
1544 {
1545 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
1546 RADIO items, but is not available on NT 3.51 and earlier. */
1547 info.fMask |= MIIM_TYPE | MIIM_STATE;
1548 info.fType = MFT_RADIOCHECK | MFT_STRING;
1549 info.dwTypeData = out_string;
1550 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
1551 }
1552
1553 set_menu_item_info (menu,
1554 item != NULL ? (UINT) item : (UINT) wv->call_data,
1555 FALSE, &info);
1556 }
1557 }
8bc53d00 1558 SAFE_FREE ();
37ad8b63 1559 return return_value;
485015ca
GV
1560}
1561
1562/* Construct native Windows menu(bar) based on widget_value tree. */
24f981c9 1563static int
485015ca
GV
1564fill_in_menu (HMENU menu, widget_value *wv)
1565{
485015ca
GV
1566 for ( ; wv != NULL; wv = wv->next)
1567 {
1568 if (wv->contents)
1569 {
1570 HMENU sub_menu = CreatePopupMenu ();
1571
1572 if (sub_menu == NULL)
1573 return 0;
1574
1575 if (!fill_in_menu (sub_menu, wv->contents) ||
1576 !add_menu_item (menu, wv, sub_menu))
1577 {
1578 DestroyMenu (sub_menu);
1579 return 0;
1580 }
1581 }
1582 else
1583 {
1584 if (!add_menu_item (menu, wv, NULL))
1585 return 0;
1586 }
1587 }
1588 return 1;
1589}
1590
7d8e57da
JR
1591/* Display help string for currently pointed to menu item. Not
1592 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
1593 available. */
1594void
59a86c99 1595w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
7d8e57da 1596{
7d8e57da
JR
1597 if (get_menu_item_info)
1598 {
1c5acb8c
JR
1599 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
1600 Lisp_Object frame, help;
7d8e57da 1601
94c7f257
JR
1602 /* No help echo on owner-draw menu items, or when the keyboard is used
1603 to navigate the menus, since tooltips are distracting if they pop
1604 up elsewhere. */
1605 if (flags & MF_OWNERDRAW || flags & MF_POPUP
1606 || !(flags & MF_MOUSESELECT))
ace9b298
JR
1607 help = Qnil;
1608 else
1609 {
1610 MENUITEMINFO info;
7d8e57da 1611
72af86bd 1612 memset (&info, 0, sizeof (info));
ace9b298
JR
1613 info.cbSize = sizeof (info);
1614 info.fMask = MIIM_DATA;
1615 get_menu_item_info (menu, item, FALSE, &info);
1616
646b5f55 1617 help = info.dwItemData ? XIL (info.dwItemData) : Qnil;
ace9b298 1618 }
e5cd3d11 1619
1c5acb8c
JR
1620 /* Store the help echo in the keyboard buffer as the X toolkit
1621 version does, rather than directly showing it. This seems to
1622 solve the GC problems that were present when we based the
1623 Windows code on the non-toolkit version. */
1624 if (f)
1625 {
1626 XSETFRAME (frame, f);
1627 kbd_buffer_store_help_event (frame, help);
1628 }
1629 else
1630 /* X version has a loop through frames here, which doesn't
1631 appear to do anything, unless it has some side effect. */
f868cd8a 1632 show_help_echo (help, Qnil, Qnil, Qnil);
7d8e57da
JR
1633 }
1634}
1635
d1fffd1d 1636/* Free memory used by owner-drawn strings. */
ace9b298 1637static void
b56ceb92 1638w32_free_submenu_strings (HMENU menu)
ace9b298
JR
1639{
1640 int i, num = GetMenuItemCount (menu);
1641 for (i = 0; i < num; i++)
1642 {
1643 MENUITEMINFO info;
72af86bd 1644 memset (&info, 0, sizeof (info));
ace9b298 1645 info.cbSize = sizeof (info);
d1fffd1d 1646 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
7d8e57da 1647
ace9b298
JR
1648 get_menu_item_info (menu, i, TRUE, &info);
1649
d1fffd1d
JR
1650 /* Owner-drawn names are held in dwItemData. */
1651 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
1652 {
1653#ifdef MENU_DEBUG
1654 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
1655#endif
6ed09cf0 1656 local_free (info.dwItemData);
d1fffd1d 1657 }
ace9b298
JR
1658
1659 /* Recurse down submenus. */
1660 if (info.hSubMenu)
1661 w32_free_submenu_strings (info.hSubMenu);
1662 }
1663}
1664
1665void
b56ceb92 1666w32_free_menu_strings (HWND hwnd)
ace9b298
JR
1667{
1668 HMENU menu = current_popup_menu;
1669
1670 if (get_menu_item_info)
1671 {
1672 /* If there is no popup menu active, free the strings from the frame's
1673 menubar. */
1674 if (!menu)
1675 menu = GetMenu (hwnd);
1676
1677 if (menu)
1678 w32_free_submenu_strings (menu);
1679 }
1680
1681 current_popup_menu = NULL;
1682}
7d8e57da 1683
485015ca 1684#endif /* HAVE_MENUS */
ace9b298 1685
e3135734
CY
1686/* The following is used by delayed window autoselection. */
1687
1688DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
1689 doc: /* Return t if a menu or popup dialog is active on selected frame. */)
5842a27b 1690 (void)
e3135734
CY
1691{
1692#ifdef HAVE_MENUS
1693 FRAME_PTR f;
1694 f = SELECTED_FRAME ();
1695 return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
1696#else
1697 return Qnil;
1698#endif /* HAVE_MENUS */
1699}
1700
b56ceb92
JB
1701void
1702syms_of_w32menu (void)
ee78dc32 1703{
019e3c1a 1704 globals_of_w32menu ();
485015ca 1705
ace9b298
JR
1706 current_popup_menu = NULL;
1707
019e3c1a 1708 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
fdc12c4d 1709
e5d3d18d 1710 defsubr (&Smenu_or_popup_active_p);
485015ca 1711#ifdef HAVE_MENUS
ee78dc32 1712 defsubr (&Sx_popup_dialog);
485015ca 1713#endif
ee78dc32 1714}
9785d95b
BK
1715
1716/*
1717 globals_of_w32menu is used to initialize those global variables that
1718 must always be initialized on startup even when the global variable
1719 initialized is non zero (see the function main in emacs.c).
1720 globals_of_w32menu is called from syms_of_w32menu when the global
1721 variable initialized is 0 and directly from main when initialized
1722 is non zero.
1723 */
b56ceb92
JB
1724void
1725globals_of_w32menu (void)
9785d95b 1726{
9d4f32e8 1727 /* See if Get/SetMenuItemInfo functions are available. */
9785d95b
BK
1728 HMODULE user32 = GetModuleHandle ("user32.dll");
1729 get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA");
1730 set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA");
1f06d367 1731 unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW");
1c9b4129 1732 unicode_message_box = (MessageBoxW_Proc) GetProcAddress (user32, "MessageBoxW");
9785d95b 1733}