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