]> code.delx.au - gnu-emacs/blob - src/xmenu.c
Merge from emacs--rel--22
[gnu-emacs] / src / xmenu.c
1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22 /* X pop-up deck-of-cards menu facility for GNU Emacs.
23 *
24 * Written by Jon Arnold and Roman Budzianowski
25 * Mods and rewrite by Robert Krawitz
26 *
27 */
28
29 /* Modified by Fred Pierresteguy on December 93
30 to make the popup menus and menubar use the Xt. */
31
32 /* Rewritten for clarity and GC protection by rms in Feb 94. */
33
34 #include <config.h>
35
36 #if 0 /* Why was this included? And without syssignal.h? */
37 /* On 4.3 this loses if it comes after xterm.h. */
38 #include <signal.h>
39 #endif
40
41 #include <stdio.h>
42
43 #include "lisp.h"
44 #include "termhooks.h"
45 #include "keyboard.h"
46 #include "keymap.h"
47 #include "frame.h"
48 #include "window.h"
49 #include "blockinput.h"
50 #include "buffer.h"
51 #include "charset.h"
52 #include "coding.h"
53 #include "sysselect.h"
54
55 #ifdef MSDOS
56 #include "msdos.h"
57 #endif
58
59 #ifdef HAVE_X_WINDOWS
60 /* This may include sys/types.h, and that somehow loses
61 if this is not done before the other system files. */
62 #include "xterm.h"
63 #endif
64
65 /* Load sys/types.h if not already loaded.
66 In some systems loading it twice is suicidal. */
67 #ifndef makedev
68 #include <sys/types.h>
69 #endif
70
71 #include "dispextern.h"
72
73 #ifdef HAVE_X_WINDOWS
74 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
75 code accepts the Emacs internal encoding. */
76 #undef HAVE_MULTILINGUAL_MENU
77 #ifdef USE_X_TOOLKIT
78 #include "widget.h"
79 #include <X11/Xlib.h>
80 #include <X11/IntrinsicP.h>
81 #include <X11/CoreP.h>
82 #include <X11/StringDefs.h>
83 #include <X11/Shell.h>
84 #ifdef USE_LUCID
85 #ifdef HAVE_XAW3D
86 #include <X11/Xaw3d/Paned.h>
87 #else /* !HAVE_XAW3D */
88 #include <X11/Xaw/Paned.h>
89 #endif /* HAVE_XAW3D */
90 #endif /* USE_LUCID */
91 #include "../lwlib/lwlib.h"
92 #else /* not USE_X_TOOLKIT */
93 #ifndef USE_GTK
94 #include "../oldXMenu/XMenu.h"
95 #endif
96 #endif /* not USE_X_TOOLKIT */
97 #endif /* HAVE_X_WINDOWS */
98
99 #ifndef TRUE
100 #define TRUE 1
101 #define FALSE 0
102 #endif /* no TRUE */
103
104 Lisp_Object Qdebug_on_next_call;
105
106 extern Lisp_Object Vmenu_updating_frame;
107
108 extern Lisp_Object Qmenu_bar;
109
110 extern Lisp_Object QCtoggle, QCradio;
111
112 extern Lisp_Object Voverriding_local_map;
113 extern Lisp_Object Voverriding_local_map_menu_flag;
114
115 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
116
117 extern Lisp_Object Qmenu_bar_update_hook;
118
119 #ifdef USE_X_TOOLKIT
120 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
121 extern XtAppContext Xt_app_con;
122
123 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
124 char **));
125 static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
126 LWLIB_ID, int));
127
128 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
129
130 #define HAVE_BOXES 1
131 #endif /* USE_X_TOOLKIT */
132
133 #ifdef USE_GTK
134 #include "gtkutil.h"
135 #define HAVE_BOXES 1
136 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
137 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
138 char **));
139 #endif
140
141 /* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
142 isn't defined. The use of HAVE_MULTILINGUAL_MENU could probably be
143 confined to an extended version of this with sections of code below
144 using it unconditionally. */
145 #ifdef USE_GTK
146 /* gtk just uses utf-8. */
147 # define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
148 #elif defined HAVE_X_I18N
149 # define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
150 #else
151 # define ENCODE_MENU_STRING(str) string_make_unibyte (str)
152 #endif
153
154 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
155 Lisp_Object, Lisp_Object, Lisp_Object,
156 Lisp_Object, Lisp_Object));
157 static int update_frame_menubar P_ ((struct frame *));
158 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
159 Lisp_Object, char **));
160 static void keymap_panes P_ ((Lisp_Object *, int, int));
161 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
162 int, int));
163 static void list_of_panes P_ ((Lisp_Object));
164 static void list_of_items P_ ((Lisp_Object));
165
166 \f
167 /* This holds a Lisp vector that holds the results of decoding
168 the keymaps or alist-of-alists that specify a menu.
169
170 It describes the panes and items within the panes.
171
172 Each pane is described by 3 elements in the vector:
173 t, the pane name, the pane's prefix key.
174 Then follow the pane's items, with 5 elements per item:
175 the item string, the enable flag, the item's value,
176 the definition, and the equivalent keyboard key's description string.
177
178 In some cases, multiple levels of menus may be described.
179 A single vector slot containing nil indicates the start of a submenu.
180 A single vector slot containing lambda indicates the end of a submenu.
181 The submenu follows a menu item which is the way to reach the submenu.
182
183 A single vector slot containing quote indicates that the
184 following items should appear on the right of a dialog box.
185
186 Using a Lisp vector to hold this information while we decode it
187 takes care of protecting all the data from GC. */
188
189 #define MENU_ITEMS_PANE_NAME 1
190 #define MENU_ITEMS_PANE_PREFIX 2
191 #define MENU_ITEMS_PANE_LENGTH 3
192
193 enum menu_item_idx
194 {
195 MENU_ITEMS_ITEM_NAME = 0,
196 MENU_ITEMS_ITEM_ENABLE,
197 MENU_ITEMS_ITEM_VALUE,
198 MENU_ITEMS_ITEM_EQUIV_KEY,
199 MENU_ITEMS_ITEM_DEFINITION,
200 MENU_ITEMS_ITEM_TYPE,
201 MENU_ITEMS_ITEM_SELECTED,
202 MENU_ITEMS_ITEM_HELP,
203 MENU_ITEMS_ITEM_LENGTH
204 };
205
206 static Lisp_Object menu_items;
207
208 /* If non-nil, means that the global vars defined here are already in use.
209 Used to detect cases where we try to re-enter this non-reentrant code. */
210 static Lisp_Object menu_items_inuse;
211
212 /* Number of slots currently allocated in menu_items. */
213 static int menu_items_allocated;
214
215 /* This is the index in menu_items of the first empty slot. */
216 static int menu_items_used;
217
218 /* The number of panes currently recorded in menu_items,
219 excluding those within submenus. */
220 static int menu_items_n_panes;
221
222 /* Current depth within submenus. */
223 static int menu_items_submenu_depth;
224
225 /* Flag which when set indicates a dialog or menu has been posted by
226 Xt on behalf of one of the widget sets. */
227 static int popup_activated_flag;
228
229 static int next_menubar_widget_id;
230
231 /* This is set nonzero after the user activates the menu bar, and set
232 to zero again after the menu bars are redisplayed by prepare_menu_bar.
233 While it is nonzero, all calls to set_frame_menubar go deep.
234
235 I don't understand why this is needed, but it does seem to be
236 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
237
238 int pending_menu_activation;
239 \f
240 #ifdef USE_X_TOOLKIT
241
242 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
243
244 static struct frame *
245 menubar_id_to_frame (id)
246 LWLIB_ID id;
247 {
248 Lisp_Object tail, frame;
249 FRAME_PTR f;
250
251 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
252 {
253 frame = XCAR (tail);
254 if (!GC_FRAMEP (frame))
255 continue;
256 f = XFRAME (frame);
257 if (!FRAME_WINDOW_P (f))
258 continue;
259 if (f->output_data.x->id == id)
260 return f;
261 }
262 return 0;
263 }
264
265 #endif
266 \f
267 /* Initialize the menu_items structure if we haven't already done so.
268 Also mark it as currently empty. */
269
270 static void
271 init_menu_items ()
272 {
273 if (!NILP (menu_items_inuse))
274 error ("Trying to use a menu from within a menu-entry");
275
276 if (NILP (menu_items))
277 {
278 menu_items_allocated = 60;
279 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
280 }
281
282 menu_items_inuse = Qt;
283 menu_items_used = 0;
284 menu_items_n_panes = 0;
285 menu_items_submenu_depth = 0;
286 }
287
288 /* Call at the end of generating the data in menu_items. */
289
290 static void
291 finish_menu_items ()
292 {
293 }
294
295 static Lisp_Object
296 unuse_menu_items (dummy)
297 Lisp_Object dummy;
298 {
299 return menu_items_inuse = Qnil;
300 }
301
302 /* Call when finished using the data for the current menu
303 in menu_items. */
304
305 static void
306 discard_menu_items ()
307 {
308 /* Free the structure if it is especially large.
309 Otherwise, hold on to it, to save time. */
310 if (menu_items_allocated > 200)
311 {
312 menu_items = Qnil;
313 menu_items_allocated = 0;
314 }
315 xassert (NILP (menu_items_inuse));
316 }
317
318 /* This undoes save_menu_items, and it is called by the specpdl unwind
319 mechanism. */
320
321 static Lisp_Object
322 restore_menu_items (saved)
323 Lisp_Object saved;
324 {
325 menu_items = XCAR (saved);
326 menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil);
327 menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
328 saved = XCDR (saved);
329 menu_items_used = XINT (XCAR (saved));
330 saved = XCDR (saved);
331 menu_items_n_panes = XINT (XCAR (saved));
332 saved = XCDR (saved);
333 menu_items_submenu_depth = XINT (XCAR (saved));
334 return Qnil;
335 }
336
337 /* Push the whole state of menu_items processing onto the specpdl.
338 It will be restored when the specpdl is unwound. */
339
340 static void
341 save_menu_items ()
342 {
343 Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil,
344 make_number (menu_items_used),
345 make_number (menu_items_n_panes),
346 make_number (menu_items_submenu_depth));
347 record_unwind_protect (restore_menu_items, saved);
348 menu_items_inuse = Qnil;
349 menu_items = Qnil;
350 }
351 \f
352 /* Make the menu_items vector twice as large. */
353
354 static void
355 grow_menu_items ()
356 {
357 Lisp_Object old;
358 int old_size = menu_items_allocated;
359 old = menu_items;
360
361 menu_items_allocated *= 2;
362
363 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
364 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
365 old_size * sizeof (Lisp_Object));
366 }
367
368 /* Begin a submenu. */
369
370 static void
371 push_submenu_start ()
372 {
373 if (menu_items_used + 1 > menu_items_allocated)
374 grow_menu_items ();
375
376 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
377 menu_items_submenu_depth++;
378 }
379
380 /* End a submenu. */
381
382 static void
383 push_submenu_end ()
384 {
385 if (menu_items_used + 1 > menu_items_allocated)
386 grow_menu_items ();
387
388 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
389 menu_items_submenu_depth--;
390 }
391
392 /* Indicate boundary between left and right. */
393
394 static void
395 push_left_right_boundary ()
396 {
397 if (menu_items_used + 1 > menu_items_allocated)
398 grow_menu_items ();
399
400 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
401 }
402
403 /* Start a new menu pane in menu_items.
404 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
405
406 static void
407 push_menu_pane (name, prefix_vec)
408 Lisp_Object name, prefix_vec;
409 {
410 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
411 grow_menu_items ();
412
413 if (menu_items_submenu_depth == 0)
414 menu_items_n_panes++;
415 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
416 XVECTOR (menu_items)->contents[menu_items_used++] = name;
417 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
418 }
419
420 /* Push one menu item into the current pane. NAME is the string to
421 display. ENABLE if non-nil means this item can be selected. KEY
422 is the key generated by choosing this item, or nil if this item
423 doesn't really have a definition. DEF is the definition of this
424 item. EQUIV is the textual description of the keyboard equivalent
425 for this item (or nil if none). TYPE is the type of this menu
426 item, one of nil, `toggle' or `radio'. */
427
428 static void
429 push_menu_item (name, enable, key, def, equiv, type, selected, help)
430 Lisp_Object name, enable, key, def, equiv, type, selected, help;
431 {
432 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
433 grow_menu_items ();
434
435 XVECTOR (menu_items)->contents[menu_items_used++] = name;
436 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
437 XVECTOR (menu_items)->contents[menu_items_used++] = key;
438 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
439 XVECTOR (menu_items)->contents[menu_items_used++] = def;
440 XVECTOR (menu_items)->contents[menu_items_used++] = type;
441 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
442 XVECTOR (menu_items)->contents[menu_items_used++] = help;
443 }
444 \f
445 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
446 and generate menu panes for them in menu_items.
447 If NOTREAL is nonzero,
448 don't bother really computing whether an item is enabled. */
449
450 static void
451 keymap_panes (keymaps, nmaps, notreal)
452 Lisp_Object *keymaps;
453 int nmaps;
454 int notreal;
455 {
456 int mapno;
457
458 init_menu_items ();
459
460 /* Loop over the given keymaps, making a pane for each map.
461 But don't make a pane that is empty--ignore that map instead.
462 P is the number of panes we have made so far. */
463 for (mapno = 0; mapno < nmaps; mapno++)
464 single_keymap_panes (keymaps[mapno],
465 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
466
467 finish_menu_items ();
468 }
469
470 /* Args passed between single_keymap_panes and single_menu_item. */
471 struct skp
472 {
473 Lisp_Object pending_maps;
474 int maxdepth, notreal;
475 int notbuttons;
476 };
477
478 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
479 void *));
480
481 /* This is a recursive subroutine of keymap_panes.
482 It handles one keymap, KEYMAP.
483 The other arguments are passed along
484 or point to local variables of the previous function.
485 If NOTREAL is nonzero, only check for equivalent key bindings, don't
486 evaluate expressions in menu items and don't make any menu.
487
488 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
489
490 static void
491 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
492 Lisp_Object keymap;
493 Lisp_Object pane_name;
494 Lisp_Object prefix;
495 int notreal;
496 int maxdepth;
497 {
498 struct skp skp;
499 struct gcpro gcpro1;
500
501 skp.pending_maps = Qnil;
502 skp.maxdepth = maxdepth;
503 skp.notreal = notreal;
504 skp.notbuttons = 0;
505
506 if (maxdepth <= 0)
507 return;
508
509 push_menu_pane (pane_name, prefix);
510
511 #ifndef HAVE_BOXES
512 /* Remember index for first item in this pane so we can go back and
513 add a prefix when (if) we see the first button. After that, notbuttons
514 is set to 0, to mark that we have seen a button and all non button
515 items need a prefix. */
516 skp.notbuttons = menu_items_used;
517 #endif
518
519 GCPRO1 (skp.pending_maps);
520 map_keymap (keymap, single_menu_item, Qnil, &skp, 1);
521 UNGCPRO;
522
523 /* Process now any submenus which want to be panes at this level. */
524 while (CONSP (skp.pending_maps))
525 {
526 Lisp_Object elt, eltcdr, string;
527 elt = XCAR (skp.pending_maps);
528 eltcdr = XCDR (elt);
529 string = XCAR (eltcdr);
530 /* We no longer discard the @ from the beginning of the string here.
531 Instead, we do this in xmenu_show. */
532 single_keymap_panes (Fcar (elt), string,
533 XCDR (eltcdr), notreal, maxdepth - 1);
534 skp.pending_maps = XCDR (skp.pending_maps);
535 }
536 }
537 \f
538 /* This is a subroutine of single_keymap_panes that handles one
539 keymap entry.
540 KEY is a key in a keymap and ITEM is its binding.
541 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
542 separate panes.
543 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
544 evaluate expressions in menu items and don't make any menu.
545 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them.
546 SKP->NOTBUTTONS is only used when simulating toggle boxes and radio
547 buttons. It keeps track of if we have seen a button in this menu or
548 not. */
549
550 static void
551 single_menu_item (key, item, dummy, skp_v)
552 Lisp_Object key, item, dummy;
553 void *skp_v;
554 {
555 Lisp_Object map, item_string, enabled;
556 struct gcpro gcpro1, gcpro2;
557 int res;
558 struct skp *skp = skp_v;
559
560 /* Parse the menu item and leave the result in item_properties. */
561 GCPRO2 (key, item);
562 res = parse_menu_item (item, skp->notreal, 0);
563 UNGCPRO;
564 if (!res)
565 return; /* Not a menu item. */
566
567 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
568
569 if (skp->notreal)
570 {
571 /* We don't want to make a menu, just traverse the keymaps to
572 precompute equivalent key bindings. */
573 if (!NILP (map))
574 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
575 return;
576 }
577
578 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
579 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
580
581 if (!NILP (map) && SREF (item_string, 0) == '@')
582 {
583 if (!NILP (enabled))
584 /* An enabled separate pane. Remember this to handle it later. */
585 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
586 skp->pending_maps);
587 return;
588 }
589
590 #ifndef HAVE_BOXES
591 /* Simulate radio buttons and toggle boxes by putting a prefix in
592 front of them. */
593 {
594 Lisp_Object prefix = Qnil;
595 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
596 if (!NILP (type))
597 {
598 Lisp_Object selected
599 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
600
601 if (skp->notbuttons)
602 /* The first button. Line up previous items in this menu. */
603 {
604 int index = skp->notbuttons; /* Index for first item this menu. */
605 int submenu = 0;
606 Lisp_Object tem;
607 while (index < menu_items_used)
608 {
609 tem
610 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
611 if (NILP (tem))
612 {
613 index++;
614 submenu++; /* Skip sub menu. */
615 }
616 else if (EQ (tem, Qlambda))
617 {
618 index++;
619 submenu--; /* End sub menu. */
620 }
621 else if (EQ (tem, Qt))
622 index += 3; /* Skip new pane marker. */
623 else if (EQ (tem, Qquote))
624 index++; /* Skip a left, right divider. */
625 else
626 {
627 if (!submenu && SREF (tem, 0) != '\0'
628 && SREF (tem, 0) != '-')
629 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
630 = concat2 (build_string (" "), tem);
631 index += MENU_ITEMS_ITEM_LENGTH;
632 }
633 }
634 skp->notbuttons = 0;
635 }
636
637 /* Calculate prefix, if any, for this item. */
638 if (EQ (type, QCtoggle))
639 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
640 else if (EQ (type, QCradio))
641 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
642 }
643 /* Not a button. If we have earlier buttons, then we need a prefix. */
644 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
645 && SREF (item_string, 0) != '-')
646 prefix = build_string (" ");
647
648 if (!NILP (prefix))
649 item_string = concat2 (prefix, item_string);
650 }
651 #endif /* not HAVE_BOXES */
652
653 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
654 if (!NILP (map))
655 /* Indicate visually that this is a submenu. */
656 item_string = concat2 (item_string, build_string (" >"));
657 #endif
658
659 push_menu_item (item_string, enabled, key,
660 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
661 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
662 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
663 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
664 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
665
666 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
667 /* Display a submenu using the toolkit. */
668 if (! (NILP (map) || NILP (enabled)))
669 {
670 push_submenu_start ();
671 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
672 push_submenu_end ();
673 }
674 #endif
675 }
676 \f
677 /* Push all the panes and items of a menu described by the
678 alist-of-alists MENU.
679 This handles old-fashioned calls to x-popup-menu. */
680
681 static void
682 list_of_panes (menu)
683 Lisp_Object menu;
684 {
685 Lisp_Object tail;
686
687 init_menu_items ();
688
689 for (tail = menu; CONSP (tail); tail = XCDR (tail))
690 {
691 Lisp_Object elt, pane_name, pane_data;
692 elt = XCAR (tail);
693 pane_name = Fcar (elt);
694 CHECK_STRING (pane_name);
695 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
696 pane_data = Fcdr (elt);
697 CHECK_CONS (pane_data);
698 list_of_items (pane_data);
699 }
700
701 finish_menu_items ();
702 }
703
704 /* Push the items in a single pane defined by the alist PANE. */
705
706 static void
707 list_of_items (pane)
708 Lisp_Object pane;
709 {
710 Lisp_Object tail, item, item1;
711
712 for (tail = pane; CONSP (tail); tail = XCDR (tail))
713 {
714 item = XCAR (tail);
715 if (STRINGP (item))
716 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
717 Qnil, Qnil, Qnil, Qnil);
718 else if (CONSP (item))
719 {
720 item1 = XCAR (item);
721 CHECK_STRING (item1);
722 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
723 Qt, Qnil, Qnil, Qnil, Qnil);
724 }
725 else
726 push_left_right_boundary ();
727
728 }
729 }
730 \f
731 #ifdef HAVE_X_WINDOWS
732 /* Return the mouse position in *X and *Y. The coordinates are window
733 relative for the edit window in frame F.
734 This is for Fx_popup_menu. The mouse_position_hook can not
735 be used for X, as it returns window relative coordinates
736 for the window where the mouse is in. This could be the menu bar,
737 the scroll bar or the edit window. Fx_popup_menu needs to be
738 sure it is the edit window. */
739 static void
740 mouse_position_for_popup (f, x, y)
741 FRAME_PTR f;
742 int *x;
743 int *y;
744 {
745 Window root, dummy_window;
746 int dummy;
747
748 BLOCK_INPUT;
749
750 XQueryPointer (FRAME_X_DISPLAY (f),
751 DefaultRootWindow (FRAME_X_DISPLAY (f)),
752
753 /* The root window which contains the pointer. */
754 &root,
755
756 /* Window pointer is on, not used */
757 &dummy_window,
758
759 /* The position on that root window. */
760 x, y,
761
762 /* x/y in dummy_window coordinates, not used. */
763 &dummy, &dummy,
764
765 /* Modifier keys and pointer buttons, about which
766 we don't care. */
767 (unsigned int *) &dummy);
768
769 UNBLOCK_INPUT;
770
771 /* xmenu_show expects window coordinates, not root window
772 coordinates. Translate. */
773 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
774 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
775 }
776
777 #endif /* HAVE_X_WINDOWS */
778
779 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
780 doc: /* Pop up a deck-of-cards menu and return user's selection.
781 POSITION is a position specification. This is either a mouse button event
782 or a list ((XOFFSET YOFFSET) WINDOW)
783 where XOFFSET and YOFFSET are positions in pixels from the top left
784 corner of WINDOW. (WINDOW may be a window or a frame object.)
785 This controls the position of the top left of the menu as a whole.
786 If POSITION is t, it means to use the current mouse position.
787
788 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
789 The menu items come from key bindings that have a menu string as well as
790 a definition; actually, the "definition" in such a key binding looks like
791 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
792 the keymap as a top-level element.
793
794 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
795 Otherwise, REAL-DEFINITION should be a valid key binding definition.
796
797 You can also use a list of keymaps as MENU.
798 Then each keymap makes a separate pane.
799
800 When MENU is a keymap or a list of keymaps, the return value is the
801 list of events corresponding to the user's choice. Note that
802 `x-popup-menu' does not actually execute the command bound to that
803 sequence of events.
804
805 Alternatively, you can specify a menu of multiple panes
806 with a list of the form (TITLE PANE1 PANE2...),
807 where each pane is a list of form (TITLE ITEM1 ITEM2...).
808 Each ITEM is normally a cons cell (STRING . VALUE);
809 but a string can appear as an item--that makes a nonselectable line
810 in the menu.
811 With this form of menu, the return value is VALUE from the chosen item.
812
813 If POSITION is nil, don't display the menu at all, just precalculate the
814 cached information about equivalent key sequences.
815
816 If the user gets rid of the menu without making a valid choice, for
817 instance by clicking the mouse away from a valid choice or by typing
818 keyboard input, then this normally results in a quit and
819 `x-popup-menu' does not return. But if POSITION is a mouse button
820 event (indicating that the user invoked the menu with the mouse) then
821 no quit occurs and `x-popup-menu' returns nil. */)
822 (position, menu)
823 Lisp_Object position, menu;
824 {
825 Lisp_Object keymap, tem;
826 int xpos = 0, ypos = 0;
827 Lisp_Object title;
828 char *error_name = NULL;
829 Lisp_Object selection = Qnil;
830 FRAME_PTR f = NULL;
831 Lisp_Object x, y, window;
832 int keymaps = 0;
833 int for_click = 0;
834 int specpdl_count = SPECPDL_INDEX ();
835 struct gcpro gcpro1;
836
837 #ifdef HAVE_MENUS
838 if (! NILP (position))
839 {
840 int get_current_pos_p = 0;
841 check_x ();
842
843 /* Decode the first argument: find the window and the coordinates. */
844 if (EQ (position, Qt)
845 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
846 || EQ (XCAR (position), Qtool_bar))))
847 {
848 get_current_pos_p = 1;
849 }
850 else
851 {
852 tem = Fcar (position);
853 if (CONSP (tem))
854 {
855 window = Fcar (Fcdr (position));
856 x = XCAR (tem);
857 y = Fcar (XCDR (tem));
858 }
859 else
860 {
861 for_click = 1;
862 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
863 window = Fcar (tem); /* POSN_WINDOW (tem) */
864 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
865 x = Fcar (tem);
866 y = Fcdr (tem);
867 }
868
869 /* If a click happens in an external tool bar or a detached
870 tool bar, x and y is NIL. In that case, use the current
871 mouse position. This happens for the help button in the
872 tool bar. Ideally popup-menu should pass NIL to
873 this function, but it doesn't. */
874 if (NILP (x) && NILP (y))
875 get_current_pos_p = 1;
876 }
877
878 if (get_current_pos_p)
879 {
880 /* Use the mouse's current position. */
881 FRAME_PTR new_f = SELECTED_FRAME ();
882 #ifdef HAVE_X_WINDOWS
883 /* Can't use mouse_position_hook for X since it returns
884 coordinates relative to the window the mouse is in,
885 we need coordinates relative to the edit widget always. */
886 if (new_f != 0)
887 {
888 int cur_x, cur_y;
889
890 mouse_position_for_popup (new_f, &cur_x, &cur_y);
891 /* cur_x/y may be negative, so use make_number. */
892 x = make_number (cur_x);
893 y = make_number (cur_y);
894 }
895
896 #else /* not HAVE_X_WINDOWS */
897 Lisp_Object bar_window;
898 enum scroll_bar_part part;
899 unsigned long time;
900
901 if (mouse_position_hook)
902 (*mouse_position_hook) (&new_f, 1, &bar_window,
903 &part, &x, &y, &time);
904 #endif /* not HAVE_X_WINDOWS */
905
906 if (new_f != 0)
907 XSETFRAME (window, new_f);
908 else
909 {
910 window = selected_window;
911 XSETFASTINT (x, 0);
912 XSETFASTINT (y, 0);
913 }
914 }
915
916 CHECK_NUMBER (x);
917 CHECK_NUMBER (y);
918
919 /* Decode where to put the menu. */
920
921 if (FRAMEP (window))
922 {
923 f = XFRAME (window);
924 xpos = 0;
925 ypos = 0;
926 }
927 else if (WINDOWP (window))
928 {
929 CHECK_LIVE_WINDOW (window);
930 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
931
932 xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
933 ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
934 }
935 else
936 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
937 but I don't want to make one now. */
938 CHECK_WINDOW (window);
939
940 xpos += XINT (x);
941 ypos += XINT (y);
942
943 XSETFRAME (Vmenu_updating_frame, f);
944 }
945 else
946 Vmenu_updating_frame = Qnil;
947 #endif /* HAVE_MENUS */
948
949 record_unwind_protect (unuse_menu_items, Qnil);
950 title = Qnil;
951 GCPRO1 (title);
952
953 /* Decode the menu items from what was specified. */
954
955 keymap = get_keymap (menu, 0, 0);
956 if (CONSP (keymap))
957 {
958 /* We were given a keymap. Extract menu info from the keymap. */
959 Lisp_Object prompt;
960
961 /* Extract the detailed info to make one pane. */
962 keymap_panes (&menu, 1, NILP (position));
963
964 /* Search for a string appearing directly as an element of the keymap.
965 That string is the title of the menu. */
966 prompt = Fkeymap_prompt (keymap);
967 if (NILP (title) && !NILP (prompt))
968 title = prompt;
969
970 /* Make that be the pane title of the first pane. */
971 if (!NILP (prompt) && menu_items_n_panes >= 0)
972 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
973
974 keymaps = 1;
975 }
976 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
977 {
978 /* We were given a list of keymaps. */
979 int nmaps = XFASTINT (Flength (menu));
980 Lisp_Object *maps
981 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
982 int i;
983
984 title = Qnil;
985
986 /* The first keymap that has a prompt string
987 supplies the menu title. */
988 for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
989 {
990 Lisp_Object prompt;
991
992 maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
993
994 prompt = Fkeymap_prompt (keymap);
995 if (NILP (title) && !NILP (prompt))
996 title = prompt;
997 }
998
999 /* Extract the detailed info to make one pane. */
1000 keymap_panes (maps, nmaps, NILP (position));
1001
1002 /* Make the title be the pane title of the first pane. */
1003 if (!NILP (title) && menu_items_n_panes >= 0)
1004 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
1005
1006 keymaps = 1;
1007 }
1008 else
1009 {
1010 /* We were given an old-fashioned menu. */
1011 title = Fcar (menu);
1012 CHECK_STRING (title);
1013
1014 list_of_panes (Fcdr (menu));
1015
1016 keymaps = 0;
1017 }
1018
1019 unbind_to (specpdl_count, Qnil);
1020
1021 if (NILP (position))
1022 {
1023 discard_menu_items ();
1024 UNGCPRO;
1025 return Qnil;
1026 }
1027
1028 #ifdef HAVE_MENUS
1029 /* Display them in a menu. */
1030 BLOCK_INPUT;
1031
1032 selection = xmenu_show (f, xpos, ypos, for_click,
1033 keymaps, title, &error_name);
1034 UNBLOCK_INPUT;
1035
1036 discard_menu_items ();
1037
1038 UNGCPRO;
1039 #endif /* HAVE_MENUS */
1040
1041 if (error_name) error (error_name);
1042 return selection;
1043 }
1044
1045 #ifdef HAVE_MENUS
1046
1047 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
1048 doc: /* Pop up a dialog box and return user's selection.
1049 POSITION specifies which frame to use.
1050 This is normally a mouse button event or a window or frame.
1051 If POSITION is t, it means to use the frame the mouse is on.
1052 The dialog box appears in the middle of the specified frame.
1053
1054 CONTENTS specifies the alternatives to display in the dialog box.
1055 It is a list of the form (DIALOG ITEM1 ITEM2...).
1056 Each ITEM is a cons cell (STRING . VALUE).
1057 The return value is VALUE from the chosen item.
1058
1059 An ITEM may also be just a string--that makes a nonselectable item.
1060 An ITEM may also be nil--that means to put all preceding items
1061 on the left of the dialog box and all following items on the right.
1062 \(By default, approximately half appear on each side.)
1063
1064 If HEADER is non-nil, the frame title for the box is "Information",
1065 otherwise it is "Question".
1066
1067 If the user gets rid of the dialog box without making a valid choice,
1068 for instance using the window manager, then this produces a quit and
1069 `x-popup-dialog' does not return. */)
1070 (position, contents, header)
1071 Lisp_Object position, contents, header;
1072 {
1073 FRAME_PTR f = NULL;
1074 Lisp_Object window;
1075
1076 check_x ();
1077
1078 /* Decode the first argument: find the window or frame to use. */
1079 if (EQ (position, Qt)
1080 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
1081 || EQ (XCAR (position), Qtool_bar))))
1082 {
1083 #if 0 /* Using the frame the mouse is on may not be right. */
1084 /* Use the mouse's current position. */
1085 FRAME_PTR new_f = SELECTED_FRAME ();
1086 Lisp_Object bar_window;
1087 enum scroll_bar_part part;
1088 unsigned long time;
1089 Lisp_Object x, y;
1090
1091 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
1092
1093 if (new_f != 0)
1094 XSETFRAME (window, new_f);
1095 else
1096 window = selected_window;
1097 #endif
1098 window = selected_window;
1099 }
1100 else if (CONSP (position))
1101 {
1102 Lisp_Object tem;
1103 tem = Fcar (position);
1104 if (CONSP (tem))
1105 window = Fcar (Fcdr (position));
1106 else
1107 {
1108 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
1109 window = Fcar (tem); /* POSN_WINDOW (tem) */
1110 }
1111 }
1112 else if (WINDOWP (position) || FRAMEP (position))
1113 window = position;
1114 else
1115 window = Qnil;
1116
1117 /* Decode where to put the menu. */
1118
1119 if (FRAMEP (window))
1120 f = XFRAME (window);
1121 else if (WINDOWP (window))
1122 {
1123 CHECK_LIVE_WINDOW (window);
1124 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
1125 }
1126 else
1127 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
1128 but I don't want to make one now. */
1129 CHECK_WINDOW (window);
1130
1131 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
1132 /* Display a menu with these alternatives
1133 in the middle of frame F. */
1134 {
1135 Lisp_Object x, y, frame, newpos;
1136 XSETFRAME (frame, f);
1137 XSETINT (x, x_pixel_width (f) / 2);
1138 XSETINT (y, x_pixel_height (f) / 2);
1139 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
1140
1141 return Fx_popup_menu (newpos,
1142 Fcons (Fcar (contents), Fcons (contents, Qnil)));
1143 }
1144 #else
1145 {
1146 Lisp_Object title;
1147 char *error_name;
1148 Lisp_Object selection;
1149 int specpdl_count = SPECPDL_INDEX ();
1150
1151 /* Decode the dialog items from what was specified. */
1152 title = Fcar (contents);
1153 CHECK_STRING (title);
1154 record_unwind_protect (unuse_menu_items, Qnil);
1155
1156 if (NILP (Fcar (Fcdr (contents))))
1157 /* No buttons specified, add an "Ok" button so users can pop down
1158 the dialog. Also, the lesstif/motif version crashes if there are
1159 no buttons. */
1160 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
1161
1162 list_of_panes (Fcons (contents, Qnil));
1163
1164 /* Display them in a dialog box. */
1165 BLOCK_INPUT;
1166 selection = xdialog_show (f, 0, title, header, &error_name);
1167 UNBLOCK_INPUT;
1168
1169 unbind_to (specpdl_count, Qnil);
1170 discard_menu_items ();
1171
1172 if (error_name) error (error_name);
1173 return selection;
1174 }
1175 #endif
1176 }
1177
1178
1179 #ifndef MSDOS
1180
1181 /* Set menu_items_inuse so no other popup menu or dialog is created. */
1182
1183 void
1184 x_menu_set_in_use (in_use)
1185 int in_use;
1186 {
1187 menu_items_inuse = in_use ? Qt : Qnil;
1188 popup_activated_flag = in_use;
1189 #ifdef USE_X_TOOLKIT
1190 if (popup_activated_flag)
1191 x_activate_timeout_atimer ();
1192 #endif
1193 }
1194
1195 /* Wait for an X event to arrive or for a timer to expire. */
1196
1197 void
1198 x_menu_wait_for_event (void *data)
1199 {
1200 extern EMACS_TIME timer_check P_ ((int));
1201
1202 /* Another way to do this is to register a timer callback, that can be
1203 done in GTK and Xt. But we have to do it like this when using only X
1204 anyway, and with callbacks we would have three variants for timer handling
1205 instead of the small ifdefs below. */
1206
1207 while (
1208 #ifdef USE_X_TOOLKIT
1209 ! XtAppPending (Xt_app_con)
1210 #elif defined USE_GTK
1211 ! gtk_events_pending ()
1212 #else
1213 ! XPending ((Display*) data)
1214 #endif
1215 )
1216 {
1217 EMACS_TIME next_time = timer_check (1);
1218 long secs = EMACS_SECS (next_time);
1219 long usecs = EMACS_USECS (next_time);
1220 SELECT_TYPE read_fds;
1221 struct x_display_info *dpyinfo;
1222 int n = 0;
1223
1224 FD_ZERO (&read_fds);
1225 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
1226 {
1227 int fd = ConnectionNumber (dpyinfo->display);
1228 FD_SET (fd, &read_fds);
1229 if (fd > n) n = fd;
1230 }
1231
1232 if (secs < 0 || (secs == 0 && usecs == 0))
1233 {
1234 /* Sometimes timer_check returns -1 (no timers) even if there are
1235 timers. So do a timeout anyway. */
1236 EMACS_SET_SECS (next_time, 1);
1237 EMACS_SET_USECS (next_time, 0);
1238 }
1239
1240 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
1241 }
1242 }
1243 #endif /* ! MSDOS */
1244
1245 \f
1246 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1247
1248 #ifdef USE_X_TOOLKIT
1249
1250 /* Loop in Xt until the menu pulldown or dialog popup has been
1251 popped down (deactivated). This is used for x-popup-menu
1252 and x-popup-dialog; it is not used for the menu bar.
1253
1254 NOTE: All calls to popup_get_selection should be protected
1255 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
1256
1257 static void
1258 popup_get_selection (initial_event, dpyinfo, id, do_timers)
1259 XEvent *initial_event;
1260 struct x_display_info *dpyinfo;
1261 LWLIB_ID id;
1262 int do_timers;
1263 {
1264 XEvent event;
1265
1266 while (popup_activated_flag)
1267 {
1268 if (initial_event)
1269 {
1270 event = *initial_event;
1271 initial_event = 0;
1272 }
1273 else
1274 {
1275 if (do_timers) x_menu_wait_for_event (0);
1276 XtAppNextEvent (Xt_app_con, &event);
1277 }
1278
1279 /* Make sure we don't consider buttons grabbed after menu goes.
1280 And make sure to deactivate for any ButtonRelease,
1281 even if XtDispatchEvent doesn't do that. */
1282 if (event.type == ButtonRelease
1283 && dpyinfo->display == event.xbutton.display)
1284 {
1285 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
1286 #ifdef USE_MOTIF /* Pretending that the event came from a
1287 Btn1Down seems the only way to convince Motif to
1288 activate its callbacks; setting the XmNmenuPost
1289 isn't working. --marcus@sysc.pdx.edu. */
1290 event.xbutton.button = 1;
1291 /* Motif only pops down menus when no Ctrl, Alt or Mod
1292 key is pressed and the button is released. So reset key state
1293 so Motif thinks this is the case. */
1294 event.xbutton.state = 0;
1295 #endif
1296 }
1297 /* Pop down on C-g and Escape. */
1298 else if (event.type == KeyPress
1299 && dpyinfo->display == event.xbutton.display)
1300 {
1301 KeySym keysym = XLookupKeysym (&event.xkey, 0);
1302
1303 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
1304 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
1305 popup_activated_flag = 0;
1306 }
1307
1308 x_dispatch_event (&event, event.xany.display);
1309 }
1310 }
1311
1312 DEFUN ("menu-bar-open", Fmenu_bar_open, Smenu_bar_open, 0, 1, "i",
1313 doc: /* Start key navigation of the menu bar in FRAME.
1314 This initially opens the first menu bar item and you can then navigate with the
1315 arrow keys, select a menu entry with the return key or cancel with the
1316 escape key. If FRAME has no menu bar this function does nothing.
1317
1318 If FRAME is nil or not given, use the selected frame. */)
1319 (frame)
1320 Lisp_Object frame;
1321 {
1322 XEvent ev;
1323 FRAME_PTR f = check_x_frame (frame);
1324 Widget menubar;
1325 BLOCK_INPUT;
1326
1327 if (FRAME_EXTERNAL_MENU_BAR (f))
1328 set_frame_menubar (f, 0, 1);
1329
1330 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
1331 if (menubar)
1332 {
1333 Window child;
1334 int error_p = 0;
1335
1336 x_catch_errors (FRAME_X_DISPLAY (f));
1337 memset (&ev, 0, sizeof ev);
1338 ev.xbutton.display = FRAME_X_DISPLAY (f);
1339 ev.xbutton.window = XtWindow (menubar);
1340 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1341 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
1342 ev.xbutton.button = Button1;
1343 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
1344 ev.xbutton.same_screen = True;
1345
1346 #ifdef USE_MOTIF
1347 {
1348 Arg al[2];
1349 WidgetList list;
1350 Cardinal nr;
1351 XtSetArg (al[0], XtNchildren, &list);
1352 XtSetArg (al[1], XtNnumChildren, &nr);
1353 XtGetValues (menubar, al, 2);
1354 ev.xbutton.window = XtWindow (list[0]);
1355 }
1356 #endif
1357
1358 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1359 /* From-window, to-window. */
1360 ev.xbutton.window, ev.xbutton.root,
1361
1362 /* From-position, to-position. */
1363 ev.xbutton.x, ev.xbutton.y,
1364 &ev.xbutton.x_root, &ev.xbutton.y_root,
1365
1366 /* Child of win. */
1367 &child);
1368 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
1369 x_uncatch_errors ();
1370
1371 if (! error_p)
1372 {
1373 ev.type = ButtonPress;
1374 ev.xbutton.state = 0;
1375
1376 XtDispatchEvent (&ev);
1377 ev.xbutton.type = ButtonRelease;
1378 ev.xbutton.state = Button1Mask;
1379 XtDispatchEvent (&ev);
1380 }
1381 }
1382
1383 UNBLOCK_INPUT;
1384
1385 return Qnil;
1386 }
1387 #endif /* USE_X_TOOLKIT */
1388
1389
1390 #ifdef USE_GTK
1391 DEFUN ("menu-bar-open", Fmenu_bar_open, Smenu_bar_open, 0, 1, "i",
1392 doc: /* Start key navigation of the menu bar in FRAME.
1393 This initially opens the first menu bar item and you can then navigate with the
1394 arrow keys, select a menu entry with the return key or cancel with the
1395 escape key. If FRAME has no menu bar this function does nothing.
1396
1397 If FRAME is nil or not given, use the selected frame. */)
1398 (frame)
1399 Lisp_Object frame;
1400 {
1401 GtkWidget *menubar;
1402 FRAME_PTR f;
1403
1404 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
1405 BLOCK_INPUT. */
1406
1407 BLOCK_INPUT;
1408 f = check_x_frame (frame);
1409
1410 if (FRAME_EXTERNAL_MENU_BAR (f))
1411 set_frame_menubar (f, 0, 1);
1412
1413 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
1414 if (menubar)
1415 {
1416 /* Activate the first menu. */
1417 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
1418
1419 gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar),
1420 GTK_WIDGET (children->data));
1421
1422 popup_activated_flag = 1;
1423 g_list_free (children);
1424 }
1425 UNBLOCK_INPUT;
1426
1427 return Qnil;
1428 }
1429
1430 /* Loop util popup_activated_flag is set to zero in a callback.
1431 Used for popup menus and dialogs. */
1432
1433 static void
1434 popup_widget_loop (do_timers, widget)
1435 int do_timers;
1436 GtkWidget *widget;
1437 {
1438 ++popup_activated_flag;
1439
1440 /* Process events in the Gtk event loop until done. */
1441 while (popup_activated_flag)
1442 {
1443 if (do_timers) x_menu_wait_for_event (0);
1444 gtk_main_iteration ();
1445 }
1446 }
1447 #endif
1448
1449 /* Activate the menu bar of frame F.
1450 This is called from keyboard.c when it gets the
1451 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
1452
1453 To activate the menu bar, we use the X button-press event
1454 that was saved in saved_menu_event.
1455 That makes the toolkit do its thing.
1456
1457 But first we recompute the menu bar contents (the whole tree).
1458
1459 The reason for saving the button event until here, instead of
1460 passing it to the toolkit right away, is that we can safely
1461 execute Lisp code. */
1462
1463 void
1464 x_activate_menubar (f)
1465 FRAME_PTR f;
1466 {
1467 if (!f->output_data.x->saved_menu_event->type)
1468 return;
1469
1470 #ifdef USE_GTK
1471 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
1472 f->output_data.x->saved_menu_event->xany.window))
1473 return;
1474 #endif
1475
1476 set_frame_menubar (f, 0, 1);
1477 BLOCK_INPUT;
1478 #ifdef USE_GTK
1479 XPutBackEvent (f->output_data.x->display_info->display,
1480 f->output_data.x->saved_menu_event);
1481 popup_activated_flag = 1;
1482 #else
1483 XtDispatchEvent (f->output_data.x->saved_menu_event);
1484 #endif
1485 UNBLOCK_INPUT;
1486 #ifdef USE_MOTIF
1487 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
1488 pending_menu_activation = 1;
1489 #endif
1490
1491 /* Ignore this if we get it a second time. */
1492 f->output_data.x->saved_menu_event->type = 0;
1493 }
1494
1495 /* This callback is invoked when the user selects a menubar cascade
1496 pushbutton, but before the pulldown menu is posted. */
1497
1498 #ifndef USE_GTK
1499 static void
1500 popup_activate_callback (widget, id, client_data)
1501 Widget widget;
1502 LWLIB_ID id;
1503 XtPointer client_data;
1504 {
1505 popup_activated_flag = 1;
1506 #ifdef USE_X_TOOLKIT
1507 x_activate_timeout_atimer ();
1508 #endif
1509 }
1510 #endif
1511
1512 /* This callback is invoked when a dialog or menu is finished being
1513 used and has been unposted. */
1514
1515 #ifdef USE_GTK
1516 static void
1517 popup_deactivate_callback (widget, client_data)
1518 GtkWidget *widget;
1519 gpointer client_data;
1520 {
1521 popup_activated_flag = 0;
1522 }
1523 #else
1524 static void
1525 popup_deactivate_callback (widget, id, client_data)
1526 Widget widget;
1527 LWLIB_ID id;
1528 XtPointer client_data;
1529 {
1530 popup_activated_flag = 0;
1531 }
1532 #endif
1533
1534
1535 /* Function that finds the frame for WIDGET and shows the HELP text
1536 for that widget.
1537 F is the frame if known, or NULL if not known. */
1538 static void
1539 show_help_event (f, widget, help)
1540 FRAME_PTR f;
1541 xt_or_gtk_widget widget;
1542 Lisp_Object help;
1543 {
1544 Lisp_Object frame;
1545
1546 if (f)
1547 {
1548 XSETFRAME (frame, f);
1549 kbd_buffer_store_help_event (frame, help);
1550 }
1551 else
1552 {
1553 #if 0 /* This code doesn't do anything useful. ++kfs */
1554 /* WIDGET is the popup menu. It's parent is the frame's
1555 widget. See which frame that is. */
1556 xt_or_gtk_widget frame_widget = XtParent (widget);
1557 Lisp_Object tail;
1558
1559 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
1560 {
1561 frame = XCAR (tail);
1562 if (GC_FRAMEP (frame)
1563 && (f = XFRAME (frame),
1564 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
1565 break;
1566 }
1567 #endif
1568 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1569 }
1570 }
1571
1572 /* Callback called when menu items are highlighted/unhighlighted
1573 while moving the mouse over them. WIDGET is the menu bar or menu
1574 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
1575 the data structure for the menu item, or null in case of
1576 unhighlighting. */
1577
1578 #ifdef USE_GTK
1579 void
1580 menu_highlight_callback (widget, call_data)
1581 GtkWidget *widget;
1582 gpointer call_data;
1583 {
1584 xg_menu_item_cb_data *cb_data;
1585 Lisp_Object help;
1586
1587 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
1588 XG_ITEM_DATA);
1589 if (! cb_data) return;
1590
1591 help = call_data ? cb_data->help : Qnil;
1592
1593 /* If popup_activated_flag is greater than 1 we are in a popup menu.
1594 Don't show help for them, they won't appear before the
1595 popup is popped down. */
1596 if (popup_activated_flag <= 1)
1597 show_help_event (cb_data->cl_data->f, widget, help);
1598 }
1599 #else
1600 void
1601 menu_highlight_callback (widget, id, call_data)
1602 Widget widget;
1603 LWLIB_ID id;
1604 void *call_data;
1605 {
1606 struct frame *f;
1607 Lisp_Object help;
1608
1609 widget_value *wv = (widget_value *) call_data;
1610
1611 help = wv ? wv->help : Qnil;
1612
1613 /* Determine the frame for the help event. */
1614 f = menubar_id_to_frame (id);
1615
1616 show_help_event (f, widget, help);
1617 }
1618 #endif
1619
1620 /* Find the menu selection and store it in the keyboard buffer.
1621 F is the frame the menu is on.
1622 MENU_BAR_ITEMS_USED is the length of VECTOR.
1623 VECTOR is an array of menu events for the whole menu. */
1624
1625 static void
1626 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
1627 FRAME_PTR f;
1628 int menu_bar_items_used;
1629 Lisp_Object vector;
1630 void *client_data;
1631 {
1632 Lisp_Object prefix, entry;
1633 Lisp_Object *subprefix_stack;
1634 int submenu_depth = 0;
1635 int i;
1636
1637 entry = Qnil;
1638 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
1639 prefix = Qnil;
1640 i = 0;
1641
1642 while (i < menu_bar_items_used)
1643 {
1644 if (EQ (XVECTOR (vector)->contents[i], Qnil))
1645 {
1646 subprefix_stack[submenu_depth++] = prefix;
1647 prefix = entry;
1648 i++;
1649 }
1650 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
1651 {
1652 prefix = subprefix_stack[--submenu_depth];
1653 i++;
1654 }
1655 else if (EQ (XVECTOR (vector)->contents[i], Qt))
1656 {
1657 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
1658 i += MENU_ITEMS_PANE_LENGTH;
1659 }
1660 else
1661 {
1662 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1663 /* The EMACS_INT cast avoids a warning. There's no problem
1664 as long as pointers have enough bits to hold small integers. */
1665 if ((int) (EMACS_INT) client_data == i)
1666 {
1667 int j;
1668 struct input_event buf;
1669 Lisp_Object frame;
1670 EVENT_INIT (buf);
1671
1672 XSETFRAME (frame, f);
1673 buf.kind = MENU_BAR_EVENT;
1674 buf.frame_or_window = frame;
1675 buf.arg = frame;
1676 kbd_buffer_store_event (&buf);
1677
1678 for (j = 0; j < submenu_depth; j++)
1679 if (!NILP (subprefix_stack[j]))
1680 {
1681 buf.kind = MENU_BAR_EVENT;
1682 buf.frame_or_window = frame;
1683 buf.arg = subprefix_stack[j];
1684 kbd_buffer_store_event (&buf);
1685 }
1686
1687 if (!NILP (prefix))
1688 {
1689 buf.kind = MENU_BAR_EVENT;
1690 buf.frame_or_window = frame;
1691 buf.arg = prefix;
1692 kbd_buffer_store_event (&buf);
1693 }
1694
1695 buf.kind = MENU_BAR_EVENT;
1696 buf.frame_or_window = frame;
1697 buf.arg = entry;
1698 kbd_buffer_store_event (&buf);
1699
1700 return;
1701 }
1702 i += MENU_ITEMS_ITEM_LENGTH;
1703 }
1704 }
1705 }
1706
1707
1708 #ifdef USE_GTK
1709 /* Gtk calls callbacks just because we tell it what item should be
1710 selected in a radio group. If this variable is set to a non-zero
1711 value, we are creating menus and don't want callbacks right now.
1712 */
1713 static int xg_crazy_callback_abort;
1714
1715 /* This callback is called from the menu bar pulldown menu
1716 when the user makes a selection.
1717 Figure out what the user chose
1718 and put the appropriate events into the keyboard buffer. */
1719 static void
1720 menubar_selection_callback (widget, client_data)
1721 GtkWidget *widget;
1722 gpointer client_data;
1723 {
1724 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1725
1726 if (xg_crazy_callback_abort)
1727 return;
1728
1729 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
1730 return;
1731
1732 /* For a group of radio buttons, GTK calls the selection callback first
1733 for the item that was active before the selection and then for the one that
1734 is active after the selection. For C-h k this means we get the help on
1735 the deselected item and then the selected item is executed. Prevent that
1736 by ignoring the non-active item. */
1737 if (GTK_IS_RADIO_MENU_ITEM (widget)
1738 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
1739 return;
1740
1741 /* When a menu is popped down, X generates a focus event (i.e. focus
1742 goes back to the frame below the menu). Since GTK buffers events,
1743 we force it out here before the menu selection event. Otherwise
1744 sit-for will exit at once if the focus event follows the menu selection
1745 event. */
1746
1747 BLOCK_INPUT;
1748 while (gtk_events_pending ())
1749 gtk_main_iteration ();
1750 UNBLOCK_INPUT;
1751
1752 find_and_call_menu_selection (cb_data->cl_data->f,
1753 cb_data->cl_data->menu_bar_items_used,
1754 cb_data->cl_data->menu_bar_vector,
1755 cb_data->call_data);
1756 }
1757
1758 #else /* not USE_GTK */
1759
1760 /* This callback is called from the menu bar pulldown menu
1761 when the user makes a selection.
1762 Figure out what the user chose
1763 and put the appropriate events into the keyboard buffer. */
1764 static void
1765 menubar_selection_callback (widget, id, client_data)
1766 Widget widget;
1767 LWLIB_ID id;
1768 XtPointer client_data;
1769 {
1770 FRAME_PTR f;
1771
1772 f = menubar_id_to_frame (id);
1773 if (!f)
1774 return;
1775 find_and_call_menu_selection (f, f->menu_bar_items_used,
1776 f->menu_bar_vector, client_data);
1777 }
1778 #endif /* not USE_GTK */
1779
1780 /* Allocate a widget_value, blocking input. */
1781
1782 widget_value *
1783 xmalloc_widget_value ()
1784 {
1785 widget_value *value;
1786
1787 BLOCK_INPUT;
1788 value = malloc_widget_value ();
1789 UNBLOCK_INPUT;
1790
1791 return value;
1792 }
1793
1794 /* This recursively calls free_widget_value on the tree of widgets.
1795 It must free all data that was malloc'ed for these widget_values.
1796 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1797 must be left alone. */
1798
1799 void
1800 free_menubar_widget_value_tree (wv)
1801 widget_value *wv;
1802 {
1803 if (! wv) return;
1804
1805 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1806
1807 if (wv->contents && (wv->contents != (widget_value*)1))
1808 {
1809 free_menubar_widget_value_tree (wv->contents);
1810 wv->contents = (widget_value *) 0xDEADBEEF;
1811 }
1812 if (wv->next)
1813 {
1814 free_menubar_widget_value_tree (wv->next);
1815 wv->next = (widget_value *) 0xDEADBEEF;
1816 }
1817 BLOCK_INPUT;
1818 free_widget_value (wv);
1819 UNBLOCK_INPUT;
1820 }
1821 \f
1822 /* Set up data in menu_items for a menu bar item
1823 whose event type is ITEM_KEY (with string ITEM_NAME)
1824 and whose contents come from the list of keymaps MAPS. */
1825
1826 static int
1827 parse_single_submenu (item_key, item_name, maps)
1828 Lisp_Object item_key, item_name, maps;
1829 {
1830 Lisp_Object length;
1831 int len;
1832 Lisp_Object *mapvec;
1833 int i;
1834 int top_level_items = 0;
1835
1836 length = Flength (maps);
1837 len = XINT (length);
1838
1839 /* Convert the list MAPS into a vector MAPVEC. */
1840 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1841 for (i = 0; i < len; i++)
1842 {
1843 mapvec[i] = Fcar (maps);
1844 maps = Fcdr (maps);
1845 }
1846
1847 /* Loop over the given keymaps, making a pane for each map.
1848 But don't make a pane that is empty--ignore that map instead. */
1849 for (i = 0; i < len; i++)
1850 {
1851 if (!KEYMAPP (mapvec[i]))
1852 {
1853 /* Here we have a command at top level in the menu bar
1854 as opposed to a submenu. */
1855 top_level_items = 1;
1856 push_menu_pane (Qnil, Qnil);
1857 push_menu_item (item_name, Qt, item_key, mapvec[i],
1858 Qnil, Qnil, Qnil, Qnil);
1859 }
1860 else
1861 {
1862 Lisp_Object prompt;
1863 prompt = Fkeymap_prompt (mapvec[i]);
1864 single_keymap_panes (mapvec[i],
1865 !NILP (prompt) ? prompt : item_name,
1866 item_key, 0, 10);
1867 }
1868 }
1869
1870 return top_level_items;
1871 }
1872
1873 /* Create a tree of widget_value objects
1874 representing the panes and items
1875 in menu_items starting at index START, up to index END. */
1876
1877 static widget_value *
1878 digest_single_submenu (start, end, top_level_items)
1879 int start, end, top_level_items;
1880 {
1881 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1882 int i;
1883 int submenu_depth = 0;
1884 widget_value **submenu_stack;
1885 int panes_seen = 0;
1886
1887 submenu_stack
1888 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1889 wv = xmalloc_widget_value ();
1890 wv->name = "menu";
1891 wv->value = 0;
1892 wv->enabled = 1;
1893 wv->button_type = BUTTON_TYPE_NONE;
1894 wv->help = Qnil;
1895 first_wv = wv;
1896 save_wv = 0;
1897 prev_wv = 0;
1898
1899 /* Loop over all panes and items made by the preceding call
1900 to parse_single_submenu and construct a tree of widget_value objects.
1901 Ignore the panes and items used by previous calls to
1902 digest_single_submenu, even though those are also in menu_items. */
1903 i = start;
1904 while (i < end)
1905 {
1906 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1907 {
1908 submenu_stack[submenu_depth++] = save_wv;
1909 save_wv = prev_wv;
1910 prev_wv = 0;
1911 i++;
1912 }
1913 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1914 {
1915 prev_wv = save_wv;
1916 save_wv = submenu_stack[--submenu_depth];
1917 i++;
1918 }
1919 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1920 && submenu_depth != 0)
1921 i += MENU_ITEMS_PANE_LENGTH;
1922 /* Ignore a nil in the item list.
1923 It's meaningful only for dialog boxes. */
1924 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1925 i += 1;
1926 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1927 {
1928 /* Create a new pane. */
1929 Lisp_Object pane_name, prefix;
1930 char *pane_string;
1931
1932 panes_seen++;
1933
1934 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1935 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1936
1937 #ifndef HAVE_MULTILINGUAL_MENU
1938 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1939 {
1940 pane_name = ENCODE_MENU_STRING (pane_name);
1941 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1942 }
1943 #endif
1944 pane_string = (NILP (pane_name)
1945 ? "" : (char *) SDATA (pane_name));
1946 /* If there is just one top-level pane, put all its items directly
1947 under the top-level menu. */
1948 if (menu_items_n_panes == 1)
1949 pane_string = "";
1950
1951 /* If the pane has a meaningful name,
1952 make the pane a top-level menu item
1953 with its items as a submenu beneath it. */
1954 if (strcmp (pane_string, ""))
1955 {
1956 wv = xmalloc_widget_value ();
1957 if (save_wv)
1958 save_wv->next = wv;
1959 else
1960 first_wv->contents = wv;
1961 wv->lname = pane_name;
1962 /* Set value to 1 so update_submenu_strings can handle '@' */
1963 wv->value = (char *)1;
1964 wv->enabled = 1;
1965 wv->button_type = BUTTON_TYPE_NONE;
1966 wv->help = Qnil;
1967 save_wv = wv;
1968 }
1969 else
1970 save_wv = first_wv;
1971
1972 prev_wv = 0;
1973 i += MENU_ITEMS_PANE_LENGTH;
1974 }
1975 else
1976 {
1977 /* Create a new item within current pane. */
1978 Lisp_Object item_name, enable, descrip, def, type, selected;
1979 Lisp_Object help;
1980
1981 /* All items should be contained in panes. */
1982 if (panes_seen == 0)
1983 abort ();
1984
1985 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1986 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1987 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1988 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1989 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1990 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1991 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1992
1993 #ifndef HAVE_MULTILINGUAL_MENU
1994 if (STRING_MULTIBYTE (item_name))
1995 {
1996 item_name = ENCODE_MENU_STRING (item_name);
1997 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1998 }
1999
2000 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2001 {
2002 descrip = ENCODE_MENU_STRING (descrip);
2003 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
2004 }
2005 #endif /* not HAVE_MULTILINGUAL_MENU */
2006
2007 wv = xmalloc_widget_value ();
2008 if (prev_wv)
2009 prev_wv->next = wv;
2010 else
2011 save_wv->contents = wv;
2012
2013 wv->lname = item_name;
2014 if (!NILP (descrip))
2015 wv->lkey = descrip;
2016 wv->value = 0;
2017 /* The EMACS_INT cast avoids a warning. There's no problem
2018 as long as pointers have enough bits to hold small integers. */
2019 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
2020 wv->enabled = !NILP (enable);
2021
2022 if (NILP (type))
2023 wv->button_type = BUTTON_TYPE_NONE;
2024 else if (EQ (type, QCradio))
2025 wv->button_type = BUTTON_TYPE_RADIO;
2026 else if (EQ (type, QCtoggle))
2027 wv->button_type = BUTTON_TYPE_TOGGLE;
2028 else
2029 abort ();
2030
2031 wv->selected = !NILP (selected);
2032 if (! STRINGP (help))
2033 help = Qnil;
2034
2035 wv->help = help;
2036
2037 prev_wv = wv;
2038
2039 i += MENU_ITEMS_ITEM_LENGTH;
2040 }
2041 }
2042
2043 /* If we have just one "menu item"
2044 that was originally a button, return it by itself. */
2045 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
2046 {
2047 wv = first_wv->contents;
2048 free_widget_value (first_wv);
2049 return wv;
2050 }
2051
2052 return first_wv;
2053 }
2054
2055 /* Walk through the widget_value tree starting at FIRST_WV and update
2056 the char * pointers from the corresponding lisp values.
2057 We do this after building the whole tree, since GC may happen while the
2058 tree is constructed, and small strings are relocated. So we must wait
2059 until no GC can happen before storing pointers into lisp values. */
2060 static void
2061 update_submenu_strings (first_wv)
2062 widget_value *first_wv;
2063 {
2064 widget_value *wv;
2065
2066 for (wv = first_wv; wv; wv = wv->next)
2067 {
2068 if (STRINGP (wv->lname))
2069 {
2070 wv->name = (char *) SDATA (wv->lname);
2071
2072 /* Ignore the @ that means "separate pane".
2073 This is a kludge, but this isn't worth more time. */
2074 if (wv->value == (char *)1)
2075 {
2076 if (wv->name[0] == '@')
2077 wv->name++;
2078 wv->value = 0;
2079 }
2080 }
2081
2082 if (STRINGP (wv->lkey))
2083 wv->key = (char *) SDATA (wv->lkey);
2084
2085 if (wv->contents)
2086 update_submenu_strings (wv->contents);
2087 }
2088 }
2089
2090 \f
2091 /* Recompute all the widgets of frame F, when the menu bar has been
2092 changed. Value is non-zero if widgets were updated. */
2093
2094 static int
2095 update_frame_menubar (f)
2096 FRAME_PTR f;
2097 {
2098 #ifdef USE_GTK
2099 return xg_update_frame_menubar (f);
2100 #else
2101 struct x_output *x = f->output_data.x;
2102 int columns, rows;
2103
2104 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
2105 return 0;
2106
2107 BLOCK_INPUT;
2108 /* Save the size of the frame because the pane widget doesn't accept
2109 to resize itself. So force it. */
2110 columns = FRAME_COLS (f);
2111 rows = FRAME_LINES (f);
2112
2113 /* Do the voodoo which means "I'm changing lots of things, don't try
2114 to refigure sizes until I'm done." */
2115 lw_refigure_widget (x->column_widget, False);
2116
2117 /* The order in which children are managed is the top to bottom
2118 order in which they are displayed in the paned window. First,
2119 remove the text-area widget. */
2120 XtUnmanageChild (x->edit_widget);
2121
2122 /* Remove the menubar that is there now, and put up the menubar that
2123 should be there. */
2124 XtManageChild (x->menubar_widget);
2125 XtMapWidget (x->menubar_widget);
2126 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
2127
2128 /* Re-manage the text-area widget, and then thrash the sizes. */
2129 XtManageChild (x->edit_widget);
2130 lw_refigure_widget (x->column_widget, True);
2131
2132 /* Force the pane widget to resize itself with the right values. */
2133 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
2134 UNBLOCK_INPUT;
2135 #endif
2136 return 1;
2137 }
2138
2139 /* Set the contents of the menubar widgets of frame F.
2140 The argument FIRST_TIME is currently ignored;
2141 it is set the first time this is called, from initialize_frame_menubar. */
2142
2143 void
2144 set_frame_menubar (f, first_time, deep_p)
2145 FRAME_PTR f;
2146 int first_time;
2147 int deep_p;
2148 {
2149 xt_or_gtk_widget menubar_widget = f->output_data.x->menubar_widget;
2150 #ifdef USE_X_TOOLKIT
2151 LWLIB_ID id;
2152 #endif
2153 Lisp_Object items;
2154 widget_value *wv, *first_wv, *prev_wv = 0;
2155 int i, last_i = 0;
2156 int *submenu_start, *submenu_end;
2157 int *submenu_top_level_items, *submenu_n_panes;
2158
2159
2160 XSETFRAME (Vmenu_updating_frame, f);
2161
2162 #ifdef USE_X_TOOLKIT
2163 if (f->output_data.x->id == 0)
2164 f->output_data.x->id = next_menubar_widget_id++;
2165 id = f->output_data.x->id;
2166 #endif
2167
2168 if (! menubar_widget)
2169 deep_p = 1;
2170 else if (pending_menu_activation && !deep_p)
2171 deep_p = 1;
2172 /* Make the first call for any given frame always go deep. */
2173 else if (!f->output_data.x->saved_menu_event && !deep_p)
2174 {
2175 deep_p = 1;
2176 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
2177 f->output_data.x->saved_menu_event->type = 0;
2178 }
2179
2180 #ifdef USE_GTK
2181 /* If we have detached menus, we must update deep so detached menus
2182 also gets updated. */
2183 deep_p = deep_p || xg_have_tear_offs ();
2184 #endif
2185
2186 if (deep_p)
2187 {
2188 /* Make a widget-value tree representing the entire menu trees. */
2189
2190 struct buffer *prev = current_buffer;
2191 Lisp_Object buffer;
2192 int specpdl_count = SPECPDL_INDEX ();
2193 int previous_menu_items_used = f->menu_bar_items_used;
2194 Lisp_Object *previous_items
2195 = (Lisp_Object *) alloca (previous_menu_items_used
2196 * sizeof (Lisp_Object));
2197
2198 /* If we are making a new widget, its contents are empty,
2199 do always reinitialize them. */
2200 if (! menubar_widget)
2201 previous_menu_items_used = 0;
2202
2203 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
2204 specbind (Qinhibit_quit, Qt);
2205 /* Don't let the debugger step into this code
2206 because it is not reentrant. */
2207 specbind (Qdebug_on_next_call, Qnil);
2208
2209 record_unwind_save_match_data ();
2210 if (NILP (Voverriding_local_map_menu_flag))
2211 {
2212 specbind (Qoverriding_terminal_local_map, Qnil);
2213 specbind (Qoverriding_local_map, Qnil);
2214 }
2215
2216 set_buffer_internal_1 (XBUFFER (buffer));
2217
2218 /* Run the Lucid hook. */
2219 safe_run_hooks (Qactivate_menubar_hook);
2220
2221 /* If it has changed current-menubar from previous value,
2222 really recompute the menubar from the value. */
2223 if (! NILP (Vlucid_menu_bar_dirty_flag))
2224 call0 (Qrecompute_lucid_menubar);
2225 safe_run_hooks (Qmenu_bar_update_hook);
2226 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
2227
2228 items = FRAME_MENU_BAR_ITEMS (f);
2229
2230 /* Save the frame's previous menu bar contents data. */
2231 if (previous_menu_items_used)
2232 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
2233 previous_menu_items_used * sizeof (Lisp_Object));
2234
2235 /* Fill in menu_items with the current menu bar contents.
2236 This can evaluate Lisp code. */
2237 save_menu_items ();
2238
2239 menu_items = f->menu_bar_vector;
2240 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
2241 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
2242 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
2243 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
2244 submenu_top_level_items
2245 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
2246 init_menu_items ();
2247 for (i = 0; i < XVECTOR (items)->size; i += 4)
2248 {
2249 Lisp_Object key, string, maps;
2250
2251 last_i = i;
2252
2253 key = XVECTOR (items)->contents[i];
2254 string = XVECTOR (items)->contents[i + 1];
2255 maps = XVECTOR (items)->contents[i + 2];
2256 if (NILP (string))
2257 break;
2258
2259 submenu_start[i] = menu_items_used;
2260
2261 menu_items_n_panes = 0;
2262 submenu_top_level_items[i]
2263 = parse_single_submenu (key, string, maps);
2264 submenu_n_panes[i] = menu_items_n_panes;
2265
2266 submenu_end[i] = menu_items_used;
2267 }
2268
2269 finish_menu_items ();
2270
2271 /* Convert menu_items into widget_value trees
2272 to display the menu. This cannot evaluate Lisp code. */
2273
2274 wv = xmalloc_widget_value ();
2275 wv->name = "menubar";
2276 wv->value = 0;
2277 wv->enabled = 1;
2278 wv->button_type = BUTTON_TYPE_NONE;
2279 wv->help = Qnil;
2280 first_wv = wv;
2281
2282 for (i = 0; i < last_i; i += 4)
2283 {
2284 menu_items_n_panes = submenu_n_panes[i];
2285 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
2286 submenu_top_level_items[i]);
2287 if (prev_wv)
2288 prev_wv->next = wv;
2289 else
2290 first_wv->contents = wv;
2291 /* Don't set wv->name here; GC during the loop might relocate it. */
2292 wv->enabled = 1;
2293 wv->button_type = BUTTON_TYPE_NONE;
2294 prev_wv = wv;
2295 }
2296
2297 set_buffer_internal_1 (prev);
2298
2299 /* If there has been no change in the Lisp-level contents
2300 of the menu bar, skip redisplaying it. Just exit. */
2301
2302 /* Compare the new menu items with the ones computed last time. */
2303 for (i = 0; i < previous_menu_items_used; i++)
2304 if (menu_items_used == i
2305 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
2306 break;
2307 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
2308 {
2309 /* The menu items have not changed. Don't bother updating
2310 the menus in any form, since it would be a no-op. */
2311 free_menubar_widget_value_tree (first_wv);
2312 discard_menu_items ();
2313 unbind_to (specpdl_count, Qnil);
2314 return;
2315 }
2316
2317 /* The menu items are different, so store them in the frame. */
2318 f->menu_bar_vector = menu_items;
2319 f->menu_bar_items_used = menu_items_used;
2320
2321 /* This calls restore_menu_items to restore menu_items, etc.,
2322 as they were outside. */
2323 unbind_to (specpdl_count, Qnil);
2324
2325 /* Now GC cannot happen during the lifetime of the widget_value,
2326 so it's safe to store data from a Lisp_String. */
2327 wv = first_wv->contents;
2328 for (i = 0; i < XVECTOR (items)->size; i += 4)
2329 {
2330 Lisp_Object string;
2331 string = XVECTOR (items)->contents[i + 1];
2332 if (NILP (string))
2333 break;
2334 wv->name = (char *) SDATA (string);
2335 update_submenu_strings (wv->contents);
2336 wv = wv->next;
2337 }
2338
2339 }
2340 else
2341 {
2342 /* Make a widget-value tree containing
2343 just the top level menu bar strings. */
2344
2345 wv = xmalloc_widget_value ();
2346 wv->name = "menubar";
2347 wv->value = 0;
2348 wv->enabled = 1;
2349 wv->button_type = BUTTON_TYPE_NONE;
2350 wv->help = Qnil;
2351 first_wv = wv;
2352
2353 items = FRAME_MENU_BAR_ITEMS (f);
2354 for (i = 0; i < XVECTOR (items)->size; i += 4)
2355 {
2356 Lisp_Object string;
2357
2358 string = XVECTOR (items)->contents[i + 1];
2359 if (NILP (string))
2360 break;
2361
2362 wv = xmalloc_widget_value ();
2363 wv->name = (char *) SDATA (string);
2364 wv->value = 0;
2365 wv->enabled = 1;
2366 wv->button_type = BUTTON_TYPE_NONE;
2367 wv->help = Qnil;
2368 /* This prevents lwlib from assuming this
2369 menu item is really supposed to be empty. */
2370 /* The EMACS_INT cast avoids a warning.
2371 This value just has to be different from small integers. */
2372 wv->call_data = (void *) (EMACS_INT) (-1);
2373
2374 if (prev_wv)
2375 prev_wv->next = wv;
2376 else
2377 first_wv->contents = wv;
2378 prev_wv = wv;
2379 }
2380
2381 /* Forget what we thought we knew about what is in the
2382 detailed contents of the menu bar menus.
2383 Changing the top level always destroys the contents. */
2384 f->menu_bar_items_used = 0;
2385 }
2386
2387 /* Create or update the menu bar widget. */
2388
2389 BLOCK_INPUT;
2390
2391 #ifdef USE_GTK
2392 xg_crazy_callback_abort = 1;
2393 if (menubar_widget)
2394 {
2395 /* The fourth arg is DEEP_P, which says to consider the entire
2396 menu trees we supply, rather than just the menu bar item names. */
2397 xg_modify_menubar_widgets (menubar_widget,
2398 f,
2399 first_wv,
2400 deep_p,
2401 G_CALLBACK (menubar_selection_callback),
2402 G_CALLBACK (popup_deactivate_callback),
2403 G_CALLBACK (menu_highlight_callback));
2404 }
2405 else
2406 {
2407 GtkWidget *wvbox = f->output_data.x->vbox_widget;
2408
2409 menubar_widget
2410 = xg_create_widget ("menubar", "menubar", f, first_wv,
2411 G_CALLBACK (menubar_selection_callback),
2412 G_CALLBACK (popup_deactivate_callback),
2413 G_CALLBACK (menu_highlight_callback));
2414
2415 f->output_data.x->menubar_widget = menubar_widget;
2416 }
2417
2418
2419 #else /* not USE_GTK */
2420 if (menubar_widget)
2421 {
2422 /* Disable resizing (done for Motif!) */
2423 lw_allow_resizing (f->output_data.x->widget, False);
2424
2425 /* The third arg is DEEP_P, which says to consider the entire
2426 menu trees we supply, rather than just the menu bar item names. */
2427 lw_modify_all_widgets (id, first_wv, deep_p);
2428
2429 /* Re-enable the edit widget to resize. */
2430 lw_allow_resizing (f->output_data.x->widget, True);
2431 }
2432 else
2433 {
2434 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
2435 XtTranslations override = XtParseTranslationTable (menuOverride);
2436
2437 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
2438 f->output_data.x->column_widget,
2439 0,
2440 popup_activate_callback,
2441 menubar_selection_callback,
2442 popup_deactivate_callback,
2443 menu_highlight_callback);
2444 f->output_data.x->menubar_widget = menubar_widget;
2445
2446 /* Make menu pop down on C-g. */
2447 XtOverrideTranslations (menubar_widget, override);
2448 }
2449
2450 {
2451 int menubar_size
2452 = (f->output_data.x->menubar_widget
2453 ? (f->output_data.x->menubar_widget->core.height
2454 + f->output_data.x->menubar_widget->core.border_width)
2455 : 0);
2456
2457 #if 0 /* Experimentally, we now get the right results
2458 for -geometry -0-0 without this. 24 Aug 96, rms. */
2459 #ifdef USE_LUCID
2460 if (FRAME_EXTERNAL_MENU_BAR (f))
2461 {
2462 Dimension ibw = 0;
2463 XtVaGetValues (f->output_data.x->column_widget,
2464 XtNinternalBorderWidth, &ibw, NULL);
2465 menubar_size += ibw;
2466 }
2467 #endif /* USE_LUCID */
2468 #endif /* 0 */
2469
2470 f->output_data.x->menubar_height = menubar_size;
2471 }
2472 #endif /* not USE_GTK */
2473
2474 free_menubar_widget_value_tree (first_wv);
2475 update_frame_menubar (f);
2476
2477 #ifdef USE_GTK
2478 xg_crazy_callback_abort = 0;
2479 #endif
2480
2481 UNBLOCK_INPUT;
2482 }
2483
2484 /* Called from Fx_create_frame to create the initial menubar of a frame
2485 before it is mapped, so that the window is mapped with the menubar already
2486 there instead of us tacking it on later and thrashing the window after it
2487 is visible. */
2488
2489 void
2490 initialize_frame_menubar (f)
2491 FRAME_PTR f;
2492 {
2493 /* This function is called before the first chance to redisplay
2494 the frame. It has to be, so the frame will have the right size. */
2495 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
2496 set_frame_menubar (f, 1, 1);
2497 }
2498
2499
2500 /* Get rid of the menu bar of frame F, and free its storage.
2501 This is used when deleting a frame, and when turning off the menu bar.
2502 For GTK this function is in gtkutil.c. */
2503
2504 #ifndef USE_GTK
2505 void
2506 free_frame_menubar (f)
2507 FRAME_PTR f;
2508 {
2509 Widget menubar_widget;
2510
2511 menubar_widget = f->output_data.x->menubar_widget;
2512
2513 f->output_data.x->menubar_height = 0;
2514
2515 if (menubar_widget)
2516 {
2517 #ifdef USE_MOTIF
2518 /* Removing the menu bar magically changes the shell widget's x
2519 and y position of (0, 0) which, when the menu bar is turned
2520 on again, leads to pull-down menuss appearing in strange
2521 positions near the upper-left corner of the display. This
2522 happens only with some window managers like twm and ctwm,
2523 but not with other like Motif's mwm or kwm, because the
2524 latter generate ConfigureNotify events when the menu bar
2525 is switched off, which fixes the shell position. */
2526 Position x0, y0, x1, y1;
2527 #endif
2528
2529 BLOCK_INPUT;
2530
2531 #ifdef USE_MOTIF
2532 if (f->output_data.x->widget)
2533 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
2534 #endif
2535
2536 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
2537 f->output_data.x->menubar_widget = NULL;
2538
2539 #ifdef USE_MOTIF
2540 if (f->output_data.x->widget)
2541 {
2542 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
2543 if (x1 == 0 && y1 == 0)
2544 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
2545 }
2546 #endif
2547
2548 UNBLOCK_INPUT;
2549 }
2550 }
2551 #endif /* not USE_GTK */
2552
2553 #endif /* USE_X_TOOLKIT || USE_GTK */
2554 \f
2555 /* xmenu_show actually displays a menu using the panes and items in menu_items
2556 and returns the value selected from it.
2557 There are two versions of xmenu_show, one for Xt and one for Xlib.
2558 Both assume input is blocked by the caller. */
2559
2560 /* F is the frame the menu is for.
2561 X and Y are the frame-relative specified position,
2562 relative to the inside upper left corner of the frame F.
2563 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
2564 KEYMAPS is 1 if this menu was specified with keymaps;
2565 in that case, we return a list containing the chosen item's value
2566 and perhaps also the pane's prefix.
2567 TITLE is the specified menu title.
2568 ERROR is a place to store an error message string in case of failure.
2569 (We return nil on failure, but the value doesn't actually matter.) */
2570
2571 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
2572
2573 /* The item selected in the popup menu. */
2574 static Lisp_Object *volatile menu_item_selection;
2575
2576 #ifdef USE_GTK
2577
2578 /* Used when position a popup menu. See menu_position_func and
2579 create_and_show_popup_menu below. */
2580 struct next_popup_x_y
2581 {
2582 FRAME_PTR f;
2583 int x;
2584 int y;
2585 };
2586
2587 /* The menu position function to use if we are not putting a popup
2588 menu where the pointer is.
2589 MENU is the menu to pop up.
2590 X and Y shall on exit contain x/y where the menu shall pop up.
2591 PUSH_IN is not documented in the GTK manual.
2592 USER_DATA is any data passed in when calling gtk_menu_popup.
2593 Here it points to a struct next_popup_x_y where the coordinates
2594 to store in *X and *Y are as well as the frame for the popup.
2595
2596 Here only X and Y are used. */
2597 static void
2598 menu_position_func (menu, x, y, push_in, user_data)
2599 GtkMenu *menu;
2600 gint *x;
2601 gint *y;
2602 gboolean *push_in;
2603 gpointer user_data;
2604 {
2605 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
2606 GtkRequisition req;
2607 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width;
2608 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height;
2609
2610 *x = data->x;
2611 *y = data->y;
2612
2613 /* Check if there is room for the menu. If not, adjust x/y so that
2614 the menu is fully visible. */
2615 gtk_widget_size_request (GTK_WIDGET (menu), &req);
2616 if (data->x + req.width > disp_width)
2617 *x -= data->x + req.width - disp_width;
2618 if (data->y + req.height > disp_height)
2619 *y -= data->y + req.height - disp_height;
2620 }
2621
2622 static void
2623 popup_selection_callback (widget, client_data)
2624 GtkWidget *widget;
2625 gpointer client_data;
2626 {
2627 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
2628
2629 if (xg_crazy_callback_abort) return;
2630 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
2631 }
2632
2633 static Lisp_Object
2634 pop_down_menu (arg)
2635 Lisp_Object arg;
2636 {
2637 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
2638
2639 popup_activated_flag = 0;
2640 BLOCK_INPUT;
2641 gtk_widget_destroy (GTK_WIDGET (p->pointer));
2642 UNBLOCK_INPUT;
2643 return Qnil;
2644 }
2645
2646 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
2647 menu pops down.
2648 menu_item_selection will be set to the selection. */
2649 static void
2650 create_and_show_popup_menu (f, first_wv, x, y, for_click)
2651 FRAME_PTR f;
2652 widget_value *first_wv;
2653 int x;
2654 int y;
2655 int for_click;
2656 {
2657 int i;
2658 GtkWidget *menu;
2659 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
2660 struct next_popup_x_y popup_x_y;
2661 int specpdl_count = SPECPDL_INDEX ();
2662
2663 xg_crazy_callback_abort = 1;
2664 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
2665 G_CALLBACK (popup_selection_callback),
2666 G_CALLBACK (popup_deactivate_callback),
2667 G_CALLBACK (menu_highlight_callback));
2668 xg_crazy_callback_abort = 0;
2669
2670 if (! for_click)
2671 {
2672 /* Not invoked by a click. pop up at x/y. */
2673 pos_func = menu_position_func;
2674
2675 /* Adjust coordinates to be root-window-relative. */
2676 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2677 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2678
2679 popup_x_y.x = x;
2680 popup_x_y.y = y;
2681 popup_x_y.f = f;
2682
2683 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
2684 }
2685 else
2686 {
2687 for (i = 0; i < 5; i++)
2688 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
2689 break;
2690 }
2691
2692 /* Display the menu. */
2693 gtk_widget_show_all (menu);
2694 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
2695
2696 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
2697
2698 if (GTK_WIDGET_MAPPED (menu))
2699 {
2700 /* Set this to one. popup_widget_loop increases it by one, so it becomes
2701 two. show_help_echo uses this to detect popup menus. */
2702 popup_activated_flag = 1;
2703 /* Process events that apply to the menu. */
2704 popup_widget_loop (1, menu);
2705 }
2706
2707 unbind_to (specpdl_count, Qnil);
2708
2709 /* Must reset this manually because the button release event is not passed
2710 to Emacs event loop. */
2711 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2712 }
2713
2714 #else /* not USE_GTK */
2715
2716 /* We need a unique id for each widget handled by the Lucid Widget
2717 library.
2718
2719 For the main windows, and popup menus, we use this counter,
2720 which we increment each time after use. This starts from 1<<16.
2721
2722 For menu bars, we use numbers starting at 0, counted in
2723 next_menubar_widget_id. */
2724 LWLIB_ID widget_id_tick;
2725
2726 static void
2727 popup_selection_callback (widget, id, client_data)
2728 Widget widget;
2729 LWLIB_ID id;
2730 XtPointer client_data;
2731 {
2732 menu_item_selection = (Lisp_Object *) client_data;
2733 }
2734
2735 /* ARG is the LWLIB ID of the dialog box, represented
2736 as a Lisp object as (HIGHPART . LOWPART). */
2737
2738 static Lisp_Object
2739 pop_down_menu (arg)
2740 Lisp_Object arg;
2741 {
2742 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
2743 | XINT (XCDR (arg)));
2744
2745 BLOCK_INPUT;
2746 lw_destroy_all_widgets (id);
2747 UNBLOCK_INPUT;
2748 popup_activated_flag = 0;
2749
2750 return Qnil;
2751 }
2752
2753 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
2754 menu pops down.
2755 menu_item_selection will be set to the selection. */
2756 static void
2757 create_and_show_popup_menu (f, first_wv, x, y, for_click)
2758 FRAME_PTR f;
2759 widget_value *first_wv;
2760 int x;
2761 int y;
2762 int for_click;
2763 {
2764 int i;
2765 Arg av[2];
2766 int ac = 0;
2767 XButtonPressedEvent dummy;
2768 LWLIB_ID menu_id;
2769 Widget menu;
2770
2771 menu_id = widget_id_tick++;
2772 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
2773 f->output_data.x->widget, 1, 0,
2774 popup_selection_callback,
2775 popup_deactivate_callback,
2776 menu_highlight_callback);
2777
2778 dummy.type = ButtonPress;
2779 dummy.serial = 0;
2780 dummy.send_event = 0;
2781 dummy.display = FRAME_X_DISPLAY (f);
2782 dummy.time = CurrentTime;
2783 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
2784 dummy.window = dummy.root;
2785 dummy.subwindow = dummy.root;
2786 dummy.x = x;
2787 dummy.y = y;
2788
2789 /* Adjust coordinates to be root-window-relative. */
2790 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2791 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2792
2793 dummy.x_root = x;
2794 dummy.y_root = y;
2795
2796 dummy.state = 0;
2797 dummy.button = 0;
2798 for (i = 0; i < 5; i++)
2799 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
2800 dummy.button = i;
2801
2802 /* Don't allow any geometry request from the user. */
2803 XtSetArg (av[ac], XtNgeometry, 0); ac++;
2804 XtSetValues (menu, av, ac);
2805
2806 /* Display the menu. */
2807 lw_popup_menu (menu, (XEvent *) &dummy);
2808 popup_activated_flag = 1;
2809 x_activate_timeout_atimer ();
2810
2811 {
2812 int fact = 4 * sizeof (LWLIB_ID);
2813 int specpdl_count = SPECPDL_INDEX ();
2814 record_unwind_protect (pop_down_menu,
2815 Fcons (make_number (menu_id >> (fact)),
2816 make_number (menu_id & ~(-1 << (fact)))));
2817
2818 /* Process events that apply to the menu. */
2819 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
2820
2821 unbind_to (specpdl_count, Qnil);
2822 }
2823 }
2824
2825 #endif /* not USE_GTK */
2826
2827 static Lisp_Object
2828 xmenu_show (f, x, y, for_click, keymaps, title, error)
2829 FRAME_PTR f;
2830 int x;
2831 int y;
2832 int for_click;
2833 int keymaps;
2834 Lisp_Object title;
2835 char **error;
2836 {
2837 int i;
2838 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
2839 widget_value **submenu_stack
2840 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
2841 Lisp_Object *subprefix_stack
2842 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
2843 int submenu_depth = 0;
2844
2845 int first_pane;
2846
2847 *error = NULL;
2848
2849 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2850 {
2851 *error = "Empty menu";
2852 return Qnil;
2853 }
2854
2855 /* Create a tree of widget_value objects
2856 representing the panes and their items. */
2857 wv = xmalloc_widget_value ();
2858 wv->name = "menu";
2859 wv->value = 0;
2860 wv->enabled = 1;
2861 wv->button_type = BUTTON_TYPE_NONE;
2862 wv->help =Qnil;
2863 first_wv = wv;
2864 first_pane = 1;
2865
2866 /* Loop over all panes and items, filling in the tree. */
2867 i = 0;
2868 while (i < menu_items_used)
2869 {
2870 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
2871 {
2872 submenu_stack[submenu_depth++] = save_wv;
2873 save_wv = prev_wv;
2874 prev_wv = 0;
2875 first_pane = 1;
2876 i++;
2877 }
2878 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
2879 {
2880 prev_wv = save_wv;
2881 save_wv = submenu_stack[--submenu_depth];
2882 first_pane = 0;
2883 i++;
2884 }
2885 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
2886 && submenu_depth != 0)
2887 i += MENU_ITEMS_PANE_LENGTH;
2888 /* Ignore a nil in the item list.
2889 It's meaningful only for dialog boxes. */
2890 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2891 i += 1;
2892 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2893 {
2894 /* Create a new pane. */
2895 Lisp_Object pane_name, prefix;
2896 char *pane_string;
2897
2898 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2899 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2900
2901 #ifndef HAVE_MULTILINGUAL_MENU
2902 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
2903 {
2904 pane_name = ENCODE_MENU_STRING (pane_name);
2905 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
2906 }
2907 #endif
2908 pane_string = (NILP (pane_name)
2909 ? "" : (char *) SDATA (pane_name));
2910 /* If there is just one top-level pane, put all its items directly
2911 under the top-level menu. */
2912 if (menu_items_n_panes == 1)
2913 pane_string = "";
2914
2915 /* If the pane has a meaningful name,
2916 make the pane a top-level menu item
2917 with its items as a submenu beneath it. */
2918 if (!keymaps && strcmp (pane_string, ""))
2919 {
2920 wv = xmalloc_widget_value ();
2921 if (save_wv)
2922 save_wv->next = wv;
2923 else
2924 first_wv->contents = wv;
2925 wv->name = pane_string;
2926 if (keymaps && !NILP (prefix))
2927 wv->name++;
2928 wv->value = 0;
2929 wv->enabled = 1;
2930 wv->button_type = BUTTON_TYPE_NONE;
2931 wv->help = Qnil;
2932 save_wv = wv;
2933 prev_wv = 0;
2934 }
2935 else if (first_pane)
2936 {
2937 save_wv = wv;
2938 prev_wv = 0;
2939 }
2940 first_pane = 0;
2941 i += MENU_ITEMS_PANE_LENGTH;
2942 }
2943 else
2944 {
2945 /* Create a new item within current pane. */
2946 Lisp_Object item_name, enable, descrip, def, type, selected, help;
2947 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2948 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2949 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2950 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
2951 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
2952 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
2953 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2954
2955 #ifndef HAVE_MULTILINGUAL_MENU
2956 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
2957 {
2958 item_name = ENCODE_MENU_STRING (item_name);
2959 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
2960 }
2961
2962 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2963 {
2964 descrip = ENCODE_MENU_STRING (descrip);
2965 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
2966 }
2967 #endif /* not HAVE_MULTILINGUAL_MENU */
2968
2969 wv = xmalloc_widget_value ();
2970 if (prev_wv)
2971 prev_wv->next = wv;
2972 else
2973 save_wv->contents = wv;
2974 wv->name = (char *) SDATA (item_name);
2975 if (!NILP (descrip))
2976 wv->key = (char *) SDATA (descrip);
2977 wv->value = 0;
2978 /* If this item has a null value,
2979 make the call_data null so that it won't display a box
2980 when the mouse is on it. */
2981 wv->call_data
2982 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
2983 wv->enabled = !NILP (enable);
2984
2985 if (NILP (type))
2986 wv->button_type = BUTTON_TYPE_NONE;
2987 else if (EQ (type, QCtoggle))
2988 wv->button_type = BUTTON_TYPE_TOGGLE;
2989 else if (EQ (type, QCradio))
2990 wv->button_type = BUTTON_TYPE_RADIO;
2991 else
2992 abort ();
2993
2994 wv->selected = !NILP (selected);
2995
2996 if (! STRINGP (help))
2997 help = Qnil;
2998
2999 wv->help = help;
3000
3001 prev_wv = wv;
3002
3003 i += MENU_ITEMS_ITEM_LENGTH;
3004 }
3005 }
3006
3007 /* Deal with the title, if it is non-nil. */
3008 if (!NILP (title))
3009 {
3010 widget_value *wv_title = xmalloc_widget_value ();
3011 widget_value *wv_sep1 = xmalloc_widget_value ();
3012 widget_value *wv_sep2 = xmalloc_widget_value ();
3013
3014 wv_sep2->name = "--";
3015 wv_sep2->next = first_wv->contents;
3016 wv_sep2->help = Qnil;
3017
3018 wv_sep1->name = "--";
3019 wv_sep1->next = wv_sep2;
3020 wv_sep1->help = Qnil;
3021
3022 #ifndef HAVE_MULTILINGUAL_MENU
3023 if (STRING_MULTIBYTE (title))
3024 title = ENCODE_MENU_STRING (title);
3025 #endif
3026
3027 wv_title->name = (char *) SDATA (title);
3028 wv_title->enabled = TRUE;
3029 wv_title->button_type = BUTTON_TYPE_NONE;
3030 wv_title->next = wv_sep1;
3031 wv_title->help = Qnil;
3032 first_wv->contents = wv_title;
3033 }
3034
3035 /* No selection has been chosen yet. */
3036 menu_item_selection = 0;
3037
3038 /* Actually create and show the menu until popped down. */
3039 create_and_show_popup_menu (f, first_wv, x, y, for_click);
3040
3041 /* Free the widget_value objects we used to specify the contents. */
3042 free_menubar_widget_value_tree (first_wv);
3043
3044 /* Find the selected item, and its pane, to return
3045 the proper value. */
3046 if (menu_item_selection != 0)
3047 {
3048 Lisp_Object prefix, entry;
3049
3050 prefix = entry = Qnil;
3051 i = 0;
3052 while (i < menu_items_used)
3053 {
3054 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
3055 {
3056 subprefix_stack[submenu_depth++] = prefix;
3057 prefix = entry;
3058 i++;
3059 }
3060 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
3061 {
3062 prefix = subprefix_stack[--submenu_depth];
3063 i++;
3064 }
3065 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
3066 {
3067 prefix
3068 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
3069 i += MENU_ITEMS_PANE_LENGTH;
3070 }
3071 /* Ignore a nil in the item list.
3072 It's meaningful only for dialog boxes. */
3073 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
3074 i += 1;
3075 else
3076 {
3077 entry
3078 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
3079 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
3080 {
3081 if (keymaps != 0)
3082 {
3083 int j;
3084
3085 entry = Fcons (entry, Qnil);
3086 if (!NILP (prefix))
3087 entry = Fcons (prefix, entry);
3088 for (j = submenu_depth - 1; j >= 0; j--)
3089 if (!NILP (subprefix_stack[j]))
3090 entry = Fcons (subprefix_stack[j], entry);
3091 }
3092 return entry;
3093 }
3094 i += MENU_ITEMS_ITEM_LENGTH;
3095 }
3096 }
3097 }
3098 else if (!for_click)
3099 /* Make "Cancel" equivalent to C-g. */
3100 Fsignal (Qquit, Qnil);
3101
3102 return Qnil;
3103 }
3104 \f
3105 #ifdef USE_GTK
3106 static void
3107 dialog_selection_callback (widget, client_data)
3108 GtkWidget *widget;
3109 gpointer client_data;
3110 {
3111 /* The EMACS_INT cast avoids a warning. There's no problem
3112 as long as pointers have enough bits to hold small integers. */
3113 if ((int) (EMACS_INT) client_data != -1)
3114 menu_item_selection = (Lisp_Object *) client_data;
3115
3116 popup_activated_flag = 0;
3117 }
3118
3119 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
3120 dialog pops down.
3121 menu_item_selection will be set to the selection. */
3122 static void
3123 create_and_show_dialog (f, first_wv)
3124 FRAME_PTR f;
3125 widget_value *first_wv;
3126 {
3127 GtkWidget *menu;
3128
3129 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
3130 G_CALLBACK (dialog_selection_callback),
3131 G_CALLBACK (popup_deactivate_callback),
3132 0);
3133
3134 if (menu)
3135 {
3136 int specpdl_count = SPECPDL_INDEX ();
3137 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
3138
3139 /* Display the menu. */
3140 gtk_widget_show_all (menu);
3141
3142 /* Process events that apply to the menu. */
3143 popup_widget_loop (1, menu);
3144
3145 unbind_to (specpdl_count, Qnil);
3146 }
3147 }
3148
3149 #else /* not USE_GTK */
3150 static void
3151 dialog_selection_callback (widget, id, client_data)
3152 Widget widget;
3153 LWLIB_ID id;
3154 XtPointer client_data;
3155 {
3156 /* The EMACS_INT cast avoids a warning. There's no problem
3157 as long as pointers have enough bits to hold small integers. */
3158 if ((int) (EMACS_INT) client_data != -1)
3159 menu_item_selection = (Lisp_Object *) client_data;
3160
3161 BLOCK_INPUT;
3162 lw_destroy_all_widgets (id);
3163 UNBLOCK_INPUT;
3164 popup_activated_flag = 0;
3165 }
3166
3167
3168 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
3169 dialog pops down.
3170 menu_item_selection will be set to the selection. */
3171 static void
3172 create_and_show_dialog (f, first_wv)
3173 FRAME_PTR f;
3174 widget_value *first_wv;
3175 {
3176 LWLIB_ID dialog_id;
3177
3178 dialog_id = widget_id_tick++;
3179 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
3180 f->output_data.x->widget, 1, 0,
3181 dialog_selection_callback, 0, 0);
3182 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
3183
3184 /* Display the dialog box. */
3185 lw_pop_up_all_widgets (dialog_id);
3186 popup_activated_flag = 1;
3187 x_activate_timeout_atimer ();
3188
3189 /* Process events that apply to the dialog box.
3190 Also handle timers. */
3191 {
3192 int count = SPECPDL_INDEX ();
3193 int fact = 4 * sizeof (LWLIB_ID);
3194
3195 /* xdialog_show_unwind is responsible for popping the dialog box down. */
3196 record_unwind_protect (pop_down_menu,
3197 Fcons (make_number (dialog_id >> (fact)),
3198 make_number (dialog_id & ~(-1 << (fact)))));
3199
3200 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
3201 dialog_id, 1);
3202
3203 unbind_to (count, Qnil);
3204 }
3205 }
3206
3207 #endif /* not USE_GTK */
3208
3209 static char * button_names [] = {
3210 "button1", "button2", "button3", "button4", "button5",
3211 "button6", "button7", "button8", "button9", "button10" };
3212
3213 static Lisp_Object
3214 xdialog_show (f, keymaps, title, header, error_name)
3215 FRAME_PTR f;
3216 int keymaps;
3217 Lisp_Object title, header;
3218 char **error_name;
3219 {
3220 int i, nb_buttons=0;
3221 char dialog_name[6];
3222
3223 widget_value *wv, *first_wv = 0, *prev_wv = 0;
3224
3225 /* Number of elements seen so far, before boundary. */
3226 int left_count = 0;
3227 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
3228 int boundary_seen = 0;
3229
3230 *error_name = NULL;
3231
3232 if (menu_items_n_panes > 1)
3233 {
3234 *error_name = "Multiple panes in dialog box";
3235 return Qnil;
3236 }
3237
3238 /* Create a tree of widget_value objects
3239 representing the text label and buttons. */
3240 {
3241 Lisp_Object pane_name, prefix;
3242 char *pane_string;
3243 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
3244 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
3245 pane_string = (NILP (pane_name)
3246 ? "" : (char *) SDATA (pane_name));
3247 prev_wv = xmalloc_widget_value ();
3248 prev_wv->value = pane_string;
3249 if (keymaps && !NILP (prefix))
3250 prev_wv->name++;
3251 prev_wv->enabled = 1;
3252 prev_wv->name = "message";
3253 prev_wv->help = Qnil;
3254 first_wv = prev_wv;
3255
3256 /* Loop over all panes and items, filling in the tree. */
3257 i = MENU_ITEMS_PANE_LENGTH;
3258 while (i < menu_items_used)
3259 {
3260
3261 /* Create a new item within current pane. */
3262 Lisp_Object item_name, enable, descrip;
3263 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
3264 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
3265 descrip
3266 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
3267
3268 if (NILP (item_name))
3269 {
3270 free_menubar_widget_value_tree (first_wv);
3271 *error_name = "Submenu in dialog items";
3272 return Qnil;
3273 }
3274 if (EQ (item_name, Qquote))
3275 {
3276 /* This is the boundary between left-side elts
3277 and right-side elts. Stop incrementing right_count. */
3278 boundary_seen = 1;
3279 i++;
3280 continue;
3281 }
3282 if (nb_buttons >= 9)
3283 {
3284 free_menubar_widget_value_tree (first_wv);
3285 *error_name = "Too many dialog items";
3286 return Qnil;
3287 }
3288
3289 wv = xmalloc_widget_value ();
3290 prev_wv->next = wv;
3291 wv->name = (char *) button_names[nb_buttons];
3292 if (!NILP (descrip))
3293 wv->key = (char *) SDATA (descrip);
3294 wv->value = (char *) SDATA (item_name);
3295 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
3296 wv->enabled = !NILP (enable);
3297 wv->help = Qnil;
3298 prev_wv = wv;
3299
3300 if (! boundary_seen)
3301 left_count++;
3302
3303 nb_buttons++;
3304 i += MENU_ITEMS_ITEM_LENGTH;
3305 }
3306
3307 /* If the boundary was not specified,
3308 by default put half on the left and half on the right. */
3309 if (! boundary_seen)
3310 left_count = nb_buttons - nb_buttons / 2;
3311
3312 wv = xmalloc_widget_value ();
3313 wv->name = dialog_name;
3314 wv->help = Qnil;
3315
3316 /* Frame title: 'Q' = Question, 'I' = Information.
3317 Can also have 'E' = Error if, one day, we want
3318 a popup for errors. */
3319 if (NILP(header))
3320 dialog_name[0] = 'Q';
3321 else
3322 dialog_name[0] = 'I';
3323
3324 /* Dialog boxes use a really stupid name encoding
3325 which specifies how many buttons to use
3326 and how many buttons are on the right. */
3327 dialog_name[1] = '0' + nb_buttons;
3328 dialog_name[2] = 'B';
3329 dialog_name[3] = 'R';
3330 /* Number of buttons to put on the right. */
3331 dialog_name[4] = '0' + nb_buttons - left_count;
3332 dialog_name[5] = 0;
3333 wv->contents = first_wv;
3334 first_wv = wv;
3335 }
3336
3337 /* No selection has been chosen yet. */
3338 menu_item_selection = 0;
3339
3340 /* Force a redisplay before showing the dialog. If a frame is created
3341 just before showing the dialog, its contents may not have been fully
3342 drawn, as this depends on timing of events from the X server. Redisplay
3343 is not done when a dialog is shown. If redisplay could be done in the
3344 X event loop (i.e. the X event loop does not run in a signal handler)
3345 this would not be needed. */
3346 Fredisplay (Qt);
3347
3348 /* Actually create and show the dialog. */
3349 create_and_show_dialog (f, first_wv);
3350
3351 /* Free the widget_value objects we used to specify the contents. */
3352 free_menubar_widget_value_tree (first_wv);
3353
3354 /* Find the selected item, and its pane, to return
3355 the proper value. */
3356 if (menu_item_selection != 0)
3357 {
3358 Lisp_Object prefix;
3359
3360 prefix = Qnil;
3361 i = 0;
3362 while (i < menu_items_used)
3363 {
3364 Lisp_Object entry;
3365
3366 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
3367 {
3368 prefix
3369 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
3370 i += MENU_ITEMS_PANE_LENGTH;
3371 }
3372 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
3373 {
3374 /* This is the boundary between left-side elts and
3375 right-side elts. */
3376 ++i;
3377 }
3378 else
3379 {
3380 entry
3381 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
3382 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
3383 {
3384 if (keymaps != 0)
3385 {
3386 entry = Fcons (entry, Qnil);
3387 if (!NILP (prefix))
3388 entry = Fcons (prefix, entry);
3389 }
3390 return entry;
3391 }
3392 i += MENU_ITEMS_ITEM_LENGTH;
3393 }
3394 }
3395 }
3396 else
3397 /* Make "Cancel" equivalent to C-g. */
3398 Fsignal (Qquit, Qnil);
3399
3400 return Qnil;
3401 }
3402
3403 #else /* not USE_X_TOOLKIT && not USE_GTK */
3404
3405 /* The frame of the last activated non-toolkit menu bar.
3406 Used to generate menu help events. */
3407
3408 static struct frame *menu_help_frame;
3409
3410
3411 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
3412
3413 PANE is the pane number, and ITEM is the menu item number in
3414 the menu (currently not used).
3415
3416 This cannot be done with generating a HELP_EVENT because
3417 XMenuActivate contains a loop that doesn't let Emacs process
3418 keyboard events. */
3419
3420 static void
3421 menu_help_callback (help_string, pane, item)
3422 char *help_string;
3423 int pane, item;
3424 {
3425 extern Lisp_Object Qmenu_item;
3426 Lisp_Object *first_item;
3427 Lisp_Object pane_name;
3428 Lisp_Object menu_object;
3429
3430 first_item = XVECTOR (menu_items)->contents;
3431 if (EQ (first_item[0], Qt))
3432 pane_name = first_item[MENU_ITEMS_PANE_NAME];
3433 else if (EQ (first_item[0], Qquote))
3434 /* This shouldn't happen, see xmenu_show. */
3435 pane_name = empty_unibyte_string;
3436 else
3437 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
3438
3439 /* (menu-item MENU-NAME PANE-NUMBER) */
3440 menu_object = Fcons (Qmenu_item,
3441 Fcons (pane_name,
3442 Fcons (make_number (pane), Qnil)));
3443 show_help_echo (help_string ? build_string (help_string) : Qnil,
3444 Qnil, menu_object, make_number (item), 1);
3445 }
3446
3447 static Lisp_Object
3448 pop_down_menu (arg)
3449 Lisp_Object arg;
3450 {
3451 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
3452 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
3453
3454 FRAME_PTR f = p1->pointer;
3455 XMenu *menu = p2->pointer;
3456
3457 BLOCK_INPUT;
3458 #ifndef MSDOS
3459 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
3460 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
3461 #endif
3462 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
3463
3464 #ifdef HAVE_X_WINDOWS
3465 /* Assume the mouse has moved out of the X window.
3466 If it has actually moved in, we will get an EnterNotify. */
3467 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
3468
3469 /* State that no mouse buttons are now held.
3470 (The oldXMenu code doesn't track this info for us.)
3471 That is not necessarily true, but the fiction leads to reasonable
3472 results, and it is a pain to ask which are actually held now. */
3473 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
3474
3475 #endif /* HAVE_X_WINDOWS */
3476
3477 UNBLOCK_INPUT;
3478
3479 return Qnil;
3480 }
3481
3482
3483 static Lisp_Object
3484 xmenu_show (f, x, y, for_click, keymaps, title, error)
3485 FRAME_PTR f;
3486 int x, y;
3487 int for_click;
3488 int keymaps;
3489 Lisp_Object title;
3490 char **error;
3491 {
3492 Window root;
3493 XMenu *menu;
3494 int pane, selidx, lpane, status;
3495 Lisp_Object entry, pane_prefix;
3496 char *datap;
3497 int ulx, uly, width, height;
3498 int dispwidth, dispheight;
3499 int i, j, lines, maxlines;
3500 int maxwidth;
3501 int dummy_int;
3502 unsigned int dummy_uint;
3503 int specpdl_count = SPECPDL_INDEX ();
3504
3505 *error = 0;
3506 if (menu_items_n_panes == 0)
3507 return Qnil;
3508
3509 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
3510 {
3511 *error = "Empty menu";
3512 return Qnil;
3513 }
3514
3515 /* Figure out which root window F is on. */
3516 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
3517 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
3518 &dummy_uint, &dummy_uint);
3519
3520 /* Make the menu on that window. */
3521 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
3522 if (menu == NULL)
3523 {
3524 *error = "Can't create menu";
3525 return Qnil;
3526 }
3527
3528 /* Don't GC while we prepare and show the menu,
3529 because we give the oldxmenu library pointers to the
3530 contents of strings. */
3531 inhibit_garbage_collection ();
3532
3533 #ifdef HAVE_X_WINDOWS
3534 /* Adjust coordinates to relative to the outer (window manager) window. */
3535 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
3536 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
3537 #endif /* HAVE_X_WINDOWS */
3538
3539 /* Adjust coordinates to be root-window-relative. */
3540 x += f->left_pos;
3541 y += f->top_pos;
3542
3543 /* Create all the necessary panes and their items. */
3544 maxlines = lines = i = 0;
3545 while (i < menu_items_used)
3546 {
3547 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
3548 {
3549 /* Create a new pane. */
3550 Lisp_Object pane_name, prefix;
3551 char *pane_string;
3552
3553 maxlines = max (maxlines, lines);
3554 lines = 0;
3555 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
3556 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
3557 pane_string = (NILP (pane_name)
3558 ? "" : (char *) SDATA (pane_name));
3559 if (keymaps && !NILP (prefix))
3560 pane_string++;
3561
3562 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
3563 if (lpane == XM_FAILURE)
3564 {
3565 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
3566 *error = "Can't create pane";
3567 return Qnil;
3568 }
3569 i += MENU_ITEMS_PANE_LENGTH;
3570
3571 /* Find the width of the widest item in this pane. */
3572 maxwidth = 0;
3573 j = i;
3574 while (j < menu_items_used)
3575 {
3576 Lisp_Object item;
3577 item = XVECTOR (menu_items)->contents[j];
3578 if (EQ (item, Qt))
3579 break;
3580 if (NILP (item))
3581 {
3582 j++;
3583 continue;
3584 }
3585 width = SBYTES (item);
3586 if (width > maxwidth)
3587 maxwidth = width;
3588
3589 j += MENU_ITEMS_ITEM_LENGTH;
3590 }
3591 }
3592 /* Ignore a nil in the item list.
3593 It's meaningful only for dialog boxes. */
3594 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
3595 i += 1;
3596 else
3597 {
3598 /* Create a new item within current pane. */
3599 Lisp_Object item_name, enable, descrip, help;
3600 unsigned char *item_data;
3601 char *help_string;
3602
3603 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
3604 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
3605 descrip
3606 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
3607 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
3608 help_string = STRINGP (help) ? SDATA (help) : NULL;
3609
3610 if (!NILP (descrip))
3611 {
3612 int gap = maxwidth - SBYTES (item_name);
3613 #ifdef C_ALLOCA
3614 Lisp_Object spacer;
3615 spacer = Fmake_string (make_number (gap), make_number (' '));
3616 item_name = concat2 (item_name, spacer);
3617 item_name = concat2 (item_name, descrip);
3618 item_data = SDATA (item_name);
3619 #else
3620 /* if alloca is fast, use that to make the space,
3621 to reduce gc needs. */
3622 item_data
3623 = (unsigned char *) alloca (maxwidth
3624 + SBYTES (descrip) + 1);
3625 bcopy (SDATA (item_name), item_data,
3626 SBYTES (item_name));
3627 for (j = SCHARS (item_name); j < maxwidth; j++)
3628 item_data[j] = ' ';
3629 bcopy (SDATA (descrip), item_data + j,
3630 SBYTES (descrip));
3631 item_data[j + SBYTES (descrip)] = 0;
3632 #endif
3633 }
3634 else
3635 item_data = SDATA (item_name);
3636
3637 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
3638 menu, lpane, 0, item_data,
3639 !NILP (enable), help_string)
3640 == XM_FAILURE)
3641 {
3642 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
3643 *error = "Can't add selection to menu";
3644 return Qnil;
3645 }
3646 i += MENU_ITEMS_ITEM_LENGTH;
3647 lines++;
3648 }
3649 }
3650
3651 maxlines = max (maxlines, lines);
3652
3653 /* All set and ready to fly. */
3654 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
3655 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
3656 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
3657 x = min (x, dispwidth);
3658 y = min (y, dispheight);
3659 x = max (x, 1);
3660 y = max (y, 1);
3661 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
3662 &ulx, &uly, &width, &height);
3663 if (ulx+width > dispwidth)
3664 {
3665 x -= (ulx + width) - dispwidth;
3666 ulx = dispwidth - width;
3667 }
3668 if (uly+height > dispheight)
3669 {
3670 y -= (uly + height) - dispheight;
3671 uly = dispheight - height;
3672 }
3673 if (ulx < 0) x -= ulx;
3674 if (uly < 0) y -= uly;
3675
3676 if (! for_click)
3677 {
3678 /* If position was not given by a mouse click, adjust so upper left
3679 corner of the menu as a whole ends up at given coordinates. This
3680 is what x-popup-menu says in its documentation. */
3681 x += width/2;
3682 y += 1.5*height/(maxlines+2);
3683 }
3684
3685 XMenuSetAEQ (menu, TRUE);
3686 XMenuSetFreeze (menu, TRUE);
3687 pane = selidx = 0;
3688
3689 #ifndef MSDOS
3690 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
3691 #endif
3692
3693 record_unwind_protect (pop_down_menu,
3694 Fcons (make_save_value (f, 0),
3695 make_save_value (menu, 0)));
3696
3697 /* Help display under X won't work because XMenuActivate contains
3698 a loop that doesn't give Emacs a chance to process it. */
3699 menu_help_frame = f;
3700 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
3701 x, y, ButtonReleaseMask, &datap,
3702 menu_help_callback);
3703
3704 switch (status)
3705 {
3706 case XM_SUCCESS:
3707 #ifdef XDEBUG
3708 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
3709 #endif
3710
3711 /* Find the item number SELIDX in pane number PANE. */
3712 i = 0;
3713 while (i < menu_items_used)
3714 {
3715 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
3716 {
3717 if (pane == 0)
3718 pane_prefix
3719 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
3720 pane--;
3721 i += MENU_ITEMS_PANE_LENGTH;
3722 }
3723 else
3724 {
3725 if (pane == -1)
3726 {
3727 if (selidx == 0)
3728 {
3729 entry
3730 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
3731 if (keymaps != 0)
3732 {
3733 entry = Fcons (entry, Qnil);
3734 if (!NILP (pane_prefix))
3735 entry = Fcons (pane_prefix, entry);
3736 }
3737 break;
3738 }
3739 selidx--;
3740 }
3741 i += MENU_ITEMS_ITEM_LENGTH;
3742 }
3743 }
3744 break;
3745
3746 case XM_FAILURE:
3747 *error = "Can't activate menu";
3748 case XM_IA_SELECT:
3749 entry = Qnil;
3750 break;
3751 case XM_NO_SELECT:
3752 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
3753 the menu was invoked with a mouse event as POSITION). */
3754 if (! for_click)
3755 Fsignal (Qquit, Qnil);
3756 entry = Qnil;
3757 break;
3758 }
3759
3760 unbind_to (specpdl_count, Qnil);
3761
3762 return entry;
3763 }
3764
3765 #endif /* not USE_X_TOOLKIT */
3766
3767 #endif /* HAVE_MENUS */
3768
3769 /* Detect if a dialog or menu has been posted. */
3770
3771 int
3772 popup_activated ()
3773 {
3774 return popup_activated_flag;
3775 }
3776
3777 /* The following is used by delayed window autoselection. */
3778
3779 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
3780 doc: /* Return t if a menu or popup dialog is active. */)
3781 ()
3782 {
3783 #ifdef HAVE_MENUS
3784 return (popup_activated ()) ? Qt : Qnil;
3785 #else
3786 return Qnil;
3787 #endif /* HAVE_MENUS */
3788 }
3789 \f
3790 void
3791 syms_of_xmenu ()
3792 {
3793 staticpro (&menu_items);
3794 menu_items = Qnil;
3795 menu_items_inuse = Qnil;
3796
3797 Qdebug_on_next_call = intern ("debug-on-next-call");
3798 staticpro (&Qdebug_on_next_call);
3799
3800 #ifdef USE_X_TOOLKIT
3801 widget_id_tick = (1<<16);
3802 next_menubar_widget_id = 1;
3803 #endif
3804
3805 defsubr (&Sx_popup_menu);
3806 defsubr (&Smenu_or_popup_active_p);
3807
3808 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
3809 defsubr (&Smenu_bar_open);
3810 Ffset (intern ("accelerate-menu"), intern (Smenu_bar_open.symbol_name));
3811 #endif
3812
3813 #ifdef HAVE_MENUS
3814 defsubr (&Sx_popup_dialog);
3815 #endif
3816 }
3817
3818 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
3819 (do not change this comment) */