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