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