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