*** empty log message ***
[bpt/emacs.git] / src / w32menu.c
CommitLineData
e9e23e23 1/* Menu support for GNU Emacs on the Microsoft W32 API.
68c45bf0 2 Copyright (C) 1986, 88, 93, 94, 96, 98, 1999 Free Software Foundation, Inc.
ee78dc32
GV
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
ee78dc32 20
ee78dc32 21#include <config.h>
68c45bf0 22#include <signal.h>
162d2499 23
ee78dc32
GV
24#include <stdio.h>
25#include "lisp.h"
26#include "termhooks.h"
15d36dee 27#include "keyboard.h"
5ee707b8 28#include "keymap.h"
ee78dc32
GV
29#include "frame.h"
30#include "window.h"
ee78dc32 31#include "blockinput.h"
fdc12c4d 32#include "buffer.h"
6915ded0
JR
33#include "charset.h"
34#include "coding.h"
ee78dc32
GV
35
36/* This may include sys/types.h, and that somehow loses
37 if this is not done before the other system files. */
38#include "w32term.h"
39
40/* Load sys/types.h if not already loaded.
41 In some systems loading it twice is suicidal. */
42#ifndef makedev
43#include <sys/types.h>
44#endif
45
46#include "dispextern.h"
47
162d2499 48#undef HAVE_MULTILINGUAL_MENU
222456a1 49#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
162d2499 50
485015ca
GV
51/******************************************************************/
52/* Definitions copied from lwlib.h */
ee78dc32 53
485015ca
GV
54typedef void * XtPointer;
55typedef char Boolean;
56
162d2499
JR
57enum button_type
58{
59 BUTTON_TYPE_NONE,
60 BUTTON_TYPE_TOGGLE,
61 BUTTON_TYPE_RADIO
62};
c8869655 63
d1fffd1d
JR
64/* This structure is based on the one in ../lwlib/lwlib.h, modified
65 for Windows. */
485015ca 66typedef struct _widget_value
ee78dc32 67{
485015ca
GV
68 /* name of widget */
69 char* name;
70 /* value (meaning depend on widget type) */
71 char* value;
72 /* keyboard equivalent. no implications for XtTranslations */
73 char* key;
d1fffd1d
JR
74 /* Help string or nil if none.
75 GC finds this string through the frame's menu_bar_vector
76 or through menu_items. */
77 Lisp_Object help;
485015ca
GV
78 /* true if enabled */
79 Boolean enabled;
80 /* true if selected */
81 Boolean selected;
162d2499
JR
82 /* The type of a button. */
83 enum button_type button_type;
485015ca
GV
84 /* true if menu title */
85 Boolean title;
86#if 0
87 /* true if was edited (maintained by get_value) */
88 Boolean edited;
89 /* true if has changed (maintained by lw library) */
90 change_type change;
91 /* true if this widget itself has changed,
92 but not counting the other widgets found in the `next' field. */
93 change_type this_one_change;
94#endif
95 /* Contents of the sub-widgets, also selected slot for checkbox */
96 struct _widget_value* contents;
97 /* data passed to callback */
98 XtPointer call_data;
99 /* next one in the list */
100 struct _widget_value* next;
101#if 0
102 /* slot for the toolkit dependent part. Always initialize to NULL. */
103 void* toolkit_data;
104 /* tell us if we should free the toolkit data slot when freeing the
105 widget_value itself. */
106 Boolean free_toolkit_data;
107
108 /* we resource the widget_value structures; this points to the next
109 one on the free list if this one has been deallocated.
110 */
111 struct _widget_value *free_list;
112#endif
113} widget_value;
114
115/* LocalAlloc/Free is a reasonably good allocator. */
116#define malloc_widget_value() (void*)LocalAlloc (LMEM_ZEROINIT, sizeof (widget_value))
117#define free_widget_value(wv) LocalFree (wv)
118
119/******************************************************************/
120
485015ca
GV
121#ifndef TRUE
122#define TRUE 1
123#define FALSE 0
124#endif /* no TRUE */
125
ace9b298
JR
126static HMENU current_popup_menu;
127
128FARPROC get_menu_item_info;
129FARPROC set_menu_item_info;
130
485015ca 131Lisp_Object Vmenu_updating_frame;
ee78dc32 132
fdc12c4d
RS
133Lisp_Object Qdebug_on_next_call;
134
ee78dc32 135extern Lisp_Object Qmenu_bar;
485015ca
GV
136extern Lisp_Object Qmouse_click, Qevent_kind;
137
138extern Lisp_Object QCtoggle, QCradio;
ee78dc32 139
fdc12c4d
RS
140extern Lisp_Object Voverriding_local_map;
141extern Lisp_Object Voverriding_local_map_menu_flag;
142
143extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
144
145extern Lisp_Object Qmenu_bar_update_hook;
146
014510b0
GV
147void set_frame_menubar ();
148
162d2499
JR
149static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
150 Lisp_Object, Lisp_Object, Lisp_Object,
151 Lisp_Object, Lisp_Object));
1c5acb8c 152#ifdef HAVE_DIALOGS
fbd6baed 153static Lisp_Object w32_dialog_show ();
1c5acb8c 154#endif
162d2499 155static Lisp_Object w32_menu_show ();
ee78dc32 156
485015ca
GV
157static void keymap_panes ();
158static void single_keymap_panes ();
159static void single_menu_item ();
160static void list_of_panes ();
161static void list_of_items ();
162\f
163/* This holds a Lisp vector that holds the results of decoding
164 the keymaps or alist-of-alists that specify a menu.
165
166 It describes the panes and items within the panes.
167
168 Each pane is described by 3 elements in the vector:
169 t, the pane name, the pane's prefix key.
170 Then follow the pane's items, with 5 elements per item:
171 the item string, the enable flag, the item's value,
172 the definition, and the equivalent keyboard key's description string.
173
174 In some cases, multiple levels of menus may be described.
175 A single vector slot containing nil indicates the start of a submenu.
176 A single vector slot containing lambda indicates the end of a submenu.
177 The submenu follows a menu item which is the way to reach the submenu.
178
179 A single vector slot containing quote indicates that the
180 following items should appear on the right of a dialog box.
181
182 Using a Lisp vector to hold this information while we decode it
183 takes care of protecting all the data from GC. */
184
185#define MENU_ITEMS_PANE_NAME 1
186#define MENU_ITEMS_PANE_PREFIX 2
187#define MENU_ITEMS_PANE_LENGTH 3
188
162d2499
JR
189enum menu_item_idx
190{
191 MENU_ITEMS_ITEM_NAME = 0,
192 MENU_ITEMS_ITEM_ENABLE,
193 MENU_ITEMS_ITEM_VALUE,
194 MENU_ITEMS_ITEM_EQUIV_KEY,
195 MENU_ITEMS_ITEM_DEFINITION,
196 MENU_ITEMS_ITEM_TYPE,
197 MENU_ITEMS_ITEM_SELECTED,
198 MENU_ITEMS_ITEM_HELP,
199 MENU_ITEMS_ITEM_LENGTH
200};
485015ca
GV
201
202static Lisp_Object menu_items;
203
204/* Number of slots currently allocated in menu_items. */
205static int menu_items_allocated;
206
207/* This is the index in menu_items of the first empty slot. */
208static int menu_items_used;
209
210/* The number of panes currently recorded in menu_items,
211 excluding those within submenus. */
212static int menu_items_n_panes;
213
214/* Current depth within submenus. */
215static int menu_items_submenu_depth;
216
217/* Flag which when set indicates a dialog or menu has been posted by
218 Xt on behalf of one of the widget sets. */
219static int popup_activated_flag;
220
162d2499
JR
221static int next_menubar_widget_id;
222
485015ca
GV
223/* This is set nonzero after the user activates the menu bar, and set
224 to zero again after the menu bars are redisplayed by prepare_menu_bar.
225 While it is nonzero, all calls to set_frame_menubar go deep.
226
227 I don't understand why this is needed, but it does seem to be
228 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
ee78dc32 229
485015ca
GV
230int pending_menu_activation;
231\f
232
233/* Return the frame whose ->output_data.w32->menubar_widget equals
162d2499 234 ID, or 0 if none. */
485015ca
GV
235
236static struct frame *
162d2499
JR
237menubar_id_to_frame (id)
238 HMENU id;
485015ca
GV
239{
240 Lisp_Object tail, frame;
241 FRAME_PTR f;
ee78dc32 242
8e713be6 243 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
485015ca 244 {
8e713be6 245 frame = XCAR (tail);
485015ca
GV
246 if (!GC_FRAMEP (frame))
247 continue;
248 f = XFRAME (frame);
162d2499 249 if (!FRAME_WINDOW_P (f))
485015ca 250 continue;
162d2499 251 if (f->output_data.w32->menubar_widget == id)
485015ca
GV
252 return f;
253 }
254 return 0;
255}
256\f
ee78dc32
GV
257/* Initialize the menu_items structure if we haven't already done so.
258 Also mark it as currently empty. */
259
485015ca
GV
260static void
261init_menu_items ()
ee78dc32 262{
485015ca 263 if (NILP (menu_items))
ee78dc32 264 {
485015ca
GV
265 menu_items_allocated = 60;
266 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
ee78dc32 267 }
485015ca
GV
268
269 menu_items_used = 0;
270 menu_items_n_panes = 0;
271 menu_items_submenu_depth = 0;
ee78dc32
GV
272}
273
485015ca
GV
274/* Call at the end of generating the data in menu_items.
275 This fills in the number of items in the last pane. */
ee78dc32 276
485015ca
GV
277static void
278finish_menu_items ()
ee78dc32 279{
ee78dc32 280}
014510b0
GV
281
282/* Call when finished using the data for the current menu
283 in menu_items. */
284
485015ca
GV
285static void
286discard_menu_items ()
014510b0 287{
485015ca
GV
288 /* Free the structure if it is especially large.
289 Otherwise, hold on to it, to save time. */
290 if (menu_items_allocated > 200)
014510b0 291 {
485015ca
GV
292 menu_items = Qnil;
293 menu_items_allocated = 0;
014510b0 294 }
014510b0
GV
295}
296
485015ca 297/* Make the menu_items vector twice as large. */
ee78dc32 298
485015ca
GV
299static void
300grow_menu_items ()
ee78dc32 301{
485015ca
GV
302 Lisp_Object old;
303 int old_size = menu_items_allocated;
304 old = menu_items;
305
306 menu_items_allocated *= 2;
307 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
308 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
309 old_size * sizeof (Lisp_Object));
ee78dc32
GV
310}
311
485015ca 312/* Begin a submenu. */
014510b0 313
485015ca
GV
314static void
315push_submenu_start ()
316{
317 if (menu_items_used + 1 > menu_items_allocated)
318 grow_menu_items ();
014510b0 319
485015ca
GV
320 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
321 menu_items_submenu_depth++;
ee78dc32 322}
485015ca
GV
323
324/* End a submenu. */
325
326static void
327push_submenu_end ()
ee78dc32 328{
485015ca
GV
329 if (menu_items_used + 1 > menu_items_allocated)
330 grow_menu_items ();
ee78dc32 331
485015ca
GV
332 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
333 menu_items_submenu_depth--;
ee78dc32
GV
334}
335
485015ca 336/* Indicate boundary between left and right. */
ee78dc32 337
485015ca
GV
338static void
339push_left_right_boundary ()
ee78dc32 340{
485015ca
GV
341 if (menu_items_used + 1 > menu_items_allocated)
342 grow_menu_items ();
343
344 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
ee78dc32
GV
345}
346
2cd23960 347/* Start a new menu pane in menu_items.
485015ca 348 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
ee78dc32 349
485015ca
GV
350static void
351push_menu_pane (name, prefix_vec)
352 Lisp_Object name, prefix_vec;
ee78dc32 353{
485015ca
GV
354 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
355 grow_menu_items ();
356
357 if (menu_items_submenu_depth == 0)
358 menu_items_n_panes++;
359 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
360 XVECTOR (menu_items)->contents[menu_items_used++] = name;
361 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
362}
ee78dc32 363
162d2499
JR
364/* Push one menu item into the current pane. NAME is the string to
365 display. ENABLE if non-nil means this item can be selected. KEY
366 is the key generated by choosing this item, or nil if this item
367 doesn't really have a definition. DEF is the definition of this
368 item. EQUIV is the textual description of the keyboard equivalent
369 for this item (or nil if none). TYPE is the type of this menu
370 item, one of nil, `toggle' or `radio'. */
485015ca
GV
371
372static void
162d2499
JR
373push_menu_item (name, enable, key, def, equiv, type, selected, help)
374 Lisp_Object name, enable, key, def, equiv, type, selected, help;
485015ca
GV
375{
376 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
377 grow_menu_items ();
378
379 XVECTOR (menu_items)->contents[menu_items_used++] = name;
380 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
381 XVECTOR (menu_items)->contents[menu_items_used++] = key;
382 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
383 XVECTOR (menu_items)->contents[menu_items_used++] = def;
162d2499
JR
384 XVECTOR (menu_items)->contents[menu_items_used++] = type;
385 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
386 XVECTOR (menu_items)->contents[menu_items_used++] = help;
ee78dc32
GV
387}
388\f
389/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
390 and generate menu panes for them in menu_items.
391 If NOTREAL is nonzero,
392 don't bother really computing whether an item is enabled. */
393
485015ca
GV
394static void
395keymap_panes (keymaps, nmaps, notreal)
ee78dc32
GV
396 Lisp_Object *keymaps;
397 int nmaps;
398 int notreal;
399{
400 int mapno;
014510b0 401
485015ca 402 init_menu_items ();
014510b0 403
485015ca
GV
404 /* Loop over the given keymaps, making a pane for each map.
405 But don't make a pane that is empty--ignore that map instead.
406 P is the number of panes we have made so far. */
407 for (mapno = 0; mapno < nmaps; mapno++)
e5cd3d11 408 single_keymap_panes (keymaps[mapno],
5ee707b8 409 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
ee78dc32 410
485015ca 411 finish_menu_items ();
ee78dc32
GV
412}
413
414/* This is a recursive subroutine of keymap_panes.
415 It handles one keymap, KEYMAP.
416 The other arguments are passed along
417 or point to local variables of the previous function.
485015ca
GV
418 If NOTREAL is nonzero, only check for equivalent key bindings, don't
419 evaluate expressions in menu items and don't make any menu.
ee78dc32 420
485015ca
GV
421 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
422
423static void
424single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
ee78dc32
GV
425 Lisp_Object keymap;
426 Lisp_Object pane_name;
427 Lisp_Object prefix;
428 int notreal;
485015ca 429 int maxdepth;
ee78dc32 430{
485015ca
GV
431 Lisp_Object pending_maps = Qnil;
432 Lisp_Object tail, item;
433 struct gcpro gcpro1, gcpro2;
485015ca
GV
434
435 if (maxdepth <= 0)
436 return;
437
438 push_menu_pane (pane_name, prefix);
439
8e713be6 440 for (tail = keymap; CONSP (tail); tail = XCDR (tail))
ee78dc32 441 {
485015ca
GV
442 GCPRO2 (keymap, pending_maps);
443 /* Look at each key binding, and if it is a menu item add it
444 to this menu. */
8e713be6 445 item = XCAR (tail);
ee78dc32 446 if (CONSP (item))
8e713be6 447 single_menu_item (XCAR (item), XCDR (item),
37ad8b63 448 &pending_maps, notreal, maxdepth);
ee78dc32
GV
449 else if (VECTORP (item))
450 {
451 /* Loop over the char values represented in the vector. */
452 int len = XVECTOR (item)->size;
453 int c;
454 for (c = 0; c < len; c++)
455 {
456 Lisp_Object character;
457 XSETFASTINT (character, c);
485015ca 458 single_menu_item (character, XVECTOR (item)->contents[c],
37ad8b63 459 &pending_maps, notreal, maxdepth);
ee78dc32
GV
460 }
461 }
485015ca 462 UNGCPRO;
ee78dc32
GV
463 }
464
465 /* Process now any submenus which want to be panes at this level. */
466 while (!NILP (pending_maps))
467 {
468 Lisp_Object elt, eltcdr, string;
469 elt = Fcar (pending_maps);
8e713be6
KR
470 eltcdr = XCDR (elt);
471 string = XCAR (eltcdr);
ee78dc32 472 /* We no longer discard the @ from the beginning of the string here.
485015ca
GV
473 Instead, we do this in w32_menu_show. */
474 single_keymap_panes (Fcar (elt), string,
8e713be6 475 XCDR (eltcdr), notreal, maxdepth - 1);
485015ca
GV
476 pending_maps = Fcdr (pending_maps);
477 }
478}
479\f
480/* This is a subroutine of single_keymap_panes that handles one
481 keymap entry.
482 KEY is a key in a keymap and ITEM is its binding.
483 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
484 separate panes.
485 If NOTREAL is nonzero, only check for equivalent key bindings, don't
486 evaluate expressions in menu items and don't make any menu.
37ad8b63 487 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
485015ca
GV
488
489static void
37ad8b63 490single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
485015ca
GV
491 Lisp_Object key, item;
492 Lisp_Object *pending_maps_ptr;
493 int maxdepth, notreal;
485015ca 494{
162d2499 495 Lisp_Object map, item_string, enabled;
485015ca
GV
496 struct gcpro gcpro1, gcpro2;
497 int res;
498
499 /* Parse the menu item and leave the result in item_properties. */
500 GCPRO2 (key, item);
501 res = parse_menu_item (item, notreal, 0);
502 UNGCPRO;
503 if (!res)
504 return; /* Not a menu item. */
505
506 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
507
508 if (notreal)
509 {
510 /* We don't want to make a menu, just traverse the keymaps to
511 precompute equivalent key bindings. */
512 if (!NILP (map))
513 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
514 return;
515 }
516
517 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
518 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
519
520 if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
521 {
522 if (!NILP (enabled))
523 /* An enabled separate pane. Remember this to handle it later. */
524 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
525 *pending_maps_ptr);
526 return;
527 }
528
485015ca
GV
529 push_menu_item (item_string, enabled, key,
530 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
162d2499
JR
531 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
532 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
533 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
534 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
485015ca 535
485015ca
GV
536 /* Display a submenu using the toolkit. */
537 if (! (NILP (map) || NILP (enabled)))
538 {
539 push_submenu_start ();
540 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
541 push_submenu_end ();
ee78dc32 542 }
ee78dc32
GV
543}
544\f
8e6208c5 545/* Push all the panes and items of a menu described by the
ee78dc32
GV
546 alist-of-alists MENU.
547 This handles old-fashioned calls to x-popup-menu. */
548
485015ca
GV
549static void
550list_of_panes (menu)
ee78dc32
GV
551 Lisp_Object menu;
552{
553 Lisp_Object tail;
014510b0 554
485015ca 555 init_menu_items ();
014510b0 556
485015ca 557 for (tail = menu; !NILP (tail); tail = Fcdr (tail))
ee78dc32
GV
558 {
559 Lisp_Object elt, pane_name, pane_data;
485015ca 560 elt = Fcar (tail);
ee78dc32 561 pane_name = Fcar (elt);
b7826503 562 CHECK_STRING (pane_name);
485015ca 563 push_menu_pane (pane_name, Qnil);
ee78dc32 564 pane_data = Fcdr (elt);
b7826503 565 CHECK_CONS (pane_data);
485015ca 566 list_of_items (pane_data);
ee78dc32 567 }
485015ca
GV
568
569 finish_menu_items ();
ee78dc32
GV
570}
571
572/* Push the items in a single pane defined by the alist PANE. */
573
485015ca
GV
574static void
575list_of_items (pane)
ee78dc32
GV
576 Lisp_Object pane;
577{
578 Lisp_Object tail, item, item1;
ee78dc32 579
ee78dc32
GV
580 for (tail = pane; !NILP (tail); tail = Fcdr (tail))
581 {
582 item = Fcar (tail);
583 if (STRINGP (item))
162d2499 584 push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
ee78dc32 585 else if (NILP (item))
485015ca 586 push_left_right_boundary ();
ee78dc32
GV
587 else
588 {
b7826503 589 CHECK_CONS (item);
ee78dc32 590 item1 = Fcar (item);
b7826503 591 CHECK_STRING (item1);
162d2499 592 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
ee78dc32
GV
593 }
594 }
ee78dc32
GV
595}
596\f
485015ca 597DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
33f09670
JR
598 doc: /* Pop up a deck-of-cards menu and return user's selection.
599POSITION is a position specification. This is either a mouse button
600event or a list ((XOFFSET YOFFSET) WINDOW) where XOFFSET and YOFFSET
601are positions in pixels from the top left corner of WINDOW's frame
602\(WINDOW may be a frame object instead of a window). This controls the
603position of the center of the first line in the first pane of the
604menu, not the top left of the menu as a whole. If POSITION is t, it
605means to use the current mouse position.
606
607MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
608The menu items come from key bindings that have a menu string as well as
609a definition; actually, the \"definition\" in such a key binding looks like
610\(STRING . REAL-DEFINITION). To give the menu a title, put a string into
611the keymap as a top-level element.
612
613If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
614Otherwise, REAL-DEFINITION should be a valid key binding definition.
615
616You can also use a list of keymaps as MENU. Then each keymap makes a
617separate pane. When MENU is a keymap or a list of keymaps, the return
618value is a list of events.
619
620Alternatively, you can specify a menu of multiple panes with a list of
621the form (TITLE PANE1 PANE2...), where each pane is a list of
622form (TITLE ITEM1 ITEM2...).
623Each ITEM is normally a cons cell (STRING . VALUE); but a string can
624appear as an item--that makes a nonselectable line in the menu.
625With this form of menu, the return value is VALUE from the chosen item.
626
627If POSITION is nil, don't display the menu at all, just precalculate the
628cached information about equivalent key sequences. */)
485015ca
GV
629 (position, menu)
630 Lisp_Object position, menu;
ee78dc32 631{
ee78dc32 632 Lisp_Object keymap, tem;
b2123f81 633 int xpos = 0, ypos = 0;
ee78dc32
GV
634 Lisp_Object title;
635 char *error_name;
636 Lisp_Object selection;
b2123f81 637 FRAME_PTR f = NULL;
ee78dc32
GV
638 Lisp_Object x, y, window;
639 int keymaps = 0;
485015ca 640 int for_click = 0;
ee78dc32 641 struct gcpro gcpro1;
485015ca
GV
642
643#ifdef HAVE_MENUS
ee78dc32
GV
644 if (! NILP (position))
645 {
485015ca
GV
646 check_w32 ();
647
ee78dc32 648 /* Decode the first argument: find the window and the coordinates. */
ef06882d 649 if (EQ (position, Qt)
0b6bb670
JR
650 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
651 || EQ (XCAR (position), Qtool_bar))))
ee78dc32
GV
652 {
653 /* Use the mouse's current position. */
162d2499 654 FRAME_PTR new_f = SELECTED_FRAME ();
ee78dc32 655 Lisp_Object bar_window;
162d2499 656 enum scroll_bar_part part;
ee78dc32 657 unsigned long time;
485015ca 658
ee78dc32 659 if (mouse_position_hook)
485015ca
GV
660 (*mouse_position_hook) (&new_f, 1, &bar_window,
661 &part, &x, &y, &time);
ee78dc32
GV
662 if (new_f != 0)
663 XSETFRAME (window, new_f);
664 else
665 {
666 window = selected_window;
667 XSETFASTINT (x, 0);
668 XSETFASTINT (y, 0);
669 }
670 }
671 else
672 {
673 tem = Fcar (position);
674 if (CONSP (tem))
675 {
676 window = Fcar (Fcdr (position));
677 x = Fcar (tem);
678 y = Fcar (Fcdr (tem));
679 }
680 else
681 {
485015ca
GV
682 for_click = 1;
683 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
684 window = Fcar (tem); /* POSN_WINDOW (tem) */
ee78dc32
GV
685 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
686 x = Fcar (tem);
687 y = Fcdr (tem);
ee78dc32
GV
688 }
689 }
485015ca 690
b7826503
PJ
691 CHECK_NUMBER (x);
692 CHECK_NUMBER (y);
ee78dc32
GV
693
694 /* Decode where to put the menu. */
485015ca 695
ee78dc32
GV
696 if (FRAMEP (window))
697 {
698 f = XFRAME (window);
ee78dc32
GV
699 xpos = 0;
700 ypos = 0;
701 }
702 else if (WINDOWP (window))
703 {
b7826503 704 CHECK_LIVE_WINDOW (window);
ee78dc32 705 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
485015ca 706
162d2499 707 xpos = (FONT_WIDTH (FRAME_FONT (f))
485015ca 708 * XFASTINT (XWINDOW (window)->left));
162d2499 709 ypos = (FRAME_LINE_HEIGHT (f)
485015ca 710 * XFASTINT (XWINDOW (window)->top));
ee78dc32
GV
711 }
712 else
713 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
714 but I don't want to make one now. */
b7826503 715 CHECK_WINDOW (window);
485015ca 716
ee78dc32
GV
717 xpos += XINT (x);
718 ypos += XINT (y);
c8869655
GV
719
720 XSETFRAME (Vmenu_updating_frame, f);
ee78dc32 721 }
c8869655 722 Vmenu_updating_frame = Qnil;
485015ca 723#endif /* HAVE_MENUS */
c8869655 724
ee78dc32
GV
725 title = Qnil;
726 GCPRO1 (title);
485015ca
GV
727
728 /* Decode the menu items from what was specified. */
729
02067692
SM
730 keymap = get_keymap (menu, 0, 0);
731 if (CONSP (keymap))
485015ca
GV
732 {
733 /* We were given a keymap. Extract menu info from the keymap. */
734 Lisp_Object prompt;
485015ca
GV
735
736 /* Extract the detailed info to make one pane. */
737 keymap_panes (&menu, 1, NILP (position));
738
739 /* Search for a string appearing directly as an element of the keymap.
740 That string is the title of the menu. */
5ee707b8 741 prompt = Fkeymap_prompt (keymap);
485015ca
GV
742 if (NILP (title) && !NILP (prompt))
743 title = prompt;
744
745 /* Make that be the pane title of the first pane. */
746 if (!NILP (prompt) && menu_items_n_panes >= 0)
747 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
748
749 keymaps = 1;
750 }
02067692 751 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
485015ca
GV
752 {
753 /* We were given a list of keymaps. */
754 int nmaps = XFASTINT (Flength (menu));
755 Lisp_Object *maps
756 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
757 int i;
758
759 title = Qnil;
760
761 /* The first keymap that has a prompt string
762 supplies the menu title. */
763 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
764 {
765 Lisp_Object prompt;
766
02067692 767 maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
485015ca 768
5ee707b8 769 prompt = Fkeymap_prompt (keymap);
485015ca
GV
770 if (NILP (title) && !NILP (prompt))
771 title = prompt;
772 }
773
774 /* Extract the detailed info to make one pane. */
775 keymap_panes (maps, nmaps, NILP (position));
776
777 /* Make the title be the pane title of the first pane. */
778 if (!NILP (title) && menu_items_n_panes >= 0)
779 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
780
781 keymaps = 1;
782 }
783 else
784 {
785 /* We were given an old-fashioned menu. */
786 title = Fcar (menu);
b7826503 787 CHECK_STRING (title);
485015ca
GV
788
789 list_of_panes (Fcdr (menu));
790
791 keymaps = 0;
792 }
ee78dc32
GV
793
794 if (NILP (position))
795 {
485015ca 796 discard_menu_items ();
ee78dc32
GV
797 UNGCPRO;
798 return Qnil;
799 }
485015ca
GV
800
801#ifdef HAVE_MENUS
ee78dc32
GV
802 /* Display them in a menu. */
803 BLOCK_INPUT;
485015ca
GV
804
805 selection = w32_menu_show (f, xpos, ypos, for_click,
806 keymaps, title, &error_name);
ee78dc32 807 UNBLOCK_INPUT;
485015ca
GV
808
809 discard_menu_items ();
810
ee78dc32 811 UNGCPRO;
485015ca
GV
812#endif /* HAVE_MENUS */
813
ee78dc32
GV
814 if (error_name) error (error_name);
815 return selection;
816}
817
485015ca
GV
818#ifdef HAVE_MENUS
819
ee78dc32 820DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
33f09670
JR
821 doc: /* Pop up a dialog box and return user's selection.
822POSITION specifies which frame to use.
823This is normally a mouse button event or a window or frame.
824If POSITION is t, it means to use the frame the mouse is on.
825The dialog box appears in the middle of the specified frame.
826
827CONTENTS specifies the alternatives to display in the dialog box.
828It is a list of the form (TITLE ITEM1 ITEM2...).
829Each ITEM is a cons cell (STRING . VALUE).
830The return value is VALUE from the chosen item.
831
832An ITEM may also be just a string--that makes a nonselectable item.
833An ITEM may also be nil--that means to put all preceding items
834on the left of the dialog box and all following items on the right.
835\(By default, approximately half appear on each side.) */)
485015ca
GV
836 (position, contents)
837 Lisp_Object position, contents;
ee78dc32 838{
b2123f81 839 FRAME_PTR f = NULL;
ee78dc32 840 Lisp_Object window;
485015ca
GV
841
842 check_w32 ();
843
ee78dc32 844 /* Decode the first argument: find the window or frame to use. */
485015ca 845 if (EQ (position, Qt)
0b6bb670
JR
846 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
847 || EQ (XCAR (position), Qtool_bar))))
ee78dc32 848 {
485015ca
GV
849#if 0 /* Using the frame the mouse is on may not be right. */
850 /* Use the mouse's current position. */
162d2499 851 FRAME_PTR new_f = SELECTED_FRAME ();
485015ca 852 Lisp_Object bar_window;
15d36dee 853 enum scroll_bar_part part;
485015ca
GV
854 unsigned long time;
855 Lisp_Object x, y;
856
857 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
858
859 if (new_f != 0)
860 XSETFRAME (window, new_f);
861 else
ee78dc32 862 window = selected_window;
485015ca
GV
863#endif
864 window = selected_window;
ee78dc32
GV
865 }
866 else if (CONSP (position))
867 {
868 Lisp_Object tem;
869 tem = Fcar (position);
485015ca 870 if (CONSP (tem))
ee78dc32
GV
871 window = Fcar (Fcdr (position));
872 else
873 {
485015ca
GV
874 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
875 window = Fcar (tem); /* POSN_WINDOW (tem) */
ee78dc32
GV
876 }
877 }
878 else if (WINDOWP (position) || FRAMEP (position))
879 window = position;
485015ca
GV
880 else
881 window = Qnil;
882
ee78dc32 883 /* Decode where to put the menu. */
485015ca 884
ee78dc32
GV
885 if (FRAMEP (window))
886 f = XFRAME (window);
887 else if (WINDOWP (window))
888 {
b7826503 889 CHECK_LIVE_WINDOW (window);
ee78dc32
GV
890 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
891 }
892 else
893 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
894 but I don't want to make one now. */
b7826503 895 CHECK_WINDOW (window);
485015ca 896
162d2499 897#ifndef HAVE_DIALOGS
ee78dc32
GV
898 /* Display a menu with these alternatives
899 in the middle of frame F. */
900 {
901 Lisp_Object x, y, frame, newpos;
902 XSETFRAME (frame, f);
903 XSETINT (x, x_pixel_width (f) / 2);
904 XSETINT (y, x_pixel_height (f) / 2);
905 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
906
907 return Fx_popup_menu (newpos,
908 Fcons (Fcar (contents), Fcons (contents, Qnil)));
909 }
162d2499 910#else /* HAVE_DIALOGS */
ee78dc32
GV
911 {
912 Lisp_Object title;
913 char *error_name;
914 Lisp_Object selection;
915
916 /* Decode the dialog items from what was specified. */
917 title = Fcar (contents);
b7826503 918 CHECK_STRING (title);
ee78dc32
GV
919
920 list_of_panes (Fcons (contents, Qnil));
921
922 /* Display them in a dialog box. */
923 BLOCK_INPUT;
485015ca 924 selection = w32_dialog_show (f, 0, title, &error_name);
ee78dc32
GV
925 UNBLOCK_INPUT;
926
927 discard_menu_items ();
928
929 if (error_name) error (error_name);
930 return selection;
931 }
162d2499 932#endif /* HAVE_DIALOGS */
ee78dc32
GV
933}
934
014510b0
GV
935/* Activate the menu bar of frame F.
936 This is called from keyboard.c when it gets the
937 menu_bar_activate_event out of the Emacs event queue.
938
939 To activate the menu bar, we signal to the input thread that it can
940 return from the WM_INITMENU message, allowing the normal Windows
941 processing of the menus.
942
943 But first we recompute the menu bar contents (the whole tree).
944
945 This way we can safely execute Lisp code. */
946
162d2499 947void
014510b0
GV
948x_activate_menubar (f)
949 FRAME_PTR f;
950{
951 set_frame_menubar (f, 0, 1);
952
953 /* Lock out further menubar changes while active. */
954 f->output_data.w32->menubar_active = 1;
955
956 /* Signal input thread to return from WM_INITMENU. */
957 complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0);
958}
959
485015ca
GV
960/* This callback is called from the menu bar pulldown menu
961 when the user makes a selection.
962 Figure out what the user chose
963 and put the appropriate events into the keyboard buffer. */
964
965void
966menubar_selection_callback (FRAME_PTR f, void * client_data)
ee78dc32 967{
485015ca
GV
968 Lisp_Object prefix, entry;
969 Lisp_Object vector;
970 Lisp_Object *subprefix_stack;
971 int submenu_depth = 0;
ee78dc32 972 int i;
fdc12c4d 973
485015ca 974 if (!f)
014510b0 975 return;
fe5a0162 976 entry = Qnil;
485015ca
GV
977 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
978 vector = f->menu_bar_vector;
979 prefix = Qnil;
980 i = 0;
981 while (i < f->menu_bar_items_used)
982 {
983 if (EQ (XVECTOR (vector)->contents[i], Qnil))
984 {
985 subprefix_stack[submenu_depth++] = prefix;
986 prefix = entry;
987 i++;
988 }
989 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
990 {
991 prefix = subprefix_stack[--submenu_depth];
992 i++;
993 }
994 else if (EQ (XVECTOR (vector)->contents[i], Qt))
995 {
996 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
997 i += MENU_ITEMS_PANE_LENGTH;
998 }
999 else
1000 {
1001 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1002 /* The EMACS_INT cast avoids a warning. There's no problem
1003 as long as pointers have enough bits to hold small integers. */
1004 if ((int) (EMACS_INT) client_data == i)
1005 {
1006 int j;
1007 struct input_event buf;
1008 Lisp_Object frame;
014510b0 1009
485015ca 1010 XSETFRAME (frame, f);
20501278
GM
1011 buf.kind = MENU_BAR_EVENT;
1012 buf.frame_or_window = frame;
1013 buf.arg = frame;
485015ca 1014 kbd_buffer_store_event (&buf);
014510b0 1015
485015ca
GV
1016 for (j = 0; j < submenu_depth; j++)
1017 if (!NILP (subprefix_stack[j]))
1018 {
20501278
GM
1019 buf.kind = MENU_BAR_EVENT;
1020 buf.frame_or_window = frame;
1021 buf.arg = subprefix_stack[j];
485015ca
GV
1022 kbd_buffer_store_event (&buf);
1023 }
fdc12c4d 1024
485015ca
GV
1025 if (!NILP (prefix))
1026 {
20501278
GM
1027 buf.kind = MENU_BAR_EVENT;
1028 buf.frame_or_window = frame;
1029 buf.arg = prefix;
485015ca
GV
1030 kbd_buffer_store_event (&buf);
1031 }
fdc12c4d 1032
20501278
GM
1033 buf.kind = MENU_BAR_EVENT;
1034 buf.frame_or_window = frame;
1035 buf.arg = entry;
485015ca 1036 kbd_buffer_store_event (&buf);
fdc12c4d 1037
485015ca
GV
1038 return;
1039 }
1040 i += MENU_ITEMS_ITEM_LENGTH;
1041 }
014510b0 1042 }
485015ca 1043}
014510b0 1044
485015ca 1045/* Allocate a widget_value, blocking input. */
014510b0 1046
485015ca
GV
1047widget_value *
1048xmalloc_widget_value ()
1049{
1050 widget_value *value;
014510b0 1051
fdc12c4d 1052 BLOCK_INPUT;
485015ca 1053 value = malloc_widget_value ();
ee78dc32 1054 UNBLOCK_INPUT;
485015ca
GV
1055
1056 return value;
ee78dc32
GV
1057}
1058
485015ca
GV
1059/* This recursively calls free_widget_value on the tree of widgets.
1060 It must free all data that was malloc'ed for these widget_values.
1061 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1062 must be left alone. */
1063
1064void
1065free_menubar_widget_value_tree (wv)
1066 widget_value *wv;
ee78dc32 1067{
485015ca 1068 if (! wv) return;
ee78dc32 1069
485015ca
GV
1070 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1071
1072 if (wv->contents && (wv->contents != (widget_value*)1))
1073 {
1074 free_menubar_widget_value_tree (wv->contents);
1075 wv->contents = (widget_value *) 0xDEADBEEF;
1076 }
1077 if (wv->next)
1078 {
1079 free_menubar_widget_value_tree (wv->next);
1080 wv->next = (widget_value *) 0xDEADBEEF;
1081 }
1082 BLOCK_INPUT;
1083 free_widget_value (wv);
ee78dc32
GV
1084 UNBLOCK_INPUT;
1085}
ee78dc32 1086\f
485015ca
GV
1087/* Return a tree of widget_value structures for a menu bar item
1088 whose event type is ITEM_KEY (with string ITEM_NAME)
1089 and whose contents come from the list of keymaps MAPS. */
ee78dc32 1090
485015ca
GV
1091static widget_value *
1092single_submenu (item_key, item_name, maps)
1093 Lisp_Object item_key, item_name, maps;
ee78dc32 1094{
485015ca
GV
1095 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1096 int i;
1097 int submenu_depth = 0;
1098 Lisp_Object length;
1099 int len;
1100 Lisp_Object *mapvec;
1101 widget_value **submenu_stack;
485015ca
GV
1102 int previous_items = menu_items_used;
1103 int top_level_items = 0;
ee78dc32 1104
485015ca
GV
1105 length = Flength (maps);
1106 len = XINT (length);
ee78dc32 1107
485015ca
GV
1108 /* Convert the list MAPS into a vector MAPVEC. */
1109 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1110 for (i = 0; i < len; i++)
ee78dc32 1111 {
485015ca
GV
1112 mapvec[i] = Fcar (maps);
1113 maps = Fcdr (maps);
ee78dc32
GV
1114 }
1115
485015ca 1116 menu_items_n_panes = 0;
ee78dc32 1117
485015ca
GV
1118 /* Loop over the given keymaps, making a pane for each map.
1119 But don't make a pane that is empty--ignore that map instead. */
1120 for (i = 0; i < len; i++)
ee78dc32 1121 {
485015ca 1122 if (SYMBOLP (mapvec[i])
02067692 1123 || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
485015ca
GV
1124 {
1125 /* Here we have a command at top level in the menu bar
1126 as opposed to a submenu. */
1127 top_level_items = 1;
1128 push_menu_pane (Qnil, Qnil);
162d2499
JR
1129 push_menu_item (item_name, Qt, item_key, mapvec[i],
1130 Qnil, Qnil, Qnil, Qnil);
485015ca
GV
1131 }
1132 else
1133 single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
ee78dc32 1134 }
485015ca
GV
1135
1136 /* Create a tree of widget_value objects
1137 representing the panes and their items. */
1138
1139 submenu_stack
1140 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1141 wv = xmalloc_widget_value ();
1142 wv->name = "menu";
1143 wv->value = 0;
1144 wv->enabled = 1;
162d2499 1145 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1146 first_wv = wv;
1147 save_wv = 0;
1148 prev_wv = 0;
1149
1150 /* Loop over all panes and items made during this call
1151 and construct a tree of widget_value objects.
1152 Ignore the panes and items made by previous calls to
1153 single_submenu, even though those are also in menu_items. */
1154 i = previous_items;
ee78dc32
GV
1155 while (i < menu_items_used)
1156 {
1157 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1158 {
485015ca
GV
1159 submenu_stack[submenu_depth++] = save_wv;
1160 save_wv = prev_wv;
1161 prev_wv = 0;
ee78dc32
GV
1162 i++;
1163 }
1164 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1165 {
485015ca
GV
1166 prev_wv = save_wv;
1167 save_wv = submenu_stack[--submenu_depth];
ee78dc32
GV
1168 i++;
1169 }
485015ca
GV
1170 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1171 && submenu_depth != 0)
1172 i += MENU_ITEMS_PANE_LENGTH;
ee78dc32
GV
1173 /* Ignore a nil in the item list.
1174 It's meaningful only for dialog boxes. */
485015ca
GV
1175 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1176 i += 1;
1177 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1178 {
1179 /* Create a new pane. */
1180 Lisp_Object pane_name, prefix;
1181 char *pane_string;
29250851 1182
485015ca
GV
1183 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1184 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
29250851 1185
162d2499
JR
1186#ifndef HAVE_MULTILINGUAL_MENU
1187 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
29250851
JR
1188 {
1189 pane_name = ENCODE_SYSTEM (pane_name);
1190 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1191 }
162d2499 1192#endif
485015ca
GV
1193 pane_string = (NILP (pane_name)
1194 ? "" : (char *) XSTRING (pane_name)->data);
1195 /* If there is just one top-level pane, put all its items directly
1196 under the top-level menu. */
1197 if (menu_items_n_panes == 1)
1198 pane_string = "";
1199
1200 /* If the pane has a meaningful name,
1201 make the pane a top-level menu item
1202 with its items as a submenu beneath it. */
1203 if (strcmp (pane_string, ""))
1204 {
1205 wv = xmalloc_widget_value ();
1206 if (save_wv)
1207 save_wv->next = wv;
1208 else
1209 first_wv->contents = wv;
1210 wv->name = pane_string;
1211 /* Ignore the @ that means "separate pane".
1212 This is a kludge, but this isn't worth more time. */
1213 if (!NILP (prefix) && wv->name[0] == '@')
1214 wv->name++;
1215 wv->value = 0;
1216 wv->enabled = 1;
162d2499 1217 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1218 }
1219 save_wv = wv;
1220 prev_wv = 0;
1221 i += MENU_ITEMS_PANE_LENGTH;
1222 }
1223 else
1224 {
1225 /* Create a new item within current pane. */
162d2499
JR
1226 Lisp_Object item_name, enable, descrip, def, type, selected;
1227 Lisp_Object help;
7d8e57da 1228
29250851
JR
1229 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1230 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1231 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1232 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1233 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1234 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1235 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
162d2499
JR
1236
1237#ifndef HAVE_MULTILINGUAL_MENU
1238 if (STRING_MULTIBYTE (item_name))
29250851
JR
1239 {
1240 item_name = ENCODE_SYSTEM (item_name);
1241 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1242 }
1243
162d2499 1244 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
29250851
JR
1245 {
1246 descrip = ENCODE_SYSTEM (descrip);
1247 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1248 }
1249#endif /* not HAVE_MULTILINGUAL_MENU */
485015ca
GV
1250
1251 wv = xmalloc_widget_value ();
1252 if (prev_wv)
1253 prev_wv->next = wv;
1254 else
1255 save_wv->contents = wv;
1256
1257 wv->name = (char *) XSTRING (item_name)->data;
1258 if (!NILP (descrip))
1259 wv->key = (char *) XSTRING (descrip)->data;
1260 wv->value = 0;
1261 /* The EMACS_INT cast avoids a warning. There's no problem
1262 as long as pointers have enough bits to hold small integers. */
1263 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1264 wv->enabled = !NILP (enable);
162d2499
JR
1265
1266 if (NILP (type))
1267 wv->button_type = BUTTON_TYPE_NONE;
1268 else if (EQ (type, QCradio))
1269 wv->button_type = BUTTON_TYPE_RADIO;
1270 else if (EQ (type, QCtoggle))
1271 wv->button_type = BUTTON_TYPE_TOGGLE;
1272 else
1273 abort ();
1274
1275 wv->selected = !NILP (selected);
d1fffd1d
JR
1276 if (!STRINGP (help))
1277 help = Qnil;
1278
1279 wv->help = help;
7d8e57da 1280
485015ca
GV
1281 prev_wv = wv;
1282
1283 i += MENU_ITEMS_ITEM_LENGTH;
1284 }
1285 }
1286
1287 /* If we have just one "menu item"
1288 that was originally a button, return it by itself. */
1289 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
1290 {
1291 wv = first_wv->contents;
1292 free_widget_value (first_wv);
1293 return wv;
1294 }
1295
1296 return first_wv;
1297}
1298\f
1299/* Set the contents of the menubar widgets of frame F.
1300 The argument FIRST_TIME is currently ignored;
1301 it is set the first time this is called, from initialize_frame_menubar. */
1302
1303void
1304set_frame_menubar (f, first_time, deep_p)
1305 FRAME_PTR f;
1306 int first_time;
1307 int deep_p;
1308{
1309 HMENU menubar_widget = f->output_data.w32->menubar_widget;
162d2499 1310 Lisp_Object items;
485015ca
GV
1311 widget_value *wv, *first_wv, *prev_wv = 0;
1312 int i;
1313
1314 /* We must not change the menubar when actually in use. */
1315 if (f->output_data.w32->menubar_active)
1316 return;
1317
1318 XSETFRAME (Vmenu_updating_frame, f);
1319
1320 if (! menubar_widget)
1321 deep_p = 1;
1322 else if (pending_menu_activation && !deep_p)
1323 deep_p = 1;
1324
1325 wv = xmalloc_widget_value ();
1326 wv->name = "menubar";
1327 wv->value = 0;
1328 wv->enabled = 1;
162d2499 1329 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1330 first_wv = wv;
1331
1332 if (deep_p)
1333 {
1334 /* Make a widget-value tree representing the entire menu trees. */
1335
1336 struct buffer *prev = current_buffer;
1337 Lisp_Object buffer;
1338 int specpdl_count = specpdl_ptr - specpdl;
1339 int previous_menu_items_used = f->menu_bar_items_used;
1340 Lisp_Object *previous_items
1341 = (Lisp_Object *) alloca (previous_menu_items_used
1342 * sizeof (Lisp_Object));
1343
1344 /* If we are making a new widget, its contents are empty,
1345 do always reinitialize them. */
1346 if (! menubar_widget)
1347 previous_menu_items_used = 0;
1348
1349 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1350 specbind (Qinhibit_quit, Qt);
1351 /* Don't let the debugger step into this code
1352 because it is not reentrant. */
1353 specbind (Qdebug_on_next_call, Qnil);
1354
1355 record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
1356 if (NILP (Voverriding_local_map_menu_flag))
1357 {
1358 specbind (Qoverriding_terminal_local_map, Qnil);
1359 specbind (Qoverriding_local_map, Qnil);
1360 }
1361
1362 set_buffer_internal_1 (XBUFFER (buffer));
1363
1364 /* Run the Lucid hook. */
c53b6500 1365 safe_run_hooks (Qactivate_menubar_hook);
485015ca
GV
1366 /* If it has changed current-menubar from previous value,
1367 really recompute the menubar from the value. */
1368 if (! NILP (Vlucid_menu_bar_dirty_flag))
1369 call0 (Qrecompute_lucid_menubar);
1370 safe_run_hooks (Qmenu_bar_update_hook);
1371 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1372
1373 items = FRAME_MENU_BAR_ITEMS (f);
1374
1375 inhibit_garbage_collection ();
1376
1377 /* Save the frame's previous menu bar contents data. */
c30dce3d
AI
1378 if (previous_menu_items_used)
1379 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1380 previous_menu_items_used * sizeof (Lisp_Object));
485015ca
GV
1381
1382 /* Fill in the current menu bar contents. */
1383 menu_items = f->menu_bar_vector;
c30dce3d 1384 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
485015ca
GV
1385 init_menu_items ();
1386 for (i = 0; i < XVECTOR (items)->size; i += 4)
1387 {
1388 Lisp_Object key, string, maps;
1389
1390 key = XVECTOR (items)->contents[i];
1391 string = XVECTOR (items)->contents[i + 1];
1392 maps = XVECTOR (items)->contents[i + 2];
1393 if (NILP (string))
1394 break;
1395
1396 wv = single_submenu (key, string, maps);
1397 if (prev_wv)
1398 prev_wv->next = wv;
1399 else
1400 first_wv->contents = wv;
1401 /* Don't set wv->name here; GC during the loop might relocate it. */
1402 wv->enabled = 1;
162d2499 1403 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1404 prev_wv = wv;
1405 }
1406
1407 finish_menu_items ();
1408
1409 set_buffer_internal_1 (prev);
1410 unbind_to (specpdl_count, Qnil);
1411
1412 /* If there has been no change in the Lisp-level contents
1413 of the menu bar, skip redisplaying it. Just exit. */
1414
1415 for (i = 0; i < previous_menu_items_used; i++)
1416 if (menu_items_used == i
1417 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1418 break;
1419 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1420 {
1421 free_menubar_widget_value_tree (first_wv);
1422 menu_items = Qnil;
1423
1424 return;
1425 }
1426
1427 /* Now GC cannot happen during the lifetime of the widget_value,
ace9b298
JR
1428 so it's safe to store data from a Lisp_String, as long as
1429 local copies are made when the actual menu is created.
1430 Windows takes care of this for normal string items, but
1431 not for owner-drawn items or additional item-info. */
485015ca
GV
1432 wv = first_wv->contents;
1433 for (i = 0; i < XVECTOR (items)->size; i += 4)
1434 {
1435 Lisp_Object string;
1436 string = XVECTOR (items)->contents[i + 1];
1437 if (NILP (string))
1438 break;
1439 wv->name = (char *) XSTRING (string)->data;
1440 wv = wv->next;
1441 }
1442
1443 f->menu_bar_vector = menu_items;
1444 f->menu_bar_items_used = menu_items_used;
1445 menu_items = Qnil;
1446 }
1447 else
1448 {
1449 /* Make a widget-value tree containing
162d2499 1450 just the top level menu bar strings. */
485015ca
GV
1451
1452 items = FRAME_MENU_BAR_ITEMS (f);
485015ca
GV
1453 for (i = 0; i < XVECTOR (items)->size; i += 4)
1454 {
1455 Lisp_Object string;
1456
1457 string = XVECTOR (items)->contents[i + 1];
1458 if (NILP (string))
1459 break;
1460
1461 wv = xmalloc_widget_value ();
1462 wv->name = (char *) XSTRING (string)->data;
1463 wv->value = 0;
1464 wv->enabled = 1;
162d2499 1465 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1466 /* This prevents lwlib from assuming this
1467 menu item is really supposed to be empty. */
1468 /* The EMACS_INT cast avoids a warning.
1469 This value just has to be different from small integers. */
1470 wv->call_data = (void *) (EMACS_INT) (-1);
1471
1472 if (prev_wv)
1473 prev_wv->next = wv;
1474 else
1475 first_wv->contents = wv;
1476 prev_wv = wv;
1477 }
1478
162d2499
JR
1479 /* Forget what we thought we knew about what is in the
1480 detailed contents of the menu bar menus.
1481 Changing the top level always destroys the contents. */
1482 f->menu_bar_items_used = 0;
485015ca
GV
1483 }
1484
1485 /* Create or update the menu bar widget. */
ee78dc32 1486
485015ca 1487 BLOCK_INPUT;
ee78dc32 1488
485015ca
GV
1489 if (menubar_widget)
1490 {
1491 /* Empty current menubar, rather than creating a fresh one. */
1492 while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
1493 ;
1494 }
1495 else
1496 {
1497 menubar_widget = CreateMenu ();
1498 }
1499 fill_in_menu (menubar_widget, first_wv->contents);
ee78dc32 1500
485015ca 1501 free_menubar_widget_value_tree (first_wv);
ee78dc32 1502
485015ca
GV
1503 {
1504 HMENU old_widget = f->output_data.w32->menubar_widget;
ee78dc32 1505
485015ca
GV
1506 f->output_data.w32->menubar_widget = menubar_widget;
1507 SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
1508 /* Causes flicker when menu bar is updated
1509 DrawMenuBar (FRAME_W32_WINDOW (f)); */
ee78dc32 1510
485015ca
GV
1511 /* Force the window size to be recomputed so that the frame's text
1512 area remains the same, if menubar has just been created. */
1513 if (old_widget == NULL)
1514 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
ee78dc32 1515 }
485015ca
GV
1516
1517 UNBLOCK_INPUT;
ee78dc32
GV
1518}
1519
485015ca
GV
1520/* Called from Fx_create_frame to create the initial menubar of a frame
1521 before it is mapped, so that the window is mapped with the menubar already
1522 there instead of us tacking it on later and thrashing the window after it
1523 is visible. */
1524
1525void
1526initialize_frame_menubar (f)
1527 FRAME_PTR f;
1528{
1529 /* This function is called before the first chance to redisplay
1530 the frame. It has to be, so the frame will have the right size. */
1531 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1532 set_frame_menubar (f, 1, 1);
ee78dc32
GV
1533}
1534
485015ca
GV
1535/* Get rid of the menu bar of frame F, and free its storage.
1536 This is used when deleting a frame, and when turning off the menu bar. */
1537
1538void
1539free_frame_menubar (f)
1540 FRAME_PTR f;
1541{
1542 BLOCK_INPUT;
1543
1544 {
1545 HMENU old = GetMenu (FRAME_W32_WINDOW (f));
1546 SetMenu (FRAME_W32_WINDOW (f), NULL);
1547 f->output_data.w32->menubar_widget = NULL;
1548 DestroyMenu (old);
1549 }
29250851 1550
485015ca
GV
1551 UNBLOCK_INPUT;
1552}
ee78dc32 1553
485015ca
GV
1554\f
1555/* w32_menu_show actually displays a menu using the panes and items in
1556 menu_items and returns the value selected from it; we assume input
1557 is blocked by the caller. */
ee78dc32
GV
1558
1559/* F is the frame the menu is for.
1560 X and Y are the frame-relative specified position,
1561 relative to the inside upper left corner of the frame F.
485015ca 1562 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
ee78dc32 1563 KEYMAPS is 1 if this menu was specified with keymaps;
485015ca
GV
1564 in that case, we return a list containing the chosen item's value
1565 and perhaps also the pane's prefix.
ee78dc32
GV
1566 TITLE is the specified menu title.
1567 ERROR is a place to store an error message string in case of failure.
1568 (We return nil on failure, but the value doesn't actually matter.) */
1569
485015ca
GV
1570static Lisp_Object
1571w32_menu_show (f, x, y, for_click, keymaps, title, error)
ee78dc32
GV
1572 FRAME_PTR f;
1573 int x;
1574 int y;
485015ca
GV
1575 int for_click;
1576 int keymaps;
1577 Lisp_Object title;
ee78dc32
GV
1578 char **error;
1579{
485015ca
GV
1580 int i;
1581 int menu_item_selection;
1582 HMENU menu;
ee78dc32 1583 POINT pos;
485015ca
GV
1584 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1585 widget_value **submenu_stack
1586 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1587 Lisp_Object *subprefix_stack
1588 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1589 int submenu_depth = 0;
485015ca 1590 int first_pane;
485015ca 1591
ee78dc32 1592 *error = NULL;
485015ca
GV
1593
1594 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
ee78dc32
GV
1595 {
1596 *error = "Empty menu";
1597 return Qnil;
1598 }
485015ca
GV
1599
1600 /* Create a tree of widget_value objects
1601 representing the panes and their items. */
1602 wv = xmalloc_widget_value ();
1603 wv->name = "menu";
1604 wv->value = 0;
1605 wv->enabled = 1;
162d2499 1606 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1607 first_wv = wv;
1608 first_pane = 1;
1609
1610 /* Loop over all panes and items, filling in the tree. */
1611 i = 0;
1612 while (i < menu_items_used)
1613 {
1614 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1615 {
1616 submenu_stack[submenu_depth++] = save_wv;
1617 save_wv = prev_wv;
1618 prev_wv = 0;
1619 first_pane = 1;
1620 i++;
1621 }
1622 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1623 {
1624 prev_wv = save_wv;
1625 save_wv = submenu_stack[--submenu_depth];
1626 first_pane = 0;
1627 i++;
1628 }
1629 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1630 && submenu_depth != 0)
1631 i += MENU_ITEMS_PANE_LENGTH;
1632 /* Ignore a nil in the item list.
1633 It's meaningful only for dialog boxes. */
1634 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1635 i += 1;
1636 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1637 {
1638 /* Create a new pane. */
1639 Lisp_Object pane_name, prefix;
1640 char *pane_string;
29250851
JR
1641 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1642 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
162d2499 1643#ifndef HAVE_MULTILINGUAL_MENU
29250851
JR
1644 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1645 {
1646 pane_name = ENCODE_SYSTEM (pane_name);
1647 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1648 }
162d2499 1649#endif
485015ca
GV
1650 pane_string = (NILP (pane_name)
1651 ? "" : (char *) XSTRING (pane_name)->data);
1652 /* If there is just one top-level pane, put all its items directly
1653 under the top-level menu. */
1654 if (menu_items_n_panes == 1)
1655 pane_string = "";
1656
1657 /* If the pane has a meaningful name,
1658 make the pane a top-level menu item
1659 with its items as a submenu beneath it. */
1660 if (!keymaps && strcmp (pane_string, ""))
1661 {
1662 wv = xmalloc_widget_value ();
1663 if (save_wv)
1664 save_wv->next = wv;
1665 else
1666 first_wv->contents = wv;
1667 wv->name = pane_string;
1668 if (keymaps && !NILP (prefix))
1669 wv->name++;
1670 wv->value = 0;
1671 wv->enabled = 1;
162d2499 1672 wv->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1673 save_wv = wv;
1674 prev_wv = 0;
1675 }
1676 else if (first_pane)
1677 {
1678 save_wv = wv;
1679 prev_wv = 0;
1680 }
1681 first_pane = 0;
1682 i += MENU_ITEMS_PANE_LENGTH;
1683 }
1684 else
1685 {
1686 /* Create a new item within current pane. */
b65a2f83 1687 Lisp_Object item_name, enable, descrip, def, type, selected, help;
b65a2f83 1688
29250851
JR
1689 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1690 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1691 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1692 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1693 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1694 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1695 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
162d2499
JR
1696
1697#ifndef HAVE_MULTILINGUAL_MENU
1698 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
29250851
JR
1699 {
1700 item_name = ENCODE_SYSTEM (item_name);
1701 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1702 }
162d2499 1703 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
29250851
JR
1704 {
1705 descrip = ENCODE_SYSTEM (descrip);
1706 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1707 }
1708#endif /* not HAVE_MULTILINGUAL_MENU */
485015ca
GV
1709
1710 wv = xmalloc_widget_value ();
1711 if (prev_wv)
1712 prev_wv->next = wv;
1713 else
1714 save_wv->contents = wv;
1715 wv->name = (char *) XSTRING (item_name)->data;
1716 if (!NILP (descrip))
1717 wv->key = (char *) XSTRING (descrip)->data;
1718 wv->value = 0;
1719 /* Use the contents index as call_data, since we are
2cd23960 1720 restricted to 16-bits. */
e59fe83b 1721 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
485015ca 1722 wv->enabled = !NILP (enable);
162d2499
JR
1723
1724 if (NILP (type))
1725 wv->button_type = BUTTON_TYPE_NONE;
1726 else if (EQ (type, QCtoggle))
1727 wv->button_type = BUTTON_TYPE_TOGGLE;
1728 else if (EQ (type, QCradio))
1729 wv->button_type = BUTTON_TYPE_RADIO;
1730 else
1731 abort ();
1732
1733 wv->selected = !NILP (selected);
d1fffd1d
JR
1734 if (!STRINGP (help))
1735 help = Qnil;
1736
1737 wv->help = help;
7d8e57da 1738
485015ca
GV
1739 prev_wv = wv;
1740
1741 i += MENU_ITEMS_ITEM_LENGTH;
1742 }
1743 }
1744
1745 /* Deal with the title, if it is non-nil. */
1746 if (!NILP (title))
1747 {
1748 widget_value *wv_title = xmalloc_widget_value ();
1749 widget_value *wv_sep = xmalloc_widget_value ();
1750
1751 /* Maybe replace this separator with a bitmap or owner-draw item
1752 so that it looks better. Having two separators looks odd. */
1753 wv_sep->name = "--";
1754 wv_sep->next = first_wv->contents;
1755
162d2499
JR
1756#ifndef HAVE_MULTILINGUAL_MENU
1757 if (STRING_MULTIBYTE (title))
6915ded0 1758 title = ENCODE_SYSTEM (title);
162d2499 1759#endif
485015ca 1760 wv_title->name = (char *) XSTRING (title)->data;
02067692
SM
1761 wv_title->enabled = TRUE;
1762 wv_title->title = TRUE;
162d2499 1763 wv_title->button_type = BUTTON_TYPE_NONE;
485015ca
GV
1764 wv_title->next = wv_sep;
1765 first_wv->contents = wv_title;
1766 }
1767
1768 /* Actually create the menu. */
ace9b298 1769 current_popup_menu = menu = CreatePopupMenu ();
485015ca 1770 fill_in_menu (menu, first_wv->contents);
162d2499 1771
485015ca 1772 /* Adjust coordinates to be root-window-relative. */
ee78dc32
GV
1773 pos.x = x;
1774 pos.y = y;
fbd6baed 1775 ClientToScreen (FRAME_W32_WINDOW (f), &pos);
485015ca 1776
485015ca
GV
1777 /* No selection has been chosen yet. */
1778 menu_item_selection = 0;
014510b0 1779
ee78dc32 1780 /* Display the menu. */
485015ca
GV
1781 menu_item_selection = SendMessage (FRAME_W32_WINDOW (f),
1782 WM_EMACS_TRACKPOPUPMENU,
1783 (WPARAM)menu, (LPARAM)&pos);
014510b0
GV
1784
1785 /* Clean up extraneous mouse events which might have been generated
1786 during the call. */
1787 discard_mouse_events ();
1788
86fb1a79
JR
1789 /* Free the widget_value objects we used to specify the contents. */
1790 free_menubar_widget_value_tree (first_wv);
1791
485015ca
GV
1792 DestroyMenu (menu);
1793
ee78dc32
GV
1794 /* Find the selected item, and its pane, to return
1795 the proper value. */
485015ca 1796 if (menu_item_selection != 0)
ee78dc32 1797 {
485015ca
GV
1798 Lisp_Object prefix, entry;
1799
fe5a0162 1800 prefix = entry = Qnil;
485015ca
GV
1801 i = 0;
1802 while (i < menu_items_used)
1803 {
1804 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1805 {
1806 subprefix_stack[submenu_depth++] = prefix;
1807 prefix = entry;
1808 i++;
1809 }
1810 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1811 {
1812 prefix = subprefix_stack[--submenu_depth];
1813 i++;
1814 }
1815 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1816 {
1817 prefix
1818 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1819 i += MENU_ITEMS_PANE_LENGTH;
1820 }
1821 /* Ignore a nil in the item list.
1822 It's meaningful only for dialog boxes. */
1823 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1824 i += 1;
1825 else
1826 {
1827 entry
1828 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1829 if (menu_item_selection == i)
1830 {
1831 if (keymaps != 0)
1832 {
1833 int j;
1834
1835 entry = Fcons (entry, Qnil);
1836 if (!NILP (prefix))
1837 entry = Fcons (prefix, entry);
1838 for (j = submenu_depth - 1; j >= 0; j--)
1839 if (!NILP (subprefix_stack[j]))
1840 entry = Fcons (subprefix_stack[j], entry);
1841 }
1842 return entry;
1843 }
1844 i += MENU_ITEMS_ITEM_LENGTH;
1845 }
1846 }
ee78dc32 1847 }
014510b0 1848
ee78dc32
GV
1849 return Qnil;
1850}
485015ca 1851\f
ee78dc32 1852
ace9b298 1853#ifdef HAVE_DIALOGS
485015ca 1854static char * button_names [] = {
ee78dc32 1855 "button1", "button2", "button3", "button4", "button5",
485015ca 1856 "button6", "button7", "button8", "button9", "button10" };
ee78dc32
GV
1857
1858static Lisp_Object
485015ca 1859w32_dialog_show (f, keymaps, title, error)
ee78dc32 1860 FRAME_PTR f;
ee78dc32
GV
1861 int keymaps;
1862 Lisp_Object title;
1863 char **error;
1864{
1865 int i, nb_buttons=0;
ee78dc32 1866 char dialog_name[6];
485015ca
GV
1867 int menu_item_selection;
1868
fe5a0162 1869 widget_value *wv, *first_wv = 0, *prev_wv = 0;
485015ca 1870
ee78dc32
GV
1871 /* Number of elements seen so far, before boundary. */
1872 int left_count = 0;
1873 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1874 int boundary_seen = 0;
485015ca 1875
ee78dc32 1876 *error = NULL;
485015ca 1877
ee78dc32
GV
1878 if (menu_items_n_panes > 1)
1879 {
1880 *error = "Multiple panes in dialog box";
1881 return Qnil;
1882 }
485015ca 1883
ee78dc32
GV
1884 /* Create a tree of widget_value objects
1885 representing the text label and buttons. */
1886 {
1887 Lisp_Object pane_name, prefix;
1888 char *pane_string;
1889 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
1890 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
1891 pane_string = (NILP (pane_name)
1892 ? "" : (char *) XSTRING (pane_name)->data);
485015ca 1893 prev_wv = xmalloc_widget_value ();
ee78dc32
GV
1894 prev_wv->value = pane_string;
1895 if (keymaps && !NILP (prefix))
1896 prev_wv->name++;
1897 prev_wv->enabled = 1;
1898 prev_wv->name = "message";
1899 first_wv = prev_wv;
485015ca 1900
ee78dc32
GV
1901 /* Loop over all panes and items, filling in the tree. */
1902 i = MENU_ITEMS_PANE_LENGTH;
1903 while (i < menu_items_used)
1904 {
1905
1906 /* Create a new item within current pane. */
b65a2f83 1907 Lisp_Object item_name, enable, descrip, help;
b65a2f83 1908
ee78dc32
GV
1909 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1910 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1911 descrip
1912 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
b65a2f83 1913 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
ee78dc32
GV
1914
1915 if (NILP (item_name))
1916 {
1917 free_menubar_widget_value_tree (first_wv);
1918 *error = "Submenu in dialog items";
1919 return Qnil;
1920 }
1921 if (EQ (item_name, Qquote))
1922 {
1923 /* This is the boundary between left-side elts
1924 and right-side elts. Stop incrementing right_count. */
1925 boundary_seen = 1;
1926 i++;
1927 continue;
1928 }
485015ca 1929 if (nb_buttons >= 9)
ee78dc32
GV
1930 {
1931 free_menubar_widget_value_tree (first_wv);
1932 *error = "Too many dialog items";
1933 return Qnil;
1934 }
485015ca
GV
1935
1936 wv = xmalloc_widget_value ();
ee78dc32
GV
1937 prev_wv->next = wv;
1938 wv->name = (char *) button_names[nb_buttons];
1939 if (!NILP (descrip))
1940 wv->key = (char *) XSTRING (descrip)->data;
1941 wv->value = (char *) XSTRING (item_name)->data;
1942 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
1943 wv->enabled = !NILP (enable);
1944 prev_wv = wv;
485015ca 1945
ee78dc32
GV
1946 if (! boundary_seen)
1947 left_count++;
485015ca 1948
ee78dc32
GV
1949 nb_buttons++;
1950 i += MENU_ITEMS_ITEM_LENGTH;
1951 }
485015ca 1952
ee78dc32
GV
1953 /* If the boundary was not specified,
1954 by default put half on the left and half on the right. */
1955 if (! boundary_seen)
1956 left_count = nb_buttons - nb_buttons / 2;
485015ca
GV
1957
1958 wv = xmalloc_widget_value ();
ee78dc32 1959 wv->name = dialog_name;
485015ca 1960
ee78dc32
GV
1961 /* Dialog boxes use a really stupid name encoding
1962 which specifies how many buttons to use
1963 and how many buttons are on the right.
1964 The Q means something also. */
1965 dialog_name[0] = 'Q';
1966 dialog_name[1] = '0' + nb_buttons;
1967 dialog_name[2] = 'B';
1968 dialog_name[3] = 'R';
1969 /* Number of buttons to put on the right. */
1970 dialog_name[4] = '0' + nb_buttons - left_count;
1971 dialog_name[5] = 0;
1972 wv->contents = first_wv;
1973 first_wv = wv;
1974 }
485015ca 1975
ee78dc32 1976 /* Actually create the dialog. */
485015ca 1977 dialog_id = widget_id_tick++;
ee78dc32 1978 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
fbd6baed 1979 f->output_data.w32->widget, 1, 0,
ee78dc32 1980 dialog_selection_callback, 0);
02067692 1981 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
485015ca 1982
ee78dc32
GV
1983 /* Free the widget_value objects we used to specify the contents. */
1984 free_menubar_widget_value_tree (first_wv);
485015ca 1985
ee78dc32
GV
1986 /* No selection has been chosen yet. */
1987 menu_item_selection = 0;
485015ca 1988
ee78dc32
GV
1989 /* Display the menu. */
1990 lw_pop_up_all_widgets (dialog_id);
485015ca
GV
1991 popup_activated_flag = 1;
1992
ee78dc32 1993 /* Process events that apply to the menu. */
485015ca 1994 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
ee78dc32 1995
485015ca 1996 lw_destroy_all_widgets (dialog_id);
ee78dc32 1997
ee78dc32
GV
1998 /* Find the selected item, and its pane, to return
1999 the proper value. */
2000 if (menu_item_selection != 0)
2001 {
2002 Lisp_Object prefix;
485015ca 2003
ee78dc32
GV
2004 prefix = Qnil;
2005 i = 0;
2006 while (i < menu_items_used)
2007 {
2008 Lisp_Object entry;
2009
2010 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2011 {
2012 prefix
2013 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2014 i += MENU_ITEMS_PANE_LENGTH;
2015 }
2016 else
2017 {
2018 entry
2019 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
485015ca 2020 if (menu_item_selection == i)
ee78dc32
GV
2021 {
2022 if (keymaps != 0)
2023 {
2024 entry = Fcons (entry, Qnil);
2025 if (!NILP (prefix))
2026 entry = Fcons (prefix, entry);
2027 }
2028 return entry;
2029 }
2030 i += MENU_ITEMS_ITEM_LENGTH;
2031 }
2032 }
2033 }
485015ca 2034
ee78dc32
GV
2035 return Qnil;
2036}
ace9b298 2037#endif /* HAVE_DIALOGS */
485015ca
GV
2038\f
2039
2040/* Is this item a separator? */
2041static int
2042name_is_separator (name)
2043 char *name;
2044{
fe5a0162
SM
2045 char *start = name;
2046
2047 /* Check if name string consists of only dashes ('-'). */
485015ca 2048 while (*name == '-') name++;
fe5a0162
SM
2049 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2050 or "--deep-shadow". We don't implement them yet, se we just treat
2051 them like normal separators. */
2052 return (*name == '\0' || start + 2 == name);
485015ca
GV
2053}
2054
2055
2056/* Indicate boundary between left and right. */
2057static int
2058add_left_right_boundary (HMENU menu)
2059{
2060 return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL);
2061}
2062
2063static int
2064add_menu_item (HMENU menu, widget_value *wv, HMENU item)
2065{
2066 UINT fuFlags;
2067 char *out_string;
37ad8b63 2068 int return_value;
485015ca
GV
2069
2070 if (name_is_separator (wv->name))
222456a1
JR
2071 {
2072 fuFlags = MF_SEPARATOR;
2073 out_string = NULL;
2074 }
485015ca
GV
2075 else
2076 {
070d1949 2077 if (wv->enabled)
485015ca
GV
2078 fuFlags = MF_STRING;
2079 else
2080 fuFlags = MF_STRING | MF_GRAYED;
2081
2082 if (wv->key != NULL)
2083 {
2084 out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2);
2085 strcpy (out_string, wv->name);
2086 strcat (out_string, "\t");
2087 strcat (out_string, wv->key);
2088 }
2089 else
2090 out_string = wv->name;
2091
d1fffd1d
JR
2092 if (item != NULL)
2093 fuFlags = MF_POPUP;
2094 else if (wv->title || wv->call_data == 0)
485015ca 2095 {
ace9b298
JR
2096 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
2097 we can't deallocate the memory otherwise. */
2098 if (get_menu_item_info)
2099 {
d1fffd1d
JR
2100 out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1);
2101#ifdef MENU_DEBUG
2102 DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData);
2103#endif
ace9b298
JR
2104 strcpy (out_string, wv->name);
2105 fuFlags = MF_OWNERDRAW | MF_DISABLED;
2106 }
2107 else
2108 fuFlags = MF_DISABLED;
485015ca 2109 }
1c5acb8c 2110
162d2499 2111 /* Draw radio buttons and tickboxes. */
4cdf6a6c 2112 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
6f665da9 2113 wv->button_type == BUTTON_TYPE_RADIO))
4cdf6a6c 2114 fuFlags |= MF_CHECKED;
37ad8b63 2115 else
4cdf6a6c 2116 fuFlags |= MF_UNCHECKED;
485015ca 2117 }
4cdf6a6c 2118
37ad8b63
JR
2119 return_value =
2120 AppendMenu (menu,
2121 fuFlags,
2122 item != NULL ? (UINT) item : (UINT) wv->call_data,
222456a1 2123 out_string );
37ad8b63
JR
2124
2125 /* This must be done after the menu item is created. */
6f665da9 2126 if (!wv->title && wv->call_data != 0)
4cdf6a6c 2127 {
4cdf6a6c
AI
2128 if (set_menu_item_info)
2129 {
2130 MENUITEMINFO info;
2131 bzero (&info, sizeof (info));
2132 info.cbSize = sizeof (info);
2133 info.fMask = MIIM_DATA;
2134
d1fffd1d
JR
2135 /* Set help string for menu item. Leave it as a Lisp_Object
2136 until it is ready to be displayed, since GC can happen while
2137 menus are active. */
ace9b298 2138 if (wv->help)
d1fffd1d 2139 info.dwItemData = (DWORD) wv->help;
4cdf6a6c
AI
2140
2141 if (wv->button_type == BUTTON_TYPE_RADIO)
2142 {
2143 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
2144 RADIO items, but is not available on NT 3.51 and earlier. */
2145 info.fMask |= MIIM_TYPE | MIIM_STATE;
2146 info.fType = MFT_RADIOCHECK | MFT_STRING;
2147 info.dwTypeData = out_string;
2148 info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
2149 }
2150
2151 set_menu_item_info (menu,
2152 item != NULL ? (UINT) item : (UINT) wv->call_data,
2153 FALSE, &info);
2154 }
2155 }
37ad8b63 2156 return return_value;
485015ca
GV
2157}
2158
2159/* Construct native Windows menu(bar) based on widget_value tree. */
15d36dee 2160int
485015ca
GV
2161fill_in_menu (HMENU menu, widget_value *wv)
2162{
2163 int items_added = 0;
ee78dc32 2164
485015ca
GV
2165 for ( ; wv != NULL; wv = wv->next)
2166 {
2167 if (wv->contents)
2168 {
2169 HMENU sub_menu = CreatePopupMenu ();
2170
2171 if (sub_menu == NULL)
2172 return 0;
2173
2174 if (!fill_in_menu (sub_menu, wv->contents) ||
2175 !add_menu_item (menu, wv, sub_menu))
2176 {
2177 DestroyMenu (sub_menu);
2178 return 0;
2179 }
2180 }
2181 else
2182 {
2183 if (!add_menu_item (menu, wv, NULL))
2184 return 0;
2185 }
2186 }
2187 return 1;
2188}
2189
162d2499
JR
2190int
2191popup_activated ()
2192{
2193 /* popup_activated_flag not actually used on W32 */
2194 return 0;
2195}
2196
7d8e57da
JR
2197/* Display help string for currently pointed to menu item. Not
2198 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
2199 available. */
2200void
59a86c99 2201w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
7d8e57da 2202{
7d8e57da
JR
2203 if (get_menu_item_info)
2204 {
1c5acb8c
JR
2205 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
2206 Lisp_Object frame, help;
7d8e57da 2207
ace9b298
JR
2208 // No help echo on owner-draw menu items.
2209 if (flags & MF_OWNERDRAW || flags & MF_POPUP)
2210 help = Qnil;
2211 else
2212 {
2213 MENUITEMINFO info;
7d8e57da 2214
ace9b298
JR
2215 bzero (&info, sizeof (info));
2216 info.cbSize = sizeof (info);
2217 info.fMask = MIIM_DATA;
2218 get_menu_item_info (menu, item, FALSE, &info);
2219
d1fffd1d 2220 help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
ace9b298 2221 }
e5cd3d11 2222
1c5acb8c
JR
2223 /* Store the help echo in the keyboard buffer as the X toolkit
2224 version does, rather than directly showing it. This seems to
2225 solve the GC problems that were present when we based the
2226 Windows code on the non-toolkit version. */
2227 if (f)
2228 {
2229 XSETFRAME (frame, f);
2230 kbd_buffer_store_help_event (frame, help);
2231 }
2232 else
2233 /* X version has a loop through frames here, which doesn't
2234 appear to do anything, unless it has some side effect. */
2235 show_help_echo (help, Qnil, Qnil, Qnil, 1);
7d8e57da
JR
2236 }
2237}
2238
d1fffd1d 2239/* Free memory used by owner-drawn strings. */
ace9b298
JR
2240static void
2241w32_free_submenu_strings (menu)
2242 HMENU menu;
2243{
2244 int i, num = GetMenuItemCount (menu);
2245 for (i = 0; i < num; i++)
2246 {
2247 MENUITEMINFO info;
2248
2249 info.cbSize = sizeof (info);
d1fffd1d 2250 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
7d8e57da 2251
ace9b298
JR
2252 get_menu_item_info (menu, i, TRUE, &info);
2253
d1fffd1d
JR
2254 /* Owner-drawn names are held in dwItemData. */
2255 if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
2256 {
2257#ifdef MENU_DEBUG
2258 DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
2259#endif
2260 LocalFree (info.dwItemData);
2261 }
ace9b298
JR
2262
2263 /* Recurse down submenus. */
2264 if (info.hSubMenu)
2265 w32_free_submenu_strings (info.hSubMenu);
2266 }
2267}
2268
2269void
2270w32_free_menu_strings (hwnd)
2271 HWND hwnd;
2272{
2273 HMENU menu = current_popup_menu;
2274
2275 if (get_menu_item_info)
2276 {
2277 /* If there is no popup menu active, free the strings from the frame's
2278 menubar. */
2279 if (!menu)
2280 menu = GetMenu (hwnd);
2281
2282 if (menu)
2283 w32_free_submenu_strings (menu);
2284 }
2285
2286 current_popup_menu = NULL;
2287}
7d8e57da 2288
485015ca 2289#endif /* HAVE_MENUS */
ace9b298 2290
485015ca 2291\f
fbd6baed 2292syms_of_w32menu ()
ee78dc32 2293{
ace9b298
JR
2294 /* See if Get/SetMenuItemInfo functions are available. */
2295 HMODULE user32 = GetModuleHandle ("user32.dll");
2296 get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
2297 set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
2298
485015ca
GV
2299 staticpro (&menu_items);
2300 menu_items = Qnil;
2301
ace9b298
JR
2302 current_popup_menu = NULL;
2303
fdc12c4d
RS
2304 Qdebug_on_next_call = intern ("debug-on-next-call");
2305 staticpro (&Qdebug_on_next_call);
2306
c8869655 2307 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
33f09670
JR
2308 doc: /* Frame for which we are updating a menu.
2309The enable predicate for a menu command should check this variable. */);
c8869655
GV
2310 Vmenu_updating_frame = Qnil;
2311
ee78dc32 2312 defsubr (&Sx_popup_menu);
485015ca 2313#ifdef HAVE_MENUS
ee78dc32 2314 defsubr (&Sx_popup_dialog);
485015ca 2315#endif
ee78dc32 2316}