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