(bug-reference-map): Bind down-mouse-1 rather than mouse-1.
[emacs.git] / src / xmenu.c
blobbba202e4504acf64f11499605f36055311022c7e
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 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 #ifndef TRUE
98 #define TRUE 1
99 #define FALSE 0
100 #endif /* no TRUE */
102 Lisp_Object Qdebug_on_next_call;
104 extern Lisp_Object Vmenu_updating_frame;
106 extern Lisp_Object Qmenu_bar;
108 extern Lisp_Object QCtoggle, QCradio;
110 extern Lisp_Object Voverriding_local_map;
111 extern Lisp_Object Voverriding_local_map_menu_flag;
113 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
115 extern Lisp_Object Qmenu_bar_update_hook;
117 #ifdef USE_X_TOOLKIT
118 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
119 extern XtAppContext Xt_app_con;
121 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
122 char **));
123 static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
124 LWLIB_ID, int));
125 #endif /* USE_X_TOOLKIT */
127 #ifdef USE_GTK
128 #include "gtkutil.h"
129 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
130 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
131 char **));
132 #endif
134 static int update_frame_menubar P_ ((struct frame *));
135 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
136 Lisp_Object, char **));
138 /* Flag which when set indicates a dialog or menu has been posted by
139 Xt on behalf of one of the widget sets. */
140 static int popup_activated_flag;
142 static int next_menubar_widget_id;
144 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
145 extern widget_value *xmalloc_widget_value P_ ((void));
146 extern widget_value *digest_single_submenu P_ ((int, int, int));
147 #endif
149 /* This is set nonzero after the user activates the menu bar, and set
150 to zero again after the menu bars are redisplayed by prepare_menu_bar.
151 While it is nonzero, all calls to set_frame_menubar go deep.
153 I don't understand why this is needed, but it does seem to be
154 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
156 int pending_menu_activation;
158 #ifdef USE_X_TOOLKIT
160 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
162 static struct frame *
163 menubar_id_to_frame (id)
164 LWLIB_ID id;
166 Lisp_Object tail, frame;
167 FRAME_PTR f;
169 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
171 frame = XCAR (tail);
172 if (!FRAMEP (frame))
173 continue;
174 f = XFRAME (frame);
175 if (!FRAME_WINDOW_P (f))
176 continue;
177 if (f->output_data.x->id == id)
178 return f;
180 return 0;
183 #endif
185 #ifdef HAVE_X_WINDOWS
186 /* Return the mouse position in *X and *Y. The coordinates are window
187 relative for the edit window in frame F.
188 This is for Fx_popup_menu. The mouse_position_hook can not
189 be used for X, as it returns window relative coordinates
190 for the window where the mouse is in. This could be the menu bar,
191 the scroll bar or the edit window. Fx_popup_menu needs to be
192 sure it is the edit window. */
193 static void
194 mouse_position_for_popup (f, x, y)
195 FRAME_PTR f;
196 int *x;
197 int *y;
199 Window root, dummy_window;
200 int dummy;
202 if (! FRAME_X_P (f))
203 abort ();
205 BLOCK_INPUT;
207 XQueryPointer (FRAME_X_DISPLAY (f),
208 DefaultRootWindow (FRAME_X_DISPLAY (f)),
210 /* The root window which contains the pointer. */
211 &root,
213 /* Window pointer is on, not used */
214 &dummy_window,
216 /* The position on that root window. */
217 x, y,
219 /* x/y in dummy_window coordinates, not used. */
220 &dummy, &dummy,
222 /* Modifier keys and pointer buttons, about which
223 we don't care. */
224 (unsigned int *) &dummy);
226 UNBLOCK_INPUT;
228 /* xmenu_show expects window coordinates, not root window
229 coordinates. Translate. */
230 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
231 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
234 #endif /* HAVE_X_WINDOWS */
236 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
237 doc: /* Pop up a deck-of-cards menu and return user's selection.
238 POSITION is a position specification. This is either a mouse button event
239 or a list ((XOFFSET YOFFSET) WINDOW)
240 where XOFFSET and YOFFSET are positions in pixels from the top left
241 corner of WINDOW. (WINDOW may be a window or a frame object.)
242 This controls the position of the top left of the menu as a whole.
243 If POSITION is t, it means to use the current mouse position.
245 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
246 The menu items come from key bindings that have a menu string as well as
247 a definition; actually, the "definition" in such a key binding looks like
248 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
249 the keymap as a top-level element.
251 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
252 Otherwise, REAL-DEFINITION should be a valid key binding definition.
254 You can also use a list of keymaps as MENU.
255 Then each keymap makes a separate pane.
257 When MENU is a keymap or a list of keymaps, the return value is the
258 list of events corresponding to the user's choice. Note that
259 `x-popup-menu' does not actually execute the command bound to that
260 sequence of events.
262 Alternatively, you can specify a menu of multiple panes
263 with a list of the form (TITLE PANE1 PANE2...),
264 where each pane is a list of form (TITLE ITEM1 ITEM2...).
265 Each ITEM is normally a cons cell (STRING . VALUE);
266 but a string can appear as an item--that makes a nonselectable line
267 in the menu.
268 With this form of menu, the return value is VALUE from the chosen item.
270 If POSITION is nil, don't display the menu at all, just precalculate the
271 cached information about equivalent key sequences.
273 If the user gets rid of the menu without making a valid choice, for
274 instance by clicking the mouse away from a valid choice or by typing
275 keyboard input, then this normally results in a quit and
276 `x-popup-menu' does not return. But if POSITION is a mouse button
277 event (indicating that the user invoked the menu with the mouse) then
278 no quit occurs and `x-popup-menu' returns nil. */)
279 (position, menu)
280 Lisp_Object position, menu;
282 Lisp_Object keymap, tem;
283 int xpos = 0, ypos = 0;
284 Lisp_Object title;
285 char *error_name = NULL;
286 Lisp_Object selection = Qnil;
287 FRAME_PTR f = NULL;
288 Lisp_Object x, y, window;
289 int keymaps = 0;
290 int for_click = 0;
291 int specpdl_count = SPECPDL_INDEX ();
292 struct gcpro gcpro1;
294 #ifdef HAVE_MENUS
295 if (! NILP (position))
297 int get_current_pos_p = 0;
298 check_x ();
300 /* Decode the first argument: find the window and the coordinates. */
301 if (EQ (position, Qt)
302 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
303 || EQ (XCAR (position), Qtool_bar))))
305 get_current_pos_p = 1;
307 else
309 tem = Fcar (position);
310 if (CONSP (tem))
312 window = Fcar (Fcdr (position));
313 x = XCAR (tem);
314 y = Fcar (XCDR (tem));
316 else
318 for_click = 1;
319 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
320 window = Fcar (tem); /* POSN_WINDOW (tem) */
321 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
322 x = Fcar (tem);
323 y = Fcdr (tem);
326 /* If a click happens in an external tool bar or a detached
327 tool bar, x and y is NIL. In that case, use the current
328 mouse position. This happens for the help button in the
329 tool bar. Ideally popup-menu should pass NIL to
330 this function, but it doesn't. */
331 if (NILP (x) && NILP (y))
332 get_current_pos_p = 1;
335 if (get_current_pos_p)
337 /* Use the mouse's current position. */
338 FRAME_PTR new_f = SELECTED_FRAME ();
339 #ifdef HAVE_X_WINDOWS
340 /* Can't use mouse_position_hook for X since it returns
341 coordinates relative to the window the mouse is in,
342 we need coordinates relative to the edit widget always. */
343 if (new_f != 0)
345 int cur_x, cur_y;
347 mouse_position_for_popup (new_f, &cur_x, &cur_y);
348 /* cur_x/y may be negative, so use make_number. */
349 x = make_number (cur_x);
350 y = make_number (cur_y);
353 #else /* not HAVE_X_WINDOWS */
354 Lisp_Object bar_window;
355 enum scroll_bar_part part;
356 unsigned long time;
358 if (mouse_position_hook)
359 (*mouse_position_hook) (&new_f, 1, &bar_window,
360 &part, &x, &y, &time);
361 #endif /* not HAVE_X_WINDOWS */
363 if (new_f != 0)
364 XSETFRAME (window, new_f);
365 else
367 window = selected_window;
368 XSETFASTINT (x, 0);
369 XSETFASTINT (y, 0);
373 CHECK_NUMBER (x);
374 CHECK_NUMBER (y);
376 /* Decode where to put the menu. */
378 if (FRAMEP (window))
380 f = XFRAME (window);
381 xpos = 0;
382 ypos = 0;
384 else if (WINDOWP (window))
386 CHECK_LIVE_WINDOW (window);
387 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
389 xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
390 ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
392 else
393 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
394 but I don't want to make one now. */
395 CHECK_WINDOW (window);
397 xpos += XINT (x);
398 ypos += XINT (y);
400 if (! FRAME_X_P (f))
401 error ("Can not put X menu on non-X terminal");
403 XSETFRAME (Vmenu_updating_frame, f);
405 else
406 Vmenu_updating_frame = Qnil;
407 #endif /* HAVE_MENUS */
409 record_unwind_protect (unuse_menu_items, Qnil);
410 title = Qnil;
411 GCPRO1 (title);
413 /* Decode the menu items from what was specified. */
415 keymap = get_keymap (menu, 0, 0);
416 if (CONSP (keymap))
418 /* We were given a keymap. Extract menu info from the keymap. */
419 Lisp_Object prompt;
421 /* Extract the detailed info to make one pane. */
422 keymap_panes (&menu, 1, NILP (position));
424 /* Search for a string appearing directly as an element of the keymap.
425 That string is the title of the menu. */
426 prompt = Fkeymap_prompt (keymap);
427 if (NILP (title) && !NILP (prompt))
428 title = prompt;
430 /* Make that be the pane title of the first pane. */
431 if (!NILP (prompt) && menu_items_n_panes >= 0)
432 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
434 keymaps = 1;
436 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
438 /* We were given a list of keymaps. */
439 int nmaps = XFASTINT (Flength (menu));
440 Lisp_Object *maps
441 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
442 int i;
444 title = Qnil;
446 /* The first keymap that has a prompt string
447 supplies the menu title. */
448 for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
450 Lisp_Object prompt;
452 maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
454 prompt = Fkeymap_prompt (keymap);
455 if (NILP (title) && !NILP (prompt))
456 title = prompt;
459 /* Extract the detailed info to make one pane. */
460 keymap_panes (maps, nmaps, NILP (position));
462 /* Make the title be the pane title of the first pane. */
463 if (!NILP (title) && menu_items_n_panes >= 0)
464 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
466 keymaps = 1;
468 else
470 /* We were given an old-fashioned menu. */
471 title = Fcar (menu);
472 CHECK_STRING (title);
474 list_of_panes (Fcdr (menu));
476 keymaps = 0;
479 unbind_to (specpdl_count, Qnil);
481 if (NILP (position))
483 discard_menu_items ();
484 UNGCPRO;
485 return Qnil;
488 #ifdef HAVE_MENUS
489 /* Display them in a menu. */
490 BLOCK_INPUT;
492 selection = xmenu_show (f, xpos, ypos, for_click,
493 keymaps, title, &error_name);
494 UNBLOCK_INPUT;
496 discard_menu_items ();
498 UNGCPRO;
499 #endif /* HAVE_MENUS */
501 if (error_name) error (error_name);
502 return selection;
505 #ifdef HAVE_MENUS
507 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
508 doc: /* Pop up a dialog box and return user's selection.
509 POSITION specifies which frame to use.
510 This is normally a mouse button event or a window or frame.
511 If POSITION is t, it means to use the frame the mouse is on.
512 The dialog box appears in the middle of the specified frame.
514 CONTENTS specifies the alternatives to display in the dialog box.
515 It is a list of the form (DIALOG ITEM1 ITEM2...).
516 Each ITEM is a cons cell (STRING . VALUE).
517 The return value is VALUE from the chosen item.
519 An ITEM may also be just a string--that makes a nonselectable item.
520 An ITEM may also be nil--that means to put all preceding items
521 on the left of the dialog box and all following items on the right.
522 \(By default, approximately half appear on each side.)
524 If HEADER is non-nil, the frame title for the box is "Information",
525 otherwise it is "Question".
527 If the user gets rid of the dialog box without making a valid choice,
528 for instance using the window manager, then this produces a quit and
529 `x-popup-dialog' does not return. */)
530 (position, contents, header)
531 Lisp_Object position, contents, header;
533 FRAME_PTR f = NULL;
534 Lisp_Object window;
536 check_x ();
538 /* Decode the first argument: find the window or frame to use. */
539 if (EQ (position, Qt)
540 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
541 || EQ (XCAR (position), Qtool_bar))))
543 #if 0 /* Using the frame the mouse is on may not be right. */
544 /* Use the mouse's current position. */
545 FRAME_PTR new_f = SELECTED_FRAME ();
546 Lisp_Object bar_window;
547 enum scroll_bar_part part;
548 unsigned long time;
549 Lisp_Object x, y;
551 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
553 if (new_f != 0)
554 XSETFRAME (window, new_f);
555 else
556 window = selected_window;
557 #endif
558 window = selected_window;
560 else if (CONSP (position))
562 Lisp_Object tem;
563 tem = Fcar (position);
564 if (CONSP (tem))
565 window = Fcar (Fcdr (position));
566 else
568 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
569 window = Fcar (tem); /* POSN_WINDOW (tem) */
572 else if (WINDOWP (position) || FRAMEP (position))
573 window = position;
574 else
575 window = Qnil;
577 /* Decode where to put the menu. */
579 if (FRAMEP (window))
580 f = XFRAME (window);
581 else if (WINDOWP (window))
583 CHECK_LIVE_WINDOW (window);
584 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
586 else
587 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
588 but I don't want to make one now. */
589 CHECK_WINDOW (window);
591 if (! FRAME_X_P (f))
592 error ("Can not put X dialog on non-X terminal");
594 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
595 /* Display a menu with these alternatives
596 in the middle of frame F. */
598 Lisp_Object x, y, frame, newpos;
599 XSETFRAME (frame, f);
600 XSETINT (x, x_pixel_width (f) / 2);
601 XSETINT (y, x_pixel_height (f) / 2);
602 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
604 return Fx_popup_menu (newpos,
605 Fcons (Fcar (contents), Fcons (contents, Qnil)));
607 #else
609 Lisp_Object title;
610 char *error_name;
611 Lisp_Object selection;
612 int specpdl_count = SPECPDL_INDEX ();
614 /* Decode the dialog items from what was specified. */
615 title = Fcar (contents);
616 CHECK_STRING (title);
617 record_unwind_protect (unuse_menu_items, Qnil);
619 if (NILP (Fcar (Fcdr (contents))))
620 /* No buttons specified, add an "Ok" button so users can pop down
621 the dialog. Also, the lesstif/motif version crashes if there are
622 no buttons. */
623 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
625 list_of_panes (Fcons (contents, Qnil));
627 /* Display them in a dialog box. */
628 BLOCK_INPUT;
629 selection = xdialog_show (f, 0, title, header, &error_name);
630 UNBLOCK_INPUT;
632 unbind_to (specpdl_count, Qnil);
633 discard_menu_items ();
635 if (error_name) error (error_name);
636 return selection;
638 #endif
642 #ifndef MSDOS
644 /* Set menu_items_inuse so no other popup menu or dialog is created. */
646 void
647 x_menu_set_in_use (in_use)
648 int in_use;
650 menu_items_inuse = in_use ? Qt : Qnil;
651 popup_activated_flag = in_use;
652 #ifdef USE_X_TOOLKIT
653 if (popup_activated_flag)
654 x_activate_timeout_atimer ();
655 #endif
658 /* Wait for an X event to arrive or for a timer to expire. */
660 void
661 x_menu_wait_for_event (void *data)
663 extern EMACS_TIME timer_check P_ ((int));
665 /* Another way to do this is to register a timer callback, that can be
666 done in GTK and Xt. But we have to do it like this when using only X
667 anyway, and with callbacks we would have three variants for timer handling
668 instead of the small ifdefs below. */
670 while (
671 #ifdef USE_X_TOOLKIT
672 ! XtAppPending (Xt_app_con)
673 #elif defined USE_GTK
674 ! gtk_events_pending ()
675 #else
676 ! XPending ((Display*) data)
677 #endif
680 EMACS_TIME next_time = timer_check (1);
681 long secs = EMACS_SECS (next_time);
682 long usecs = EMACS_USECS (next_time);
683 SELECT_TYPE read_fds;
684 struct x_display_info *dpyinfo;
685 int n = 0;
687 FD_ZERO (&read_fds);
688 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
690 int fd = ConnectionNumber (dpyinfo->display);
691 FD_SET (fd, &read_fds);
692 if (fd > n) n = fd;
695 if (secs < 0 || (secs == 0 && usecs == 0))
697 /* Sometimes timer_check returns -1 (no timers) even if there are
698 timers. So do a timeout anyway. */
699 EMACS_SET_SECS (next_time, 1);
700 EMACS_SET_USECS (next_time, 0);
703 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
706 #endif /* ! MSDOS */
709 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
711 #ifdef USE_X_TOOLKIT
713 /* Loop in Xt until the menu pulldown or dialog popup has been
714 popped down (deactivated). This is used for x-popup-menu
715 and x-popup-dialog; it is not used for the menu bar.
717 NOTE: All calls to popup_get_selection should be protected
718 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
720 static void
721 popup_get_selection (initial_event, dpyinfo, id, do_timers)
722 XEvent *initial_event;
723 struct x_display_info *dpyinfo;
724 LWLIB_ID id;
725 int do_timers;
727 XEvent event;
729 while (popup_activated_flag)
731 if (initial_event)
733 event = *initial_event;
734 initial_event = 0;
736 else
738 if (do_timers) x_menu_wait_for_event (0);
739 XtAppNextEvent (Xt_app_con, &event);
742 /* Make sure we don't consider buttons grabbed after menu goes.
743 And make sure to deactivate for any ButtonRelease,
744 even if XtDispatchEvent doesn't do that. */
745 if (event.type == ButtonRelease
746 && dpyinfo->display == event.xbutton.display)
748 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
749 #ifdef USE_MOTIF /* Pretending that the event came from a
750 Btn1Down seems the only way to convince Motif to
751 activate its callbacks; setting the XmNmenuPost
752 isn't working. --marcus@sysc.pdx.edu. */
753 event.xbutton.button = 1;
754 /* Motif only pops down menus when no Ctrl, Alt or Mod
755 key is pressed and the button is released. So reset key state
756 so Motif thinks this is the case. */
757 event.xbutton.state = 0;
758 #endif
760 /* Pop down on C-g and Escape. */
761 else if (event.type == KeyPress
762 && dpyinfo->display == event.xbutton.display)
764 KeySym keysym = XLookupKeysym (&event.xkey, 0);
766 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
767 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
768 popup_activated_flag = 0;
771 x_dispatch_event (&event, event.xany.display);
775 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
776 doc: /* Start key navigation of the menu bar in FRAME.
777 This initially opens the first menu bar item and you can then navigate with the
778 arrow keys, select a menu entry with the return key or cancel with the
779 escape key. If FRAME has no menu bar this function does nothing.
781 If FRAME is nil or not given, use the selected frame. */)
782 (frame)
783 Lisp_Object frame;
785 XEvent ev;
786 FRAME_PTR f = check_x_frame (frame);
787 Widget menubar;
788 BLOCK_INPUT;
790 if (FRAME_EXTERNAL_MENU_BAR (f))
791 set_frame_menubar (f, 0, 1);
793 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
794 if (menubar)
796 Window child;
797 int error_p = 0;
799 x_catch_errors (FRAME_X_DISPLAY (f));
800 memset (&ev, 0, sizeof ev);
801 ev.xbutton.display = FRAME_X_DISPLAY (f);
802 ev.xbutton.window = XtWindow (menubar);
803 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
804 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
805 ev.xbutton.button = Button1;
806 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
807 ev.xbutton.same_screen = True;
809 #ifdef USE_MOTIF
811 Arg al[2];
812 WidgetList list;
813 Cardinal nr;
814 XtSetArg (al[0], XtNchildren, &list);
815 XtSetArg (al[1], XtNnumChildren, &nr);
816 XtGetValues (menubar, al, 2);
817 ev.xbutton.window = XtWindow (list[0]);
819 #endif
821 XTranslateCoordinates (FRAME_X_DISPLAY (f),
822 /* From-window, to-window. */
823 ev.xbutton.window, ev.xbutton.root,
825 /* From-position, to-position. */
826 ev.xbutton.x, ev.xbutton.y,
827 &ev.xbutton.x_root, &ev.xbutton.y_root,
829 /* Child of win. */
830 &child);
831 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
832 x_uncatch_errors ();
834 if (! error_p)
836 ev.type = ButtonPress;
837 ev.xbutton.state = 0;
839 XtDispatchEvent (&ev);
840 ev.xbutton.type = ButtonRelease;
841 ev.xbutton.state = Button1Mask;
842 XtDispatchEvent (&ev);
846 UNBLOCK_INPUT;
848 return Qnil;
850 #endif /* USE_X_TOOLKIT */
853 #ifdef USE_GTK
854 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
855 doc: /* Start key navigation of the menu bar in FRAME.
856 This initially opens the first menu bar item and you can then navigate with the
857 arrow keys, select a menu entry with the return key or cancel with the
858 escape key. If FRAME has no menu bar this function does nothing.
860 If FRAME is nil or not given, use the selected frame. */)
861 (frame)
862 Lisp_Object frame;
864 GtkWidget *menubar;
865 FRAME_PTR f;
867 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
868 BLOCK_INPUT. */
870 BLOCK_INPUT;
871 f = check_x_frame (frame);
873 if (FRAME_EXTERNAL_MENU_BAR (f))
874 set_frame_menubar (f, 0, 1);
876 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
877 if (menubar)
879 /* Activate the first menu. */
880 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
882 gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar),
883 GTK_WIDGET (children->data));
885 popup_activated_flag = 1;
886 g_list_free (children);
888 UNBLOCK_INPUT;
890 return Qnil;
893 /* Loop util popup_activated_flag is set to zero in a callback.
894 Used for popup menus and dialogs. */
896 static void
897 popup_widget_loop (do_timers, widget)
898 int do_timers;
899 GtkWidget *widget;
901 ++popup_activated_flag;
903 /* Process events in the Gtk event loop until done. */
904 while (popup_activated_flag)
906 if (do_timers) x_menu_wait_for_event (0);
907 gtk_main_iteration ();
910 #endif
912 /* Activate the menu bar of frame F.
913 This is called from keyboard.c when it gets the
914 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
916 To activate the menu bar, we use the X button-press event
917 that was saved in saved_menu_event.
918 That makes the toolkit do its thing.
920 But first we recompute the menu bar contents (the whole tree).
922 The reason for saving the button event until here, instead of
923 passing it to the toolkit right away, is that we can safely
924 execute Lisp code. */
926 void
927 x_activate_menubar (f)
928 FRAME_PTR f;
930 if (! FRAME_X_P (f))
931 abort ();
933 if (!f->output_data.x->saved_menu_event->type)
934 return;
936 #ifdef USE_GTK
937 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
938 f->output_data.x->saved_menu_event->xany.window))
939 return;
940 #endif
942 set_frame_menubar (f, 0, 1);
943 BLOCK_INPUT;
944 #ifdef USE_GTK
945 XPutBackEvent (f->output_data.x->display_info->display,
946 f->output_data.x->saved_menu_event);
947 popup_activated_flag = 1;
948 #else
949 XtDispatchEvent (f->output_data.x->saved_menu_event);
950 #endif
951 UNBLOCK_INPUT;
952 #ifdef USE_MOTIF
953 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
954 pending_menu_activation = 1;
955 #endif
957 /* Ignore this if we get it a second time. */
958 f->output_data.x->saved_menu_event->type = 0;
961 /* This callback is invoked when the user selects a menubar cascade
962 pushbutton, but before the pulldown menu is posted. */
964 #ifndef USE_GTK
965 static void
966 popup_activate_callback (widget, id, client_data)
967 Widget widget;
968 LWLIB_ID id;
969 XtPointer client_data;
971 popup_activated_flag = 1;
972 #ifdef USE_X_TOOLKIT
973 x_activate_timeout_atimer ();
974 #endif
976 #endif
978 /* This callback is invoked when a dialog or menu is finished being
979 used and has been unposted. */
981 #ifdef USE_GTK
982 static void
983 popup_deactivate_callback (widget, client_data)
984 GtkWidget *widget;
985 gpointer client_data;
987 popup_activated_flag = 0;
989 #else
990 static void
991 popup_deactivate_callback (widget, id, client_data)
992 Widget widget;
993 LWLIB_ID id;
994 XtPointer client_data;
996 popup_activated_flag = 0;
998 #endif
1001 /* Function that finds the frame for WIDGET and shows the HELP text
1002 for that widget.
1003 F is the frame if known, or NULL if not known. */
1004 static void
1005 show_help_event (f, widget, help)
1006 FRAME_PTR f;
1007 xt_or_gtk_widget widget;
1008 Lisp_Object help;
1010 Lisp_Object frame;
1012 if (f)
1014 XSETFRAME (frame, f);
1015 kbd_buffer_store_help_event (frame, help);
1017 else
1019 #if 0 /* This code doesn't do anything useful. ++kfs */
1020 /* WIDGET is the popup menu. It's parent is the frame's
1021 widget. See which frame that is. */
1022 xt_or_gtk_widget frame_widget = XtParent (widget);
1023 Lisp_Object tail;
1025 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
1027 frame = XCAR (tail);
1028 if (FRAMEP (frame)
1029 && (f = XFRAME (frame),
1030 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
1031 break;
1033 #endif
1034 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1038 /* Callback called when menu items are highlighted/unhighlighted
1039 while moving the mouse over them. WIDGET is the menu bar or menu
1040 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
1041 the data structure for the menu item, or null in case of
1042 unhighlighting. */
1044 #ifdef USE_GTK
1045 void
1046 menu_highlight_callback (widget, call_data)
1047 GtkWidget *widget;
1048 gpointer call_data;
1050 xg_menu_item_cb_data *cb_data;
1051 Lisp_Object help;
1053 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
1054 XG_ITEM_DATA);
1055 if (! cb_data) return;
1057 help = call_data ? cb_data->help : Qnil;
1059 /* If popup_activated_flag is greater than 1 we are in a popup menu.
1060 Don't show help for them, they won't appear before the
1061 popup is popped down. */
1062 if (popup_activated_flag <= 1)
1063 show_help_event (cb_data->cl_data->f, widget, help);
1065 #else
1066 void
1067 menu_highlight_callback (widget, id, call_data)
1068 Widget widget;
1069 LWLIB_ID id;
1070 void *call_data;
1072 struct frame *f;
1073 Lisp_Object help;
1075 widget_value *wv = (widget_value *) call_data;
1077 help = wv ? wv->help : Qnil;
1079 /* Determine the frame for the help event. */
1080 f = menubar_id_to_frame (id);
1082 show_help_event (f, widget, help);
1084 #endif
1086 #ifdef USE_GTK
1087 /* Gtk calls callbacks just because we tell it what item should be
1088 selected in a radio group. If this variable is set to a non-zero
1089 value, we are creating menus and don't want callbacks right now.
1091 static int xg_crazy_callback_abort;
1093 /* This callback is called from the menu bar pulldown menu
1094 when the user makes a selection.
1095 Figure out what the user chose
1096 and put the appropriate events into the keyboard buffer. */
1097 static void
1098 menubar_selection_callback (widget, client_data)
1099 GtkWidget *widget;
1100 gpointer client_data;
1102 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1104 if (xg_crazy_callback_abort)
1105 return;
1107 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
1108 return;
1110 /* For a group of radio buttons, GTK calls the selection callback first
1111 for the item that was active before the selection and then for the one that
1112 is active after the selection. For C-h k this means we get the help on
1113 the deselected item and then the selected item is executed. Prevent that
1114 by ignoring the non-active item. */
1115 if (GTK_IS_RADIO_MENU_ITEM (widget)
1116 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
1117 return;
1119 /* When a menu is popped down, X generates a focus event (i.e. focus
1120 goes back to the frame below the menu). Since GTK buffers events,
1121 we force it out here before the menu selection event. Otherwise
1122 sit-for will exit at once if the focus event follows the menu selection
1123 event. */
1125 BLOCK_INPUT;
1126 while (gtk_events_pending ())
1127 gtk_main_iteration ();
1128 UNBLOCK_INPUT;
1130 find_and_call_menu_selection (cb_data->cl_data->f,
1131 cb_data->cl_data->menu_bar_items_used,
1132 cb_data->cl_data->menu_bar_vector,
1133 cb_data->call_data);
1136 #else /* not USE_GTK */
1138 /* This callback is called from the menu bar pulldown menu
1139 when the user makes a selection.
1140 Figure out what the user chose
1141 and put the appropriate events into the keyboard buffer. */
1142 static void
1143 menubar_selection_callback (widget, id, client_data)
1144 Widget widget;
1145 LWLIB_ID id;
1146 XtPointer client_data;
1148 FRAME_PTR f;
1150 f = menubar_id_to_frame (id);
1151 if (!f)
1152 return;
1153 find_and_call_menu_selection (f, f->menu_bar_items_used,
1154 f->menu_bar_vector, client_data);
1156 #endif /* not USE_GTK */
1158 /* Recompute all the widgets of frame F, when the menu bar has been
1159 changed. Value is non-zero if widgets were updated. */
1161 static int
1162 update_frame_menubar (f)
1163 FRAME_PTR f;
1165 #ifdef USE_GTK
1166 return xg_update_frame_menubar (f);
1167 #else
1168 struct x_output *x;
1169 int columns, rows;
1171 if (! FRAME_X_P (f))
1172 abort ();
1174 x = f->output_data.x;
1176 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
1177 return 0;
1179 BLOCK_INPUT;
1180 /* Save the size of the frame because the pane widget doesn't accept
1181 to resize itself. So force it. */
1182 columns = FRAME_COLS (f);
1183 rows = FRAME_LINES (f);
1185 /* Do the voodoo which means "I'm changing lots of things, don't try
1186 to refigure sizes until I'm done." */
1187 lw_refigure_widget (x->column_widget, False);
1189 /* The order in which children are managed is the top to bottom
1190 order in which they are displayed in the paned window. First,
1191 remove the text-area widget. */
1192 XtUnmanageChild (x->edit_widget);
1194 /* Remove the menubar that is there now, and put up the menubar that
1195 should be there. */
1196 XtManageChild (x->menubar_widget);
1197 XtMapWidget (x->menubar_widget);
1198 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
1200 /* Re-manage the text-area widget, and then thrash the sizes. */
1201 XtManageChild (x->edit_widget);
1202 lw_refigure_widget (x->column_widget, True);
1204 /* Force the pane widget to resize itself with the right values. */
1205 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
1206 UNBLOCK_INPUT;
1207 #endif
1208 return 1;
1211 /* Set the contents of the menubar widgets of frame F.
1212 The argument FIRST_TIME is currently ignored;
1213 it is set the first time this is called, from initialize_frame_menubar. */
1215 void
1216 set_frame_menubar (f, first_time, deep_p)
1217 FRAME_PTR f;
1218 int first_time;
1219 int deep_p;
1221 xt_or_gtk_widget menubar_widget;
1222 #ifdef USE_X_TOOLKIT
1223 LWLIB_ID id;
1224 #endif
1225 Lisp_Object items;
1226 widget_value *wv, *first_wv, *prev_wv = 0;
1227 int i, last_i = 0;
1228 int *submenu_start, *submenu_end;
1229 int *submenu_top_level_items, *submenu_n_panes;
1231 if (! FRAME_X_P (f))
1232 abort ();
1234 menubar_widget = f->output_data.x->menubar_widget;
1236 XSETFRAME (Vmenu_updating_frame, f);
1238 #ifdef USE_X_TOOLKIT
1239 if (f->output_data.x->id == 0)
1240 f->output_data.x->id = next_menubar_widget_id++;
1241 id = f->output_data.x->id;
1242 #endif
1244 if (! menubar_widget)
1245 deep_p = 1;
1246 else if (pending_menu_activation && !deep_p)
1247 deep_p = 1;
1248 /* Make the first call for any given frame always go deep. */
1249 else if (!f->output_data.x->saved_menu_event && !deep_p)
1251 deep_p = 1;
1252 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
1253 f->output_data.x->saved_menu_event->type = 0;
1256 #ifdef USE_GTK
1257 /* If we have detached menus, we must update deep so detached menus
1258 also gets updated. */
1259 deep_p = deep_p || xg_have_tear_offs ();
1260 #endif
1262 if (deep_p)
1264 /* Make a widget-value tree representing the entire menu trees. */
1266 struct buffer *prev = current_buffer;
1267 Lisp_Object buffer;
1268 int specpdl_count = SPECPDL_INDEX ();
1269 int previous_menu_items_used = f->menu_bar_items_used;
1270 Lisp_Object *previous_items
1271 = (Lisp_Object *) alloca (previous_menu_items_used
1272 * sizeof (Lisp_Object));
1274 /* If we are making a new widget, its contents are empty,
1275 do always reinitialize them. */
1276 if (! menubar_widget)
1277 previous_menu_items_used = 0;
1279 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1280 specbind (Qinhibit_quit, Qt);
1281 /* Don't let the debugger step into this code
1282 because it is not reentrant. */
1283 specbind (Qdebug_on_next_call, Qnil);
1285 record_unwind_save_match_data ();
1286 if (NILP (Voverriding_local_map_menu_flag))
1288 specbind (Qoverriding_terminal_local_map, Qnil);
1289 specbind (Qoverriding_local_map, Qnil);
1292 set_buffer_internal_1 (XBUFFER (buffer));
1294 /* Run the Lucid hook. */
1295 safe_run_hooks (Qactivate_menubar_hook);
1297 /* If it has changed current-menubar from previous value,
1298 really recompute the menubar from the value. */
1299 if (! NILP (Vlucid_menu_bar_dirty_flag))
1300 call0 (Qrecompute_lucid_menubar);
1301 safe_run_hooks (Qmenu_bar_update_hook);
1302 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1304 items = FRAME_MENU_BAR_ITEMS (f);
1306 /* Save the frame's previous menu bar contents data. */
1307 if (previous_menu_items_used)
1308 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1309 previous_menu_items_used * sizeof (Lisp_Object));
1311 /* Fill in menu_items with the current menu bar contents.
1312 This can evaluate Lisp code. */
1313 save_menu_items ();
1315 menu_items = f->menu_bar_vector;
1316 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1317 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1318 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1319 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1320 submenu_top_level_items
1321 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1322 init_menu_items ();
1323 for (i = 0; i < XVECTOR (items)->size; i += 4)
1325 Lisp_Object key, string, maps;
1327 last_i = i;
1329 key = XVECTOR (items)->contents[i];
1330 string = XVECTOR (items)->contents[i + 1];
1331 maps = XVECTOR (items)->contents[i + 2];
1332 if (NILP (string))
1333 break;
1335 submenu_start[i] = menu_items_used;
1337 menu_items_n_panes = 0;
1338 submenu_top_level_items[i]
1339 = parse_single_submenu (key, string, maps);
1340 submenu_n_panes[i] = menu_items_n_panes;
1342 submenu_end[i] = menu_items_used;
1345 finish_menu_items ();
1347 /* Convert menu_items into widget_value trees
1348 to display the menu. This cannot evaluate Lisp code. */
1350 wv = xmalloc_widget_value ();
1351 wv->name = "menubar";
1352 wv->value = 0;
1353 wv->enabled = 1;
1354 wv->button_type = BUTTON_TYPE_NONE;
1355 wv->help = Qnil;
1356 first_wv = wv;
1358 for (i = 0; i < last_i; i += 4)
1360 menu_items_n_panes = submenu_n_panes[i];
1361 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1362 submenu_top_level_items[i]);
1363 if (prev_wv)
1364 prev_wv->next = wv;
1365 else
1366 first_wv->contents = wv;
1367 /* Don't set wv->name here; GC during the loop might relocate it. */
1368 wv->enabled = 1;
1369 wv->button_type = BUTTON_TYPE_NONE;
1370 prev_wv = wv;
1373 set_buffer_internal_1 (prev);
1375 /* If there has been no change in the Lisp-level contents
1376 of the menu bar, skip redisplaying it. Just exit. */
1378 /* Compare the new menu items with the ones computed last time. */
1379 for (i = 0; i < previous_menu_items_used; i++)
1380 if (menu_items_used == i
1381 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1382 break;
1383 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1385 /* The menu items have not changed. Don't bother updating
1386 the menus in any form, since it would be a no-op. */
1387 free_menubar_widget_value_tree (first_wv);
1388 discard_menu_items ();
1389 unbind_to (specpdl_count, Qnil);
1390 return;
1393 /* The menu items are different, so store them in the frame. */
1394 f->menu_bar_vector = menu_items;
1395 f->menu_bar_items_used = menu_items_used;
1397 /* This undoes save_menu_items. */
1398 unbind_to (specpdl_count, Qnil);
1400 /* Now GC cannot happen during the lifetime of the widget_value,
1401 so it's safe to store data from a Lisp_String. */
1402 wv = first_wv->contents;
1403 for (i = 0; i < XVECTOR (items)->size; i += 4)
1405 Lisp_Object string;
1406 string = XVECTOR (items)->contents[i + 1];
1407 if (NILP (string))
1408 break;
1409 wv->name = (char *) SDATA (string);
1410 update_submenu_strings (wv->contents);
1411 wv = wv->next;
1415 else
1417 /* Make a widget-value tree containing
1418 just the top level menu bar strings. */
1420 wv = xmalloc_widget_value ();
1421 wv->name = "menubar";
1422 wv->value = 0;
1423 wv->enabled = 1;
1424 wv->button_type = BUTTON_TYPE_NONE;
1425 wv->help = Qnil;
1426 first_wv = wv;
1428 items = FRAME_MENU_BAR_ITEMS (f);
1429 for (i = 0; i < XVECTOR (items)->size; i += 4)
1431 Lisp_Object string;
1433 string = XVECTOR (items)->contents[i + 1];
1434 if (NILP (string))
1435 break;
1437 wv = xmalloc_widget_value ();
1438 wv->name = (char *) SDATA (string);
1439 wv->value = 0;
1440 wv->enabled = 1;
1441 wv->button_type = BUTTON_TYPE_NONE;
1442 wv->help = Qnil;
1443 /* This prevents lwlib from assuming this
1444 menu item is really supposed to be empty. */
1445 /* The EMACS_INT cast avoids a warning.
1446 This value just has to be different from small integers. */
1447 wv->call_data = (void *) (EMACS_INT) (-1);
1449 if (prev_wv)
1450 prev_wv->next = wv;
1451 else
1452 first_wv->contents = wv;
1453 prev_wv = wv;
1456 /* Forget what we thought we knew about what is in the
1457 detailed contents of the menu bar menus.
1458 Changing the top level always destroys the contents. */
1459 f->menu_bar_items_used = 0;
1462 /* Create or update the menu bar widget. */
1464 BLOCK_INPUT;
1466 #ifdef USE_GTK
1467 xg_crazy_callback_abort = 1;
1468 if (menubar_widget)
1470 /* The fourth arg is DEEP_P, which says to consider the entire
1471 menu trees we supply, rather than just the menu bar item names. */
1472 xg_modify_menubar_widgets (menubar_widget,
1474 first_wv,
1475 deep_p,
1476 G_CALLBACK (menubar_selection_callback),
1477 G_CALLBACK (popup_deactivate_callback),
1478 G_CALLBACK (menu_highlight_callback));
1480 else
1482 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1484 menubar_widget
1485 = xg_create_widget ("menubar", "menubar", f, first_wv,
1486 G_CALLBACK (menubar_selection_callback),
1487 G_CALLBACK (popup_deactivate_callback),
1488 G_CALLBACK (menu_highlight_callback));
1490 f->output_data.x->menubar_widget = menubar_widget;
1494 #else /* not USE_GTK */
1495 if (menubar_widget)
1497 /* Disable resizing (done for Motif!) */
1498 lw_allow_resizing (f->output_data.x->widget, False);
1500 /* The third arg is DEEP_P, which says to consider the entire
1501 menu trees we supply, rather than just the menu bar item names. */
1502 lw_modify_all_widgets (id, first_wv, deep_p);
1504 /* Re-enable the edit widget to resize. */
1505 lw_allow_resizing (f->output_data.x->widget, True);
1507 else
1509 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1510 XtTranslations override = XtParseTranslationTable (menuOverride);
1512 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1513 f->output_data.x->column_widget,
1515 popup_activate_callback,
1516 menubar_selection_callback,
1517 popup_deactivate_callback,
1518 menu_highlight_callback);
1519 f->output_data.x->menubar_widget = menubar_widget;
1521 /* Make menu pop down on C-g. */
1522 XtOverrideTranslations (menubar_widget, override);
1526 int menubar_size
1527 = (f->output_data.x->menubar_widget
1528 ? (f->output_data.x->menubar_widget->core.height
1529 + f->output_data.x->menubar_widget->core.border_width)
1530 : 0);
1532 #if 0 /* Experimentally, we now get the right results
1533 for -geometry -0-0 without this. 24 Aug 96, rms. */
1534 #ifdef USE_LUCID
1535 if (FRAME_EXTERNAL_MENU_BAR (f))
1537 Dimension ibw = 0;
1538 XtVaGetValues (f->output_data.x->column_widget,
1539 XtNinternalBorderWidth, &ibw, NULL);
1540 menubar_size += ibw;
1542 #endif /* USE_LUCID */
1543 #endif /* 0 */
1545 f->output_data.x->menubar_height = menubar_size;
1547 #endif /* not USE_GTK */
1549 free_menubar_widget_value_tree (first_wv);
1550 update_frame_menubar (f);
1552 #ifdef USE_GTK
1553 xg_crazy_callback_abort = 0;
1554 #endif
1556 UNBLOCK_INPUT;
1559 /* Called from Fx_create_frame to create the initial menubar of a frame
1560 before it is mapped, so that the window is mapped with the menubar already
1561 there instead of us tacking it on later and thrashing the window after it
1562 is visible. */
1564 void
1565 initialize_frame_menubar (f)
1566 FRAME_PTR f;
1568 /* This function is called before the first chance to redisplay
1569 the frame. It has to be, so the frame will have the right size. */
1570 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1571 set_frame_menubar (f, 1, 1);
1575 /* Get rid of the menu bar of frame F, and free its storage.
1576 This is used when deleting a frame, and when turning off the menu bar.
1577 For GTK this function is in gtkutil.c. */
1579 #ifndef USE_GTK
1580 void
1581 free_frame_menubar (f)
1582 FRAME_PTR f;
1584 Widget menubar_widget;
1586 if (! FRAME_X_P (f))
1587 abort ();
1589 menubar_widget = f->output_data.x->menubar_widget;
1591 f->output_data.x->menubar_height = 0;
1593 if (menubar_widget)
1595 #ifdef USE_MOTIF
1596 /* Removing the menu bar magically changes the shell widget's x
1597 and y position of (0, 0) which, when the menu bar is turned
1598 on again, leads to pull-down menuss appearing in strange
1599 positions near the upper-left corner of the display. This
1600 happens only with some window managers like twm and ctwm,
1601 but not with other like Motif's mwm or kwm, because the
1602 latter generate ConfigureNotify events when the menu bar
1603 is switched off, which fixes the shell position. */
1604 Position x0, y0, x1, y1;
1605 #endif
1607 BLOCK_INPUT;
1609 #ifdef USE_MOTIF
1610 if (f->output_data.x->widget)
1611 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1612 #endif
1614 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1615 f->output_data.x->menubar_widget = NULL;
1617 #ifdef USE_MOTIF
1618 if (f->output_data.x->widget)
1620 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1621 if (x1 == 0 && y1 == 0)
1622 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1624 #endif
1626 UNBLOCK_INPUT;
1629 #endif /* not USE_GTK */
1631 #endif /* USE_X_TOOLKIT || USE_GTK */
1633 /* xmenu_show actually displays a menu using the panes and items in menu_items
1634 and returns the value selected from it.
1635 There are two versions of xmenu_show, one for Xt and one for Xlib.
1636 Both assume input is blocked by the caller. */
1638 /* F is the frame the menu is for.
1639 X and Y are the frame-relative specified position,
1640 relative to the inside upper left corner of the frame F.
1641 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1642 KEYMAPS is 1 if this menu was specified with keymaps;
1643 in that case, we return a list containing the chosen item's value
1644 and perhaps also the pane's prefix.
1645 TITLE is the specified menu title.
1646 ERROR is a place to store an error message string in case of failure.
1647 (We return nil on failure, but the value doesn't actually matter.) */
1649 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1651 /* The item selected in the popup menu. */
1652 static Lisp_Object *volatile menu_item_selection;
1654 #ifdef USE_GTK
1656 /* Used when position a popup menu. See menu_position_func and
1657 create_and_show_popup_menu below. */
1658 struct next_popup_x_y
1660 FRAME_PTR f;
1661 int x;
1662 int y;
1665 /* The menu position function to use if we are not putting a popup
1666 menu where the pointer is.
1667 MENU is the menu to pop up.
1668 X and Y shall on exit contain x/y where the menu shall pop up.
1669 PUSH_IN is not documented in the GTK manual.
1670 USER_DATA is any data passed in when calling gtk_menu_popup.
1671 Here it points to a struct next_popup_x_y where the coordinates
1672 to store in *X and *Y are as well as the frame for the popup.
1674 Here only X and Y are used. */
1675 static void
1676 menu_position_func (menu, x, y, push_in, user_data)
1677 GtkMenu *menu;
1678 gint *x;
1679 gint *y;
1680 gboolean *push_in;
1681 gpointer user_data;
1683 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1684 GtkRequisition req;
1685 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width;
1686 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height;
1688 *x = data->x;
1689 *y = data->y;
1691 /* Check if there is room for the menu. If not, adjust x/y so that
1692 the menu is fully visible. */
1693 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1694 if (data->x + req.width > disp_width)
1695 *x -= data->x + req.width - disp_width;
1696 if (data->y + req.height > disp_height)
1697 *y -= data->y + req.height - disp_height;
1700 static void
1701 popup_selection_callback (widget, client_data)
1702 GtkWidget *widget;
1703 gpointer client_data;
1705 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1707 if (xg_crazy_callback_abort) return;
1708 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1711 static Lisp_Object
1712 pop_down_menu (arg)
1713 Lisp_Object arg;
1715 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1717 popup_activated_flag = 0;
1718 BLOCK_INPUT;
1719 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1720 UNBLOCK_INPUT;
1721 return Qnil;
1724 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1725 menu pops down.
1726 menu_item_selection will be set to the selection. */
1727 static void
1728 create_and_show_popup_menu (f, first_wv, x, y, for_click)
1729 FRAME_PTR f;
1730 widget_value *first_wv;
1731 int x;
1732 int y;
1733 int for_click;
1735 int i;
1736 GtkWidget *menu;
1737 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1738 struct next_popup_x_y popup_x_y;
1739 int specpdl_count = SPECPDL_INDEX ();
1741 if (! FRAME_X_P (f))
1742 abort ();
1744 xg_crazy_callback_abort = 1;
1745 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1746 G_CALLBACK (popup_selection_callback),
1747 G_CALLBACK (popup_deactivate_callback),
1748 G_CALLBACK (menu_highlight_callback));
1749 xg_crazy_callback_abort = 0;
1751 if (! for_click)
1753 /* Not invoked by a click. pop up at x/y. */
1754 pos_func = menu_position_func;
1756 /* Adjust coordinates to be root-window-relative. */
1757 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1758 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1760 popup_x_y.x = x;
1761 popup_x_y.y = y;
1762 popup_x_y.f = f;
1764 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1766 else
1768 for (i = 0; i < 5; i++)
1769 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1770 break;
1773 /* Display the menu. */
1774 gtk_widget_show_all (menu);
1775 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
1777 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1779 if (GTK_WIDGET_MAPPED (menu))
1781 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1782 two. show_help_echo uses this to detect popup menus. */
1783 popup_activated_flag = 1;
1784 /* Process events that apply to the menu. */
1785 popup_widget_loop (1, menu);
1788 unbind_to (specpdl_count, Qnil);
1790 /* Must reset this manually because the button release event is not passed
1791 to Emacs event loop. */
1792 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1795 #else /* not USE_GTK */
1797 /* We need a unique id for each widget handled by the Lucid Widget
1798 library.
1800 For the main windows, and popup menus, we use this counter,
1801 which we increment each time after use. This starts from 1<<16.
1803 For menu bars, we use numbers starting at 0, counted in
1804 next_menubar_widget_id. */
1805 LWLIB_ID widget_id_tick;
1807 static void
1808 popup_selection_callback (widget, id, client_data)
1809 Widget widget;
1810 LWLIB_ID id;
1811 XtPointer client_data;
1813 menu_item_selection = (Lisp_Object *) client_data;
1816 /* ARG is the LWLIB ID of the dialog box, represented
1817 as a Lisp object as (HIGHPART . LOWPART). */
1819 static Lisp_Object
1820 pop_down_menu (arg)
1821 Lisp_Object arg;
1823 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1824 | XINT (XCDR (arg)));
1826 BLOCK_INPUT;
1827 lw_destroy_all_widgets (id);
1828 UNBLOCK_INPUT;
1829 popup_activated_flag = 0;
1831 return Qnil;
1834 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1835 menu pops down.
1836 menu_item_selection will be set to the selection. */
1837 static void
1838 create_and_show_popup_menu (f, first_wv, x, y, for_click)
1839 FRAME_PTR f;
1840 widget_value *first_wv;
1841 int x;
1842 int y;
1843 int for_click;
1845 int i;
1846 Arg av[2];
1847 int ac = 0;
1848 XButtonPressedEvent dummy;
1849 LWLIB_ID menu_id;
1850 Widget menu;
1852 if (! FRAME_X_P (f))
1853 abort ();
1855 menu_id = widget_id_tick++;
1856 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1857 f->output_data.x->widget, 1, 0,
1858 popup_selection_callback,
1859 popup_deactivate_callback,
1860 menu_highlight_callback);
1862 dummy.type = ButtonPress;
1863 dummy.serial = 0;
1864 dummy.send_event = 0;
1865 dummy.display = FRAME_X_DISPLAY (f);
1866 dummy.time = CurrentTime;
1867 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1868 dummy.window = dummy.root;
1869 dummy.subwindow = dummy.root;
1870 dummy.x = x;
1871 dummy.y = y;
1873 /* Adjust coordinates to be root-window-relative. */
1874 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1875 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1877 dummy.x_root = x;
1878 dummy.y_root = y;
1880 dummy.state = 0;
1881 dummy.button = 0;
1882 for (i = 0; i < 5; i++)
1883 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1884 dummy.button = i;
1886 /* Don't allow any geometry request from the user. */
1887 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1888 XtSetValues (menu, av, ac);
1890 /* Display the menu. */
1891 lw_popup_menu (menu, (XEvent *) &dummy);
1892 popup_activated_flag = 1;
1893 x_activate_timeout_atimer ();
1896 int fact = 4 * sizeof (LWLIB_ID);
1897 int specpdl_count = SPECPDL_INDEX ();
1898 record_unwind_protect (pop_down_menu,
1899 Fcons (make_number (menu_id >> (fact)),
1900 make_number (menu_id & ~(-1 << (fact)))));
1902 /* Process events that apply to the menu. */
1903 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1905 unbind_to (specpdl_count, Qnil);
1909 #endif /* not USE_GTK */
1911 static Lisp_Object
1912 xmenu_show (f, x, y, for_click, keymaps, title, error)
1913 FRAME_PTR f;
1914 int x;
1915 int y;
1916 int for_click;
1917 int keymaps;
1918 Lisp_Object title;
1919 char **error;
1921 int i;
1922 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1923 widget_value **submenu_stack
1924 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1925 Lisp_Object *subprefix_stack
1926 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1927 int submenu_depth = 0;
1929 int first_pane;
1931 if (! FRAME_X_P (f))
1932 abort ();
1934 *error = NULL;
1936 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1938 *error = "Empty menu";
1939 return Qnil;
1942 /* Create a tree of widget_value objects
1943 representing the panes and their items. */
1944 wv = xmalloc_widget_value ();
1945 wv->name = "menu";
1946 wv->value = 0;
1947 wv->enabled = 1;
1948 wv->button_type = BUTTON_TYPE_NONE;
1949 wv->help =Qnil;
1950 first_wv = wv;
1951 first_pane = 1;
1953 /* Loop over all panes and items, filling in the tree. */
1954 i = 0;
1955 while (i < menu_items_used)
1957 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1959 submenu_stack[submenu_depth++] = save_wv;
1960 save_wv = prev_wv;
1961 prev_wv = 0;
1962 first_pane = 1;
1963 i++;
1965 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1967 prev_wv = save_wv;
1968 save_wv = submenu_stack[--submenu_depth];
1969 first_pane = 0;
1970 i++;
1972 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1973 && submenu_depth != 0)
1974 i += MENU_ITEMS_PANE_LENGTH;
1975 /* Ignore a nil in the item list.
1976 It's meaningful only for dialog boxes. */
1977 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1978 i += 1;
1979 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1981 /* Create a new pane. */
1982 Lisp_Object pane_name, prefix;
1983 char *pane_string;
1985 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1986 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1988 #ifndef HAVE_MULTILINGUAL_MENU
1989 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1991 pane_name = ENCODE_MENU_STRING (pane_name);
1992 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1994 #endif
1995 pane_string = (NILP (pane_name)
1996 ? "" : (char *) SDATA (pane_name));
1997 /* If there is just one top-level pane, put all its items directly
1998 under the top-level menu. */
1999 if (menu_items_n_panes == 1)
2000 pane_string = "";
2002 /* If the pane has a meaningful name,
2003 make the pane a top-level menu item
2004 with its items as a submenu beneath it. */
2005 if (!keymaps && strcmp (pane_string, ""))
2007 wv = xmalloc_widget_value ();
2008 if (save_wv)
2009 save_wv->next = wv;
2010 else
2011 first_wv->contents = wv;
2012 wv->name = pane_string;
2013 if (keymaps && !NILP (prefix))
2014 wv->name++;
2015 wv->value = 0;
2016 wv->enabled = 1;
2017 wv->button_type = BUTTON_TYPE_NONE;
2018 wv->help = Qnil;
2019 save_wv = wv;
2020 prev_wv = 0;
2022 else if (first_pane)
2024 save_wv = wv;
2025 prev_wv = 0;
2027 first_pane = 0;
2028 i += MENU_ITEMS_PANE_LENGTH;
2030 else
2032 /* Create a new item within current pane. */
2033 Lisp_Object item_name, enable, descrip, def, type, selected, help;
2034 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2035 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2036 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2037 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
2038 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
2039 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
2040 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2042 #ifndef HAVE_MULTILINGUAL_MENU
2043 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
2045 item_name = ENCODE_MENU_STRING (item_name);
2046 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
2049 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2051 descrip = ENCODE_MENU_STRING (descrip);
2052 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
2054 #endif /* not HAVE_MULTILINGUAL_MENU */
2056 wv = xmalloc_widget_value ();
2057 if (prev_wv)
2058 prev_wv->next = wv;
2059 else
2060 save_wv->contents = wv;
2061 wv->name = (char *) SDATA (item_name);
2062 if (!NILP (descrip))
2063 wv->key = (char *) SDATA (descrip);
2064 wv->value = 0;
2065 /* If this item has a null value,
2066 make the call_data null so that it won't display a box
2067 when the mouse is on it. */
2068 wv->call_data
2069 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
2070 wv->enabled = !NILP (enable);
2072 if (NILP (type))
2073 wv->button_type = BUTTON_TYPE_NONE;
2074 else if (EQ (type, QCtoggle))
2075 wv->button_type = BUTTON_TYPE_TOGGLE;
2076 else if (EQ (type, QCradio))
2077 wv->button_type = BUTTON_TYPE_RADIO;
2078 else
2079 abort ();
2081 wv->selected = !NILP (selected);
2083 if (! STRINGP (help))
2084 help = Qnil;
2086 wv->help = help;
2088 prev_wv = wv;
2090 i += MENU_ITEMS_ITEM_LENGTH;
2094 /* Deal with the title, if it is non-nil. */
2095 if (!NILP (title))
2097 widget_value *wv_title = xmalloc_widget_value ();
2098 widget_value *wv_sep1 = xmalloc_widget_value ();
2099 widget_value *wv_sep2 = xmalloc_widget_value ();
2101 wv_sep2->name = "--";
2102 wv_sep2->next = first_wv->contents;
2103 wv_sep2->help = Qnil;
2105 wv_sep1->name = "--";
2106 wv_sep1->next = wv_sep2;
2107 wv_sep1->help = Qnil;
2109 #ifndef HAVE_MULTILINGUAL_MENU
2110 if (STRING_MULTIBYTE (title))
2111 title = ENCODE_MENU_STRING (title);
2112 #endif
2114 wv_title->name = (char *) SDATA (title);
2115 wv_title->enabled = TRUE;
2116 wv_title->button_type = BUTTON_TYPE_NONE;
2117 wv_title->help = Qnil;
2118 wv_title->next = wv_sep1;
2119 first_wv->contents = wv_title;
2122 /* No selection has been chosen yet. */
2123 menu_item_selection = 0;
2125 /* Actually create and show the menu until popped down. */
2126 create_and_show_popup_menu (f, first_wv, x, y, for_click);
2128 /* Free the widget_value objects we used to specify the contents. */
2129 free_menubar_widget_value_tree (first_wv);
2131 /* Find the selected item, and its pane, to return
2132 the proper value. */
2133 if (menu_item_selection != 0)
2135 Lisp_Object prefix, entry;
2137 prefix = entry = Qnil;
2138 i = 0;
2139 while (i < menu_items_used)
2141 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
2143 subprefix_stack[submenu_depth++] = prefix;
2144 prefix = entry;
2145 i++;
2147 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
2149 prefix = subprefix_stack[--submenu_depth];
2150 i++;
2152 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2154 prefix
2155 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2156 i += MENU_ITEMS_PANE_LENGTH;
2158 /* Ignore a nil in the item list.
2159 It's meaningful only for dialog boxes. */
2160 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2161 i += 1;
2162 else
2164 entry
2165 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2166 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2168 if (keymaps != 0)
2170 int j;
2172 entry = Fcons (entry, Qnil);
2173 if (!NILP (prefix))
2174 entry = Fcons (prefix, entry);
2175 for (j = submenu_depth - 1; j >= 0; j--)
2176 if (!NILP (subprefix_stack[j]))
2177 entry = Fcons (subprefix_stack[j], entry);
2179 return entry;
2181 i += MENU_ITEMS_ITEM_LENGTH;
2185 else if (!for_click)
2186 /* Make "Cancel" equivalent to C-g. */
2187 Fsignal (Qquit, Qnil);
2189 return Qnil;
2192 #ifdef USE_GTK
2193 static void
2194 dialog_selection_callback (widget, client_data)
2195 GtkWidget *widget;
2196 gpointer client_data;
2198 /* The EMACS_INT cast avoids a warning. There's no problem
2199 as long as pointers have enough bits to hold small integers. */
2200 if ((int) (EMACS_INT) client_data != -1)
2201 menu_item_selection = (Lisp_Object *) client_data;
2203 popup_activated_flag = 0;
2206 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2207 dialog pops down.
2208 menu_item_selection will be set to the selection. */
2209 static void
2210 create_and_show_dialog (f, first_wv)
2211 FRAME_PTR f;
2212 widget_value *first_wv;
2214 GtkWidget *menu;
2216 if (! FRAME_X_P (f))
2217 abort ();
2219 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2220 G_CALLBACK (dialog_selection_callback),
2221 G_CALLBACK (popup_deactivate_callback),
2224 if (menu)
2226 int specpdl_count = SPECPDL_INDEX ();
2227 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
2229 /* Display the menu. */
2230 gtk_widget_show_all (menu);
2232 /* Process events that apply to the menu. */
2233 popup_widget_loop (1, menu);
2235 unbind_to (specpdl_count, Qnil);
2239 #else /* not USE_GTK */
2240 static void
2241 dialog_selection_callback (widget, id, client_data)
2242 Widget widget;
2243 LWLIB_ID id;
2244 XtPointer client_data;
2246 /* The EMACS_INT cast avoids a warning. There's no problem
2247 as long as pointers have enough bits to hold small integers. */
2248 if ((int) (EMACS_INT) client_data != -1)
2249 menu_item_selection = (Lisp_Object *) client_data;
2251 BLOCK_INPUT;
2252 lw_destroy_all_widgets (id);
2253 UNBLOCK_INPUT;
2254 popup_activated_flag = 0;
2258 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2259 dialog pops down.
2260 menu_item_selection will be set to the selection. */
2261 static void
2262 create_and_show_dialog (f, first_wv)
2263 FRAME_PTR f;
2264 widget_value *first_wv;
2266 LWLIB_ID dialog_id;
2268 if (!FRAME_X_P (f))
2269 abort();
2271 dialog_id = widget_id_tick++;
2272 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2273 f->output_data.x->widget, 1, 0,
2274 dialog_selection_callback, 0, 0);
2275 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2277 /* Display the dialog box. */
2278 lw_pop_up_all_widgets (dialog_id);
2279 popup_activated_flag = 1;
2280 x_activate_timeout_atimer ();
2282 /* Process events that apply to the dialog box.
2283 Also handle timers. */
2285 int count = SPECPDL_INDEX ();
2286 int fact = 4 * sizeof (LWLIB_ID);
2288 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2289 record_unwind_protect (pop_down_menu,
2290 Fcons (make_number (dialog_id >> (fact)),
2291 make_number (dialog_id & ~(-1 << (fact)))));
2293 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2294 dialog_id, 1);
2296 unbind_to (count, Qnil);
2300 #endif /* not USE_GTK */
2302 static char * button_names [] = {
2303 "button1", "button2", "button3", "button4", "button5",
2304 "button6", "button7", "button8", "button9", "button10" };
2306 static Lisp_Object
2307 xdialog_show (f, keymaps, title, header, error_name)
2308 FRAME_PTR f;
2309 int keymaps;
2310 Lisp_Object title, header;
2311 char **error_name;
2313 int i, nb_buttons=0;
2314 char dialog_name[6];
2316 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2318 /* Number of elements seen so far, before boundary. */
2319 int left_count = 0;
2320 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2321 int boundary_seen = 0;
2323 if (! FRAME_X_P (f))
2324 abort ();
2326 *error_name = NULL;
2328 if (menu_items_n_panes > 1)
2330 *error_name = "Multiple panes in dialog box";
2331 return Qnil;
2334 /* Create a tree of widget_value objects
2335 representing the text label and buttons. */
2337 Lisp_Object pane_name, prefix;
2338 char *pane_string;
2339 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2340 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2341 pane_string = (NILP (pane_name)
2342 ? "" : (char *) SDATA (pane_name));
2343 prev_wv = xmalloc_widget_value ();
2344 prev_wv->value = pane_string;
2345 if (keymaps && !NILP (prefix))
2346 prev_wv->name++;
2347 prev_wv->enabled = 1;
2348 prev_wv->name = "message";
2349 prev_wv->help = Qnil;
2350 first_wv = prev_wv;
2352 /* Loop over all panes and items, filling in the tree. */
2353 i = MENU_ITEMS_PANE_LENGTH;
2354 while (i < menu_items_used)
2357 /* Create a new item within current pane. */
2358 Lisp_Object item_name, enable, descrip;
2359 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2360 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2361 descrip
2362 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2364 if (NILP (item_name))
2366 free_menubar_widget_value_tree (first_wv);
2367 *error_name = "Submenu in dialog items";
2368 return Qnil;
2370 if (EQ (item_name, Qquote))
2372 /* This is the boundary between left-side elts
2373 and right-side elts. Stop incrementing right_count. */
2374 boundary_seen = 1;
2375 i++;
2376 continue;
2378 if (nb_buttons >= 9)
2380 free_menubar_widget_value_tree (first_wv);
2381 *error_name = "Too many dialog items";
2382 return Qnil;
2385 wv = xmalloc_widget_value ();
2386 prev_wv->next = wv;
2387 wv->name = (char *) button_names[nb_buttons];
2388 if (!NILP (descrip))
2389 wv->key = (char *) SDATA (descrip);
2390 wv->value = (char *) SDATA (item_name);
2391 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2392 wv->enabled = !NILP (enable);
2393 wv->help = Qnil;
2394 prev_wv = wv;
2396 if (! boundary_seen)
2397 left_count++;
2399 nb_buttons++;
2400 i += MENU_ITEMS_ITEM_LENGTH;
2403 /* If the boundary was not specified,
2404 by default put half on the left and half on the right. */
2405 if (! boundary_seen)
2406 left_count = nb_buttons - nb_buttons / 2;
2408 wv = xmalloc_widget_value ();
2409 wv->name = dialog_name;
2410 wv->help = Qnil;
2412 /* Frame title: 'Q' = Question, 'I' = Information.
2413 Can also have 'E' = Error if, one day, we want
2414 a popup for errors. */
2415 if (NILP(header))
2416 dialog_name[0] = 'Q';
2417 else
2418 dialog_name[0] = 'I';
2420 /* Dialog boxes use a really stupid name encoding
2421 which specifies how many buttons to use
2422 and how many buttons are on the right. */
2423 dialog_name[1] = '0' + nb_buttons;
2424 dialog_name[2] = 'B';
2425 dialog_name[3] = 'R';
2426 /* Number of buttons to put on the right. */
2427 dialog_name[4] = '0' + nb_buttons - left_count;
2428 dialog_name[5] = 0;
2429 wv->contents = first_wv;
2430 first_wv = wv;
2433 /* No selection has been chosen yet. */
2434 menu_item_selection = 0;
2436 /* Force a redisplay before showing the dialog. If a frame is created
2437 just before showing the dialog, its contents may not have been fully
2438 drawn, as this depends on timing of events from the X server. Redisplay
2439 is not done when a dialog is shown. If redisplay could be done in the
2440 X event loop (i.e. the X event loop does not run in a signal handler)
2441 this would not be needed. */
2442 Fredisplay (Qt);
2444 /* Actually create and show the dialog. */
2445 create_and_show_dialog (f, first_wv);
2447 /* Free the widget_value objects we used to specify the contents. */
2448 free_menubar_widget_value_tree (first_wv);
2450 /* Find the selected item, and its pane, to return
2451 the proper value. */
2452 if (menu_item_selection != 0)
2454 Lisp_Object prefix;
2456 prefix = Qnil;
2457 i = 0;
2458 while (i < menu_items_used)
2460 Lisp_Object entry;
2462 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2464 prefix
2465 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2466 i += MENU_ITEMS_PANE_LENGTH;
2468 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2470 /* This is the boundary between left-side elts and
2471 right-side elts. */
2472 ++i;
2474 else
2476 entry
2477 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2478 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2480 if (keymaps != 0)
2482 entry = Fcons (entry, Qnil);
2483 if (!NILP (prefix))
2484 entry = Fcons (prefix, entry);
2486 return entry;
2488 i += MENU_ITEMS_ITEM_LENGTH;
2492 else
2493 /* Make "Cancel" equivalent to C-g. */
2494 Fsignal (Qquit, Qnil);
2496 return Qnil;
2499 #else /* not USE_X_TOOLKIT && not USE_GTK */
2501 /* The frame of the last activated non-toolkit menu bar.
2502 Used to generate menu help events. */
2504 static struct frame *menu_help_frame;
2507 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2509 PANE is the pane number, and ITEM is the menu item number in
2510 the menu (currently not used).
2512 This cannot be done with generating a HELP_EVENT because
2513 XMenuActivate contains a loop that doesn't let Emacs process
2514 keyboard events. */
2516 static void
2517 menu_help_callback (help_string, pane, item)
2518 char *help_string;
2519 int pane, item;
2521 extern Lisp_Object Qmenu_item;
2522 Lisp_Object *first_item;
2523 Lisp_Object pane_name;
2524 Lisp_Object menu_object;
2526 first_item = XVECTOR (menu_items)->contents;
2527 if (EQ (first_item[0], Qt))
2528 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2529 else if (EQ (first_item[0], Qquote))
2530 /* This shouldn't happen, see xmenu_show. */
2531 pane_name = empty_unibyte_string;
2532 else
2533 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2535 /* (menu-item MENU-NAME PANE-NUMBER) */
2536 menu_object = Fcons (Qmenu_item,
2537 Fcons (pane_name,
2538 Fcons (make_number (pane), Qnil)));
2539 show_help_echo (help_string ? build_string (help_string) : Qnil,
2540 Qnil, menu_object, make_number (item), 1);
2543 static Lisp_Object
2544 pop_down_menu (arg)
2545 Lisp_Object arg;
2547 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2548 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2550 FRAME_PTR f = p1->pointer;
2551 XMenu *menu = p2->pointer;
2553 BLOCK_INPUT;
2554 #ifndef MSDOS
2555 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2556 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2557 #endif
2558 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2560 #ifdef HAVE_X_WINDOWS
2561 /* Assume the mouse has moved out of the X window.
2562 If it has actually moved in, we will get an EnterNotify. */
2563 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2565 /* State that no mouse buttons are now held.
2566 (The oldXMenu code doesn't track this info for us.)
2567 That is not necessarily true, but the fiction leads to reasonable
2568 results, and it is a pain to ask which are actually held now. */
2569 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2571 #endif /* HAVE_X_WINDOWS */
2573 UNBLOCK_INPUT;
2575 return Qnil;
2579 static Lisp_Object
2580 xmenu_show (f, x, y, for_click, keymaps, title, error)
2581 FRAME_PTR f;
2582 int x, y;
2583 int for_click;
2584 int keymaps;
2585 Lisp_Object title;
2586 char **error;
2588 Window root;
2589 XMenu *menu;
2590 int pane, selidx, lpane, status;
2591 Lisp_Object entry, pane_prefix;
2592 char *datap;
2593 int ulx, uly, width, height;
2594 int dispwidth, dispheight;
2595 int i, j, lines, maxlines;
2596 int maxwidth;
2597 int dummy_int;
2598 unsigned int dummy_uint;
2599 int specpdl_count = SPECPDL_INDEX ();
2601 if (! FRAME_X_P (f))
2602 abort ();
2604 *error = 0;
2605 if (menu_items_n_panes == 0)
2606 return Qnil;
2608 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2610 *error = "Empty menu";
2611 return Qnil;
2614 /* Figure out which root window F is on. */
2615 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2616 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2617 &dummy_uint, &dummy_uint);
2619 /* Make the menu on that window. */
2620 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2621 if (menu == NULL)
2623 *error = "Can't create menu";
2624 return Qnil;
2627 /* Don't GC while we prepare and show the menu,
2628 because we give the oldxmenu library pointers to the
2629 contents of strings. */
2630 inhibit_garbage_collection ();
2632 #ifdef HAVE_X_WINDOWS
2633 /* Adjust coordinates to relative to the outer (window manager) window. */
2634 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2635 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2636 #endif /* HAVE_X_WINDOWS */
2638 /* Adjust coordinates to be root-window-relative. */
2639 x += f->left_pos;
2640 y += f->top_pos;
2642 /* Create all the necessary panes and their items. */
2643 maxlines = lines = i = 0;
2644 while (i < menu_items_used)
2646 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2648 /* Create a new pane. */
2649 Lisp_Object pane_name, prefix;
2650 char *pane_string;
2652 maxlines = max (maxlines, lines);
2653 lines = 0;
2654 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2655 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2656 pane_string = (NILP (pane_name)
2657 ? "" : (char *) SDATA (pane_name));
2658 if (keymaps && !NILP (prefix))
2659 pane_string++;
2661 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2662 if (lpane == XM_FAILURE)
2664 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2665 *error = "Can't create pane";
2666 return Qnil;
2668 i += MENU_ITEMS_PANE_LENGTH;
2670 /* Find the width of the widest item in this pane. */
2671 maxwidth = 0;
2672 j = i;
2673 while (j < menu_items_used)
2675 Lisp_Object item;
2676 item = XVECTOR (menu_items)->contents[j];
2677 if (EQ (item, Qt))
2678 break;
2679 if (NILP (item))
2681 j++;
2682 continue;
2684 width = SBYTES (item);
2685 if (width > maxwidth)
2686 maxwidth = width;
2688 j += MENU_ITEMS_ITEM_LENGTH;
2691 /* Ignore a nil in the item list.
2692 It's meaningful only for dialog boxes. */
2693 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2694 i += 1;
2695 else
2697 /* Create a new item within current pane. */
2698 Lisp_Object item_name, enable, descrip, help;
2699 unsigned char *item_data;
2700 char *help_string;
2702 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2703 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2704 descrip
2705 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2706 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2707 help_string = STRINGP (help) ? SDATA (help) : NULL;
2709 if (!NILP (descrip))
2711 int gap = maxwidth - SBYTES (item_name);
2712 /* if alloca is fast, use that to make the space,
2713 to reduce gc needs. */
2714 item_data
2715 = (unsigned char *) alloca (maxwidth
2716 + SBYTES (descrip) + 1);
2717 bcopy (SDATA (item_name), item_data,
2718 SBYTES (item_name));
2719 for (j = SCHARS (item_name); j < maxwidth; j++)
2720 item_data[j] = ' ';
2721 bcopy (SDATA (descrip), item_data + j,
2722 SBYTES (descrip));
2723 item_data[j + SBYTES (descrip)] = 0;
2725 else
2726 item_data = SDATA (item_name);
2728 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2729 menu, lpane, 0, item_data,
2730 !NILP (enable), help_string)
2731 == XM_FAILURE)
2733 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2734 *error = "Can't add selection to menu";
2735 return Qnil;
2737 i += MENU_ITEMS_ITEM_LENGTH;
2738 lines++;
2742 maxlines = max (maxlines, lines);
2744 /* All set and ready to fly. */
2745 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2746 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2747 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2748 x = min (x, dispwidth);
2749 y = min (y, dispheight);
2750 x = max (x, 1);
2751 y = max (y, 1);
2752 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2753 &ulx, &uly, &width, &height);
2754 if (ulx+width > dispwidth)
2756 x -= (ulx + width) - dispwidth;
2757 ulx = dispwidth - width;
2759 if (uly+height > dispheight)
2761 y -= (uly + height) - dispheight;
2762 uly = dispheight - height;
2764 if (ulx < 0) x -= ulx;
2765 if (uly < 0) y -= uly;
2767 if (! for_click)
2769 /* If position was not given by a mouse click, adjust so upper left
2770 corner of the menu as a whole ends up at given coordinates. This
2771 is what x-popup-menu says in its documentation. */
2772 x += width/2;
2773 y += 1.5*height/(maxlines+2);
2776 XMenuSetAEQ (menu, TRUE);
2777 XMenuSetFreeze (menu, TRUE);
2778 pane = selidx = 0;
2780 #ifndef MSDOS
2781 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2782 #endif
2784 record_unwind_protect (pop_down_menu,
2785 Fcons (make_save_value (f, 0),
2786 make_save_value (menu, 0)));
2788 /* Help display under X won't work because XMenuActivate contains
2789 a loop that doesn't give Emacs a chance to process it. */
2790 menu_help_frame = f;
2791 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2792 x, y, ButtonReleaseMask, &datap,
2793 menu_help_callback);
2795 switch (status)
2797 case XM_SUCCESS:
2798 #ifdef XDEBUG
2799 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2800 #endif
2802 /* Find the item number SELIDX in pane number PANE. */
2803 i = 0;
2804 while (i < menu_items_used)
2806 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2808 if (pane == 0)
2809 pane_prefix
2810 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2811 pane--;
2812 i += MENU_ITEMS_PANE_LENGTH;
2814 else
2816 if (pane == -1)
2818 if (selidx == 0)
2820 entry
2821 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2822 if (keymaps != 0)
2824 entry = Fcons (entry, Qnil);
2825 if (!NILP (pane_prefix))
2826 entry = Fcons (pane_prefix, entry);
2828 break;
2830 selidx--;
2832 i += MENU_ITEMS_ITEM_LENGTH;
2835 break;
2837 case XM_FAILURE:
2838 *error = "Can't activate menu";
2839 case XM_IA_SELECT:
2840 entry = Qnil;
2841 break;
2842 case XM_NO_SELECT:
2843 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2844 the menu was invoked with a mouse event as POSITION). */
2845 if (! for_click)
2846 Fsignal (Qquit, Qnil);
2847 entry = Qnil;
2848 break;
2851 unbind_to (specpdl_count, Qnil);
2853 return entry;
2856 #endif /* not USE_X_TOOLKIT */
2858 #endif /* HAVE_MENUS */
2860 /* Detect if a dialog or menu has been posted. */
2863 popup_activated ()
2865 return popup_activated_flag;
2868 /* The following is used by delayed window autoselection. */
2870 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2871 doc: /* Return t if a menu or popup dialog is active. */)
2874 #ifdef HAVE_MENUS
2875 return (popup_activated ()) ? Qt : Qnil;
2876 #else
2877 return Qnil;
2878 #endif /* HAVE_MENUS */
2881 void
2882 syms_of_xmenu ()
2884 Qdebug_on_next_call = intern ("debug-on-next-call");
2885 staticpro (&Qdebug_on_next_call);
2887 #ifdef USE_X_TOOLKIT
2888 widget_id_tick = (1<<16);
2889 next_menubar_widget_id = 1;
2890 #endif
2892 defsubr (&Sx_popup_menu);
2893 defsubr (&Smenu_or_popup_active_p);
2895 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2896 defsubr (&Sx_menu_bar_open_internal);
2897 Ffset (intern ("accelerate-menu"),
2898 intern (Sx_menu_bar_open_internal.symbol_name));
2899 #endif
2901 #ifdef HAVE_MENUS
2902 defsubr (&Sx_popup_dialog);
2903 #endif
2906 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2907 (do not change this comment) */