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. */
34 #if 0 /* Why was this included? And without syssignal.h? */
35 /* On 4.3 this loses if it comes after xterm.h. */
45 #include "termhooks.h"
47 #include "blockinput.h"
51 #include "sysselect.h"
58 /* This may include sys/types.h, and that somehow loses
59 if this is not done before the other system files. */
63 /* Load sys/types.h if not already loaded.
64 In some systems loading it twice is suicidal. */
66 #include <sys/types.h>
69 #include "dispextern.h"
72 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
73 code accepts the Emacs internal encoding. */
74 #undef HAVE_MULTILINGUAL_MENU
78 #include <X11/IntrinsicP.h>
79 #include <X11/CoreP.h>
80 #include <X11/StringDefs.h>
81 #include <X11/Shell.h>
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 */
92 #include "../oldXMenu/XMenu.h"
94 #endif /* not USE_X_TOOLKIT */
95 #endif /* HAVE_X_WINDOWS */
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
;
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
,
123 static void popup_get_selection
P_ ((XEvent
*, struct x_display_info
*,
125 #endif /* USE_X_TOOLKIT */
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
,
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));
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
;
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
)
166 Lisp_Object tail
, frame
;
169 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
175 if (!FRAME_WINDOW_P (f
))
177 if (f
->output_data
.x
->id
== id
)
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. */
194 mouse_position_for_popup (f
, x
, y
)
199 Window root
, dummy_window
;
207 XQueryPointer (FRAME_X_DISPLAY (f
),
208 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
210 /* The root window which contains the pointer. */
213 /* Window pointer is on, not used */
216 /* The position on that root window. */
219 /* x/y in dummy_window coordinates, not used. */
222 /* Modifier keys and pointer buttons, about which
224 (unsigned int *) &dummy
);
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
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
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. */)
280 Lisp_Object position
, menu
;
282 Lisp_Object keymap
, tem
;
283 int xpos
= 0, ypos
= 0;
285 char *error_name
= NULL
;
286 Lisp_Object selection
= Qnil
;
288 Lisp_Object x
, y
, window
;
291 int specpdl_count
= SPECPDL_INDEX ();
295 if (! NILP (position
))
297 int get_current_pos_p
= 0;
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;
309 tem
= Fcar (position
);
312 window
= Fcar (Fcdr (position
));
314 y
= Fcar (XCDR (tem
));
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) */
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. */
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
;
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 */
364 XSETFRAME (window
, new_f
);
367 window
= selected_window
;
376 /* Decode where to put the menu. */
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
));
393 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
394 but I don't want to make one now. */
395 CHECK_WINDOW (window
);
401 error ("Can not put X menu on non-X terminal");
403 XSETFRAME (Vmenu_updating_frame
, f
);
406 Vmenu_updating_frame
= Qnil
;
407 #endif /* HAVE_MENUS */
409 record_unwind_protect (unuse_menu_items
, Qnil
);
413 /* Decode the menu items from what was specified. */
415 keymap
= get_keymap (menu
, 0, 0);
418 /* We were given a keymap. Extract menu info from the keymap. */
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
))
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
;
436 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
438 /* We were given a list of keymaps. */
439 int nmaps
= XFASTINT (Flength (menu
));
441 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
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
))
452 maps
[i
++] = keymap
= get_keymap (XCAR (tem
), 1, 0);
454 prompt
= Fkeymap_prompt (keymap
);
455 if (NILP (title
) && !NILP (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
;
470 /* We were given an old-fashioned menu. */
472 CHECK_STRING (title
);
474 list_of_panes (Fcdr (menu
));
479 unbind_to (specpdl_count
, Qnil
);
483 discard_menu_items ();
489 /* Display them in a menu. */
492 selection
= xmenu_show (f
, xpos
, ypos
, for_click
,
493 keymaps
, title
, &error_name
);
496 discard_menu_items ();
499 #endif /* HAVE_MENUS */
501 if (error_name
) error (error_name
);
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
;
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
;
551 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
554 XSETFRAME (window
, new_f
);
556 window
= selected_window
;
558 window
= selected_window
;
560 else if (CONSP (position
))
563 tem
= Fcar (position
);
565 window
= Fcar (Fcdr (position
));
568 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
569 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
572 else if (WINDOWP (position
) || FRAMEP (position
))
577 /* Decode where to put the menu. */
581 else if (WINDOWP (window
))
583 CHECK_LIVE_WINDOW (window
);
584 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
587 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
588 but I don't want to make one now. */
589 CHECK_WINDOW (window
);
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
)));
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
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. */
629 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
632 unbind_to (specpdl_count
, Qnil
);
633 discard_menu_items ();
635 if (error_name
) error (error_name
);
644 /* Set menu_items_inuse so no other popup menu or dialog is created. */
647 x_menu_set_in_use (in_use
)
650 menu_items_inuse
= in_use
? Qt
: Qnil
;
651 popup_activated_flag
= in_use
;
653 if (popup_activated_flag
)
654 x_activate_timeout_atimer ();
658 /* Wait for an X event to arrive or for a timer to expire. */
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. */
672 ! XtAppPending (Xt_app_con
)
673 #elif defined USE_GTK
674 ! gtk_events_pending ()
676 ! XPending ((Display
*) data
)
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
;
688 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
690 int fd
= ConnectionNumber (dpyinfo
->display
);
691 FD_SET (fd
, &read_fds
);
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
);
709 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
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. */
721 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
722 XEvent
*initial_event
;
723 struct x_display_info
*dpyinfo
;
729 while (popup_activated_flag
)
733 event
= *initial_event
;
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;
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. */)
786 FRAME_PTR f
= check_x_frame (frame
);
790 if (FRAME_EXTERNAL_MENU_BAR (f
))
791 set_frame_menubar (f
, 0, 1);
793 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
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
;
814 XtSetArg (al
[0], XtNchildren
, &list
);
815 XtSetArg (al
[1], XtNnumChildren
, &nr
);
816 XtGetValues (menubar
, al
, 2);
817 ev
.xbutton
.window
= XtWindow (list
[0]);
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
,
831 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
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
);
850 #endif /* USE_X_TOOLKIT */
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. */)
867 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
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
;
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
);
893 /* Loop util popup_activated_flag is set to zero in a callback.
894 Used for popup menus and dialogs. */
897 popup_widget_loop (do_timers
, 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 ();
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. */
927 x_activate_menubar (f
)
933 if (!f
->output_data
.x
->saved_menu_event
->type
)
937 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
938 f
->output_data
.x
->saved_menu_event
->xany
.window
))
942 set_frame_menubar (f
, 0, 1);
945 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
946 f
->output_data
.x
->saved_menu_event
);
947 popup_activated_flag
= 1;
949 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
953 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
954 pending_menu_activation
= 1;
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. */
966 popup_activate_callback (widget
, id
, client_data
)
969 XtPointer client_data
;
971 popup_activated_flag
= 1;
973 x_activate_timeout_atimer ();
978 /* This callback is invoked when a dialog or menu is finished being
979 used and has been unposted. */
983 popup_deactivate_callback (widget
, client_data
)
985 gpointer client_data
;
987 popup_activated_flag
= 0;
991 popup_deactivate_callback (widget
, id
, client_data
)
994 XtPointer client_data
;
996 popup_activated_flag
= 0;
1001 /* Function that finds the frame for WIDGET and shows the HELP text
1003 F is the frame if known, or NULL if not known. */
1005 show_help_event (f
, widget
, help
)
1007 xt_or_gtk_widget widget
;
1014 XSETFRAME (frame
, f
);
1015 kbd_buffer_store_help_event (frame
, help
);
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
);
1025 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
1027 frame
= XCAR (tail
);
1029 && (f
= XFRAME (frame
),
1030 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
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
1046 menu_highlight_callback (widget
, call_data
)
1050 xg_menu_item_cb_data
*cb_data
;
1053 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
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
);
1067 menu_highlight_callback (widget
, id
, call_data
)
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
);
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. */
1098 menubar_selection_callback (widget
, client_data
)
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
)
1107 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
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
)))
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
1126 while (gtk_events_pending ())
1127 gtk_main_iteration ();
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. */
1143 menubar_selection_callback (widget
, id
, client_data
)
1146 XtPointer client_data
;
1150 f
= menubar_id_to_frame (id
);
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. */
1162 update_frame_menubar (f
)
1166 return xg_update_frame_menubar (f
);
1171 if (! FRAME_X_P (f
))
1174 x
= f
->output_data
.x
;
1176 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
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
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
);
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. */
1216 set_frame_menubar (f
, first_time
, deep_p
)
1221 xt_or_gtk_widget menubar_widget
;
1222 #ifdef USE_X_TOOLKIT
1226 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1228 int *submenu_start
, *submenu_end
;
1229 int *submenu_top_level_items
, *submenu_n_panes
;
1231 if (! FRAME_X_P (f
))
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
;
1244 if (! menubar_widget
)
1246 else if (pending_menu_activation
&& !deep_p
)
1248 /* Make the first call for any given frame always go deep. */
1249 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1252 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1253 f
->output_data
.x
->saved_menu_event
->type
= 0;
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 ();
1264 /* Make a widget-value tree representing the entire menu trees. */
1266 struct buffer
*prev
= current_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. */
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 *));
1323 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1325 Lisp_Object key
, string
, maps
;
1329 key
= XVECTOR (items
)->contents
[i
];
1330 string
= XVECTOR (items
)->contents
[i
+ 1];
1331 maps
= XVECTOR (items
)->contents
[i
+ 2];
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";
1354 wv
->button_type
= BUTTON_TYPE_NONE
;
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
]);
1366 first_wv
->contents
= wv
;
1367 /* Don't set wv->name here; GC during the loop might relocate it. */
1369 wv
->button_type
= BUTTON_TYPE_NONE
;
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
])))
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
);
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)
1406 string
= XVECTOR (items
)->contents
[i
+ 1];
1409 wv
->name
= (char *) SDATA (string
);
1410 update_submenu_strings (wv
->contents
);
1417 /* Make a widget-value tree containing
1418 just the top level menu bar strings. */
1420 wv
= xmalloc_widget_value ();
1421 wv
->name
= "menubar";
1424 wv
->button_type
= BUTTON_TYPE_NONE
;
1428 items
= FRAME_MENU_BAR_ITEMS (f
);
1429 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1433 string
= XVECTOR (items
)->contents
[i
+ 1];
1437 wv
= xmalloc_widget_value ();
1438 wv
->name
= (char *) SDATA (string
);
1441 wv
->button_type
= BUTTON_TYPE_NONE
;
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);
1452 first_wv
->contents
= 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. */
1467 xg_crazy_callback_abort
= 1;
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
,
1476 G_CALLBACK (menubar_selection_callback
),
1477 G_CALLBACK (popup_deactivate_callback
),
1478 G_CALLBACK (menu_highlight_callback
));
1482 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_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 */
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
);
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
);
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
)
1532 #if 0 /* Experimentally, we now get the right results
1533 for -geometry -0-0 without this. 24 Aug 96, rms. */
1535 if (FRAME_EXTERNAL_MENU_BAR (f
))
1538 XtVaGetValues (f
->output_data
.x
->column_widget
,
1539 XtNinternalBorderWidth
, &ibw
, NULL
);
1540 menubar_size
+= ibw
;
1542 #endif /* USE_LUCID */
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
);
1553 xg_crazy_callback_abort
= 0;
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
1565 initialize_frame_menubar (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. */
1581 free_frame_menubar (f
)
1584 Widget menubar_widget
;
1586 if (! FRAME_X_P (f
))
1589 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1591 f
->output_data
.x
->menubar_height
= 0;
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
;
1610 if (f
->output_data
.x
->widget
)
1611 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1614 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1615 f
->output_data
.x
->menubar_widget
= NULL
;
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
);
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
;
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
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. */
1676 menu_position_func (menu
, x
, y
, push_in
, user_data
)
1683 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1685 int disp_width
= FRAME_X_DISPLAY_INFO (data
->f
)->width
;
1686 int disp_height
= FRAME_X_DISPLAY_INFO (data
->f
)->height
;
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
;
1701 popup_selection_callback (widget
, client_data
)
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
;
1715 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1717 popup_activated_flag
= 0;
1719 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1724 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1726 menu_item_selection will be set to the selection. */
1728 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
1730 widget_value
*first_wv
;
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
))
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;
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
);
1764 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1768 for (i
= 0; i
< 5; i
++)
1769 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
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
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
;
1808 popup_selection_callback (widget
, id
, client_data
)
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). */
1823 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1824 | XINT (XCDR (arg
)));
1827 lw_destroy_all_widgets (id
);
1829 popup_activated_flag
= 0;
1834 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1836 menu_item_selection will be set to the selection. */
1838 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
1840 widget_value
*first_wv
;
1848 XButtonPressedEvent dummy
;
1852 if (! FRAME_X_P (f
))
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
;
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
;
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
);
1882 for (i
= 0; i
< 5; i
++)
1883 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << 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 */
1912 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
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;
1931 if (! FRAME_X_P (f
))
1936 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1938 *error
= "Empty menu";
1942 /* Create a tree of widget_value objects
1943 representing the panes and their items. */
1944 wv
= xmalloc_widget_value ();
1948 wv
->button_type
= BUTTON_TYPE_NONE
;
1953 /* Loop over all panes and items, filling in the tree. */
1955 while (i
< menu_items_used
)
1957 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1959 submenu_stack
[submenu_depth
++] = save_wv
;
1965 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1968 save_wv
= submenu_stack
[--submenu_depth
];
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
))
1979 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1981 /* Create a new pane. */
1982 Lisp_Object pane_name
, prefix
;
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
);
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)
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 ();
2011 first_wv
->contents
= wv
;
2012 wv
->name
= pane_string
;
2013 if (keymaps
&& !NILP (prefix
))
2017 wv
->button_type
= BUTTON_TYPE_NONE
;
2022 else if (first_pane
)
2028 i
+= MENU_ITEMS_PANE_LENGTH
;
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 ();
2060 save_wv
->contents
= wv
;
2061 wv
->name
= (char *) SDATA (item_name
);
2062 if (!NILP (descrip
))
2063 wv
->key
= (char *) SDATA (descrip
);
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. */
2069 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
2070 wv
->enabled
= !NILP (enable
);
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
;
2081 wv
->selected
= !NILP (selected
);
2083 if (! STRINGP (help
))
2090 i
+= MENU_ITEMS_ITEM_LENGTH
;
2094 /* Deal with the title, if it is non-nil. */
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
);
2114 wv_title
->name
= (char *) SDATA (title
);
2115 wv_title
->enabled
= TRUE
;
2116 wv_title
->button_type
= BUTTON_TYPE_NONE
;
2117 wv_title
->next
= wv_sep1
;
2118 wv_title
->help
= Qnil
;
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
;
2139 while (i
< menu_items_used
)
2141 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2143 subprefix_stack
[submenu_depth
++] = prefix
;
2147 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2149 prefix
= subprefix_stack
[--submenu_depth
];
2152 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
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
))
2165 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2166 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2172 entry
= Fcons (entry
, Qnil
);
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
);
2181 i
+= MENU_ITEMS_ITEM_LENGTH
;
2185 else if (!for_click
)
2186 /* Make "Cancel" equivalent to C-g. */
2187 Fsignal (Qquit
, Qnil
);
2194 dialog_selection_callback (widget
, client_data
)
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
2208 menu_item_selection will be set to the selection. */
2210 create_and_show_dialog (f
, first_wv
)
2212 widget_value
*first_wv
;
2216 if (! FRAME_X_P (f
))
2219 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
2220 G_CALLBACK (dialog_selection_callback
),
2221 G_CALLBACK (popup_deactivate_callback
),
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 */
2241 dialog_selection_callback (widget
, id
, client_data
)
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
;
2252 lw_destroy_all_widgets (id
);
2254 popup_activated_flag
= 0;
2258 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2260 menu_item_selection will be set to the selection. */
2262 create_and_show_dialog (f
, first_wv
)
2264 widget_value
*first_wv
;
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
),
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" };
2307 xdialog_show (f
, keymaps
, title
, header
, error_name
)
2310 Lisp_Object title
, header
;
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. */
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
))
2328 if (menu_items_n_panes
> 1)
2330 *error_name
= "Multiple panes in dialog box";
2334 /* Create a tree of widget_value objects
2335 representing the text label and buttons. */
2337 Lisp_Object pane_name
, prefix
;
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
))
2347 prev_wv
->enabled
= 1;
2348 prev_wv
->name
= "message";
2349 prev_wv
->help
= Qnil
;
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
];
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";
2370 if (EQ (item_name
, Qquote
))
2372 /* This is the boundary between left-side elts
2373 and right-side elts. Stop incrementing right_count. */
2378 if (nb_buttons
>= 9)
2380 free_menubar_widget_value_tree (first_wv
);
2381 *error_name
= "Too many dialog items";
2385 wv
= xmalloc_widget_value ();
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
);
2396 if (! boundary_seen
)
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
;
2412 /* Frame title: 'Q' = Question, 'I' = Information.
2413 Can also have 'E' = Error if, one day, we want
2414 a popup for errors. */
2416 dialog_name
[0] = 'Q';
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
;
2429 wv
->contents
= first_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. */
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)
2458 while (i
< menu_items_used
)
2462 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
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
2477 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2478 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2482 entry
= Fcons (entry
, Qnil
);
2484 entry
= Fcons (prefix
, entry
);
2488 i
+= MENU_ITEMS_ITEM_LENGTH
;
2493 /* Make "Cancel" equivalent to C-g. */
2494 Fsignal (Qquit
, 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
2517 menu_help_callback (help_string
, 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
;
2533 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2535 /* (menu-item MENU-NAME PANE-NUMBER) */
2536 menu_object
= Fcons (Qmenu_item
,
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);
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
;
2555 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2556 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
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 */
2580 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
2590 int pane
, selidx
, lpane
, status
;
2591 Lisp_Object entry
, pane_prefix
;
2593 int ulx
, uly
, width
, height
;
2594 int dispwidth
, dispheight
;
2595 int i
, j
, lines
, maxlines
;
2598 unsigned int dummy_uint
;
2599 int specpdl_count
= SPECPDL_INDEX ();
2601 if (! FRAME_X_P (f
))
2605 if (menu_items_n_panes
== 0)
2608 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2610 *error
= "Empty menu";
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");
2623 *error
= "Can't create menu";
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. */
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
;
2652 maxlines
= max (maxlines
, lines
);
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
))
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";
2668 i
+= MENU_ITEMS_PANE_LENGTH
;
2670 /* Find the width of the widest item in this pane. */
2673 while (j
< menu_items_used
)
2676 item
= XVECTOR (menu_items
)->contents
[j
];
2684 width
= SBYTES (item
);
2685 if (width
> maxwidth
)
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
))
2697 /* Create a new item within current pane. */
2698 Lisp_Object item_name
, enable
, descrip
, help
;
2699 unsigned char *item_data
;
2702 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2703 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
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. */
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
++)
2721 bcopy (SDATA (descrip
), item_data
+ j
,
2723 item_data
[j
+ SBYTES (descrip
)] = 0;
2726 item_data
= SDATA (item_name
);
2728 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2729 menu
, lpane
, 0, item_data
,
2730 !NILP (enable
), help_string
)
2733 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2734 *error
= "Can't add selection to menu";
2737 i
+= MENU_ITEMS_ITEM_LENGTH
;
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
);
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
;
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. */
2773 y
+= 1.5*height
/(maxlines
+2);
2776 XMenuSetAEQ (menu
, TRUE
);
2777 XMenuSetFreeze (menu
, TRUE
);
2781 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
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
);
2799 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2802 /* Find the item number SELIDX in pane number PANE. */
2804 while (i
< menu_items_used
)
2806 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2810 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2812 i
+= MENU_ITEMS_PANE_LENGTH
;
2821 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2824 entry
= Fcons (entry
, Qnil
);
2825 if (!NILP (pane_prefix
))
2826 entry
= Fcons (pane_prefix
, entry
);
2832 i
+= MENU_ITEMS_ITEM_LENGTH
;
2838 *error
= "Can't activate menu";
2843 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2844 the menu was invoked with a mouse event as POSITION). */
2846 Fsignal (Qquit
, Qnil
);
2851 unbind_to (specpdl_count
, Qnil
);
2856 #endif /* not USE_X_TOOLKIT */
2858 #endif /* HAVE_MENUS */
2860 /* Detect if a dialog or menu has been posted. */
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. */)
2875 return (popup_activated ()) ? Qt
: Qnil
;
2878 #endif /* HAVE_MENUS */
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;
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
));
2902 defsubr (&Sx_popup_dialog
);
2906 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2907 (do not change this comment) */