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