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