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