(erc-button-keymap): Bind `follow-link'.
[emacs.git] / src / xmenu.c
blobc6d7b0d95852428980d0852a9ffd9d1d3b87eef7
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, 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
27 /* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
30 /* Rewritten for clarity and GC protection by rms in Feb 94. */
32 #include <config.h>
34 #if 0 /* Why was this included? And without syssignal.h? */
35 /* On 4.3 this loses if it comes after xterm.h. */
36 #include <signal.h>
37 #endif
39 #include <stdio.h>
41 #include "lisp.h"
42 #include "keyboard.h"
43 #include "keymap.h"
44 #include "frame.h"
45 #include "termhooks.h"
46 #include "window.h"
47 #include "blockinput.h"
48 #include "buffer.h"
49 #include "charset.h"
50 #include "coding.h"
51 #include "sysselect.h"
53 #ifdef MSDOS
54 #include "msdos.h"
55 #endif
57 #ifdef HAVE_X_WINDOWS
58 /* This may include sys/types.h, and that somehow loses
59 if this is not done before the other system files. */
60 #include "xterm.h"
61 #endif
63 /* Load sys/types.h if not already loaded.
64 In some systems loading it twice is suicidal. */
65 #ifndef makedev
66 #include <sys/types.h>
67 #endif
69 #include "dispextern.h"
71 #ifdef HAVE_X_WINDOWS
72 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
73 code accepts the Emacs internal encoding. */
74 #undef HAVE_MULTILINGUAL_MENU
75 #ifdef USE_X_TOOLKIT
76 #include "widget.h"
77 #include <X11/Xlib.h>
78 #include <X11/IntrinsicP.h>
79 #include <X11/CoreP.h>
80 #include <X11/StringDefs.h>
81 #include <X11/Shell.h>
82 #ifdef USE_LUCID
83 #ifdef HAVE_XAW3D
84 #include <X11/Xaw3d/Paned.h>
85 #else /* !HAVE_XAW3D */
86 #include <X11/Xaw/Paned.h>
87 #endif /* HAVE_XAW3D */
88 #endif /* USE_LUCID */
89 #include "../lwlib/lwlib.h"
90 #else /* not USE_X_TOOLKIT */
91 #ifndef USE_GTK
92 #include "../oldXMenu/XMenu.h"
93 #endif
94 #endif /* not USE_X_TOOLKIT */
95 #endif /* HAVE_X_WINDOWS */
97 #ifdef USE_GTK
98 #include "gtkutil.h"
99 #endif
101 #include "menu.h"
103 #ifndef TRUE
104 #define TRUE 1
105 #define FALSE 0
106 #endif /* no TRUE */
108 Lisp_Object Qdebug_on_next_call;
110 extern Lisp_Object Vmenu_updating_frame;
112 extern Lisp_Object Qmenu_bar;
114 extern Lisp_Object QCtoggle, QCradio;
116 extern Lisp_Object Voverriding_local_map;
117 extern Lisp_Object Voverriding_local_map_menu_flag;
119 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
121 extern Lisp_Object Qmenu_bar_update_hook;
123 #ifdef USE_X_TOOLKIT
124 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
125 extern XtAppContext Xt_app_con;
127 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
128 char **));
129 static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
130 LWLIB_ID, int));
131 #endif /* USE_X_TOOLKIT */
133 #ifdef USE_GTK
134 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
135 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
136 char **));
137 #endif
139 static int update_frame_menubar P_ ((struct frame *));
140 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
141 Lisp_Object, char **));
143 /* Flag which when set indicates a dialog or menu has been posted by
144 Xt on behalf of one of the widget sets. */
145 static int popup_activated_flag;
147 static int next_menubar_widget_id;
149 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
150 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
151 extern widget_value *xmalloc_widget_value P_ ((void));
152 extern widget_value *digest_single_submenu P_ ((int, int, int));
153 #endif
155 /* This is set nonzero after the user activates the menu bar, and set
156 to zero again after the menu bars are redisplayed by prepare_menu_bar.
157 While it is nonzero, all calls to set_frame_menubar go deep.
159 I don't understand why this is needed, but it does seem to be
160 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
162 int pending_menu_activation;
164 #ifdef USE_X_TOOLKIT
166 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
168 static struct frame *
169 menubar_id_to_frame (id)
170 LWLIB_ID id;
172 Lisp_Object tail, frame;
173 FRAME_PTR f;
175 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
177 frame = XCAR (tail);
178 if (!FRAMEP (frame))
179 continue;
180 f = XFRAME (frame);
181 if (!FRAME_WINDOW_P (f))
182 continue;
183 if (f->output_data.x->id == id)
184 return f;
186 return 0;
189 #endif
191 #ifdef HAVE_X_WINDOWS
192 /* Return the mouse position in *X and *Y. The coordinates are window
193 relative for the edit window in frame F.
194 This is for Fx_popup_menu. The mouse_position_hook can not
195 be used for X, as it returns window relative coordinates
196 for the window where the mouse is in. This could be the menu bar,
197 the scroll bar or the edit window. Fx_popup_menu needs to be
198 sure it is the edit window. */
199 static void
200 mouse_position_for_popup (f, x, y)
201 FRAME_PTR f;
202 int *x;
203 int *y;
205 Window root, dummy_window;
206 int dummy;
208 if (! FRAME_X_P (f))
209 abort ();
211 BLOCK_INPUT;
213 XQueryPointer (FRAME_X_DISPLAY (f),
214 DefaultRootWindow (FRAME_X_DISPLAY (f)),
216 /* The root window which contains the pointer. */
217 &root,
219 /* Window pointer is on, not used */
220 &dummy_window,
222 /* The position on that root window. */
223 x, y,
225 /* x/y in dummy_window coordinates, not used. */
226 &dummy, &dummy,
228 /* Modifier keys and pointer buttons, about which
229 we don't care. */
230 (unsigned int *) &dummy);
232 UNBLOCK_INPUT;
234 /* xmenu_show expects window coordinates, not root window
235 coordinates. Translate. */
236 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
237 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
240 #endif /* HAVE_X_WINDOWS */
242 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
243 doc: /* Pop up a deck-of-cards menu and return user's selection.
244 POSITION is a position specification. This is either a mouse button event
245 or a list ((XOFFSET YOFFSET) WINDOW)
246 where XOFFSET and YOFFSET are positions in pixels from the top left
247 corner of WINDOW. (WINDOW may be a window or a frame object.)
248 This controls the position of the top left of the menu as a whole.
249 If POSITION is t, it means to use the current mouse position.
251 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
252 The menu items come from key bindings that have a menu string as well as
253 a definition; actually, the "definition" in such a key binding looks like
254 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
255 the keymap as a top-level element.
257 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
258 Otherwise, REAL-DEFINITION should be a valid key binding definition.
260 You can also use a list of keymaps as MENU.
261 Then each keymap makes a separate pane.
263 When MENU is a keymap or a list of keymaps, the return value is the
264 list of events corresponding to the user's choice. Note that
265 `x-popup-menu' does not actually execute the command bound to that
266 sequence of events.
268 Alternatively, you can specify a menu of multiple panes
269 with a list of the form (TITLE PANE1 PANE2...),
270 where each pane is a list of form (TITLE ITEM1 ITEM2...).
271 Each ITEM is normally a cons cell (STRING . VALUE);
272 but a string can appear as an item--that makes a nonselectable line
273 in the menu.
274 With this form of menu, the return value is VALUE from the chosen item.
276 If POSITION is nil, don't display the menu at all, just precalculate the
277 cached information about equivalent key sequences.
279 If the user gets rid of the menu without making a valid choice, for
280 instance by clicking the mouse away from a valid choice or by typing
281 keyboard input, then this normally results in a quit and
282 `x-popup-menu' does not return. But if POSITION is a mouse button
283 event (indicating that the user invoked the menu with the mouse) then
284 no quit occurs and `x-popup-menu' returns nil. */)
285 (position, menu)
286 Lisp_Object position, menu;
288 Lisp_Object keymap, tem;
289 int xpos = 0, ypos = 0;
290 Lisp_Object title;
291 char *error_name = NULL;
292 Lisp_Object selection = Qnil;
293 FRAME_PTR f = NULL;
294 Lisp_Object x, y, window;
295 int keymaps = 0;
296 int for_click = 0;
297 int specpdl_count = SPECPDL_INDEX ();
298 struct gcpro gcpro1;
300 #ifdef HAVE_MENUS
301 if (! NILP (position))
303 int get_current_pos_p = 0;
304 check_x ();
306 /* Decode the first argument: find the window and the coordinates. */
307 if (EQ (position, Qt)
308 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
309 || EQ (XCAR (position), Qtool_bar))))
311 get_current_pos_p = 1;
313 else
315 tem = Fcar (position);
316 if (CONSP (tem))
318 window = Fcar (Fcdr (position));
319 x = XCAR (tem);
320 y = Fcar (XCDR (tem));
322 else
324 for_click = 1;
325 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
326 window = Fcar (tem); /* POSN_WINDOW (tem) */
327 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
328 x = Fcar (tem);
329 y = Fcdr (tem);
332 /* If a click happens in an external tool bar or a detached
333 tool bar, x and y is NIL. In that case, use the current
334 mouse position. This happens for the help button in the
335 tool bar. Ideally popup-menu should pass NIL to
336 this function, but it doesn't. */
337 if (NILP (x) && NILP (y))
338 get_current_pos_p = 1;
341 if (get_current_pos_p)
343 /* Use the mouse's current position. */
344 FRAME_PTR new_f = SELECTED_FRAME ();
345 #ifdef HAVE_X_WINDOWS
346 /* Can't use mouse_position_hook for X since it returns
347 coordinates relative to the window the mouse is in,
348 we need coordinates relative to the edit widget always. */
349 if (new_f != 0)
351 int cur_x, cur_y;
353 mouse_position_for_popup (new_f, &cur_x, &cur_y);
354 /* cur_x/y may be negative, so use make_number. */
355 x = make_number (cur_x);
356 y = make_number (cur_y);
359 #else /* not HAVE_X_WINDOWS */
360 Lisp_Object bar_window;
361 enum scroll_bar_part part;
362 unsigned long time;
363 void (*mouse_position_hook) P_ ((struct frame **, int,
364 Lisp_Object *,
365 enum scroll_bar_part *,
366 Lisp_Object *,
367 Lisp_Object *,
368 unsigned long *)) =
369 new_f->terminal->mouse_position_hook;
371 if (mouse_position_hook)
372 (*mouse_position_hook) (&new_f, 1, &bar_window,
373 &part, &x, &y, &time);
374 #endif /* not HAVE_X_WINDOWS */
376 if (new_f != 0)
377 XSETFRAME (window, new_f);
378 else
380 window = selected_window;
381 XSETFASTINT (x, 0);
382 XSETFASTINT (y, 0);
386 CHECK_NUMBER (x);
387 CHECK_NUMBER (y);
389 /* Decode where to put the menu. */
391 if (FRAMEP (window))
393 f = XFRAME (window);
394 xpos = 0;
395 ypos = 0;
397 else if (WINDOWP (window))
399 CHECK_LIVE_WINDOW (window);
400 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
402 xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
403 ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
405 else
406 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
407 but I don't want to make one now. */
408 CHECK_WINDOW (window);
410 xpos += XINT (x);
411 ypos += XINT (y);
413 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
414 error ("Can not put X menu on this terminal");
416 XSETFRAME (Vmenu_updating_frame, f);
418 else
419 Vmenu_updating_frame = Qnil;
420 #endif /* HAVE_MENUS */
422 record_unwind_protect (unuse_menu_items, Qnil);
423 title = Qnil;
424 GCPRO1 (title);
426 /* Decode the menu items from what was specified. */
428 keymap = get_keymap (menu, 0, 0);
429 if (CONSP (keymap))
431 /* We were given a keymap. Extract menu info from the keymap. */
432 Lisp_Object prompt;
434 /* Extract the detailed info to make one pane. */
435 keymap_panes (&menu, 1, NILP (position));
437 /* Search for a string appearing directly as an element of the keymap.
438 That string is the title of the menu. */
439 prompt = Fkeymap_prompt (keymap);
440 if (NILP (title) && !NILP (prompt))
441 title = prompt;
443 /* Make that be the pane title of the first pane. */
444 if (!NILP (prompt) && menu_items_n_panes >= 0)
445 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
447 keymaps = 1;
449 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
451 /* We were given a list of keymaps. */
452 int nmaps = XFASTINT (Flength (menu));
453 Lisp_Object *maps
454 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
455 int i;
457 title = Qnil;
459 /* The first keymap that has a prompt string
460 supplies the menu title. */
461 for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
463 Lisp_Object prompt;
465 maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
467 prompt = Fkeymap_prompt (keymap);
468 if (NILP (title) && !NILP (prompt))
469 title = prompt;
472 /* Extract the detailed info to make one pane. */
473 keymap_panes (maps, nmaps, NILP (position));
475 /* Make the title be the pane title of the first pane. */
476 if (!NILP (title) && menu_items_n_panes >= 0)
477 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
479 keymaps = 1;
481 else
483 /* We were given an old-fashioned menu. */
484 title = Fcar (menu);
485 CHECK_STRING (title);
487 list_of_panes (Fcdr (menu));
489 keymaps = 0;
492 unbind_to (specpdl_count, Qnil);
494 if (NILP (position))
496 discard_menu_items ();
497 UNGCPRO;
498 return Qnil;
501 #ifdef HAVE_MENUS
502 /* Display them in a menu. */
503 BLOCK_INPUT;
505 selection = xmenu_show (f, xpos, ypos, for_click,
506 keymaps, title, &error_name);
507 UNBLOCK_INPUT;
509 discard_menu_items ();
511 UNGCPRO;
512 #endif /* HAVE_MENUS */
514 if (error_name) error (error_name);
515 return selection;
518 #ifdef HAVE_MENUS
520 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
521 doc: /* Pop up a dialog box and return user's selection.
522 POSITION specifies which frame to use.
523 This is normally a mouse button event or a window or frame.
524 If POSITION is t, it means to use the frame the mouse is on.
525 The dialog box appears in the middle of the specified frame.
527 CONTENTS specifies the alternatives to display in the dialog box.
528 It is a list of the form (DIALOG ITEM1 ITEM2...).
529 Each ITEM is a cons cell (STRING . VALUE).
530 The return value is VALUE from the chosen item.
532 An ITEM may also be just a string--that makes a nonselectable item.
533 An ITEM may also be nil--that means to put all preceding items
534 on the left of the dialog box and all following items on the right.
535 \(By default, approximately half appear on each side.)
537 If HEADER is non-nil, the frame title for the box is "Information",
538 otherwise it is "Question".
540 If the user gets rid of the dialog box without making a valid choice,
541 for instance using the window manager, then this produces a quit and
542 `x-popup-dialog' does not return. */)
543 (position, contents, header)
544 Lisp_Object position, contents, header;
546 FRAME_PTR f = NULL;
547 Lisp_Object window;
549 check_x ();
551 /* Decode the first argument: find the window or frame to use. */
552 if (EQ (position, Qt)
553 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
554 || EQ (XCAR (position), Qtool_bar))))
556 #if 0 /* Using the frame the mouse is on may not be right. */
557 /* Use the mouse's current position. */
558 FRAME_PTR new_f = SELECTED_FRAME ();
559 Lisp_Object bar_window;
560 enum scroll_bar_part part;
561 unsigned long time;
562 Lisp_Object x, y;
564 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
566 if (new_f != 0)
567 XSETFRAME (window, new_f);
568 else
569 window = selected_window;
570 #endif
571 window = selected_window;
573 else if (CONSP (position))
575 Lisp_Object tem;
576 tem = Fcar (position);
577 if (CONSP (tem))
578 window = Fcar (Fcdr (position));
579 else
581 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
582 window = Fcar (tem); /* POSN_WINDOW (tem) */
585 else if (WINDOWP (position) || FRAMEP (position))
586 window = position;
587 else
588 window = Qnil;
590 /* Decode where to put the menu. */
592 if (FRAMEP (window))
593 f = XFRAME (window);
594 else if (WINDOWP (window))
596 CHECK_LIVE_WINDOW (window);
597 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
599 else
600 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
601 but I don't want to make one now. */
602 CHECK_WINDOW (window);
604 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
605 error ("Can not put X dialog on this terminal");
607 /* Force a redisplay before showing the dialog. If a frame is created
608 just before showing the dialog, its contents may not have been fully
609 drawn, as this depends on timing of events from the X server. Redisplay
610 is not done when a dialog is shown. If redisplay could be done in the
611 X event loop (i.e. the X event loop does not run in a signal handler)
612 this would not be needed.
614 Do this before creating the widget value that points to Lisp
615 string contents, because Fredisplay may GC and relocate them. */
616 Fredisplay (Qt);
618 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
619 /* Display a menu with these alternatives
620 in the middle of frame F. */
622 Lisp_Object x, y, frame, newpos;
623 XSETFRAME (frame, f);
624 XSETINT (x, x_pixel_width (f) / 2);
625 XSETINT (y, x_pixel_height (f) / 2);
626 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
628 return Fx_popup_menu (newpos,
629 Fcons (Fcar (contents), Fcons (contents, Qnil)));
631 #else
633 Lisp_Object title;
634 char *error_name;
635 Lisp_Object selection;
636 int specpdl_count = SPECPDL_INDEX ();
638 /* Decode the dialog items from what was specified. */
639 title = Fcar (contents);
640 CHECK_STRING (title);
641 record_unwind_protect (unuse_menu_items, Qnil);
643 if (NILP (Fcar (Fcdr (contents))))
644 /* No buttons specified, add an "Ok" button so users can pop down
645 the dialog. Also, the lesstif/motif version crashes if there are
646 no buttons. */
647 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
649 list_of_panes (Fcons (contents, Qnil));
651 /* Display them in a dialog box. */
652 BLOCK_INPUT;
653 selection = xdialog_show (f, 0, title, header, &error_name);
654 UNBLOCK_INPUT;
656 unbind_to (specpdl_count, Qnil);
657 discard_menu_items ();
659 if (error_name) error (error_name);
660 return selection;
662 #endif
666 #ifndef MSDOS
668 /* Set menu_items_inuse so no other popup menu or dialog is created. */
670 void
671 x_menu_set_in_use (in_use)
672 int in_use;
674 menu_items_inuse = in_use ? Qt : Qnil;
675 popup_activated_flag = in_use;
676 #ifdef USE_X_TOOLKIT
677 if (popup_activated_flag)
678 x_activate_timeout_atimer ();
679 #endif
682 /* Wait for an X event to arrive or for a timer to expire. */
684 void
685 x_menu_wait_for_event (void *data)
687 extern EMACS_TIME timer_check P_ ((int));
689 /* Another way to do this is to register a timer callback, that can be
690 done in GTK and Xt. But we have to do it like this when using only X
691 anyway, and with callbacks we would have three variants for timer handling
692 instead of the small ifdefs below. */
694 while (
695 #ifdef USE_X_TOOLKIT
696 ! XtAppPending (Xt_app_con)
697 #elif defined USE_GTK
698 ! gtk_events_pending ()
699 #else
700 ! XPending ((Display*) data)
701 #endif
704 EMACS_TIME next_time = timer_check (1);
705 long secs = EMACS_SECS (next_time);
706 long usecs = EMACS_USECS (next_time);
707 SELECT_TYPE read_fds;
708 struct x_display_info *dpyinfo;
709 int n = 0;
711 FD_ZERO (&read_fds);
712 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
714 int fd = ConnectionNumber (dpyinfo->display);
715 FD_SET (fd, &read_fds);
716 if (fd > n) n = fd;
719 if (secs < 0 || (secs == 0 && usecs == 0))
721 /* Sometimes timer_check returns -1 (no timers) even if there are
722 timers. So do a timeout anyway. */
723 EMACS_SET_SECS (next_time, 1);
724 EMACS_SET_USECS (next_time, 0);
727 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
730 #endif /* ! MSDOS */
733 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
735 #ifdef USE_X_TOOLKIT
737 /* Loop in Xt until the menu pulldown or dialog popup has been
738 popped down (deactivated). This is used for x-popup-menu
739 and x-popup-dialog; it is not used for the menu bar.
741 NOTE: All calls to popup_get_selection should be protected
742 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
744 static void
745 popup_get_selection (initial_event, dpyinfo, id, do_timers)
746 XEvent *initial_event;
747 struct x_display_info *dpyinfo;
748 LWLIB_ID id;
749 int do_timers;
751 XEvent event;
753 while (popup_activated_flag)
755 if (initial_event)
757 event = *initial_event;
758 initial_event = 0;
760 else
762 if (do_timers) x_menu_wait_for_event (0);
763 XtAppNextEvent (Xt_app_con, &event);
766 /* Make sure we don't consider buttons grabbed after menu goes.
767 And make sure to deactivate for any ButtonRelease,
768 even if XtDispatchEvent doesn't do that. */
769 if (event.type == ButtonRelease
770 && dpyinfo->display == event.xbutton.display)
772 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
773 #ifdef USE_MOTIF /* Pretending that the event came from a
774 Btn1Down seems the only way to convince Motif to
775 activate its callbacks; setting the XmNmenuPost
776 isn't working. --marcus@sysc.pdx.edu. */
777 event.xbutton.button = 1;
778 /* Motif only pops down menus when no Ctrl, Alt or Mod
779 key is pressed and the button is released. So reset key state
780 so Motif thinks this is the case. */
781 event.xbutton.state = 0;
782 #endif
784 /* Pop down on C-g and Escape. */
785 else if (event.type == KeyPress
786 && dpyinfo->display == event.xbutton.display)
788 KeySym keysym = XLookupKeysym (&event.xkey, 0);
790 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
791 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
792 popup_activated_flag = 0;
795 x_dispatch_event (&event, event.xany.display);
799 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
800 doc: /* Start key navigation of the menu bar in FRAME.
801 This initially opens the first menu bar item and you can then navigate with the
802 arrow keys, select a menu entry with the return key or cancel with the
803 escape key. If FRAME has no menu bar this function does nothing.
805 If FRAME is nil or not given, use the selected frame. */)
806 (frame)
807 Lisp_Object frame;
809 XEvent ev;
810 FRAME_PTR f = check_x_frame (frame);
811 Widget menubar;
812 BLOCK_INPUT;
814 if (FRAME_EXTERNAL_MENU_BAR (f))
815 set_frame_menubar (f, 0, 1);
817 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
818 if (menubar)
820 Window child;
821 int error_p = 0;
823 x_catch_errors (FRAME_X_DISPLAY (f));
824 memset (&ev, 0, sizeof ev);
825 ev.xbutton.display = FRAME_X_DISPLAY (f);
826 ev.xbutton.window = XtWindow (menubar);
827 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
828 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
829 ev.xbutton.button = Button1;
830 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
831 ev.xbutton.same_screen = True;
833 #ifdef USE_MOTIF
835 Arg al[2];
836 WidgetList list;
837 Cardinal nr;
838 XtSetArg (al[0], XtNchildren, &list);
839 XtSetArg (al[1], XtNnumChildren, &nr);
840 XtGetValues (menubar, al, 2);
841 ev.xbutton.window = XtWindow (list[0]);
843 #endif
845 XTranslateCoordinates (FRAME_X_DISPLAY (f),
846 /* From-window, to-window. */
847 ev.xbutton.window, ev.xbutton.root,
849 /* From-position, to-position. */
850 ev.xbutton.x, ev.xbutton.y,
851 &ev.xbutton.x_root, &ev.xbutton.y_root,
853 /* Child of win. */
854 &child);
855 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
856 x_uncatch_errors ();
858 if (! error_p)
860 ev.type = ButtonPress;
861 ev.xbutton.state = 0;
863 XtDispatchEvent (&ev);
864 ev.xbutton.type = ButtonRelease;
865 ev.xbutton.state = Button1Mask;
866 XtDispatchEvent (&ev);
870 UNBLOCK_INPUT;
872 return Qnil;
874 #endif /* USE_X_TOOLKIT */
877 #ifdef USE_GTK
878 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
879 doc: /* Start key navigation of the menu bar in FRAME.
880 This initially opens the first menu bar item and you can then navigate with the
881 arrow keys, select a menu entry with the return key or cancel with the
882 escape key. If FRAME has no menu bar this function does nothing.
884 If FRAME is nil or not given, use the selected frame. */)
885 (frame)
886 Lisp_Object frame;
888 GtkWidget *menubar;
889 FRAME_PTR f;
891 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
892 BLOCK_INPUT. */
894 BLOCK_INPUT;
895 f = check_x_frame (frame);
897 if (FRAME_EXTERNAL_MENU_BAR (f))
898 set_frame_menubar (f, 0, 1);
900 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
901 if (menubar)
903 /* Activate the first menu. */
904 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
906 if (children)
908 g_signal_emit_by_name (children->data, "activate_item");
909 popup_activated_flag = 1;
910 g_list_free (children);
913 UNBLOCK_INPUT;
915 return Qnil;
918 /* Loop util popup_activated_flag is set to zero in a callback.
919 Used for popup menus and dialogs. */
921 static void
922 popup_widget_loop (do_timers, widget)
923 int do_timers;
924 GtkWidget *widget;
926 ++popup_activated_flag;
928 /* Process events in the Gtk event loop until done. */
929 while (popup_activated_flag)
931 if (do_timers) x_menu_wait_for_event (0);
932 gtk_main_iteration ();
935 #endif
937 /* Activate the menu bar of frame F.
938 This is called from keyboard.c when it gets the
939 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
941 To activate the menu bar, we use the X button-press event
942 that was saved in saved_menu_event.
943 That makes the toolkit do its thing.
945 But first we recompute the menu bar contents (the whole tree).
947 The reason for saving the button event until here, instead of
948 passing it to the toolkit right away, is that we can safely
949 execute Lisp code. */
951 void
952 x_activate_menubar (f)
953 FRAME_PTR f;
955 if (! FRAME_X_P (f))
956 abort ();
958 if (!f->output_data.x->saved_menu_event->type)
959 return;
961 #ifdef USE_GTK
962 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
963 f->output_data.x->saved_menu_event->xany.window))
964 return;
965 #endif
967 set_frame_menubar (f, 0, 1);
968 BLOCK_INPUT;
969 #ifdef USE_GTK
970 XPutBackEvent (f->output_data.x->display_info->display,
971 f->output_data.x->saved_menu_event);
972 popup_activated_flag = 1;
973 #else
974 XtDispatchEvent (f->output_data.x->saved_menu_event);
975 #endif
976 UNBLOCK_INPUT;
977 #ifdef USE_MOTIF
978 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
979 pending_menu_activation = 1;
980 #endif
982 /* Ignore this if we get it a second time. */
983 f->output_data.x->saved_menu_event->type = 0;
986 /* This callback is invoked when the user selects a menubar cascade
987 pushbutton, but before the pulldown menu is posted. */
989 #ifndef USE_GTK
990 static void
991 popup_activate_callback (widget, id, client_data)
992 Widget widget;
993 LWLIB_ID id;
994 XtPointer client_data;
996 popup_activated_flag = 1;
997 #ifdef USE_X_TOOLKIT
998 x_activate_timeout_atimer ();
999 #endif
1001 #endif
1003 /* This callback is invoked when a dialog or menu is finished being
1004 used and has been unposted. */
1006 #ifdef USE_GTK
1007 static void
1008 popup_deactivate_callback (widget, client_data)
1009 GtkWidget *widget;
1010 gpointer client_data;
1012 popup_activated_flag = 0;
1014 #else
1015 static void
1016 popup_deactivate_callback (widget, id, client_data)
1017 Widget widget;
1018 LWLIB_ID id;
1019 XtPointer client_data;
1021 popup_activated_flag = 0;
1023 #endif
1026 /* Function that finds the frame for WIDGET and shows the HELP text
1027 for that widget.
1028 F is the frame if known, or NULL if not known. */
1029 static void
1030 show_help_event (f, widget, help)
1031 FRAME_PTR f;
1032 xt_or_gtk_widget widget;
1033 Lisp_Object help;
1035 Lisp_Object frame;
1037 if (f)
1039 XSETFRAME (frame, f);
1040 kbd_buffer_store_help_event (frame, help);
1042 else
1044 #if 0 /* This code doesn't do anything useful. ++kfs */
1045 /* WIDGET is the popup menu. It's parent is the frame's
1046 widget. See which frame that is. */
1047 xt_or_gtk_widget frame_widget = XtParent (widget);
1048 Lisp_Object tail;
1050 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
1052 frame = XCAR (tail);
1053 if (FRAMEP (frame)
1054 && (f = XFRAME (frame),
1055 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
1056 break;
1058 #endif
1059 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1063 /* Callback called when menu items are highlighted/unhighlighted
1064 while moving the mouse over them. WIDGET is the menu bar or menu
1065 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
1066 the data structure for the menu item, or null in case of
1067 unhighlighting. */
1069 #ifdef USE_GTK
1070 void
1071 menu_highlight_callback (widget, call_data)
1072 GtkWidget *widget;
1073 gpointer call_data;
1075 xg_menu_item_cb_data *cb_data;
1076 Lisp_Object help;
1078 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
1079 XG_ITEM_DATA);
1080 if (! cb_data) return;
1082 help = call_data ? cb_data->help : Qnil;
1084 /* If popup_activated_flag is greater than 1 we are in a popup menu.
1085 Don't show help for them, they won't appear before the
1086 popup is popped down. */
1087 if (popup_activated_flag <= 1)
1088 show_help_event (cb_data->cl_data->f, widget, help);
1090 #else
1091 void
1092 menu_highlight_callback (widget, id, call_data)
1093 Widget widget;
1094 LWLIB_ID id;
1095 void *call_data;
1097 struct frame *f;
1098 Lisp_Object help;
1100 widget_value *wv = (widget_value *) call_data;
1102 help = wv ? wv->help : Qnil;
1104 /* Determine the frame for the help event. */
1105 f = menubar_id_to_frame (id);
1107 show_help_event (f, widget, help);
1109 #endif
1111 #ifdef USE_GTK
1112 /* Gtk calls callbacks just because we tell it what item should be
1113 selected in a radio group. If this variable is set to a non-zero
1114 value, we are creating menus and don't want callbacks right now.
1116 static int xg_crazy_callback_abort;
1118 /* This callback is called from the menu bar pulldown menu
1119 when the user makes a selection.
1120 Figure out what the user chose
1121 and put the appropriate events into the keyboard buffer. */
1122 static void
1123 menubar_selection_callback (widget, client_data)
1124 GtkWidget *widget;
1125 gpointer client_data;
1127 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1129 if (xg_crazy_callback_abort)
1130 return;
1132 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
1133 return;
1135 /* For a group of radio buttons, GTK calls the selection callback first
1136 for the item that was active before the selection and then for the one that
1137 is active after the selection. For C-h k this means we get the help on
1138 the deselected item and then the selected item is executed. Prevent that
1139 by ignoring the non-active item. */
1140 if (GTK_IS_RADIO_MENU_ITEM (widget)
1141 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
1142 return;
1144 /* When a menu is popped down, X generates a focus event (i.e. focus
1145 goes back to the frame below the menu). Since GTK buffers events,
1146 we force it out here before the menu selection event. Otherwise
1147 sit-for will exit at once if the focus event follows the menu selection
1148 event. */
1150 BLOCK_INPUT;
1151 while (gtk_events_pending ())
1152 gtk_main_iteration ();
1153 UNBLOCK_INPUT;
1155 find_and_call_menu_selection (cb_data->cl_data->f,
1156 cb_data->cl_data->menu_bar_items_used,
1157 cb_data->cl_data->menu_bar_vector,
1158 cb_data->call_data);
1161 #else /* not USE_GTK */
1163 /* This callback is called from the menu bar pulldown menu
1164 when the user makes a selection.
1165 Figure out what the user chose
1166 and put the appropriate events into the keyboard buffer. */
1167 static void
1168 menubar_selection_callback (widget, id, client_data)
1169 Widget widget;
1170 LWLIB_ID id;
1171 XtPointer client_data;
1173 FRAME_PTR f;
1175 f = menubar_id_to_frame (id);
1176 if (!f)
1177 return;
1178 find_and_call_menu_selection (f, f->menu_bar_items_used,
1179 f->menu_bar_vector, client_data);
1181 #endif /* not USE_GTK */
1183 /* Recompute all the widgets of frame F, when the menu bar has been
1184 changed. Value is non-zero if widgets were updated. */
1186 static int
1187 update_frame_menubar (f)
1188 FRAME_PTR f;
1190 #ifdef USE_GTK
1191 return xg_update_frame_menubar (f);
1192 #else
1193 struct x_output *x;
1194 int columns, rows;
1196 if (! FRAME_X_P (f))
1197 abort ();
1199 x = f->output_data.x;
1201 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
1202 return 0;
1204 BLOCK_INPUT;
1205 /* Save the size of the frame because the pane widget doesn't accept
1206 to resize itself. So force it. */
1207 columns = FRAME_COLS (f);
1208 rows = FRAME_LINES (f);
1210 /* Do the voodoo which means "I'm changing lots of things, don't try
1211 to refigure sizes until I'm done." */
1212 lw_refigure_widget (x->column_widget, False);
1214 /* The order in which children are managed is the top to bottom
1215 order in which they are displayed in the paned window. First,
1216 remove the text-area widget. */
1217 XtUnmanageChild (x->edit_widget);
1219 /* Remove the menubar that is there now, and put up the menubar that
1220 should be there. */
1221 XtManageChild (x->menubar_widget);
1222 XtMapWidget (x->menubar_widget);
1223 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
1225 /* Re-manage the text-area widget, and then thrash the sizes. */
1226 XtManageChild (x->edit_widget);
1227 lw_refigure_widget (x->column_widget, True);
1229 /* Force the pane widget to resize itself with the right values. */
1230 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
1231 UNBLOCK_INPUT;
1232 #endif
1233 return 1;
1236 /* Set the contents of the menubar widgets of frame F.
1237 The argument FIRST_TIME is currently ignored;
1238 it is set the first time this is called, from initialize_frame_menubar. */
1240 void
1241 set_frame_menubar (f, first_time, deep_p)
1242 FRAME_PTR f;
1243 int first_time;
1244 int deep_p;
1246 xt_or_gtk_widget menubar_widget;
1247 #ifdef USE_X_TOOLKIT
1248 LWLIB_ID id;
1249 #endif
1250 Lisp_Object items;
1251 widget_value *wv, *first_wv, *prev_wv = 0;
1252 int i, last_i = 0;
1253 int *submenu_start, *submenu_end;
1254 int *submenu_top_level_items, *submenu_n_panes;
1256 if (! FRAME_X_P (f))
1257 abort ();
1259 menubar_widget = f->output_data.x->menubar_widget;
1261 XSETFRAME (Vmenu_updating_frame, f);
1263 #ifdef USE_X_TOOLKIT
1264 if (f->output_data.x->id == 0)
1265 f->output_data.x->id = next_menubar_widget_id++;
1266 id = f->output_data.x->id;
1267 #endif
1269 if (! menubar_widget)
1270 deep_p = 1;
1271 else if (pending_menu_activation && !deep_p)
1272 deep_p = 1;
1273 /* Make the first call for any given frame always go deep. */
1274 else if (!f->output_data.x->saved_menu_event && !deep_p)
1276 deep_p = 1;
1277 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
1278 f->output_data.x->saved_menu_event->type = 0;
1281 #ifdef USE_GTK
1282 /* If we have detached menus, we must update deep so detached menus
1283 also gets updated. */
1284 deep_p = deep_p || xg_have_tear_offs ();
1285 #endif
1287 if (deep_p)
1289 /* Make a widget-value tree representing the entire menu trees. */
1291 struct buffer *prev = current_buffer;
1292 Lisp_Object buffer;
1293 int specpdl_count = SPECPDL_INDEX ();
1294 int previous_menu_items_used = f->menu_bar_items_used;
1295 Lisp_Object *previous_items
1296 = (Lisp_Object *) alloca (previous_menu_items_used
1297 * sizeof (Lisp_Object));
1299 /* If we are making a new widget, its contents are empty,
1300 do always reinitialize them. */
1301 if (! menubar_widget)
1302 previous_menu_items_used = 0;
1304 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1305 specbind (Qinhibit_quit, Qt);
1306 /* Don't let the debugger step into this code
1307 because it is not reentrant. */
1308 specbind (Qdebug_on_next_call, Qnil);
1310 record_unwind_save_match_data ();
1311 if (NILP (Voverriding_local_map_menu_flag))
1313 specbind (Qoverriding_terminal_local_map, Qnil);
1314 specbind (Qoverriding_local_map, Qnil);
1317 set_buffer_internal_1 (XBUFFER (buffer));
1319 /* Run the Lucid hook. */
1320 safe_run_hooks (Qactivate_menubar_hook);
1322 /* If it has changed current-menubar from previous value,
1323 really recompute the menubar from the value. */
1324 if (! NILP (Vlucid_menu_bar_dirty_flag))
1325 call0 (Qrecompute_lucid_menubar);
1326 safe_run_hooks (Qmenu_bar_update_hook);
1327 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1329 items = FRAME_MENU_BAR_ITEMS (f);
1331 /* Save the frame's previous menu bar contents data. */
1332 if (previous_menu_items_used)
1333 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1334 previous_menu_items_used * sizeof (Lisp_Object));
1336 /* Fill in menu_items with the current menu bar contents.
1337 This can evaluate Lisp code. */
1338 save_menu_items ();
1340 menu_items = f->menu_bar_vector;
1341 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1342 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1343 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1344 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1345 submenu_top_level_items
1346 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1347 init_menu_items ();
1348 for (i = 0; i < XVECTOR (items)->size; i += 4)
1350 Lisp_Object key, string, maps;
1352 last_i = i;
1354 key = XVECTOR (items)->contents[i];
1355 string = XVECTOR (items)->contents[i + 1];
1356 maps = XVECTOR (items)->contents[i + 2];
1357 if (NILP (string))
1358 break;
1360 submenu_start[i] = menu_items_used;
1362 menu_items_n_panes = 0;
1363 submenu_top_level_items[i]
1364 = parse_single_submenu (key, string, maps);
1365 submenu_n_panes[i] = menu_items_n_panes;
1367 submenu_end[i] = menu_items_used;
1370 finish_menu_items ();
1372 /* Convert menu_items into widget_value trees
1373 to display the menu. This cannot evaluate Lisp code. */
1375 wv = xmalloc_widget_value ();
1376 wv->name = "menubar";
1377 wv->value = 0;
1378 wv->enabled = 1;
1379 wv->button_type = BUTTON_TYPE_NONE;
1380 wv->help = Qnil;
1381 first_wv = wv;
1383 for (i = 0; i < last_i; i += 4)
1385 menu_items_n_panes = submenu_n_panes[i];
1386 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1387 submenu_top_level_items[i]);
1388 if (prev_wv)
1389 prev_wv->next = wv;
1390 else
1391 first_wv->contents = wv;
1392 /* Don't set wv->name here; GC during the loop might relocate it. */
1393 wv->enabled = 1;
1394 wv->button_type = BUTTON_TYPE_NONE;
1395 prev_wv = wv;
1398 set_buffer_internal_1 (prev);
1400 /* If there has been no change in the Lisp-level contents
1401 of the menu bar, skip redisplaying it. Just exit. */
1403 /* Compare the new menu items with the ones computed last time. */
1404 for (i = 0; i < previous_menu_items_used; i++)
1405 if (menu_items_used == i
1406 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1407 break;
1408 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1410 /* The menu items have not changed. Don't bother updating
1411 the menus in any form, since it would be a no-op. */
1412 free_menubar_widget_value_tree (first_wv);
1413 discard_menu_items ();
1414 unbind_to (specpdl_count, Qnil);
1415 return;
1418 /* The menu items are different, so store them in the frame. */
1419 f->menu_bar_vector = menu_items;
1420 f->menu_bar_items_used = menu_items_used;
1422 /* This undoes save_menu_items. */
1423 unbind_to (specpdl_count, Qnil);
1425 /* Now GC cannot happen during the lifetime of the widget_value,
1426 so it's safe to store data from a Lisp_String. */
1427 wv = first_wv->contents;
1428 for (i = 0; i < XVECTOR (items)->size; i += 4)
1430 Lisp_Object string;
1431 string = XVECTOR (items)->contents[i + 1];
1432 if (NILP (string))
1433 break;
1434 wv->name = (char *) SDATA (string);
1435 update_submenu_strings (wv->contents);
1436 wv = wv->next;
1440 else
1442 /* Make a widget-value tree containing
1443 just the top level menu bar strings. */
1445 wv = xmalloc_widget_value ();
1446 wv->name = "menubar";
1447 wv->value = 0;
1448 wv->enabled = 1;
1449 wv->button_type = BUTTON_TYPE_NONE;
1450 wv->help = Qnil;
1451 first_wv = wv;
1453 items = FRAME_MENU_BAR_ITEMS (f);
1454 for (i = 0; i < XVECTOR (items)->size; i += 4)
1456 Lisp_Object string;
1458 string = XVECTOR (items)->contents[i + 1];
1459 if (NILP (string))
1460 break;
1462 wv = xmalloc_widget_value ();
1463 wv->name = (char *) SDATA (string);
1464 wv->value = 0;
1465 wv->enabled = 1;
1466 wv->button_type = BUTTON_TYPE_NONE;
1467 wv->help = Qnil;
1468 /* This prevents lwlib from assuming this
1469 menu item is really supposed to be empty. */
1470 /* The EMACS_INT cast avoids a warning.
1471 This value just has to be different from small integers. */
1472 wv->call_data = (void *) (EMACS_INT) (-1);
1474 if (prev_wv)
1475 prev_wv->next = wv;
1476 else
1477 first_wv->contents = wv;
1478 prev_wv = wv;
1481 /* Forget what we thought we knew about what is in the
1482 detailed contents of the menu bar menus.
1483 Changing the top level always destroys the contents. */
1484 f->menu_bar_items_used = 0;
1487 /* Create or update the menu bar widget. */
1489 BLOCK_INPUT;
1491 #ifdef USE_GTK
1492 xg_crazy_callback_abort = 1;
1493 if (menubar_widget)
1495 /* The fourth arg is DEEP_P, which says to consider the entire
1496 menu trees we supply, rather than just the menu bar item names. */
1497 xg_modify_menubar_widgets (menubar_widget,
1499 first_wv,
1500 deep_p,
1501 G_CALLBACK (menubar_selection_callback),
1502 G_CALLBACK (popup_deactivate_callback),
1503 G_CALLBACK (menu_highlight_callback));
1505 else
1507 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1509 menubar_widget
1510 = xg_create_widget ("menubar", "menubar", f, first_wv,
1511 G_CALLBACK (menubar_selection_callback),
1512 G_CALLBACK (popup_deactivate_callback),
1513 G_CALLBACK (menu_highlight_callback));
1515 f->output_data.x->menubar_widget = menubar_widget;
1519 #else /* not USE_GTK */
1520 if (menubar_widget)
1522 /* Disable resizing (done for Motif!) */
1523 lw_allow_resizing (f->output_data.x->widget, False);
1525 /* The third arg is DEEP_P, which says to consider the entire
1526 menu trees we supply, rather than just the menu bar item names. */
1527 lw_modify_all_widgets (id, first_wv, deep_p);
1529 /* Re-enable the edit widget to resize. */
1530 lw_allow_resizing (f->output_data.x->widget, True);
1532 else
1534 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1535 XtTranslations override = XtParseTranslationTable (menuOverride);
1537 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1538 f->output_data.x->column_widget,
1540 popup_activate_callback,
1541 menubar_selection_callback,
1542 popup_deactivate_callback,
1543 menu_highlight_callback);
1544 f->output_data.x->menubar_widget = menubar_widget;
1546 /* Make menu pop down on C-g. */
1547 XtOverrideTranslations (menubar_widget, override);
1551 int menubar_size
1552 = (f->output_data.x->menubar_widget
1553 ? (f->output_data.x->menubar_widget->core.height
1554 + f->output_data.x->menubar_widget->core.border_width)
1555 : 0);
1557 #if 0 /* Experimentally, we now get the right results
1558 for -geometry -0-0 without this. 24 Aug 96, rms. */
1559 #ifdef USE_LUCID
1560 if (FRAME_EXTERNAL_MENU_BAR (f))
1562 Dimension ibw = 0;
1563 XtVaGetValues (f->output_data.x->column_widget,
1564 XtNinternalBorderWidth, &ibw, NULL);
1565 menubar_size += ibw;
1567 #endif /* USE_LUCID */
1568 #endif /* 0 */
1570 f->output_data.x->menubar_height = menubar_size;
1572 #endif /* not USE_GTK */
1574 free_menubar_widget_value_tree (first_wv);
1575 update_frame_menubar (f);
1577 #ifdef USE_GTK
1578 xg_crazy_callback_abort = 0;
1579 #endif
1581 UNBLOCK_INPUT;
1584 /* Called from Fx_create_frame to create the initial menubar of a frame
1585 before it is mapped, so that the window is mapped with the menubar already
1586 there instead of us tacking it on later and thrashing the window after it
1587 is visible. */
1589 void
1590 initialize_frame_menubar (f)
1591 FRAME_PTR f;
1593 /* This function is called before the first chance to redisplay
1594 the frame. It has to be, so the frame will have the right size. */
1595 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1596 set_frame_menubar (f, 1, 1);
1600 /* Get rid of the menu bar of frame F, and free its storage.
1601 This is used when deleting a frame, and when turning off the menu bar.
1602 For GTK this function is in gtkutil.c. */
1604 #ifndef USE_GTK
1605 void
1606 free_frame_menubar (f)
1607 FRAME_PTR f;
1609 Widget menubar_widget;
1611 if (! FRAME_X_P (f))
1612 abort ();
1614 menubar_widget = f->output_data.x->menubar_widget;
1616 f->output_data.x->menubar_height = 0;
1618 if (menubar_widget)
1620 #ifdef USE_MOTIF
1621 /* Removing the menu bar magically changes the shell widget's x
1622 and y position of (0, 0) which, when the menu bar is turned
1623 on again, leads to pull-down menuss appearing in strange
1624 positions near the upper-left corner of the display. This
1625 happens only with some window managers like twm and ctwm,
1626 but not with other like Motif's mwm or kwm, because the
1627 latter generate ConfigureNotify events when the menu bar
1628 is switched off, which fixes the shell position. */
1629 Position x0, y0, x1, y1;
1630 #endif
1632 BLOCK_INPUT;
1634 #ifdef USE_MOTIF
1635 if (f->output_data.x->widget)
1636 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1637 #endif
1639 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1640 f->output_data.x->menubar_widget = NULL;
1642 #ifdef USE_MOTIF
1643 if (f->output_data.x->widget)
1645 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1646 if (x1 == 0 && y1 == 0)
1647 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1649 #endif
1651 UNBLOCK_INPUT;
1654 #endif /* not USE_GTK */
1656 #endif /* USE_X_TOOLKIT || USE_GTK */
1658 /* xmenu_show actually displays a menu using the panes and items in menu_items
1659 and returns the value selected from it.
1660 There are two versions of xmenu_show, one for Xt and one for Xlib.
1661 Both assume input is blocked by the caller. */
1663 /* F is the frame the menu is for.
1664 X and Y are the frame-relative specified position,
1665 relative to the inside upper left corner of the frame F.
1666 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1667 KEYMAPS is 1 if this menu was specified with keymaps;
1668 in that case, we return a list containing the chosen item's value
1669 and perhaps also the pane's prefix.
1670 TITLE is the specified menu title.
1671 ERROR is a place to store an error message string in case of failure.
1672 (We return nil on failure, but the value doesn't actually matter.) */
1674 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1676 /* The item selected in the popup menu. */
1677 static Lisp_Object *volatile menu_item_selection;
1679 #ifdef USE_GTK
1681 /* Used when position a popup menu. See menu_position_func and
1682 create_and_show_popup_menu below. */
1683 struct next_popup_x_y
1685 FRAME_PTR f;
1686 int x;
1687 int y;
1690 /* The menu position function to use if we are not putting a popup
1691 menu where the pointer is.
1692 MENU is the menu to pop up.
1693 X and Y shall on exit contain x/y where the menu shall pop up.
1694 PUSH_IN is not documented in the GTK manual.
1695 USER_DATA is any data passed in when calling gtk_menu_popup.
1696 Here it points to a struct next_popup_x_y where the coordinates
1697 to store in *X and *Y are as well as the frame for the popup.
1699 Here only X and Y are used. */
1700 static void
1701 menu_position_func (menu, x, y, push_in, user_data)
1702 GtkMenu *menu;
1703 gint *x;
1704 gint *y;
1705 gboolean *push_in;
1706 gpointer user_data;
1708 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1709 GtkRequisition req;
1710 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1711 int disp_width = x_display_pixel_width (dpyinfo);
1712 int disp_height = x_display_pixel_height (dpyinfo);
1714 *x = data->x;
1715 *y = data->y;
1717 /* Check if there is room for the menu. If not, adjust x/y so that
1718 the menu is fully visible. */
1719 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1720 if (data->x + req.width > disp_width)
1721 *x -= data->x + req.width - disp_width;
1722 if (data->y + req.height > disp_height)
1723 *y -= data->y + req.height - disp_height;
1726 static void
1727 popup_selection_callback (widget, client_data)
1728 GtkWidget *widget;
1729 gpointer client_data;
1731 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1733 if (xg_crazy_callback_abort) return;
1734 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1737 static Lisp_Object
1738 pop_down_menu (arg)
1739 Lisp_Object arg;
1741 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1743 popup_activated_flag = 0;
1744 BLOCK_INPUT;
1745 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1746 UNBLOCK_INPUT;
1747 return Qnil;
1750 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1751 menu pops down.
1752 menu_item_selection will be set to the selection. */
1753 static void
1754 create_and_show_popup_menu (f, first_wv, x, y, for_click)
1755 FRAME_PTR f;
1756 widget_value *first_wv;
1757 int x;
1758 int y;
1759 int for_click;
1761 int i;
1762 GtkWidget *menu;
1763 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1764 struct next_popup_x_y popup_x_y;
1765 int specpdl_count = SPECPDL_INDEX ();
1767 if (! FRAME_X_P (f))
1768 abort ();
1770 xg_crazy_callback_abort = 1;
1771 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1772 G_CALLBACK (popup_selection_callback),
1773 G_CALLBACK (popup_deactivate_callback),
1774 G_CALLBACK (menu_highlight_callback));
1775 xg_crazy_callback_abort = 0;
1777 if (! for_click)
1779 /* Not invoked by a click. pop up at x/y. */
1780 pos_func = menu_position_func;
1782 /* Adjust coordinates to be root-window-relative. */
1783 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1784 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1786 popup_x_y.x = x;
1787 popup_x_y.y = y;
1788 popup_x_y.f = f;
1790 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1792 else
1794 for (i = 0; i < 5; i++)
1795 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1796 break;
1799 /* Display the menu. */
1800 gtk_widget_show_all (menu);
1801 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
1803 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1805 if (GTK_WIDGET_MAPPED (menu))
1807 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1808 two. show_help_echo uses this to detect popup menus. */
1809 popup_activated_flag = 1;
1810 /* Process events that apply to the menu. */
1811 popup_widget_loop (1, menu);
1814 unbind_to (specpdl_count, Qnil);
1816 /* Must reset this manually because the button release event is not passed
1817 to Emacs event loop. */
1818 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1821 #else /* not USE_GTK */
1823 /* We need a unique id for each widget handled by the Lucid Widget
1824 library.
1826 For the main windows, and popup menus, we use this counter,
1827 which we increment each time after use. This starts from 1<<16.
1829 For menu bars, we use numbers starting at 0, counted in
1830 next_menubar_widget_id. */
1831 LWLIB_ID widget_id_tick;
1833 static void
1834 popup_selection_callback (widget, id, client_data)
1835 Widget widget;
1836 LWLIB_ID id;
1837 XtPointer client_data;
1839 menu_item_selection = (Lisp_Object *) client_data;
1842 /* ARG is the LWLIB ID of the dialog box, represented
1843 as a Lisp object as (HIGHPART . LOWPART). */
1845 static Lisp_Object
1846 pop_down_menu (arg)
1847 Lisp_Object arg;
1849 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1850 | XINT (XCDR (arg)));
1852 BLOCK_INPUT;
1853 lw_destroy_all_widgets (id);
1854 UNBLOCK_INPUT;
1855 popup_activated_flag = 0;
1857 return Qnil;
1860 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1861 menu pops down.
1862 menu_item_selection will be set to the selection. */
1863 static void
1864 create_and_show_popup_menu (f, first_wv, x, y, for_click)
1865 FRAME_PTR f;
1866 widget_value *first_wv;
1867 int x;
1868 int y;
1869 int for_click;
1871 int i;
1872 Arg av[2];
1873 int ac = 0;
1874 XButtonPressedEvent dummy;
1875 LWLIB_ID menu_id;
1876 Widget menu;
1878 if (! FRAME_X_P (f))
1879 abort ();
1881 menu_id = widget_id_tick++;
1882 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1883 f->output_data.x->widget, 1, 0,
1884 popup_selection_callback,
1885 popup_deactivate_callback,
1886 menu_highlight_callback);
1888 dummy.type = ButtonPress;
1889 dummy.serial = 0;
1890 dummy.send_event = 0;
1891 dummy.display = FRAME_X_DISPLAY (f);
1892 dummy.time = CurrentTime;
1893 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1894 dummy.window = dummy.root;
1895 dummy.subwindow = dummy.root;
1896 dummy.x = x;
1897 dummy.y = y;
1899 /* Adjust coordinates to be root-window-relative. */
1900 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1901 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1903 dummy.x_root = x;
1904 dummy.y_root = y;
1906 dummy.state = 0;
1907 dummy.button = 0;
1908 for (i = 0; i < 5; i++)
1909 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1910 dummy.button = i;
1912 /* Don't allow any geometry request from the user. */
1913 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1914 XtSetValues (menu, av, ac);
1916 /* Display the menu. */
1917 lw_popup_menu (menu, (XEvent *) &dummy);
1918 popup_activated_flag = 1;
1919 x_activate_timeout_atimer ();
1922 int fact = 4 * sizeof (LWLIB_ID);
1923 int specpdl_count = SPECPDL_INDEX ();
1924 record_unwind_protect (pop_down_menu,
1925 Fcons (make_number (menu_id >> (fact)),
1926 make_number (menu_id & ~(-1 << (fact)))));
1928 /* Process events that apply to the menu. */
1929 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1931 unbind_to (specpdl_count, Qnil);
1935 #endif /* not USE_GTK */
1937 static Lisp_Object
1938 xmenu_show (f, x, y, for_click, keymaps, title, error)
1939 FRAME_PTR f;
1940 int x;
1941 int y;
1942 int for_click;
1943 int keymaps;
1944 Lisp_Object title;
1945 char **error;
1947 int i;
1948 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1949 widget_value **submenu_stack
1950 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1951 Lisp_Object *subprefix_stack
1952 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1953 int submenu_depth = 0;
1955 int first_pane;
1957 if (! FRAME_X_P (f))
1958 abort ();
1960 *error = NULL;
1962 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1964 *error = "Empty menu";
1965 return Qnil;
1968 /* Create a tree of widget_value objects
1969 representing the panes and their items. */
1970 wv = xmalloc_widget_value ();
1971 wv->name = "menu";
1972 wv->value = 0;
1973 wv->enabled = 1;
1974 wv->button_type = BUTTON_TYPE_NONE;
1975 wv->help =Qnil;
1976 first_wv = wv;
1977 first_pane = 1;
1979 /* Loop over all panes and items, filling in the tree. */
1980 i = 0;
1981 while (i < menu_items_used)
1983 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1985 submenu_stack[submenu_depth++] = save_wv;
1986 save_wv = prev_wv;
1987 prev_wv = 0;
1988 first_pane = 1;
1989 i++;
1991 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1993 prev_wv = save_wv;
1994 save_wv = submenu_stack[--submenu_depth];
1995 first_pane = 0;
1996 i++;
1998 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1999 && submenu_depth != 0)
2000 i += MENU_ITEMS_PANE_LENGTH;
2001 /* Ignore a nil in the item list.
2002 It's meaningful only for dialog boxes. */
2003 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2004 i += 1;
2005 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2007 /* Create a new pane. */
2008 Lisp_Object pane_name, prefix;
2009 char *pane_string;
2011 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2012 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2014 #ifndef HAVE_MULTILINGUAL_MENU
2015 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
2017 pane_name = ENCODE_MENU_STRING (pane_name);
2018 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
2020 #endif
2021 pane_string = (NILP (pane_name)
2022 ? "" : (char *) SDATA (pane_name));
2023 /* If there is just one top-level pane, put all its items directly
2024 under the top-level menu. */
2025 if (menu_items_n_panes == 1)
2026 pane_string = "";
2028 /* If the pane has a meaningful name,
2029 make the pane a top-level menu item
2030 with its items as a submenu beneath it. */
2031 if (!keymaps && strcmp (pane_string, ""))
2033 wv = xmalloc_widget_value ();
2034 if (save_wv)
2035 save_wv->next = wv;
2036 else
2037 first_wv->contents = wv;
2038 wv->name = pane_string;
2039 if (keymaps && !NILP (prefix))
2040 wv->name++;
2041 wv->value = 0;
2042 wv->enabled = 1;
2043 wv->button_type = BUTTON_TYPE_NONE;
2044 wv->help = Qnil;
2045 save_wv = wv;
2046 prev_wv = 0;
2048 else if (first_pane)
2050 save_wv = wv;
2051 prev_wv = 0;
2053 first_pane = 0;
2054 i += MENU_ITEMS_PANE_LENGTH;
2056 else
2058 /* Create a new item within current pane. */
2059 Lisp_Object item_name, enable, descrip, def, type, selected, help;
2060 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2061 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2062 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2063 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
2064 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
2065 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
2066 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2068 #ifndef HAVE_MULTILINGUAL_MENU
2069 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
2071 item_name = ENCODE_MENU_STRING (item_name);
2072 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
2075 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2077 descrip = ENCODE_MENU_STRING (descrip);
2078 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
2080 #endif /* not HAVE_MULTILINGUAL_MENU */
2082 wv = xmalloc_widget_value ();
2083 if (prev_wv)
2084 prev_wv->next = wv;
2085 else
2086 save_wv->contents = wv;
2087 wv->name = (char *) SDATA (item_name);
2088 if (!NILP (descrip))
2089 wv->key = (char *) SDATA (descrip);
2090 wv->value = 0;
2091 /* If this item has a null value,
2092 make the call_data null so that it won't display a box
2093 when the mouse is on it. */
2094 wv->call_data
2095 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
2096 wv->enabled = !NILP (enable);
2098 if (NILP (type))
2099 wv->button_type = BUTTON_TYPE_NONE;
2100 else if (EQ (type, QCtoggle))
2101 wv->button_type = BUTTON_TYPE_TOGGLE;
2102 else if (EQ (type, QCradio))
2103 wv->button_type = BUTTON_TYPE_RADIO;
2104 else
2105 abort ();
2107 wv->selected = !NILP (selected);
2109 if (! STRINGP (help))
2110 help = Qnil;
2112 wv->help = help;
2114 prev_wv = wv;
2116 i += MENU_ITEMS_ITEM_LENGTH;
2120 /* Deal with the title, if it is non-nil. */
2121 if (!NILP (title))
2123 widget_value *wv_title = xmalloc_widget_value ();
2124 widget_value *wv_sep1 = xmalloc_widget_value ();
2125 widget_value *wv_sep2 = xmalloc_widget_value ();
2127 wv_sep2->name = "--";
2128 wv_sep2->next = first_wv->contents;
2129 wv_sep2->help = Qnil;
2131 wv_sep1->name = "--";
2132 wv_sep1->next = wv_sep2;
2133 wv_sep1->help = Qnil;
2135 #ifndef HAVE_MULTILINGUAL_MENU
2136 if (STRING_MULTIBYTE (title))
2137 title = ENCODE_MENU_STRING (title);
2138 #endif
2140 wv_title->name = (char *) SDATA (title);
2141 wv_title->enabled = TRUE;
2142 wv_title->button_type = BUTTON_TYPE_NONE;
2143 wv_title->help = Qnil;
2144 wv_title->next = wv_sep1;
2145 first_wv->contents = wv_title;
2148 /* No selection has been chosen yet. */
2149 menu_item_selection = 0;
2151 /* Actually create and show the menu until popped down. */
2152 create_and_show_popup_menu (f, first_wv, x, y, for_click);
2154 /* Free the widget_value objects we used to specify the contents. */
2155 free_menubar_widget_value_tree (first_wv);
2157 /* Find the selected item, and its pane, to return
2158 the proper value. */
2159 if (menu_item_selection != 0)
2161 Lisp_Object prefix, entry;
2163 prefix = entry = Qnil;
2164 i = 0;
2165 while (i < menu_items_used)
2167 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
2169 subprefix_stack[submenu_depth++] = prefix;
2170 prefix = entry;
2171 i++;
2173 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
2175 prefix = subprefix_stack[--submenu_depth];
2176 i++;
2178 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2180 prefix
2181 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2182 i += MENU_ITEMS_PANE_LENGTH;
2184 /* Ignore a nil in the item list.
2185 It's meaningful only for dialog boxes. */
2186 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2187 i += 1;
2188 else
2190 entry
2191 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2192 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2194 if (keymaps != 0)
2196 int j;
2198 entry = Fcons (entry, Qnil);
2199 if (!NILP (prefix))
2200 entry = Fcons (prefix, entry);
2201 for (j = submenu_depth - 1; j >= 0; j--)
2202 if (!NILP (subprefix_stack[j]))
2203 entry = Fcons (subprefix_stack[j], entry);
2205 return entry;
2207 i += MENU_ITEMS_ITEM_LENGTH;
2211 else if (!for_click)
2212 /* Make "Cancel" equivalent to C-g. */
2213 Fsignal (Qquit, Qnil);
2215 return Qnil;
2218 #ifdef USE_GTK
2219 static void
2220 dialog_selection_callback (widget, client_data)
2221 GtkWidget *widget;
2222 gpointer client_data;
2224 /* The EMACS_INT cast avoids a warning. There's no problem
2225 as long as pointers have enough bits to hold small integers. */
2226 if ((int) (EMACS_INT) client_data != -1)
2227 menu_item_selection = (Lisp_Object *) client_data;
2229 popup_activated_flag = 0;
2232 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2233 dialog pops down.
2234 menu_item_selection will be set to the selection. */
2235 static void
2236 create_and_show_dialog (f, first_wv)
2237 FRAME_PTR f;
2238 widget_value *first_wv;
2240 GtkWidget *menu;
2242 if (! FRAME_X_P (f))
2243 abort ();
2245 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2246 G_CALLBACK (dialog_selection_callback),
2247 G_CALLBACK (popup_deactivate_callback),
2250 if (menu)
2252 int specpdl_count = SPECPDL_INDEX ();
2253 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
2255 /* Display the menu. */
2256 gtk_widget_show_all (menu);
2258 /* Process events that apply to the menu. */
2259 popup_widget_loop (1, menu);
2261 unbind_to (specpdl_count, Qnil);
2265 #else /* not USE_GTK */
2266 static void
2267 dialog_selection_callback (widget, id, client_data)
2268 Widget widget;
2269 LWLIB_ID id;
2270 XtPointer client_data;
2272 /* The EMACS_INT cast avoids a warning. There's no problem
2273 as long as pointers have enough bits to hold small integers. */
2274 if ((int) (EMACS_INT) client_data != -1)
2275 menu_item_selection = (Lisp_Object *) client_data;
2277 BLOCK_INPUT;
2278 lw_destroy_all_widgets (id);
2279 UNBLOCK_INPUT;
2280 popup_activated_flag = 0;
2284 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2285 dialog pops down.
2286 menu_item_selection will be set to the selection. */
2287 static void
2288 create_and_show_dialog (f, first_wv)
2289 FRAME_PTR f;
2290 widget_value *first_wv;
2292 LWLIB_ID dialog_id;
2294 if (!FRAME_X_P (f))
2295 abort();
2297 dialog_id = widget_id_tick++;
2298 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2299 f->output_data.x->widget, 1, 0,
2300 dialog_selection_callback, 0, 0);
2301 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2303 /* Display the dialog box. */
2304 lw_pop_up_all_widgets (dialog_id);
2305 popup_activated_flag = 1;
2306 x_activate_timeout_atimer ();
2308 /* Process events that apply to the dialog box.
2309 Also handle timers. */
2311 int count = SPECPDL_INDEX ();
2312 int fact = 4 * sizeof (LWLIB_ID);
2314 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2315 record_unwind_protect (pop_down_menu,
2316 Fcons (make_number (dialog_id >> (fact)),
2317 make_number (dialog_id & ~(-1 << (fact)))));
2319 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2320 dialog_id, 1);
2322 unbind_to (count, Qnil);
2326 #endif /* not USE_GTK */
2328 static char * button_names [] = {
2329 "button1", "button2", "button3", "button4", "button5",
2330 "button6", "button7", "button8", "button9", "button10" };
2332 static Lisp_Object
2333 xdialog_show (f, keymaps, title, header, error_name)
2334 FRAME_PTR f;
2335 int keymaps;
2336 Lisp_Object title, header;
2337 char **error_name;
2339 int i, nb_buttons=0;
2340 char dialog_name[6];
2342 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2344 /* Number of elements seen so far, before boundary. */
2345 int left_count = 0;
2346 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2347 int boundary_seen = 0;
2349 if (! FRAME_X_P (f))
2350 abort ();
2352 *error_name = NULL;
2354 if (menu_items_n_panes > 1)
2356 *error_name = "Multiple panes in dialog box";
2357 return Qnil;
2360 /* Create a tree of widget_value objects
2361 representing the text label and buttons. */
2363 Lisp_Object pane_name, prefix;
2364 char *pane_string;
2365 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2366 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2367 pane_string = (NILP (pane_name)
2368 ? "" : (char *) SDATA (pane_name));
2369 prev_wv = xmalloc_widget_value ();
2370 prev_wv->value = pane_string;
2371 if (keymaps && !NILP (prefix))
2372 prev_wv->name++;
2373 prev_wv->enabled = 1;
2374 prev_wv->name = "message";
2375 prev_wv->help = Qnil;
2376 first_wv = prev_wv;
2378 /* Loop over all panes and items, filling in the tree. */
2379 i = MENU_ITEMS_PANE_LENGTH;
2380 while (i < menu_items_used)
2383 /* Create a new item within current pane. */
2384 Lisp_Object item_name, enable, descrip;
2385 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2386 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2387 descrip
2388 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2390 if (NILP (item_name))
2392 free_menubar_widget_value_tree (first_wv);
2393 *error_name = "Submenu in dialog items";
2394 return Qnil;
2396 if (EQ (item_name, Qquote))
2398 /* This is the boundary between left-side elts
2399 and right-side elts. Stop incrementing right_count. */
2400 boundary_seen = 1;
2401 i++;
2402 continue;
2404 if (nb_buttons >= 9)
2406 free_menubar_widget_value_tree (first_wv);
2407 *error_name = "Too many dialog items";
2408 return Qnil;
2411 wv = xmalloc_widget_value ();
2412 prev_wv->next = wv;
2413 wv->name = (char *) button_names[nb_buttons];
2414 if (!NILP (descrip))
2415 wv->key = (char *) SDATA (descrip);
2416 wv->value = (char *) SDATA (item_name);
2417 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2418 wv->enabled = !NILP (enable);
2419 wv->help = Qnil;
2420 prev_wv = wv;
2422 if (! boundary_seen)
2423 left_count++;
2425 nb_buttons++;
2426 i += MENU_ITEMS_ITEM_LENGTH;
2429 /* If the boundary was not specified,
2430 by default put half on the left and half on the right. */
2431 if (! boundary_seen)
2432 left_count = nb_buttons - nb_buttons / 2;
2434 wv = xmalloc_widget_value ();
2435 wv->name = dialog_name;
2436 wv->help = Qnil;
2438 /* Frame title: 'Q' = Question, 'I' = Information.
2439 Can also have 'E' = Error if, one day, we want
2440 a popup for errors. */
2441 if (NILP(header))
2442 dialog_name[0] = 'Q';
2443 else
2444 dialog_name[0] = 'I';
2446 /* Dialog boxes use a really stupid name encoding
2447 which specifies how many buttons to use
2448 and how many buttons are on the right. */
2449 dialog_name[1] = '0' + nb_buttons;
2450 dialog_name[2] = 'B';
2451 dialog_name[3] = 'R';
2452 /* Number of buttons to put on the right. */
2453 dialog_name[4] = '0' + nb_buttons - left_count;
2454 dialog_name[5] = 0;
2455 wv->contents = first_wv;
2456 first_wv = wv;
2459 /* No selection has been chosen yet. */
2460 menu_item_selection = 0;
2462 /* Actually create and show the dialog. */
2463 create_and_show_dialog (f, first_wv);
2465 /* Free the widget_value objects we used to specify the contents. */
2466 free_menubar_widget_value_tree (first_wv);
2468 /* Find the selected item, and its pane, to return
2469 the proper value. */
2470 if (menu_item_selection != 0)
2472 Lisp_Object prefix;
2474 prefix = Qnil;
2475 i = 0;
2476 while (i < menu_items_used)
2478 Lisp_Object entry;
2480 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2482 prefix
2483 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2484 i += MENU_ITEMS_PANE_LENGTH;
2486 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2488 /* This is the boundary between left-side elts and
2489 right-side elts. */
2490 ++i;
2492 else
2494 entry
2495 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2496 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2498 if (keymaps != 0)
2500 entry = Fcons (entry, Qnil);
2501 if (!NILP (prefix))
2502 entry = Fcons (prefix, entry);
2504 return entry;
2506 i += MENU_ITEMS_ITEM_LENGTH;
2510 else
2511 /* Make "Cancel" equivalent to C-g. */
2512 Fsignal (Qquit, Qnil);
2514 return Qnil;
2517 #else /* not USE_X_TOOLKIT && not USE_GTK */
2519 /* The frame of the last activated non-toolkit menu bar.
2520 Used to generate menu help events. */
2522 static struct frame *menu_help_frame;
2525 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2527 PANE is the pane number, and ITEM is the menu item number in
2528 the menu (currently not used).
2530 This cannot be done with generating a HELP_EVENT because
2531 XMenuActivate contains a loop that doesn't let Emacs process
2532 keyboard events. */
2534 static void
2535 menu_help_callback (help_string, pane, item)
2536 char *help_string;
2537 int pane, item;
2539 extern Lisp_Object Qmenu_item;
2540 Lisp_Object *first_item;
2541 Lisp_Object pane_name;
2542 Lisp_Object menu_object;
2544 first_item = XVECTOR (menu_items)->contents;
2545 if (EQ (first_item[0], Qt))
2546 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2547 else if (EQ (first_item[0], Qquote))
2548 /* This shouldn't happen, see xmenu_show. */
2549 pane_name = empty_unibyte_string;
2550 else
2551 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2553 /* (menu-item MENU-NAME PANE-NUMBER) */
2554 menu_object = Fcons (Qmenu_item,
2555 Fcons (pane_name,
2556 Fcons (make_number (pane), Qnil)));
2557 show_help_echo (help_string ? build_string (help_string) : Qnil,
2558 Qnil, menu_object, make_number (item), 1);
2561 static Lisp_Object
2562 pop_down_menu (arg)
2563 Lisp_Object arg;
2565 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2566 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2568 FRAME_PTR f = p1->pointer;
2569 XMenu *menu = p2->pointer;
2571 BLOCK_INPUT;
2572 #ifndef MSDOS
2573 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2574 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2575 #endif
2576 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2578 #ifdef HAVE_X_WINDOWS
2579 /* Assume the mouse has moved out of the X window.
2580 If it has actually moved in, we will get an EnterNotify. */
2581 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2583 /* State that no mouse buttons are now held.
2584 (The oldXMenu code doesn't track this info for us.)
2585 That is not necessarily true, but the fiction leads to reasonable
2586 results, and it is a pain to ask which are actually held now. */
2587 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2589 #endif /* HAVE_X_WINDOWS */
2591 UNBLOCK_INPUT;
2593 return Qnil;
2597 static Lisp_Object
2598 xmenu_show (f, x, y, for_click, keymaps, title, error)
2599 FRAME_PTR f;
2600 int x, y;
2601 int for_click;
2602 int keymaps;
2603 Lisp_Object title;
2604 char **error;
2606 Window root;
2607 XMenu *menu;
2608 int pane, selidx, lpane, status;
2609 Lisp_Object entry, pane_prefix;
2610 char *datap;
2611 int ulx, uly, width, height;
2612 int dispwidth, dispheight;
2613 int i, j, lines, maxlines;
2614 int maxwidth;
2615 int dummy_int;
2616 unsigned int dummy_uint;
2617 int specpdl_count = SPECPDL_INDEX ();
2619 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2620 abort ();
2622 *error = 0;
2623 if (menu_items_n_panes == 0)
2624 return Qnil;
2626 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2628 *error = "Empty menu";
2629 return Qnil;
2632 /* Figure out which root window F is on. */
2633 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2634 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2635 &dummy_uint, &dummy_uint);
2637 /* Make the menu on that window. */
2638 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2639 if (menu == NULL)
2641 *error = "Can't create menu";
2642 return Qnil;
2645 /* Don't GC while we prepare and show the menu,
2646 because we give the oldxmenu library pointers to the
2647 contents of strings. */
2648 inhibit_garbage_collection ();
2650 #ifdef HAVE_X_WINDOWS
2651 /* Adjust coordinates to relative to the outer (window manager) window. */
2652 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2653 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2654 #endif /* HAVE_X_WINDOWS */
2656 /* Adjust coordinates to be root-window-relative. */
2657 x += f->left_pos;
2658 y += f->top_pos;
2660 /* Create all the necessary panes and their items. */
2661 maxlines = lines = i = 0;
2662 while (i < menu_items_used)
2664 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2666 /* Create a new pane. */
2667 Lisp_Object pane_name, prefix;
2668 char *pane_string;
2670 maxlines = max (maxlines, lines);
2671 lines = 0;
2672 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2673 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2674 pane_string = (NILP (pane_name)
2675 ? "" : (char *) SDATA (pane_name));
2676 if (keymaps && !NILP (prefix))
2677 pane_string++;
2679 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2680 if (lpane == XM_FAILURE)
2682 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2683 *error = "Can't create pane";
2684 return Qnil;
2686 i += MENU_ITEMS_PANE_LENGTH;
2688 /* Find the width of the widest item in this pane. */
2689 maxwidth = 0;
2690 j = i;
2691 while (j < menu_items_used)
2693 Lisp_Object item;
2694 item = XVECTOR (menu_items)->contents[j];
2695 if (EQ (item, Qt))
2696 break;
2697 if (NILP (item))
2699 j++;
2700 continue;
2702 width = SBYTES (item);
2703 if (width > maxwidth)
2704 maxwidth = width;
2706 j += MENU_ITEMS_ITEM_LENGTH;
2709 /* Ignore a nil in the item list.
2710 It's meaningful only for dialog boxes. */
2711 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2712 i += 1;
2713 else
2715 /* Create a new item within current pane. */
2716 Lisp_Object item_name, enable, descrip, help;
2717 unsigned char *item_data;
2718 char *help_string;
2720 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2721 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2722 descrip
2723 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2724 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2725 help_string = STRINGP (help) ? SDATA (help) : NULL;
2727 if (!NILP (descrip))
2729 int gap = maxwidth - SBYTES (item_name);
2730 /* if alloca is fast, use that to make the space,
2731 to reduce gc needs. */
2732 item_data
2733 = (unsigned char *) alloca (maxwidth
2734 + SBYTES (descrip) + 1);
2735 bcopy (SDATA (item_name), item_data,
2736 SBYTES (item_name));
2737 for (j = SCHARS (item_name); j < maxwidth; j++)
2738 item_data[j] = ' ';
2739 bcopy (SDATA (descrip), item_data + j,
2740 SBYTES (descrip));
2741 item_data[j + SBYTES (descrip)] = 0;
2743 else
2744 item_data = SDATA (item_name);
2746 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2747 menu, lpane, 0, item_data,
2748 !NILP (enable), help_string)
2749 == XM_FAILURE)
2751 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2752 *error = "Can't add selection to menu";
2753 return Qnil;
2755 i += MENU_ITEMS_ITEM_LENGTH;
2756 lines++;
2760 maxlines = max (maxlines, lines);
2762 /* All set and ready to fly. */
2763 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2764 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2765 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2766 x = min (x, dispwidth);
2767 y = min (y, dispheight);
2768 x = max (x, 1);
2769 y = max (y, 1);
2770 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2771 &ulx, &uly, &width, &height);
2772 if (ulx+width > dispwidth)
2774 x -= (ulx + width) - dispwidth;
2775 ulx = dispwidth - width;
2777 if (uly+height > dispheight)
2779 y -= (uly + height) - dispheight;
2780 uly = dispheight - height;
2782 #ifndef HAVE_X_WINDOWS
2783 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2785 /* Move the menu away of the echo area, to avoid overwriting the
2786 menu with help echo messages or vice versa. */
2787 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2789 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2790 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2792 else
2794 y--;
2795 uly--;
2798 #endif
2799 if (ulx < 0) x -= ulx;
2800 if (uly < 0) y -= uly;
2802 if (! for_click)
2804 /* If position was not given by a mouse click, adjust so upper left
2805 corner of the menu as a whole ends up at given coordinates. This
2806 is what x-popup-menu says in its documentation. */
2807 x += width/2;
2808 y += 1.5*height/(maxlines+2);
2811 XMenuSetAEQ (menu, TRUE);
2812 XMenuSetFreeze (menu, TRUE);
2813 pane = selidx = 0;
2815 #ifndef MSDOS
2816 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2817 #endif
2819 record_unwind_protect (pop_down_menu,
2820 Fcons (make_save_value (f, 0),
2821 make_save_value (menu, 0)));
2823 /* Help display under X won't work because XMenuActivate contains
2824 a loop that doesn't give Emacs a chance to process it. */
2825 menu_help_frame = f;
2826 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2827 x, y, ButtonReleaseMask, &datap,
2828 menu_help_callback);
2830 switch (status)
2832 case XM_SUCCESS:
2833 #ifdef XDEBUG
2834 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2835 #endif
2837 /* Find the item number SELIDX in pane number PANE. */
2838 i = 0;
2839 while (i < menu_items_used)
2841 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2843 if (pane == 0)
2844 pane_prefix
2845 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2846 pane--;
2847 i += MENU_ITEMS_PANE_LENGTH;
2849 else
2851 if (pane == -1)
2853 if (selidx == 0)
2855 entry
2856 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2857 if (keymaps != 0)
2859 entry = Fcons (entry, Qnil);
2860 if (!NILP (pane_prefix))
2861 entry = Fcons (pane_prefix, entry);
2863 break;
2865 selidx--;
2867 i += MENU_ITEMS_ITEM_LENGTH;
2870 break;
2872 case XM_FAILURE:
2873 *error = "Can't activate menu";
2874 case XM_IA_SELECT:
2875 entry = Qnil;
2876 break;
2877 case XM_NO_SELECT:
2878 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2879 the menu was invoked with a mouse event as POSITION). */
2880 if (! for_click)
2881 Fsignal (Qquit, Qnil);
2882 entry = Qnil;
2883 break;
2886 unbind_to (specpdl_count, Qnil);
2888 return entry;
2891 #endif /* not USE_X_TOOLKIT */
2893 #endif /* HAVE_MENUS */
2895 /* Detect if a dialog or menu has been posted. */
2898 popup_activated ()
2900 return popup_activated_flag;
2903 /* The following is used by delayed window autoselection. */
2905 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2906 doc: /* Return t if a menu or popup dialog is active. */)
2909 #ifdef HAVE_MENUS
2910 return (popup_activated ()) ? Qt : Qnil;
2911 #else
2912 return Qnil;
2913 #endif /* HAVE_MENUS */
2916 void
2917 syms_of_xmenu ()
2919 Qdebug_on_next_call = intern ("debug-on-next-call");
2920 staticpro (&Qdebug_on_next_call);
2922 #ifdef USE_X_TOOLKIT
2923 widget_id_tick = (1<<16);
2924 next_menubar_widget_id = 1;
2925 #endif
2927 defsubr (&Sx_popup_menu);
2928 defsubr (&Smenu_or_popup_active_p);
2930 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2931 defsubr (&Sx_menu_bar_open_internal);
2932 Ffset (intern ("accelerate-menu"),
2933 intern (Sx_menu_bar_open_internal.symbol_name));
2934 #endif
2936 #ifdef HAVE_MENUS
2937 defsubr (&Sx_popup_dialog);
2938 #endif
2941 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2942 (do not change this comment) */