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