Fix typos.
[emacs.git] / src / xmenu.c
blobca0bcdf7d23580d30816e7160774f1608299d8f8
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 #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 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
150 extern widget_value *xmalloc_widget_value P_ ((void));
151 extern widget_value *digest_single_submenu P_ ((int, int, int));
152 #endif
154 /* This is set nonzero after the user activates the menu bar, and set
155 to zero again after the menu bars are redisplayed by prepare_menu_bar.
156 While it is nonzero, all calls to set_frame_menubar go deep.
158 I don't understand why this is needed, but it does seem to be
159 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
161 int pending_menu_activation;
163 #ifdef USE_X_TOOLKIT
165 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
167 static struct frame *
168 menubar_id_to_frame (id)
169 LWLIB_ID id;
171 Lisp_Object tail, frame;
172 FRAME_PTR f;
174 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
176 frame = XCAR (tail);
177 if (!FRAMEP (frame))
178 continue;
179 f = XFRAME (frame);
180 if (!FRAME_WINDOW_P (f))
181 continue;
182 if (f->output_data.x->id == id)
183 return f;
185 return 0;
188 #endif
190 #ifdef HAVE_X_WINDOWS
191 /* Return the mouse position in *X and *Y. The coordinates are window
192 relative for the edit window in frame F.
193 This is for Fx_popup_menu. The mouse_position_hook can not
194 be used for X, as it returns window relative coordinates
195 for the window where the mouse is in. This could be the menu bar,
196 the scroll bar or the edit window. Fx_popup_menu needs to be
197 sure it is the edit window. */
198 static void
199 mouse_position_for_popup (f, x, y)
200 FRAME_PTR f;
201 int *x;
202 int *y;
204 Window root, dummy_window;
205 int dummy;
207 if (! FRAME_X_P (f))
208 abort ();
210 BLOCK_INPUT;
212 XQueryPointer (FRAME_X_DISPLAY (f),
213 DefaultRootWindow (FRAME_X_DISPLAY (f)),
215 /* The root window which contains the pointer. */
216 &root,
218 /* Window pointer is on, not used */
219 &dummy_window,
221 /* The position on that root window. */
222 x, y,
224 /* x/y in dummy_window coordinates, not used. */
225 &dummy, &dummy,
227 /* Modifier keys and pointer buttons, about which
228 we don't care. */
229 (unsigned int *) &dummy);
231 UNBLOCK_INPUT;
233 /* xmenu_show expects window coordinates, not root window
234 coordinates. Translate. */
235 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
236 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
239 #endif /* HAVE_X_WINDOWS */
241 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
242 doc: /* Pop up a deck-of-cards menu and return user's selection.
243 POSITION is a position specification. This is either a mouse button event
244 or a list ((XOFFSET YOFFSET) WINDOW)
245 where XOFFSET and YOFFSET are positions in pixels from the top left
246 corner of WINDOW. (WINDOW may be a window or a frame object.)
247 This controls the position of the top left of the menu as a whole.
248 If POSITION is t, it means to use the current mouse position.
250 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
251 The menu items come from key bindings that have a menu string as well as
252 a definition; actually, the "definition" in such a key binding looks like
253 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
254 the keymap as a top-level element.
256 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
257 Otherwise, REAL-DEFINITION should be a valid key binding definition.
259 You can also use a list of keymaps as MENU.
260 Then each keymap makes a separate pane.
262 When MENU is a keymap or a list of keymaps, the return value is the
263 list of events corresponding to the user's choice. Note that
264 `x-popup-menu' does not actually execute the command bound to that
265 sequence of events.
267 Alternatively, you can specify a menu of multiple panes
268 with a list of the form (TITLE PANE1 PANE2...),
269 where each pane is a list of form (TITLE ITEM1 ITEM2...).
270 Each ITEM is normally a cons cell (STRING . VALUE);
271 but a string can appear as an item--that makes a nonselectable line
272 in the menu.
273 With this form of menu, the return value is VALUE from the chosen item.
275 If POSITION is nil, don't display the menu at all, just precalculate the
276 cached information about equivalent key sequences.
278 If the user gets rid of the menu without making a valid choice, for
279 instance by clicking the mouse away from a valid choice or by typing
280 keyboard input, then this normally results in a quit and
281 `x-popup-menu' does not return. But if POSITION is a mouse button
282 event (indicating that the user invoked the menu with the mouse) then
283 no quit occurs and `x-popup-menu' returns nil. */)
284 (position, menu)
285 Lisp_Object position, menu;
287 Lisp_Object keymap, tem;
288 int xpos = 0, ypos = 0;
289 Lisp_Object title;
290 char *error_name = NULL;
291 Lisp_Object selection = Qnil;
292 FRAME_PTR f = NULL;
293 Lisp_Object x, y, window;
294 int keymaps = 0;
295 int for_click = 0;
296 int specpdl_count = SPECPDL_INDEX ();
297 struct gcpro gcpro1;
299 #ifdef HAVE_MENUS
300 if (! NILP (position))
302 int get_current_pos_p = 0;
303 check_x ();
305 /* Decode the first argument: find the window and the coordinates. */
306 if (EQ (position, Qt)
307 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
308 || EQ (XCAR (position), Qtool_bar))))
310 get_current_pos_p = 1;
312 else
314 tem = Fcar (position);
315 if (CONSP (tem))
317 window = Fcar (Fcdr (position));
318 x = XCAR (tem);
319 y = Fcar (XCDR (tem));
321 else
323 for_click = 1;
324 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
325 window = Fcar (tem); /* POSN_WINDOW (tem) */
326 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
327 x = Fcar (tem);
328 y = Fcdr (tem);
331 /* If a click happens in an external tool bar or a detached
332 tool bar, x and y is NIL. In that case, use the current
333 mouse position. This happens for the help button in the
334 tool bar. Ideally popup-menu should pass NIL to
335 this function, but it doesn't. */
336 if (NILP (x) && NILP (y))
337 get_current_pos_p = 1;
340 if (get_current_pos_p)
342 /* Use the mouse's current position. */
343 FRAME_PTR new_f = SELECTED_FRAME ();
344 #ifdef HAVE_X_WINDOWS
345 /* Can't use mouse_position_hook for X since it returns
346 coordinates relative to the window the mouse is in,
347 we need coordinates relative to the edit widget always. */
348 if (new_f != 0)
350 int cur_x, cur_y;
352 mouse_position_for_popup (new_f, &cur_x, &cur_y);
353 /* cur_x/y may be negative, so use make_number. */
354 x = make_number (cur_x);
355 y = make_number (cur_y);
358 #else /* not HAVE_X_WINDOWS */
359 Lisp_Object bar_window;
360 enum scroll_bar_part part;
361 unsigned long time;
363 if (mouse_position_hook)
364 (*mouse_position_hook) (&new_f, 1, &bar_window,
365 &part, &x, &y, &time);
366 #endif /* not HAVE_X_WINDOWS */
368 if (new_f != 0)
369 XSETFRAME (window, new_f);
370 else
372 window = selected_window;
373 XSETFASTINT (x, 0);
374 XSETFASTINT (y, 0);
378 CHECK_NUMBER (x);
379 CHECK_NUMBER (y);
381 /* Decode where to put the menu. */
383 if (FRAMEP (window))
385 f = XFRAME (window);
386 xpos = 0;
387 ypos = 0;
389 else if (WINDOWP (window))
391 CHECK_LIVE_WINDOW (window);
392 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
394 xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
395 ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
397 else
398 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
399 but I don't want to make one now. */
400 CHECK_WINDOW (window);
402 xpos += XINT (x);
403 ypos += XINT (y);
405 if (! FRAME_X_P (f))
406 error ("Can not put X menu on non-X terminal");
408 XSETFRAME (Vmenu_updating_frame, f);
410 else
411 Vmenu_updating_frame = Qnil;
412 #endif /* HAVE_MENUS */
414 record_unwind_protect (unuse_menu_items, Qnil);
415 title = Qnil;
416 GCPRO1 (title);
418 /* Decode the menu items from what was specified. */
420 keymap = get_keymap (menu, 0, 0);
421 if (CONSP (keymap))
423 /* We were given a keymap. Extract menu info from the keymap. */
424 Lisp_Object prompt;
426 /* Extract the detailed info to make one pane. */
427 keymap_panes (&menu, 1, NILP (position));
429 /* Search for a string appearing directly as an element of the keymap.
430 That string is the title of the menu. */
431 prompt = Fkeymap_prompt (keymap);
432 if (NILP (title) && !NILP (prompt))
433 title = prompt;
435 /* Make that be the pane title of the first pane. */
436 if (!NILP (prompt) && menu_items_n_panes >= 0)
437 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
439 keymaps = 1;
441 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
443 /* We were given a list of keymaps. */
444 int nmaps = XFASTINT (Flength (menu));
445 Lisp_Object *maps
446 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
447 int i;
449 title = Qnil;
451 /* The first keymap that has a prompt string
452 supplies the menu title. */
453 for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
455 Lisp_Object prompt;
457 maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
459 prompt = Fkeymap_prompt (keymap);
460 if (NILP (title) && !NILP (prompt))
461 title = prompt;
464 /* Extract the detailed info to make one pane. */
465 keymap_panes (maps, nmaps, NILP (position));
467 /* Make the title be the pane title of the first pane. */
468 if (!NILP (title) && menu_items_n_panes >= 0)
469 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
471 keymaps = 1;
473 else
475 /* We were given an old-fashioned menu. */
476 title = Fcar (menu);
477 CHECK_STRING (title);
479 list_of_panes (Fcdr (menu));
481 keymaps = 0;
484 unbind_to (specpdl_count, Qnil);
486 if (NILP (position))
488 discard_menu_items ();
489 UNGCPRO;
490 return Qnil;
493 #ifdef HAVE_MENUS
494 /* Display them in a menu. */
495 BLOCK_INPUT;
497 selection = xmenu_show (f, xpos, ypos, for_click,
498 keymaps, title, &error_name);
499 UNBLOCK_INPUT;
501 discard_menu_items ();
503 UNGCPRO;
504 #endif /* HAVE_MENUS */
506 if (error_name) error (error_name);
507 return selection;
510 #ifdef HAVE_MENUS
512 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
513 doc: /* Pop up a dialog box and return user's selection.
514 POSITION specifies which frame to use.
515 This is normally a mouse button event or a window or frame.
516 If POSITION is t, it means to use the frame the mouse is on.
517 The dialog box appears in the middle of the specified frame.
519 CONTENTS specifies the alternatives to display in the dialog box.
520 It is a list of the form (DIALOG ITEM1 ITEM2...).
521 Each ITEM is a cons cell (STRING . VALUE).
522 The return value is VALUE from the chosen item.
524 An ITEM may also be just a string--that makes a nonselectable item.
525 An ITEM may also be nil--that means to put all preceding items
526 on the left of the dialog box and all following items on the right.
527 \(By default, approximately half appear on each side.)
529 If HEADER is non-nil, the frame title for the box is "Information",
530 otherwise it is "Question".
532 If the user gets rid of the dialog box without making a valid choice,
533 for instance using the window manager, then this produces a quit and
534 `x-popup-dialog' does not return. */)
535 (position, contents, header)
536 Lisp_Object position, contents, header;
538 FRAME_PTR f = NULL;
539 Lisp_Object window;
541 check_x ();
543 /* Decode the first argument: find the window or frame to use. */
544 if (EQ (position, Qt)
545 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
546 || EQ (XCAR (position), Qtool_bar))))
548 #if 0 /* Using the frame the mouse is on may not be right. */
549 /* Use the mouse's current position. */
550 FRAME_PTR new_f = SELECTED_FRAME ();
551 Lisp_Object bar_window;
552 enum scroll_bar_part part;
553 unsigned long time;
554 Lisp_Object x, y;
556 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
558 if (new_f != 0)
559 XSETFRAME (window, new_f);
560 else
561 window = selected_window;
562 #endif
563 window = selected_window;
565 else if (CONSP (position))
567 Lisp_Object tem;
568 tem = Fcar (position);
569 if (CONSP (tem))
570 window = Fcar (Fcdr (position));
571 else
573 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
574 window = Fcar (tem); /* POSN_WINDOW (tem) */
577 else if (WINDOWP (position) || FRAMEP (position))
578 window = position;
579 else
580 window = Qnil;
582 /* Decode where to put the menu. */
584 if (FRAMEP (window))
585 f = XFRAME (window);
586 else if (WINDOWP (window))
588 CHECK_LIVE_WINDOW (window);
589 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
591 else
592 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
593 but I don't want to make one now. */
594 CHECK_WINDOW (window);
596 if (! FRAME_X_P (f))
597 error ("Can not put X dialog on non-X terminal");
599 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
600 /* Display a menu with these alternatives
601 in the middle of frame F. */
603 Lisp_Object x, y, frame, newpos;
604 XSETFRAME (frame, f);
605 XSETINT (x, x_pixel_width (f) / 2);
606 XSETINT (y, x_pixel_height (f) / 2);
607 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
609 return Fx_popup_menu (newpos,
610 Fcons (Fcar (contents), Fcons (contents, Qnil)));
612 #else
614 Lisp_Object title;
615 char *error_name;
616 Lisp_Object selection;
617 int specpdl_count = SPECPDL_INDEX ();
619 /* Decode the dialog items from what was specified. */
620 title = Fcar (contents);
621 CHECK_STRING (title);
622 record_unwind_protect (unuse_menu_items, Qnil);
624 if (NILP (Fcar (Fcdr (contents))))
625 /* No buttons specified, add an "Ok" button so users can pop down
626 the dialog. Also, the lesstif/motif version crashes if there are
627 no buttons. */
628 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
630 list_of_panes (Fcons (contents, Qnil));
632 /* Display them in a dialog box. */
633 BLOCK_INPUT;
634 selection = xdialog_show (f, 0, title, header, &error_name);
635 UNBLOCK_INPUT;
637 unbind_to (specpdl_count, Qnil);
638 discard_menu_items ();
640 if (error_name) error (error_name);
641 return selection;
643 #endif
647 #ifndef MSDOS
649 /* Set menu_items_inuse so no other popup menu or dialog is created. */
651 void
652 x_menu_set_in_use (in_use)
653 int in_use;
655 menu_items_inuse = in_use ? Qt : Qnil;
656 popup_activated_flag = in_use;
657 #ifdef USE_X_TOOLKIT
658 if (popup_activated_flag)
659 x_activate_timeout_atimer ();
660 #endif
663 /* Wait for an X event to arrive or for a timer to expire. */
665 void
666 x_menu_wait_for_event (void *data)
668 extern EMACS_TIME timer_check P_ ((int));
670 /* Another way to do this is to register a timer callback, that can be
671 done in GTK and Xt. But we have to do it like this when using only X
672 anyway, and with callbacks we would have three variants for timer handling
673 instead of the small ifdefs below. */
675 while (
676 #ifdef USE_X_TOOLKIT
677 ! XtAppPending (Xt_app_con)
678 #elif defined USE_GTK
679 ! gtk_events_pending ()
680 #else
681 ! XPending ((Display*) data)
682 #endif
685 EMACS_TIME next_time = timer_check (1);
686 long secs = EMACS_SECS (next_time);
687 long usecs = EMACS_USECS (next_time);
688 SELECT_TYPE read_fds;
689 struct x_display_info *dpyinfo;
690 int n = 0;
692 FD_ZERO (&read_fds);
693 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
695 int fd = ConnectionNumber (dpyinfo->display);
696 FD_SET (fd, &read_fds);
697 if (fd > n) n = fd;
700 if (secs < 0 || (secs == 0 && usecs == 0))
702 /* Sometimes timer_check returns -1 (no timers) even if there are
703 timers. So do a timeout anyway. */
704 EMACS_SET_SECS (next_time, 1);
705 EMACS_SET_USECS (next_time, 0);
708 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time);
711 #endif /* ! MSDOS */
714 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
716 #ifdef USE_X_TOOLKIT
718 /* Loop in Xt until the menu pulldown or dialog popup has been
719 popped down (deactivated). This is used for x-popup-menu
720 and x-popup-dialog; it is not used for the menu bar.
722 NOTE: All calls to popup_get_selection should be protected
723 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
725 static void
726 popup_get_selection (initial_event, dpyinfo, id, do_timers)
727 XEvent *initial_event;
728 struct x_display_info *dpyinfo;
729 LWLIB_ID id;
730 int do_timers;
732 XEvent event;
734 while (popup_activated_flag)
736 if (initial_event)
738 event = *initial_event;
739 initial_event = 0;
741 else
743 if (do_timers) x_menu_wait_for_event (0);
744 XtAppNextEvent (Xt_app_con, &event);
747 /* Make sure we don't consider buttons grabbed after menu goes.
748 And make sure to deactivate for any ButtonRelease,
749 even if XtDispatchEvent doesn't do that. */
750 if (event.type == ButtonRelease
751 && dpyinfo->display == event.xbutton.display)
753 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
754 #ifdef USE_MOTIF /* Pretending that the event came from a
755 Btn1Down seems the only way to convince Motif to
756 activate its callbacks; setting the XmNmenuPost
757 isn't working. --marcus@sysc.pdx.edu. */
758 event.xbutton.button = 1;
759 /* Motif only pops down menus when no Ctrl, Alt or Mod
760 key is pressed and the button is released. So reset key state
761 so Motif thinks this is the case. */
762 event.xbutton.state = 0;
763 #endif
765 /* Pop down on C-g and Escape. */
766 else if (event.type == KeyPress
767 && dpyinfo->display == event.xbutton.display)
769 KeySym keysym = XLookupKeysym (&event.xkey, 0);
771 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
772 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
773 popup_activated_flag = 0;
776 x_dispatch_event (&event, event.xany.display);
780 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
781 doc: /* Start key navigation of the menu bar in FRAME.
782 This initially opens the first menu bar item and you can then navigate with the
783 arrow keys, select a menu entry with the return key or cancel with the
784 escape key. If FRAME has no menu bar this function does nothing.
786 If FRAME is nil or not given, use the selected frame. */)
787 (frame)
788 Lisp_Object frame;
790 XEvent ev;
791 FRAME_PTR f = check_x_frame (frame);
792 Widget menubar;
793 BLOCK_INPUT;
795 if (FRAME_EXTERNAL_MENU_BAR (f))
796 set_frame_menubar (f, 0, 1);
798 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
799 if (menubar)
801 Window child;
802 int error_p = 0;
804 x_catch_errors (FRAME_X_DISPLAY (f));
805 memset (&ev, 0, sizeof ev);
806 ev.xbutton.display = FRAME_X_DISPLAY (f);
807 ev.xbutton.window = XtWindow (menubar);
808 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
809 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
810 ev.xbutton.button = Button1;
811 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
812 ev.xbutton.same_screen = True;
814 #ifdef USE_MOTIF
816 Arg al[2];
817 WidgetList list;
818 Cardinal nr;
819 XtSetArg (al[0], XtNchildren, &list);
820 XtSetArg (al[1], XtNnumChildren, &nr);
821 XtGetValues (menubar, al, 2);
822 ev.xbutton.window = XtWindow (list[0]);
824 #endif
826 XTranslateCoordinates (FRAME_X_DISPLAY (f),
827 /* From-window, to-window. */
828 ev.xbutton.window, ev.xbutton.root,
830 /* From-position, to-position. */
831 ev.xbutton.x, ev.xbutton.y,
832 &ev.xbutton.x_root, &ev.xbutton.y_root,
834 /* Child of win. */
835 &child);
836 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
837 x_uncatch_errors ();
839 if (! error_p)
841 ev.type = ButtonPress;
842 ev.xbutton.state = 0;
844 XtDispatchEvent (&ev);
845 ev.xbutton.type = ButtonRelease;
846 ev.xbutton.state = Button1Mask;
847 XtDispatchEvent (&ev);
851 UNBLOCK_INPUT;
853 return Qnil;
855 #endif /* USE_X_TOOLKIT */
858 #ifdef USE_GTK
859 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
860 doc: /* Start key navigation of the menu bar in FRAME.
861 This initially opens the first menu bar item and you can then navigate with the
862 arrow keys, select a menu entry with the return key or cancel with the
863 escape key. If FRAME has no menu bar this function does nothing.
865 If FRAME is nil or not given, use the selected frame. */)
866 (frame)
867 Lisp_Object frame;
869 GtkWidget *menubar;
870 FRAME_PTR f;
872 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
873 BLOCK_INPUT. */
875 BLOCK_INPUT;
876 f = check_x_frame (frame);
878 if (FRAME_EXTERNAL_MENU_BAR (f))
879 set_frame_menubar (f, 0, 1);
881 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
882 if (menubar)
884 /* Activate the first menu. */
885 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
887 gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar),
888 GTK_WIDGET (children->data));
890 popup_activated_flag = 1;
891 g_list_free (children);
893 UNBLOCK_INPUT;
895 return Qnil;
898 /* Loop util popup_activated_flag is set to zero in a callback.
899 Used for popup menus and dialogs. */
901 static void
902 popup_widget_loop (do_timers, widget)
903 int do_timers;
904 GtkWidget *widget;
906 ++popup_activated_flag;
908 /* Process events in the Gtk event loop until done. */
909 while (popup_activated_flag)
911 if (do_timers) x_menu_wait_for_event (0);
912 gtk_main_iteration ();
915 #endif
917 /* Activate the menu bar of frame F.
918 This is called from keyboard.c when it gets the
919 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
921 To activate the menu bar, we use the X button-press event
922 that was saved in saved_menu_event.
923 That makes the toolkit do its thing.
925 But first we recompute the menu bar contents (the whole tree).
927 The reason for saving the button event until here, instead of
928 passing it to the toolkit right away, is that we can safely
929 execute Lisp code. */
931 void
932 x_activate_menubar (f)
933 FRAME_PTR f;
935 if (! FRAME_X_P (f))
936 abort ();
938 if (!f->output_data.x->saved_menu_event->type)
939 return;
941 #ifdef USE_GTK
942 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
943 f->output_data.x->saved_menu_event->xany.window))
944 return;
945 #endif
947 set_frame_menubar (f, 0, 1);
948 BLOCK_INPUT;
949 #ifdef USE_GTK
950 XPutBackEvent (f->output_data.x->display_info->display,
951 f->output_data.x->saved_menu_event);
952 popup_activated_flag = 1;
953 #else
954 XtDispatchEvent (f->output_data.x->saved_menu_event);
955 #endif
956 UNBLOCK_INPUT;
957 #ifdef USE_MOTIF
958 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
959 pending_menu_activation = 1;
960 #endif
962 /* Ignore this if we get it a second time. */
963 f->output_data.x->saved_menu_event->type = 0;
966 /* This callback is invoked when the user selects a menubar cascade
967 pushbutton, but before the pulldown menu is posted. */
969 #ifndef USE_GTK
970 static void
971 popup_activate_callback (widget, id, client_data)
972 Widget widget;
973 LWLIB_ID id;
974 XtPointer client_data;
976 popup_activated_flag = 1;
977 #ifdef USE_X_TOOLKIT
978 x_activate_timeout_atimer ();
979 #endif
981 #endif
983 /* This callback is invoked when a dialog or menu is finished being
984 used and has been unposted. */
986 #ifdef USE_GTK
987 static void
988 popup_deactivate_callback (widget, client_data)
989 GtkWidget *widget;
990 gpointer client_data;
992 popup_activated_flag = 0;
994 #else
995 static void
996 popup_deactivate_callback (widget, id, client_data)
997 Widget widget;
998 LWLIB_ID id;
999 XtPointer client_data;
1001 popup_activated_flag = 0;
1003 #endif
1006 /* Function that finds the frame for WIDGET and shows the HELP text
1007 for that widget.
1008 F is the frame if known, or NULL if not known. */
1009 static void
1010 show_help_event (f, widget, help)
1011 FRAME_PTR f;
1012 xt_or_gtk_widget widget;
1013 Lisp_Object help;
1015 Lisp_Object frame;
1017 if (f)
1019 XSETFRAME (frame, f);
1020 kbd_buffer_store_help_event (frame, help);
1022 else
1024 #if 0 /* This code doesn't do anything useful. ++kfs */
1025 /* WIDGET is the popup menu. It's parent is the frame's
1026 widget. See which frame that is. */
1027 xt_or_gtk_widget frame_widget = XtParent (widget);
1028 Lisp_Object tail;
1030 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
1032 frame = XCAR (tail);
1033 if (FRAMEP (frame)
1034 && (f = XFRAME (frame),
1035 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
1036 break;
1038 #endif
1039 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1043 /* Callback called when menu items are highlighted/unhighlighted
1044 while moving the mouse over them. WIDGET is the menu bar or menu
1045 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
1046 the data structure for the menu item, or null in case of
1047 unhighlighting. */
1049 #ifdef USE_GTK
1050 void
1051 menu_highlight_callback (widget, call_data)
1052 GtkWidget *widget;
1053 gpointer call_data;
1055 xg_menu_item_cb_data *cb_data;
1056 Lisp_Object help;
1058 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
1059 XG_ITEM_DATA);
1060 if (! cb_data) return;
1062 help = call_data ? cb_data->help : Qnil;
1064 /* If popup_activated_flag is greater than 1 we are in a popup menu.
1065 Don't show help for them, they won't appear before the
1066 popup is popped down. */
1067 if (popup_activated_flag <= 1)
1068 show_help_event (cb_data->cl_data->f, widget, help);
1070 #else
1071 void
1072 menu_highlight_callback (widget, id, call_data)
1073 Widget widget;
1074 LWLIB_ID id;
1075 void *call_data;
1077 struct frame *f;
1078 Lisp_Object help;
1080 widget_value *wv = (widget_value *) call_data;
1082 help = wv ? wv->help : Qnil;
1084 /* Determine the frame for the help event. */
1085 f = menubar_id_to_frame (id);
1087 show_help_event (f, widget, help);
1089 #endif
1091 #ifdef USE_GTK
1092 /* Gtk calls callbacks just because we tell it what item should be
1093 selected in a radio group. If this variable is set to a non-zero
1094 value, we are creating menus and don't want callbacks right now.
1096 static int xg_crazy_callback_abort;
1098 /* This callback is called from the menu bar pulldown menu
1099 when the user makes a selection.
1100 Figure out what the user chose
1101 and put the appropriate events into the keyboard buffer. */
1102 static void
1103 menubar_selection_callback (widget, client_data)
1104 GtkWidget *widget;
1105 gpointer client_data;
1107 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1109 if (xg_crazy_callback_abort)
1110 return;
1112 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
1113 return;
1115 /* For a group of radio buttons, GTK calls the selection callback first
1116 for the item that was active before the selection and then for the one that
1117 is active after the selection. For C-h k this means we get the help on
1118 the deselected item and then the selected item is executed. Prevent that
1119 by ignoring the non-active item. */
1120 if (GTK_IS_RADIO_MENU_ITEM (widget)
1121 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
1122 return;
1124 /* When a menu is popped down, X generates a focus event (i.e. focus
1125 goes back to the frame below the menu). Since GTK buffers events,
1126 we force it out here before the menu selection event. Otherwise
1127 sit-for will exit at once if the focus event follows the menu selection
1128 event. */
1130 BLOCK_INPUT;
1131 while (gtk_events_pending ())
1132 gtk_main_iteration ();
1133 UNBLOCK_INPUT;
1135 find_and_call_menu_selection (cb_data->cl_data->f,
1136 cb_data->cl_data->menu_bar_items_used,
1137 cb_data->cl_data->menu_bar_vector,
1138 cb_data->call_data);
1141 #else /* not USE_GTK */
1143 /* This callback is called from the menu bar pulldown menu
1144 when the user makes a selection.
1145 Figure out what the user chose
1146 and put the appropriate events into the keyboard buffer. */
1147 static void
1148 menubar_selection_callback (widget, id, client_data)
1149 Widget widget;
1150 LWLIB_ID id;
1151 XtPointer client_data;
1153 FRAME_PTR f;
1155 f = menubar_id_to_frame (id);
1156 if (!f)
1157 return;
1158 find_and_call_menu_selection (f, f->menu_bar_items_used,
1159 f->menu_bar_vector, client_data);
1161 #endif /* not USE_GTK */
1163 /* Recompute all the widgets of frame F, when the menu bar has been
1164 changed. Value is non-zero if widgets were updated. */
1166 static int
1167 update_frame_menubar (f)
1168 FRAME_PTR f;
1170 #ifdef USE_GTK
1171 return xg_update_frame_menubar (f);
1172 #else
1173 struct x_output *x;
1174 int columns, rows;
1176 if (! FRAME_X_P (f))
1177 abort ();
1179 x = f->output_data.x;
1181 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
1182 return 0;
1184 BLOCK_INPUT;
1185 /* Save the size of the frame because the pane widget doesn't accept
1186 to resize itself. So force it. */
1187 columns = FRAME_COLS (f);
1188 rows = FRAME_LINES (f);
1190 /* Do the voodoo which means "I'm changing lots of things, don't try
1191 to refigure sizes until I'm done." */
1192 lw_refigure_widget (x->column_widget, False);
1194 /* The order in which children are managed is the top to bottom
1195 order in which they are displayed in the paned window. First,
1196 remove the text-area widget. */
1197 XtUnmanageChild (x->edit_widget);
1199 /* Remove the menubar that is there now, and put up the menubar that
1200 should be there. */
1201 XtManageChild (x->menubar_widget);
1202 XtMapWidget (x->menubar_widget);
1203 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
1205 /* Re-manage the text-area widget, and then thrash the sizes. */
1206 XtManageChild (x->edit_widget);
1207 lw_refigure_widget (x->column_widget, True);
1209 /* Force the pane widget to resize itself with the right values. */
1210 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
1211 UNBLOCK_INPUT;
1212 #endif
1213 return 1;
1216 /* Set the contents of the menubar widgets of frame F.
1217 The argument FIRST_TIME is currently ignored;
1218 it is set the first time this is called, from initialize_frame_menubar. */
1220 void
1221 set_frame_menubar (f, first_time, deep_p)
1222 FRAME_PTR f;
1223 int first_time;
1224 int deep_p;
1226 xt_or_gtk_widget menubar_widget;
1227 #ifdef USE_X_TOOLKIT
1228 LWLIB_ID id;
1229 #endif
1230 Lisp_Object items;
1231 widget_value *wv, *first_wv, *prev_wv = 0;
1232 int i, last_i = 0;
1233 int *submenu_start, *submenu_end;
1234 int *submenu_top_level_items, *submenu_n_panes;
1236 if (! FRAME_X_P (f))
1237 abort ();
1239 menubar_widget = f->output_data.x->menubar_widget;
1241 XSETFRAME (Vmenu_updating_frame, f);
1243 #ifdef USE_X_TOOLKIT
1244 if (f->output_data.x->id == 0)
1245 f->output_data.x->id = next_menubar_widget_id++;
1246 id = f->output_data.x->id;
1247 #endif
1249 if (! menubar_widget)
1250 deep_p = 1;
1251 else if (pending_menu_activation && !deep_p)
1252 deep_p = 1;
1253 /* Make the first call for any given frame always go deep. */
1254 else if (!f->output_data.x->saved_menu_event && !deep_p)
1256 deep_p = 1;
1257 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
1258 f->output_data.x->saved_menu_event->type = 0;
1261 #ifdef USE_GTK
1262 /* If we have detached menus, we must update deep so detached menus
1263 also gets updated. */
1264 deep_p = deep_p || xg_have_tear_offs ();
1265 #endif
1267 if (deep_p)
1269 /* Make a widget-value tree representing the entire menu trees. */
1271 struct buffer *prev = current_buffer;
1272 Lisp_Object buffer;
1273 int specpdl_count = SPECPDL_INDEX ();
1274 int previous_menu_items_used = f->menu_bar_items_used;
1275 Lisp_Object *previous_items
1276 = (Lisp_Object *) alloca (previous_menu_items_used
1277 * sizeof (Lisp_Object));
1279 /* If we are making a new widget, its contents are empty,
1280 do always reinitialize them. */
1281 if (! menubar_widget)
1282 previous_menu_items_used = 0;
1284 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1285 specbind (Qinhibit_quit, Qt);
1286 /* Don't let the debugger step into this code
1287 because it is not reentrant. */
1288 specbind (Qdebug_on_next_call, Qnil);
1290 record_unwind_save_match_data ();
1291 if (NILP (Voverriding_local_map_menu_flag))
1293 specbind (Qoverriding_terminal_local_map, Qnil);
1294 specbind (Qoverriding_local_map, Qnil);
1297 set_buffer_internal_1 (XBUFFER (buffer));
1299 /* Run the Lucid hook. */
1300 safe_run_hooks (Qactivate_menubar_hook);
1302 /* If it has changed current-menubar from previous value,
1303 really recompute the menubar from the value. */
1304 if (! NILP (Vlucid_menu_bar_dirty_flag))
1305 call0 (Qrecompute_lucid_menubar);
1306 safe_run_hooks (Qmenu_bar_update_hook);
1307 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1309 items = FRAME_MENU_BAR_ITEMS (f);
1311 /* Save the frame's previous menu bar contents data. */
1312 if (previous_menu_items_used)
1313 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1314 previous_menu_items_used * sizeof (Lisp_Object));
1316 /* Fill in menu_items with the current menu bar contents.
1317 This can evaluate Lisp code. */
1318 save_menu_items ();
1320 menu_items = f->menu_bar_vector;
1321 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1322 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1323 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1324 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1325 submenu_top_level_items
1326 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1327 init_menu_items ();
1328 for (i = 0; i < XVECTOR (items)->size; i += 4)
1330 Lisp_Object key, string, maps;
1332 last_i = i;
1334 key = XVECTOR (items)->contents[i];
1335 string = XVECTOR (items)->contents[i + 1];
1336 maps = XVECTOR (items)->contents[i + 2];
1337 if (NILP (string))
1338 break;
1340 submenu_start[i] = menu_items_used;
1342 menu_items_n_panes = 0;
1343 submenu_top_level_items[i]
1344 = parse_single_submenu (key, string, maps);
1345 submenu_n_panes[i] = menu_items_n_panes;
1347 submenu_end[i] = menu_items_used;
1350 finish_menu_items ();
1352 /* Convert menu_items into widget_value trees
1353 to display the menu. This cannot evaluate Lisp code. */
1355 wv = xmalloc_widget_value ();
1356 wv->name = "menubar";
1357 wv->value = 0;
1358 wv->enabled = 1;
1359 wv->button_type = BUTTON_TYPE_NONE;
1360 wv->help = Qnil;
1361 first_wv = wv;
1363 for (i = 0; i < last_i; i += 4)
1365 menu_items_n_panes = submenu_n_panes[i];
1366 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1367 submenu_top_level_items[i]);
1368 if (prev_wv)
1369 prev_wv->next = wv;
1370 else
1371 first_wv->contents = wv;
1372 /* Don't set wv->name here; GC during the loop might relocate it. */
1373 wv->enabled = 1;
1374 wv->button_type = BUTTON_TYPE_NONE;
1375 prev_wv = wv;
1378 set_buffer_internal_1 (prev);
1380 /* If there has been no change in the Lisp-level contents
1381 of the menu bar, skip redisplaying it. Just exit. */
1383 /* Compare the new menu items with the ones computed last time. */
1384 for (i = 0; i < previous_menu_items_used; i++)
1385 if (menu_items_used == i
1386 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1387 break;
1388 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1390 /* The menu items have not changed. Don't bother updating
1391 the menus in any form, since it would be a no-op. */
1392 free_menubar_widget_value_tree (first_wv);
1393 discard_menu_items ();
1394 unbind_to (specpdl_count, Qnil);
1395 return;
1398 /* The menu items are different, so store them in the frame. */
1399 f->menu_bar_vector = menu_items;
1400 f->menu_bar_items_used = menu_items_used;
1402 /* This undoes save_menu_items. */
1403 unbind_to (specpdl_count, Qnil);
1405 /* Now GC cannot happen during the lifetime of the widget_value,
1406 so it's safe to store data from a Lisp_String. */
1407 wv = first_wv->contents;
1408 for (i = 0; i < XVECTOR (items)->size; i += 4)
1410 Lisp_Object string;
1411 string = XVECTOR (items)->contents[i + 1];
1412 if (NILP (string))
1413 break;
1414 wv->name = (char *) SDATA (string);
1415 update_submenu_strings (wv->contents);
1416 wv = wv->next;
1420 else
1422 /* Make a widget-value tree containing
1423 just the top level menu bar strings. */
1425 wv = xmalloc_widget_value ();
1426 wv->name = "menubar";
1427 wv->value = 0;
1428 wv->enabled = 1;
1429 wv->button_type = BUTTON_TYPE_NONE;
1430 wv->help = Qnil;
1431 first_wv = wv;
1433 items = FRAME_MENU_BAR_ITEMS (f);
1434 for (i = 0; i < XVECTOR (items)->size; i += 4)
1436 Lisp_Object string;
1438 string = XVECTOR (items)->contents[i + 1];
1439 if (NILP (string))
1440 break;
1442 wv = xmalloc_widget_value ();
1443 wv->name = (char *) SDATA (string);
1444 wv->value = 0;
1445 wv->enabled = 1;
1446 wv->button_type = BUTTON_TYPE_NONE;
1447 wv->help = Qnil;
1448 /* This prevents lwlib from assuming this
1449 menu item is really supposed to be empty. */
1450 /* The EMACS_INT cast avoids a warning.
1451 This value just has to be different from small integers. */
1452 wv->call_data = (void *) (EMACS_INT) (-1);
1454 if (prev_wv)
1455 prev_wv->next = wv;
1456 else
1457 first_wv->contents = wv;
1458 prev_wv = wv;
1461 /* Forget what we thought we knew about what is in the
1462 detailed contents of the menu bar menus.
1463 Changing the top level always destroys the contents. */
1464 f->menu_bar_items_used = 0;
1467 /* Create or update the menu bar widget. */
1469 BLOCK_INPUT;
1471 #ifdef USE_GTK
1472 xg_crazy_callback_abort = 1;
1473 if (menubar_widget)
1475 /* The fourth arg is DEEP_P, which says to consider the entire
1476 menu trees we supply, rather than just the menu bar item names. */
1477 xg_modify_menubar_widgets (menubar_widget,
1479 first_wv,
1480 deep_p,
1481 G_CALLBACK (menubar_selection_callback),
1482 G_CALLBACK (popup_deactivate_callback),
1483 G_CALLBACK (menu_highlight_callback));
1485 else
1487 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1489 menubar_widget
1490 = xg_create_widget ("menubar", "menubar", f, first_wv,
1491 G_CALLBACK (menubar_selection_callback),
1492 G_CALLBACK (popup_deactivate_callback),
1493 G_CALLBACK (menu_highlight_callback));
1495 f->output_data.x->menubar_widget = menubar_widget;
1499 #else /* not USE_GTK */
1500 if (menubar_widget)
1502 /* Disable resizing (done for Motif!) */
1503 lw_allow_resizing (f->output_data.x->widget, False);
1505 /* The third arg is DEEP_P, which says to consider the entire
1506 menu trees we supply, rather than just the menu bar item names. */
1507 lw_modify_all_widgets (id, first_wv, deep_p);
1509 /* Re-enable the edit widget to resize. */
1510 lw_allow_resizing (f->output_data.x->widget, True);
1512 else
1514 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1515 XtTranslations override = XtParseTranslationTable (menuOverride);
1517 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1518 f->output_data.x->column_widget,
1520 popup_activate_callback,
1521 menubar_selection_callback,
1522 popup_deactivate_callback,
1523 menu_highlight_callback);
1524 f->output_data.x->menubar_widget = menubar_widget;
1526 /* Make menu pop down on C-g. */
1527 XtOverrideTranslations (menubar_widget, override);
1531 int menubar_size
1532 = (f->output_data.x->menubar_widget
1533 ? (f->output_data.x->menubar_widget->core.height
1534 + f->output_data.x->menubar_widget->core.border_width)
1535 : 0);
1537 #if 0 /* Experimentally, we now get the right results
1538 for -geometry -0-0 without this. 24 Aug 96, rms. */
1539 #ifdef USE_LUCID
1540 if (FRAME_EXTERNAL_MENU_BAR (f))
1542 Dimension ibw = 0;
1543 XtVaGetValues (f->output_data.x->column_widget,
1544 XtNinternalBorderWidth, &ibw, NULL);
1545 menubar_size += ibw;
1547 #endif /* USE_LUCID */
1548 #endif /* 0 */
1550 f->output_data.x->menubar_height = menubar_size;
1552 #endif /* not USE_GTK */
1554 free_menubar_widget_value_tree (first_wv);
1555 update_frame_menubar (f);
1557 #ifdef USE_GTK
1558 xg_crazy_callback_abort = 0;
1559 #endif
1561 UNBLOCK_INPUT;
1564 /* Called from Fx_create_frame to create the initial menubar of a frame
1565 before it is mapped, so that the window is mapped with the menubar already
1566 there instead of us tacking it on later and thrashing the window after it
1567 is visible. */
1569 void
1570 initialize_frame_menubar (f)
1571 FRAME_PTR f;
1573 /* This function is called before the first chance to redisplay
1574 the frame. It has to be, so the frame will have the right size. */
1575 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1576 set_frame_menubar (f, 1, 1);
1580 /* Get rid of the menu bar of frame F, and free its storage.
1581 This is used when deleting a frame, and when turning off the menu bar.
1582 For GTK this function is in gtkutil.c. */
1584 #ifndef USE_GTK
1585 void
1586 free_frame_menubar (f)
1587 FRAME_PTR f;
1589 Widget menubar_widget;
1591 if (! FRAME_X_P (f))
1592 abort ();
1594 menubar_widget = f->output_data.x->menubar_widget;
1596 f->output_data.x->menubar_height = 0;
1598 if (menubar_widget)
1600 #ifdef USE_MOTIF
1601 /* Removing the menu bar magically changes the shell widget's x
1602 and y position of (0, 0) which, when the menu bar is turned
1603 on again, leads to pull-down menuss appearing in strange
1604 positions near the upper-left corner of the display. This
1605 happens only with some window managers like twm and ctwm,
1606 but not with other like Motif's mwm or kwm, because the
1607 latter generate ConfigureNotify events when the menu bar
1608 is switched off, which fixes the shell position. */
1609 Position x0, y0, x1, y1;
1610 #endif
1612 BLOCK_INPUT;
1614 #ifdef USE_MOTIF
1615 if (f->output_data.x->widget)
1616 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1617 #endif
1619 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1620 f->output_data.x->menubar_widget = NULL;
1622 #ifdef USE_MOTIF
1623 if (f->output_data.x->widget)
1625 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1626 if (x1 == 0 && y1 == 0)
1627 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1629 #endif
1631 UNBLOCK_INPUT;
1634 #endif /* not USE_GTK */
1636 #endif /* USE_X_TOOLKIT || USE_GTK */
1638 /* xmenu_show actually displays a menu using the panes and items in menu_items
1639 and returns the value selected from it.
1640 There are two versions of xmenu_show, one for Xt and one for Xlib.
1641 Both assume input is blocked by the caller. */
1643 /* F is the frame the menu is for.
1644 X and Y are the frame-relative specified position,
1645 relative to the inside upper left corner of the frame F.
1646 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1647 KEYMAPS is 1 if this menu was specified with keymaps;
1648 in that case, we return a list containing the chosen item's value
1649 and perhaps also the pane's prefix.
1650 TITLE is the specified menu title.
1651 ERROR is a place to store an error message string in case of failure.
1652 (We return nil on failure, but the value doesn't actually matter.) */
1654 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1656 /* The item selected in the popup menu. */
1657 static Lisp_Object *volatile menu_item_selection;
1659 #ifdef USE_GTK
1661 /* Used when position a popup menu. See menu_position_func and
1662 create_and_show_popup_menu below. */
1663 struct next_popup_x_y
1665 FRAME_PTR f;
1666 int x;
1667 int y;
1670 /* The menu position function to use if we are not putting a popup
1671 menu where the pointer is.
1672 MENU is the menu to pop up.
1673 X and Y shall on exit contain x/y where the menu shall pop up.
1674 PUSH_IN is not documented in the GTK manual.
1675 USER_DATA is any data passed in when calling gtk_menu_popup.
1676 Here it points to a struct next_popup_x_y where the coordinates
1677 to store in *X and *Y are as well as the frame for the popup.
1679 Here only X and Y are used. */
1680 static void
1681 menu_position_func (menu, x, y, push_in, user_data)
1682 GtkMenu *menu;
1683 gint *x;
1684 gint *y;
1685 gboolean *push_in;
1686 gpointer user_data;
1688 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1689 GtkRequisition req;
1690 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width;
1691 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height;
1693 *x = data->x;
1694 *y = data->y;
1696 /* Check if there is room for the menu. If not, adjust x/y so that
1697 the menu is fully visible. */
1698 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1699 if (data->x + req.width > disp_width)
1700 *x -= data->x + req.width - disp_width;
1701 if (data->y + req.height > disp_height)
1702 *y -= data->y + req.height - disp_height;
1705 static void
1706 popup_selection_callback (widget, client_data)
1707 GtkWidget *widget;
1708 gpointer client_data;
1710 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1712 if (xg_crazy_callback_abort) return;
1713 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1716 static Lisp_Object
1717 pop_down_menu (arg)
1718 Lisp_Object arg;
1720 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1722 popup_activated_flag = 0;
1723 BLOCK_INPUT;
1724 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1725 UNBLOCK_INPUT;
1726 return Qnil;
1729 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1730 menu pops down.
1731 menu_item_selection will be set to the selection. */
1732 static void
1733 create_and_show_popup_menu (f, first_wv, x, y, for_click)
1734 FRAME_PTR f;
1735 widget_value *first_wv;
1736 int x;
1737 int y;
1738 int for_click;
1740 int i;
1741 GtkWidget *menu;
1742 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1743 struct next_popup_x_y popup_x_y;
1744 int specpdl_count = SPECPDL_INDEX ();
1746 if (! FRAME_X_P (f))
1747 abort ();
1749 xg_crazy_callback_abort = 1;
1750 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1751 G_CALLBACK (popup_selection_callback),
1752 G_CALLBACK (popup_deactivate_callback),
1753 G_CALLBACK (menu_highlight_callback));
1754 xg_crazy_callback_abort = 0;
1756 if (! for_click)
1758 /* Not invoked by a click. pop up at x/y. */
1759 pos_func = menu_position_func;
1761 /* Adjust coordinates to be root-window-relative. */
1762 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1763 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1765 popup_x_y.x = x;
1766 popup_x_y.y = y;
1767 popup_x_y.f = f;
1769 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1771 else
1773 for (i = 0; i < 5; i++)
1774 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1775 break;
1778 /* Display the menu. */
1779 gtk_widget_show_all (menu);
1780 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
1782 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1784 if (GTK_WIDGET_MAPPED (menu))
1786 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1787 two. show_help_echo uses this to detect popup menus. */
1788 popup_activated_flag = 1;
1789 /* Process events that apply to the menu. */
1790 popup_widget_loop (1, menu);
1793 unbind_to (specpdl_count, Qnil);
1795 /* Must reset this manually because the button release event is not passed
1796 to Emacs event loop. */
1797 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1800 #else /* not USE_GTK */
1802 /* We need a unique id for each widget handled by the Lucid Widget
1803 library.
1805 For the main windows, and popup menus, we use this counter,
1806 which we increment each time after use. This starts from 1<<16.
1808 For menu bars, we use numbers starting at 0, counted in
1809 next_menubar_widget_id. */
1810 LWLIB_ID widget_id_tick;
1812 static void
1813 popup_selection_callback (widget, id, client_data)
1814 Widget widget;
1815 LWLIB_ID id;
1816 XtPointer client_data;
1818 menu_item_selection = (Lisp_Object *) client_data;
1821 /* ARG is the LWLIB ID of the dialog box, represented
1822 as a Lisp object as (HIGHPART . LOWPART). */
1824 static Lisp_Object
1825 pop_down_menu (arg)
1826 Lisp_Object arg;
1828 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1829 | XINT (XCDR (arg)));
1831 BLOCK_INPUT;
1832 lw_destroy_all_widgets (id);
1833 UNBLOCK_INPUT;
1834 popup_activated_flag = 0;
1836 return Qnil;
1839 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1840 menu pops down.
1841 menu_item_selection will be set to the selection. */
1842 static void
1843 create_and_show_popup_menu (f, first_wv, x, y, for_click)
1844 FRAME_PTR f;
1845 widget_value *first_wv;
1846 int x;
1847 int y;
1848 int for_click;
1850 int i;
1851 Arg av[2];
1852 int ac = 0;
1853 XButtonPressedEvent dummy;
1854 LWLIB_ID menu_id;
1855 Widget menu;
1857 if (! FRAME_X_P (f))
1858 abort ();
1860 menu_id = widget_id_tick++;
1861 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1862 f->output_data.x->widget, 1, 0,
1863 popup_selection_callback,
1864 popup_deactivate_callback,
1865 menu_highlight_callback);
1867 dummy.type = ButtonPress;
1868 dummy.serial = 0;
1869 dummy.send_event = 0;
1870 dummy.display = FRAME_X_DISPLAY (f);
1871 dummy.time = CurrentTime;
1872 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1873 dummy.window = dummy.root;
1874 dummy.subwindow = dummy.root;
1875 dummy.x = x;
1876 dummy.y = y;
1878 /* Adjust coordinates to be root-window-relative. */
1879 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1880 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1882 dummy.x_root = x;
1883 dummy.y_root = y;
1885 dummy.state = 0;
1886 dummy.button = 0;
1887 for (i = 0; i < 5; i++)
1888 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1889 dummy.button = i;
1891 /* Don't allow any geometry request from the user. */
1892 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1893 XtSetValues (menu, av, ac);
1895 /* Display the menu. */
1896 lw_popup_menu (menu, (XEvent *) &dummy);
1897 popup_activated_flag = 1;
1898 x_activate_timeout_atimer ();
1901 int fact = 4 * sizeof (LWLIB_ID);
1902 int specpdl_count = SPECPDL_INDEX ();
1903 record_unwind_protect (pop_down_menu,
1904 Fcons (make_number (menu_id >> (fact)),
1905 make_number (menu_id & ~(-1 << (fact)))));
1907 /* Process events that apply to the menu. */
1908 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1910 unbind_to (specpdl_count, Qnil);
1914 #endif /* not USE_GTK */
1916 static Lisp_Object
1917 xmenu_show (f, x, y, for_click, keymaps, title, error)
1918 FRAME_PTR f;
1919 int x;
1920 int y;
1921 int for_click;
1922 int keymaps;
1923 Lisp_Object title;
1924 char **error;
1926 int i;
1927 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1928 widget_value **submenu_stack
1929 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1930 Lisp_Object *subprefix_stack
1931 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1932 int submenu_depth = 0;
1934 int first_pane;
1936 if (! FRAME_X_P (f))
1937 abort ();
1939 *error = NULL;
1941 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1943 *error = "Empty menu";
1944 return Qnil;
1947 /* Create a tree of widget_value objects
1948 representing the panes and their items. */
1949 wv = xmalloc_widget_value ();
1950 wv->name = "menu";
1951 wv->value = 0;
1952 wv->enabled = 1;
1953 wv->button_type = BUTTON_TYPE_NONE;
1954 wv->help =Qnil;
1955 first_wv = wv;
1956 first_pane = 1;
1958 /* Loop over all panes and items, filling in the tree. */
1959 i = 0;
1960 while (i < menu_items_used)
1962 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1964 submenu_stack[submenu_depth++] = save_wv;
1965 save_wv = prev_wv;
1966 prev_wv = 0;
1967 first_pane = 1;
1968 i++;
1970 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1972 prev_wv = save_wv;
1973 save_wv = submenu_stack[--submenu_depth];
1974 first_pane = 0;
1975 i++;
1977 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1978 && submenu_depth != 0)
1979 i += MENU_ITEMS_PANE_LENGTH;
1980 /* Ignore a nil in the item list.
1981 It's meaningful only for dialog boxes. */
1982 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1983 i += 1;
1984 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1986 /* Create a new pane. */
1987 Lisp_Object pane_name, prefix;
1988 char *pane_string;
1990 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1991 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1993 #ifndef HAVE_MULTILINGUAL_MENU
1994 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1996 pane_name = ENCODE_MENU_STRING (pane_name);
1997 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1999 #endif
2000 pane_string = (NILP (pane_name)
2001 ? "" : (char *) SDATA (pane_name));
2002 /* If there is just one top-level pane, put all its items directly
2003 under the top-level menu. */
2004 if (menu_items_n_panes == 1)
2005 pane_string = "";
2007 /* If the pane has a meaningful name,
2008 make the pane a top-level menu item
2009 with its items as a submenu beneath it. */
2010 if (!keymaps && strcmp (pane_string, ""))
2012 wv = xmalloc_widget_value ();
2013 if (save_wv)
2014 save_wv->next = wv;
2015 else
2016 first_wv->contents = wv;
2017 wv->name = pane_string;
2018 if (keymaps && !NILP (prefix))
2019 wv->name++;
2020 wv->value = 0;
2021 wv->enabled = 1;
2022 wv->button_type = BUTTON_TYPE_NONE;
2023 wv->help = Qnil;
2024 save_wv = wv;
2025 prev_wv = 0;
2027 else if (first_pane)
2029 save_wv = wv;
2030 prev_wv = 0;
2032 first_pane = 0;
2033 i += MENU_ITEMS_PANE_LENGTH;
2035 else
2037 /* Create a new item within current pane. */
2038 Lisp_Object item_name, enable, descrip, def, type, selected, help;
2039 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2040 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2041 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2042 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
2043 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
2044 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
2045 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2047 #ifndef HAVE_MULTILINGUAL_MENU
2048 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
2050 item_name = ENCODE_MENU_STRING (item_name);
2051 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
2054 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2056 descrip = ENCODE_MENU_STRING (descrip);
2057 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
2059 #endif /* not HAVE_MULTILINGUAL_MENU */
2061 wv = xmalloc_widget_value ();
2062 if (prev_wv)
2063 prev_wv->next = wv;
2064 else
2065 save_wv->contents = wv;
2066 wv->name = (char *) SDATA (item_name);
2067 if (!NILP (descrip))
2068 wv->key = (char *) SDATA (descrip);
2069 wv->value = 0;
2070 /* If this item has a null value,
2071 make the call_data null so that it won't display a box
2072 when the mouse is on it. */
2073 wv->call_data
2074 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
2075 wv->enabled = !NILP (enable);
2077 if (NILP (type))
2078 wv->button_type = BUTTON_TYPE_NONE;
2079 else if (EQ (type, QCtoggle))
2080 wv->button_type = BUTTON_TYPE_TOGGLE;
2081 else if (EQ (type, QCradio))
2082 wv->button_type = BUTTON_TYPE_RADIO;
2083 else
2084 abort ();
2086 wv->selected = !NILP (selected);
2088 if (! STRINGP (help))
2089 help = Qnil;
2091 wv->help = help;
2093 prev_wv = wv;
2095 i += MENU_ITEMS_ITEM_LENGTH;
2099 /* Deal with the title, if it is non-nil. */
2100 if (!NILP (title))
2102 widget_value *wv_title = xmalloc_widget_value ();
2103 widget_value *wv_sep1 = xmalloc_widget_value ();
2104 widget_value *wv_sep2 = xmalloc_widget_value ();
2106 wv_sep2->name = "--";
2107 wv_sep2->next = first_wv->contents;
2108 wv_sep2->help = Qnil;
2110 wv_sep1->name = "--";
2111 wv_sep1->next = wv_sep2;
2112 wv_sep1->help = Qnil;
2114 #ifndef HAVE_MULTILINGUAL_MENU
2115 if (STRING_MULTIBYTE (title))
2116 title = ENCODE_MENU_STRING (title);
2117 #endif
2119 wv_title->name = (char *) SDATA (title);
2120 wv_title->enabled = TRUE;
2121 wv_title->button_type = BUTTON_TYPE_NONE;
2122 wv_title->help = Qnil;
2123 wv_title->next = wv_sep1;
2124 first_wv->contents = wv_title;
2127 /* No selection has been chosen yet. */
2128 menu_item_selection = 0;
2130 /* Actually create and show the menu until popped down. */
2131 create_and_show_popup_menu (f, first_wv, x, y, for_click);
2133 /* Free the widget_value objects we used to specify the contents. */
2134 free_menubar_widget_value_tree (first_wv);
2136 /* Find the selected item, and its pane, to return
2137 the proper value. */
2138 if (menu_item_selection != 0)
2140 Lisp_Object prefix, entry;
2142 prefix = entry = Qnil;
2143 i = 0;
2144 while (i < menu_items_used)
2146 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
2148 subprefix_stack[submenu_depth++] = prefix;
2149 prefix = entry;
2150 i++;
2152 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
2154 prefix = subprefix_stack[--submenu_depth];
2155 i++;
2157 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2159 prefix
2160 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2161 i += MENU_ITEMS_PANE_LENGTH;
2163 /* Ignore a nil in the item list.
2164 It's meaningful only for dialog boxes. */
2165 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2166 i += 1;
2167 else
2169 entry
2170 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2171 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2173 if (keymaps != 0)
2175 int j;
2177 entry = Fcons (entry, Qnil);
2178 if (!NILP (prefix))
2179 entry = Fcons (prefix, entry);
2180 for (j = submenu_depth - 1; j >= 0; j--)
2181 if (!NILP (subprefix_stack[j]))
2182 entry = Fcons (subprefix_stack[j], entry);
2184 return entry;
2186 i += MENU_ITEMS_ITEM_LENGTH;
2190 else if (!for_click)
2191 /* Make "Cancel" equivalent to C-g. */
2192 Fsignal (Qquit, Qnil);
2194 return Qnil;
2197 #ifdef USE_GTK
2198 static void
2199 dialog_selection_callback (widget, client_data)
2200 GtkWidget *widget;
2201 gpointer client_data;
2203 /* The EMACS_INT cast avoids a warning. There's no problem
2204 as long as pointers have enough bits to hold small integers. */
2205 if ((int) (EMACS_INT) client_data != -1)
2206 menu_item_selection = (Lisp_Object *) client_data;
2208 popup_activated_flag = 0;
2211 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2212 dialog pops down.
2213 menu_item_selection will be set to the selection. */
2214 static void
2215 create_and_show_dialog (f, first_wv)
2216 FRAME_PTR f;
2217 widget_value *first_wv;
2219 GtkWidget *menu;
2221 if (! FRAME_X_P (f))
2222 abort ();
2224 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2225 G_CALLBACK (dialog_selection_callback),
2226 G_CALLBACK (popup_deactivate_callback),
2229 if (menu)
2231 int specpdl_count = SPECPDL_INDEX ();
2232 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
2234 /* Display the menu. */
2235 gtk_widget_show_all (menu);
2237 /* Process events that apply to the menu. */
2238 popup_widget_loop (1, menu);
2240 unbind_to (specpdl_count, Qnil);
2244 #else /* not USE_GTK */
2245 static void
2246 dialog_selection_callback (widget, id, client_data)
2247 Widget widget;
2248 LWLIB_ID id;
2249 XtPointer client_data;
2251 /* The EMACS_INT cast avoids a warning. There's no problem
2252 as long as pointers have enough bits to hold small integers. */
2253 if ((int) (EMACS_INT) client_data != -1)
2254 menu_item_selection = (Lisp_Object *) client_data;
2256 BLOCK_INPUT;
2257 lw_destroy_all_widgets (id);
2258 UNBLOCK_INPUT;
2259 popup_activated_flag = 0;
2263 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2264 dialog pops down.
2265 menu_item_selection will be set to the selection. */
2266 static void
2267 create_and_show_dialog (f, first_wv)
2268 FRAME_PTR f;
2269 widget_value *first_wv;
2271 LWLIB_ID dialog_id;
2273 if (!FRAME_X_P (f))
2274 abort();
2276 dialog_id = widget_id_tick++;
2277 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2278 f->output_data.x->widget, 1, 0,
2279 dialog_selection_callback, 0, 0);
2280 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2282 /* Display the dialog box. */
2283 lw_pop_up_all_widgets (dialog_id);
2284 popup_activated_flag = 1;
2285 x_activate_timeout_atimer ();
2287 /* Process events that apply to the dialog box.
2288 Also handle timers. */
2290 int count = SPECPDL_INDEX ();
2291 int fact = 4 * sizeof (LWLIB_ID);
2293 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2294 record_unwind_protect (pop_down_menu,
2295 Fcons (make_number (dialog_id >> (fact)),
2296 make_number (dialog_id & ~(-1 << (fact)))));
2298 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2299 dialog_id, 1);
2301 unbind_to (count, Qnil);
2305 #endif /* not USE_GTK */
2307 static char * button_names [] = {
2308 "button1", "button2", "button3", "button4", "button5",
2309 "button6", "button7", "button8", "button9", "button10" };
2311 static Lisp_Object
2312 xdialog_show (f, keymaps, title, header, error_name)
2313 FRAME_PTR f;
2314 int keymaps;
2315 Lisp_Object title, header;
2316 char **error_name;
2318 int i, nb_buttons=0;
2319 char dialog_name[6];
2321 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2323 /* Number of elements seen so far, before boundary. */
2324 int left_count = 0;
2325 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2326 int boundary_seen = 0;
2328 if (! FRAME_X_P (f))
2329 abort ();
2331 *error_name = NULL;
2333 if (menu_items_n_panes > 1)
2335 *error_name = "Multiple panes in dialog box";
2336 return Qnil;
2339 /* Create a tree of widget_value objects
2340 representing the text label and buttons. */
2342 Lisp_Object pane_name, prefix;
2343 char *pane_string;
2344 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2345 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2346 pane_string = (NILP (pane_name)
2347 ? "" : (char *) SDATA (pane_name));
2348 prev_wv = xmalloc_widget_value ();
2349 prev_wv->value = pane_string;
2350 if (keymaps && !NILP (prefix))
2351 prev_wv->name++;
2352 prev_wv->enabled = 1;
2353 prev_wv->name = "message";
2354 prev_wv->help = Qnil;
2355 first_wv = prev_wv;
2357 /* Loop over all panes and items, filling in the tree. */
2358 i = MENU_ITEMS_PANE_LENGTH;
2359 while (i < menu_items_used)
2362 /* Create a new item within current pane. */
2363 Lisp_Object item_name, enable, descrip;
2364 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2365 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2366 descrip
2367 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2369 if (NILP (item_name))
2371 free_menubar_widget_value_tree (first_wv);
2372 *error_name = "Submenu in dialog items";
2373 return Qnil;
2375 if (EQ (item_name, Qquote))
2377 /* This is the boundary between left-side elts
2378 and right-side elts. Stop incrementing right_count. */
2379 boundary_seen = 1;
2380 i++;
2381 continue;
2383 if (nb_buttons >= 9)
2385 free_menubar_widget_value_tree (first_wv);
2386 *error_name = "Too many dialog items";
2387 return Qnil;
2390 wv = xmalloc_widget_value ();
2391 prev_wv->next = wv;
2392 wv->name = (char *) button_names[nb_buttons];
2393 if (!NILP (descrip))
2394 wv->key = (char *) SDATA (descrip);
2395 wv->value = (char *) SDATA (item_name);
2396 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2397 wv->enabled = !NILP (enable);
2398 wv->help = Qnil;
2399 prev_wv = wv;
2401 if (! boundary_seen)
2402 left_count++;
2404 nb_buttons++;
2405 i += MENU_ITEMS_ITEM_LENGTH;
2408 /* If the boundary was not specified,
2409 by default put half on the left and half on the right. */
2410 if (! boundary_seen)
2411 left_count = nb_buttons - nb_buttons / 2;
2413 wv = xmalloc_widget_value ();
2414 wv->name = dialog_name;
2415 wv->help = Qnil;
2417 /* Frame title: 'Q' = Question, 'I' = Information.
2418 Can also have 'E' = Error if, one day, we want
2419 a popup for errors. */
2420 if (NILP(header))
2421 dialog_name[0] = 'Q';
2422 else
2423 dialog_name[0] = 'I';
2425 /* Dialog boxes use a really stupid name encoding
2426 which specifies how many buttons to use
2427 and how many buttons are on the right. */
2428 dialog_name[1] = '0' + nb_buttons;
2429 dialog_name[2] = 'B';
2430 dialog_name[3] = 'R';
2431 /* Number of buttons to put on the right. */
2432 dialog_name[4] = '0' + nb_buttons - left_count;
2433 dialog_name[5] = 0;
2434 wv->contents = first_wv;
2435 first_wv = wv;
2438 /* No selection has been chosen yet. */
2439 menu_item_selection = 0;
2441 /* Force a redisplay before showing the dialog. If a frame is created
2442 just before showing the dialog, its contents may not have been fully
2443 drawn, as this depends on timing of events from the X server. Redisplay
2444 is not done when a dialog is shown. If redisplay could be done in the
2445 X event loop (i.e. the X event loop does not run in a signal handler)
2446 this would not be needed. */
2447 Fredisplay (Qt);
2449 /* Actually create and show the dialog. */
2450 create_and_show_dialog (f, first_wv);
2452 /* Free the widget_value objects we used to specify the contents. */
2453 free_menubar_widget_value_tree (first_wv);
2455 /* Find the selected item, and its pane, to return
2456 the proper value. */
2457 if (menu_item_selection != 0)
2459 Lisp_Object prefix;
2461 prefix = Qnil;
2462 i = 0;
2463 while (i < menu_items_used)
2465 Lisp_Object entry;
2467 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2469 prefix
2470 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2471 i += MENU_ITEMS_PANE_LENGTH;
2473 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2475 /* This is the boundary between left-side elts and
2476 right-side elts. */
2477 ++i;
2479 else
2481 entry
2482 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2483 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2485 if (keymaps != 0)
2487 entry = Fcons (entry, Qnil);
2488 if (!NILP (prefix))
2489 entry = Fcons (prefix, entry);
2491 return entry;
2493 i += MENU_ITEMS_ITEM_LENGTH;
2497 else
2498 /* Make "Cancel" equivalent to C-g. */
2499 Fsignal (Qquit, Qnil);
2501 return Qnil;
2504 #else /* not USE_X_TOOLKIT && not USE_GTK */
2506 /* The frame of the last activated non-toolkit menu bar.
2507 Used to generate menu help events. */
2509 static struct frame *menu_help_frame;
2512 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2514 PANE is the pane number, and ITEM is the menu item number in
2515 the menu (currently not used).
2517 This cannot be done with generating a HELP_EVENT because
2518 XMenuActivate contains a loop that doesn't let Emacs process
2519 keyboard events. */
2521 static void
2522 menu_help_callback (help_string, pane, item)
2523 char *help_string;
2524 int pane, item;
2526 extern Lisp_Object Qmenu_item;
2527 Lisp_Object *first_item;
2528 Lisp_Object pane_name;
2529 Lisp_Object menu_object;
2531 first_item = XVECTOR (menu_items)->contents;
2532 if (EQ (first_item[0], Qt))
2533 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2534 else if (EQ (first_item[0], Qquote))
2535 /* This shouldn't happen, see xmenu_show. */
2536 pane_name = empty_unibyte_string;
2537 else
2538 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2540 /* (menu-item MENU-NAME PANE-NUMBER) */
2541 menu_object = Fcons (Qmenu_item,
2542 Fcons (pane_name,
2543 Fcons (make_number (pane), Qnil)));
2544 show_help_echo (help_string ? build_string (help_string) : Qnil,
2545 Qnil, menu_object, make_number (item), 1);
2548 static Lisp_Object
2549 pop_down_menu (arg)
2550 Lisp_Object arg;
2552 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2553 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2555 FRAME_PTR f = p1->pointer;
2556 XMenu *menu = p2->pointer;
2558 BLOCK_INPUT;
2559 #ifndef MSDOS
2560 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2561 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2562 #endif
2563 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2565 #ifdef HAVE_X_WINDOWS
2566 /* Assume the mouse has moved out of the X window.
2567 If it has actually moved in, we will get an EnterNotify. */
2568 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2570 /* State that no mouse buttons are now held.
2571 (The oldXMenu code doesn't track this info for us.)
2572 That is not necessarily true, but the fiction leads to reasonable
2573 results, and it is a pain to ask which are actually held now. */
2574 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2576 #endif /* HAVE_X_WINDOWS */
2578 UNBLOCK_INPUT;
2580 return Qnil;
2584 static Lisp_Object
2585 xmenu_show (f, x, y, for_click, keymaps, title, error)
2586 FRAME_PTR f;
2587 int x, y;
2588 int for_click;
2589 int keymaps;
2590 Lisp_Object title;
2591 char **error;
2593 Window root;
2594 XMenu *menu;
2595 int pane, selidx, lpane, status;
2596 Lisp_Object entry, pane_prefix;
2597 char *datap;
2598 int ulx, uly, width, height;
2599 int dispwidth, dispheight;
2600 int i, j, lines, maxlines;
2601 int maxwidth;
2602 int dummy_int;
2603 unsigned int dummy_uint;
2604 int specpdl_count = SPECPDL_INDEX ();
2606 if (! FRAME_X_P (f))
2607 abort ();
2609 *error = 0;
2610 if (menu_items_n_panes == 0)
2611 return Qnil;
2613 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2615 *error = "Empty menu";
2616 return Qnil;
2619 /* Figure out which root window F is on. */
2620 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2621 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2622 &dummy_uint, &dummy_uint);
2624 /* Make the menu on that window. */
2625 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2626 if (menu == NULL)
2628 *error = "Can't create menu";
2629 return Qnil;
2632 /* Don't GC while we prepare and show the menu,
2633 because we give the oldxmenu library pointers to the
2634 contents of strings. */
2635 inhibit_garbage_collection ();
2637 #ifdef HAVE_X_WINDOWS
2638 /* Adjust coordinates to relative to the outer (window manager) window. */
2639 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2640 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2641 #endif /* HAVE_X_WINDOWS */
2643 /* Adjust coordinates to be root-window-relative. */
2644 x += f->left_pos;
2645 y += f->top_pos;
2647 /* Create all the necessary panes and their items. */
2648 maxlines = lines = i = 0;
2649 while (i < menu_items_used)
2651 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2653 /* Create a new pane. */
2654 Lisp_Object pane_name, prefix;
2655 char *pane_string;
2657 maxlines = max (maxlines, lines);
2658 lines = 0;
2659 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2660 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2661 pane_string = (NILP (pane_name)
2662 ? "" : (char *) SDATA (pane_name));
2663 if (keymaps && !NILP (prefix))
2664 pane_string++;
2666 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2667 if (lpane == XM_FAILURE)
2669 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2670 *error = "Can't create pane";
2671 return Qnil;
2673 i += MENU_ITEMS_PANE_LENGTH;
2675 /* Find the width of the widest item in this pane. */
2676 maxwidth = 0;
2677 j = i;
2678 while (j < menu_items_used)
2680 Lisp_Object item;
2681 item = XVECTOR (menu_items)->contents[j];
2682 if (EQ (item, Qt))
2683 break;
2684 if (NILP (item))
2686 j++;
2687 continue;
2689 width = SBYTES (item);
2690 if (width > maxwidth)
2691 maxwidth = width;
2693 j += MENU_ITEMS_ITEM_LENGTH;
2696 /* Ignore a nil in the item list.
2697 It's meaningful only for dialog boxes. */
2698 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2699 i += 1;
2700 else
2702 /* Create a new item within current pane. */
2703 Lisp_Object item_name, enable, descrip, help;
2704 unsigned char *item_data;
2705 char *help_string;
2707 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2708 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2709 descrip
2710 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2711 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2712 help_string = STRINGP (help) ? SDATA (help) : NULL;
2714 if (!NILP (descrip))
2716 int gap = maxwidth - SBYTES (item_name);
2717 /* if alloca is fast, use that to make the space,
2718 to reduce gc needs. */
2719 item_data
2720 = (unsigned char *) alloca (maxwidth
2721 + SBYTES (descrip) + 1);
2722 bcopy (SDATA (item_name), item_data,
2723 SBYTES (item_name));
2724 for (j = SCHARS (item_name); j < maxwidth; j++)
2725 item_data[j] = ' ';
2726 bcopy (SDATA (descrip), item_data + j,
2727 SBYTES (descrip));
2728 item_data[j + SBYTES (descrip)] = 0;
2730 else
2731 item_data = SDATA (item_name);
2733 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2734 menu, lpane, 0, item_data,
2735 !NILP (enable), help_string)
2736 == XM_FAILURE)
2738 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2739 *error = "Can't add selection to menu";
2740 return Qnil;
2742 i += MENU_ITEMS_ITEM_LENGTH;
2743 lines++;
2747 maxlines = max (maxlines, lines);
2749 /* All set and ready to fly. */
2750 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2751 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2752 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2753 x = min (x, dispwidth);
2754 y = min (y, dispheight);
2755 x = max (x, 1);
2756 y = max (y, 1);
2757 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2758 &ulx, &uly, &width, &height);
2759 if (ulx+width > dispwidth)
2761 x -= (ulx + width) - dispwidth;
2762 ulx = dispwidth - width;
2764 if (uly+height > dispheight)
2766 y -= (uly + height) - dispheight;
2767 uly = dispheight - height;
2769 if (ulx < 0) x -= ulx;
2770 if (uly < 0) y -= uly;
2772 if (! for_click)
2774 /* If position was not given by a mouse click, adjust so upper left
2775 corner of the menu as a whole ends up at given coordinates. This
2776 is what x-popup-menu says in its documentation. */
2777 x += width/2;
2778 y += 1.5*height/(maxlines+2);
2781 XMenuSetAEQ (menu, TRUE);
2782 XMenuSetFreeze (menu, TRUE);
2783 pane = selidx = 0;
2785 #ifndef MSDOS
2786 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2787 #endif
2789 record_unwind_protect (pop_down_menu,
2790 Fcons (make_save_value (f, 0),
2791 make_save_value (menu, 0)));
2793 /* Help display under X won't work because XMenuActivate contains
2794 a loop that doesn't give Emacs a chance to process it. */
2795 menu_help_frame = f;
2796 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2797 x, y, ButtonReleaseMask, &datap,
2798 menu_help_callback);
2800 switch (status)
2802 case XM_SUCCESS:
2803 #ifdef XDEBUG
2804 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2805 #endif
2807 /* Find the item number SELIDX in pane number PANE. */
2808 i = 0;
2809 while (i < menu_items_used)
2811 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2813 if (pane == 0)
2814 pane_prefix
2815 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2816 pane--;
2817 i += MENU_ITEMS_PANE_LENGTH;
2819 else
2821 if (pane == -1)
2823 if (selidx == 0)
2825 entry
2826 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2827 if (keymaps != 0)
2829 entry = Fcons (entry, Qnil);
2830 if (!NILP (pane_prefix))
2831 entry = Fcons (pane_prefix, entry);
2833 break;
2835 selidx--;
2837 i += MENU_ITEMS_ITEM_LENGTH;
2840 break;
2842 case XM_FAILURE:
2843 *error = "Can't activate menu";
2844 case XM_IA_SELECT:
2845 entry = Qnil;
2846 break;
2847 case XM_NO_SELECT:
2848 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2849 the menu was invoked with a mouse event as POSITION). */
2850 if (! for_click)
2851 Fsignal (Qquit, Qnil);
2852 entry = Qnil;
2853 break;
2856 unbind_to (specpdl_count, Qnil);
2858 return entry;
2861 #endif /* not USE_X_TOOLKIT */
2863 #endif /* HAVE_MENUS */
2865 /* Detect if a dialog or menu has been posted. */
2868 popup_activated ()
2870 return popup_activated_flag;
2873 /* The following is used by delayed window autoselection. */
2875 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2876 doc: /* Return t if a menu or popup dialog is active. */)
2879 #ifdef HAVE_MENUS
2880 return (popup_activated ()) ? Qt : Qnil;
2881 #else
2882 return Qnil;
2883 #endif /* HAVE_MENUS */
2886 void
2887 syms_of_xmenu ()
2889 Qdebug_on_next_call = intern ("debug-on-next-call");
2890 staticpro (&Qdebug_on_next_call);
2892 #ifdef USE_X_TOOLKIT
2893 widget_id_tick = (1<<16);
2894 next_menubar_widget_id = 1;
2895 #endif
2897 defsubr (&Sx_popup_menu);
2898 defsubr (&Smenu_or_popup_active_p);
2900 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2901 defsubr (&Sx_menu_bar_open_internal);
2902 Ffset (intern ("accelerate-menu"),
2903 intern (Sx_menu_bar_open_internal.symbol_name));
2904 #endif
2906 #ifdef HAVE_MENUS
2907 defsubr (&Sx_popup_dialog);
2908 #endif
2911 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2912 (do not change this comment) */