1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
27 /* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
30 /* Rewritten for clarity and GC protection by rms in Feb 94. */
34 #if 0 /* Why was this included? And without syssignal.h? */
35 /* On 4.3 this loses if it comes after xterm.h. */
46 #include "termhooks.h"
48 #include "blockinput.h"
52 #include "sysselect.h"
59 /* This may include sys/types.h, and that somehow loses
60 if this is not done before the other system files. */
64 /* Load sys/types.h if not already loaded.
65 In some systems loading it twice is suicidal. */
67 #include <sys/types.h>
70 #include "dispextern.h"
73 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
74 code accepts the Emacs internal encoding. */
75 #undef HAVE_MULTILINGUAL_MENU
79 #include <X11/IntrinsicP.h>
80 #include <X11/CoreP.h>
81 #include <X11/StringDefs.h>
82 #include <X11/Shell.h>
85 #include <X11/Xaw3d/Paned.h>
86 #else /* !HAVE_XAW3D */
87 #include <X11/Xaw/Paned.h>
88 #endif /* HAVE_XAW3D */
89 #endif /* USE_LUCID */
90 #include "../lwlib/lwlib.h"
91 #else /* not USE_X_TOOLKIT */
93 #include "../oldXMenu/XMenu.h"
95 #endif /* not USE_X_TOOLKIT */
96 #endif /* HAVE_X_WINDOWS */
109 Lisp_Object Qdebug_on_next_call
;
111 extern Lisp_Object Vmenu_updating_frame
;
113 extern Lisp_Object Qmenu_bar
;
115 extern Lisp_Object QCtoggle
, QCradio
;
117 extern Lisp_Object Voverriding_local_map
;
118 extern Lisp_Object Voverriding_local_map_menu_flag
;
120 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
122 extern Lisp_Object Qmenu_bar_update_hook
;
125 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
126 extern XtAppContext Xt_app_con
;
128 static Lisp_Object xdialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
130 static void popup_get_selection
P_ ((XEvent
*, struct x_display_info
*,
132 #endif /* USE_X_TOOLKIT */
135 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
136 static Lisp_Object xdialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
140 static int update_frame_menubar
P_ ((struct frame
*));
141 static Lisp_Object xmenu_show
P_ ((struct frame
*, int, int, int, int,
142 Lisp_Object
, char **, EMACS_UINT
));
144 /* Flag which when set indicates a dialog or menu has been posted by
145 Xt on behalf of one of the widget sets. */
146 static int popup_activated_flag
;
148 static int next_menubar_widget_id
;
150 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
151 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
152 extern widget_value
*xmalloc_widget_value
P_ ((void));
153 extern widget_value
*digest_single_submenu
P_ ((int, int, int));
156 /* This is set nonzero after the user activates the menu bar, and set
157 to zero again after the menu bars are redisplayed by prepare_menu_bar.
158 While it is nonzero, all calls to set_frame_menubar go deep.
160 I don't understand why this is needed, but it does seem to be
161 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
163 int pending_menu_activation
;
167 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
169 static struct frame
*
170 menubar_id_to_frame (id
)
173 Lisp_Object tail
, frame
;
176 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
182 if (!FRAME_WINDOW_P (f
))
184 if (f
->output_data
.x
->id
== id
)
192 #ifdef HAVE_X_WINDOWS
193 /* Return the mouse position in *X and *Y. The coordinates are window
194 relative for the edit window in frame F.
195 This is for Fx_popup_menu. The mouse_position_hook can not
196 be used for X, as it returns window relative coordinates
197 for the window where the mouse is in. This could be the menu bar,
198 the scroll bar or the edit window. Fx_popup_menu needs to be
199 sure it is the edit window. */
201 mouse_position_for_popup (f
, x
, y
)
206 Window root
, dummy_window
;
214 XQueryPointer (FRAME_X_DISPLAY (f
),
215 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
217 /* The root window which contains the pointer. */
220 /* Window pointer is on, not used */
223 /* The position on that root window. */
226 /* x/y in dummy_window coordinates, not used. */
229 /* Modifier keys and pointer buttons, about which
231 (unsigned int *) &dummy
);
235 /* xmenu_show expects window coordinates, not root window
236 coordinates. Translate. */
237 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
238 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
241 #endif /* HAVE_X_WINDOWS */
243 DEFUN ("x-popup-menu", Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
244 doc
: /* Pop up a deck-of-cards menu and return user's selection.
245 POSITION is a position specification. This is either a mouse button event
246 or a list ((XOFFSET YOFFSET) WINDOW)
247 where XOFFSET and YOFFSET are positions in pixels from the top left
248 corner of WINDOW. (WINDOW may be a window or a frame object.)
249 This controls the position of the top left of the menu as a whole.
250 If POSITION is t, it means to use the current mouse position.
252 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
253 The menu items come from key bindings that have a menu string as well as
254 a definition; actually, the "definition" in such a key binding looks like
255 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
256 the keymap as a top-level element.
258 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
259 Otherwise, REAL-DEFINITION should be a valid key binding definition.
261 You can also use a list of keymaps as MENU.
262 Then each keymap makes a separate pane.
264 When MENU is a keymap or a list of keymaps, the return value is the
265 list of events corresponding to the user's choice. Note that
266 `x-popup-menu' does not actually execute the command bound to that
269 Alternatively, you can specify a menu of multiple panes
270 with a list of the form (TITLE PANE1 PANE2...),
271 where each pane is a list of form (TITLE ITEM1 ITEM2...).
272 Each ITEM is normally a cons cell (STRING . VALUE);
273 but a string can appear as an item--that makes a nonselectable line
275 With this form of menu, the return value is VALUE from the chosen item.
277 If POSITION is nil, don't display the menu at all, just precalculate the
278 cached information about equivalent key sequences.
280 If the user gets rid of the menu without making a valid choice, for
281 instance by clicking the mouse away from a valid choice or by typing
282 keyboard input, then this normally results in a quit and
283 `x-popup-menu' does not return. But if POSITION is a mouse button
284 event (indicating that the user invoked the menu with the mouse) then
285 no quit occurs and `x-popup-menu' returns nil. */)
287 Lisp_Object position
, menu
;
289 Lisp_Object keymap
, tem
;
290 int xpos
= 0, ypos
= 0;
292 char *error_name
= NULL
;
293 Lisp_Object selection
= Qnil
;
295 Lisp_Object x
, y
, window
;
298 int specpdl_count
= SPECPDL_INDEX ();
299 Lisp_Object timestamp
= Qnil
;
303 if (! NILP (position
))
305 int get_current_pos_p
= 0;
308 /* Decode the first argument: find the window and the coordinates. */
309 if (EQ (position
, Qt
)
310 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
311 || EQ (XCAR (position
), Qtool_bar
))))
313 get_current_pos_p
= 1;
317 tem
= Fcar (position
);
320 window
= Fcar (Fcdr (position
));
322 y
= Fcar (XCDR (tem
));
327 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
328 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
329 tem
= Fcdr (Fcdr (tem
));
330 x
= Fcar (Fcar (tem
));
331 y
= Fcdr (Fcar (tem
));
332 timestamp
= Fcar (Fcdr (tem
));
335 /* If a click happens in an external tool bar or a detached
336 tool bar, x and y is NIL. In that case, use the current
337 mouse position. This happens for the help button in the
338 tool bar. Ideally popup-menu should pass NIL to
339 this function, but it doesn't. */
340 if (NILP (x
) && NILP (y
))
341 get_current_pos_p
= 1;
344 if (get_current_pos_p
)
346 /* Use the mouse's current position. */
347 FRAME_PTR new_f
= SELECTED_FRAME ();
348 #ifdef HAVE_X_WINDOWS
349 /* Can't use mouse_position_hook for X since it returns
350 coordinates relative to the window the mouse is in,
351 we need coordinates relative to the edit widget always. */
356 mouse_position_for_popup (new_f
, &cur_x
, &cur_y
);
357 /* cur_x/y may be negative, so use make_number. */
358 x
= make_number (cur_x
);
359 y
= make_number (cur_y
);
362 #else /* not HAVE_X_WINDOWS */
363 Lisp_Object bar_window
;
364 enum scroll_bar_part part
;
366 void (*mouse_position_hook
) P_ ((struct frame
**, int,
368 enum scroll_bar_part
*,
372 new_f
->terminal
->mouse_position_hook
;
374 if (mouse_position_hook
)
375 (*mouse_position_hook
) (&new_f
, 1, &bar_window
,
376 &part
, &x
, &y
, &time
);
377 #endif /* not HAVE_X_WINDOWS */
380 XSETFRAME (window
, new_f
);
383 window
= selected_window
;
392 /* Decode where to put the menu. */
400 else if (WINDOWP (window
))
402 CHECK_LIVE_WINDOW (window
);
403 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
405 xpos
= WINDOW_LEFT_EDGE_X (XWINDOW (window
));
406 ypos
= WINDOW_TOP_EDGE_Y (XWINDOW (window
));
409 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
410 but I don't want to make one now. */
411 CHECK_WINDOW (window
);
416 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
417 error ("Can not put X menu on this terminal");
419 XSETFRAME (Vmenu_updating_frame
, f
);
422 Vmenu_updating_frame
= Qnil
;
423 #endif /* HAVE_MENUS */
425 record_unwind_protect (unuse_menu_items
, Qnil
);
429 /* Decode the menu items from what was specified. */
431 keymap
= get_keymap (menu
, 0, 0);
434 /* We were given a keymap. Extract menu info from the keymap. */
437 /* Extract the detailed info to make one pane. */
438 keymap_panes (&menu
, 1, NILP (position
));
440 /* Search for a string appearing directly as an element of the keymap.
441 That string is the title of the menu. */
442 prompt
= Fkeymap_prompt (keymap
);
443 if (NILP (title
) && !NILP (prompt
))
446 /* Make that be the pane title of the first pane. */
447 if (!NILP (prompt
) && menu_items_n_panes
>= 0)
448 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
452 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
454 /* We were given a list of keymaps. */
455 int nmaps
= XFASTINT (Flength (menu
));
457 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
462 /* The first keymap that has a prompt string
463 supplies the menu title. */
464 for (tem
= menu
, i
= 0; CONSP (tem
); tem
= XCDR (tem
))
468 maps
[i
++] = keymap
= get_keymap (XCAR (tem
), 1, 0);
470 prompt
= Fkeymap_prompt (keymap
);
471 if (NILP (title
) && !NILP (prompt
))
475 /* Extract the detailed info to make one pane. */
476 keymap_panes (maps
, nmaps
, NILP (position
));
478 /* Make the title be the pane title of the first pane. */
479 if (!NILP (title
) && menu_items_n_panes
>= 0)
480 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title
;
486 /* We were given an old-fashioned menu. */
488 CHECK_STRING (title
);
490 list_of_panes (Fcdr (menu
));
495 unbind_to (specpdl_count
, Qnil
);
499 discard_menu_items ();
505 /* Display them in a menu. */
508 selection
= xmenu_show (f
, xpos
, ypos
, for_click
,
509 keymaps
, title
, &error_name
,
510 INTEGERP (timestamp
) ? XUINT (timestamp
) : 0);
513 discard_menu_items ();
516 #endif /* HAVE_MENUS */
518 if (error_name
) error (error_name
);
524 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
525 doc
: /* Pop up a dialog box and return user's selection.
526 POSITION specifies which frame to use.
527 This is normally a mouse button event or a window or frame.
528 If POSITION is t, it means to use the frame the mouse is on.
529 The dialog box appears in the middle of the specified frame.
531 CONTENTS specifies the alternatives to display in the dialog box.
532 It is a list of the form (DIALOG ITEM1 ITEM2...).
533 Each ITEM is a cons cell (STRING . VALUE).
534 The return value is VALUE from the chosen item.
536 An ITEM may also be just a string--that makes a nonselectable item.
537 An ITEM may also be nil--that means to put all preceding items
538 on the left of the dialog box and all following items on the right.
539 \(By default, approximately half appear on each side.)
541 If HEADER is non-nil, the frame title for the box is "Information",
542 otherwise it is "Question".
544 If the user gets rid of the dialog box without making a valid choice,
545 for instance using the window manager, then this produces a quit and
546 `x-popup-dialog' does not return. */)
547 (position
, contents
, header
)
548 Lisp_Object position
, contents
, header
;
555 /* Decode the first argument: find the window or frame to use. */
556 if (EQ (position
, Qt
)
557 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
558 || EQ (XCAR (position
), Qtool_bar
))))
560 #if 0 /* Using the frame the mouse is on may not be right. */
561 /* Use the mouse's current position. */
562 FRAME_PTR new_f
= SELECTED_FRAME ();
563 Lisp_Object bar_window
;
564 enum scroll_bar_part part
;
568 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
571 XSETFRAME (window
, new_f
);
573 window
= selected_window
;
575 window
= selected_window
;
577 else if (CONSP (position
))
580 tem
= Fcar (position
);
582 window
= Fcar (Fcdr (position
));
585 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
586 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
589 else if (WINDOWP (position
) || FRAMEP (position
))
594 /* Decode where to put the menu. */
598 else if (WINDOWP (window
))
600 CHECK_LIVE_WINDOW (window
);
601 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
604 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
605 but I don't want to make one now. */
606 CHECK_WINDOW (window
);
608 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
609 error ("Can not put X dialog on this terminal");
611 /* Force a redisplay before showing the dialog. If a frame is created
612 just before showing the dialog, its contents may not have been fully
613 drawn, as this depends on timing of events from the X server. Redisplay
614 is not done when a dialog is shown. If redisplay could be done in the
615 X event loop (i.e. the X event loop does not run in a signal handler)
616 this would not be needed.
618 Do this before creating the widget value that points to Lisp
619 string contents, because Fredisplay may GC and relocate them. */
622 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
623 /* Display a menu with these alternatives
624 in the middle of frame F. */
626 Lisp_Object x
, y
, frame
, newpos
;
627 XSETFRAME (frame
, f
);
628 XSETINT (x
, x_pixel_width (f
) / 2);
629 XSETINT (y
, x_pixel_height (f
) / 2);
630 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
632 return Fx_popup_menu (newpos
,
633 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
639 Lisp_Object selection
;
640 int specpdl_count
= SPECPDL_INDEX ();
642 /* Decode the dialog items from what was specified. */
643 title
= Fcar (contents
);
644 CHECK_STRING (title
);
645 record_unwind_protect (unuse_menu_items
, Qnil
);
647 if (NILP (Fcar (Fcdr (contents
))))
648 /* No buttons specified, add an "Ok" button so users can pop down
649 the dialog. Also, the lesstif/motif version crashes if there are
651 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
653 list_of_panes (Fcons (contents
, Qnil
));
655 /* Display them in a dialog box. */
657 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
660 unbind_to (specpdl_count
, Qnil
);
661 discard_menu_items ();
663 if (error_name
) error (error_name
);
672 /* Set menu_items_inuse so no other popup menu or dialog is created. */
675 x_menu_set_in_use (in_use
)
678 menu_items_inuse
= in_use
? Qt
: Qnil
;
679 popup_activated_flag
= in_use
;
681 if (popup_activated_flag
)
682 x_activate_timeout_atimer ();
686 /* Wait for an X event to arrive or for a timer to expire. */
689 x_menu_wait_for_event (void *data
)
691 extern EMACS_TIME timer_check
P_ ((int));
693 /* Another way to do this is to register a timer callback, that can be
694 done in GTK and Xt. But we have to do it like this when using only X
695 anyway, and with callbacks we would have three variants for timer handling
696 instead of the small ifdefs below. */
700 ! XtAppPending (Xt_app_con
)
701 #elif defined USE_GTK
702 ! gtk_events_pending ()
704 ! XPending ((Display
*) data
)
708 EMACS_TIME next_time
= timer_check (1);
709 long secs
= EMACS_SECS (next_time
);
710 long usecs
= EMACS_USECS (next_time
);
711 SELECT_TYPE read_fds
;
712 struct x_display_info
*dpyinfo
;
716 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
718 int fd
= ConnectionNumber (dpyinfo
->display
);
719 FD_SET (fd
, &read_fds
);
723 if (secs
< 0 || (secs
== 0 && usecs
== 0))
725 /* Sometimes timer_check returns -1 (no timers) even if there are
726 timers. So do a timeout anyway. */
727 EMACS_SET_SECS (next_time
, 1);
728 EMACS_SET_USECS (next_time
, 0);
731 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, &next_time
);
737 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
741 /* Loop in Xt until the menu pulldown or dialog popup has been
742 popped down (deactivated). This is used for x-popup-menu
743 and x-popup-dialog; it is not used for the menu bar.
745 NOTE: All calls to popup_get_selection should be protected
746 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
749 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
750 XEvent
*initial_event
;
751 struct x_display_info
*dpyinfo
;
757 while (popup_activated_flag
)
761 event
= *initial_event
;
766 if (do_timers
) x_menu_wait_for_event (0);
767 XtAppNextEvent (Xt_app_con
, &event
);
770 /* Make sure we don't consider buttons grabbed after menu goes.
771 And make sure to deactivate for any ButtonRelease,
772 even if XtDispatchEvent doesn't do that. */
773 if (event
.type
== ButtonRelease
774 && dpyinfo
->display
== event
.xbutton
.display
)
776 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
777 #ifdef USE_MOTIF /* Pretending that the event came from a
778 Btn1Down seems the only way to convince Motif to
779 activate its callbacks; setting the XmNmenuPost
780 isn't working. --marcus@sysc.pdx.edu. */
781 event
.xbutton
.button
= 1;
782 /* Motif only pops down menus when no Ctrl, Alt or Mod
783 key is pressed and the button is released. So reset key state
784 so Motif thinks this is the case. */
785 event
.xbutton
.state
= 0;
788 /* Pop down on C-g and Escape. */
789 else if (event
.type
== KeyPress
790 && dpyinfo
->display
== event
.xbutton
.display
)
792 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
794 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
795 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
796 popup_activated_flag
= 0;
799 x_dispatch_event (&event
, event
.xany
.display
);
803 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
804 doc
: /* Start key navigation of the menu bar in FRAME.
805 This initially opens the first menu bar item and you can then navigate with the
806 arrow keys, select a menu entry with the return key or cancel with the
807 escape key. If FRAME has no menu bar this function does nothing.
809 If FRAME is nil or not given, use the selected frame. */)
814 FRAME_PTR f
= check_x_frame (frame
);
818 if (FRAME_EXTERNAL_MENU_BAR (f
))
819 set_frame_menubar (f
, 0, 1);
821 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
827 x_catch_errors (FRAME_X_DISPLAY (f
));
828 memset (&ev
, 0, sizeof ev
);
829 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
830 ev
.xbutton
.window
= XtWindow (menubar
);
831 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
832 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
833 ev
.xbutton
.button
= Button1
;
834 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
835 ev
.xbutton
.same_screen
= True
;
842 XtSetArg (al
[0], XtNchildren
, &list
);
843 XtSetArg (al
[1], XtNnumChildren
, &nr
);
844 XtGetValues (menubar
, al
, 2);
845 ev
.xbutton
.window
= XtWindow (list
[0]);
849 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
850 /* From-window, to-window. */
851 ev
.xbutton
.window
, ev
.xbutton
.root
,
853 /* From-position, to-position. */
854 ev
.xbutton
.x
, ev
.xbutton
.y
,
855 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
859 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
864 ev
.type
= ButtonPress
;
865 ev
.xbutton
.state
= 0;
867 XtDispatchEvent (&ev
);
868 ev
.xbutton
.type
= ButtonRelease
;
869 ev
.xbutton
.state
= Button1Mask
;
870 XtDispatchEvent (&ev
);
878 #endif /* USE_X_TOOLKIT */
882 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
883 doc
: /* Start key navigation of the menu bar in FRAME.
884 This initially opens the first menu bar item and you can then navigate with the
885 arrow keys, select a menu entry with the return key or cancel with the
886 escape key. If FRAME has no menu bar this function does nothing.
888 If FRAME is nil or not given, use the selected frame. */)
895 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
899 f
= check_x_frame (frame
);
901 if (FRAME_EXTERNAL_MENU_BAR (f
))
902 set_frame_menubar (f
, 0, 1);
904 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
907 /* Activate the first menu. */
908 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
912 g_signal_emit_by_name (children
->data
, "activate_item");
913 popup_activated_flag
= 1;
914 g_list_free (children
);
922 /* Loop util popup_activated_flag is set to zero in a callback.
923 Used for popup menus and dialogs. */
926 popup_widget_loop (do_timers
, widget
)
930 ++popup_activated_flag
;
932 /* Process events in the Gtk event loop until done. */
933 while (popup_activated_flag
)
935 if (do_timers
) x_menu_wait_for_event (0);
936 gtk_main_iteration ();
941 /* Activate the menu bar of frame F.
942 This is called from keyboard.c when it gets the
943 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
945 To activate the menu bar, we use the X button-press event
946 that was saved in saved_menu_event.
947 That makes the toolkit do its thing.
949 But first we recompute the menu bar contents (the whole tree).
951 The reason for saving the button event until here, instead of
952 passing it to the toolkit right away, is that we can safely
953 execute Lisp code. */
956 x_activate_menubar (f
)
962 if (!f
->output_data
.x
->saved_menu_event
->type
)
966 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
967 f
->output_data
.x
->saved_menu_event
->xany
.window
))
971 set_frame_menubar (f
, 0, 1);
974 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
975 f
->output_data
.x
->saved_menu_event
);
976 popup_activated_flag
= 1;
978 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
982 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
983 pending_menu_activation
= 1;
986 /* Ignore this if we get it a second time. */
987 f
->output_data
.x
->saved_menu_event
->type
= 0;
990 /* This callback is invoked when the user selects a menubar cascade
991 pushbutton, but before the pulldown menu is posted. */
995 popup_activate_callback (widget
, id
, client_data
)
998 XtPointer client_data
;
1000 popup_activated_flag
= 1;
1001 #ifdef USE_X_TOOLKIT
1002 x_activate_timeout_atimer ();
1007 /* This callback is invoked when a dialog or menu is finished being
1008 used and has been unposted. */
1012 popup_deactivate_callback (widget
, client_data
)
1014 gpointer client_data
;
1016 popup_activated_flag
= 0;
1020 popup_deactivate_callback (widget
, id
, client_data
)
1023 XtPointer client_data
;
1025 popup_activated_flag
= 0;
1030 /* Function that finds the frame for WIDGET and shows the HELP text
1032 F is the frame if known, or NULL if not known. */
1034 show_help_event (f
, widget
, help
)
1036 xt_or_gtk_widget widget
;
1043 XSETFRAME (frame
, f
);
1044 kbd_buffer_store_help_event (frame
, help
);
1048 #if 0 /* This code doesn't do anything useful. ++kfs */
1049 /* WIDGET is the popup menu. It's parent is the frame's
1050 widget. See which frame that is. */
1051 xt_or_gtk_widget frame_widget
= XtParent (widget
);
1054 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
1056 frame
= XCAR (tail
);
1058 && (f
= XFRAME (frame
),
1059 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
1063 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
1067 /* Callback called when menu items are highlighted/unhighlighted
1068 while moving the mouse over them. WIDGET is the menu bar or menu
1069 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
1070 the data structure for the menu item, or null in case of
1075 menu_highlight_callback (widget
, call_data
)
1079 xg_menu_item_cb_data
*cb_data
;
1082 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
1084 if (! cb_data
) return;
1086 help
= call_data
? cb_data
->help
: Qnil
;
1088 /* If popup_activated_flag is greater than 1 we are in a popup menu.
1089 Don't show help for them, they won't appear before the
1090 popup is popped down. */
1091 if (popup_activated_flag
<= 1)
1092 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
1096 menu_highlight_callback (widget
, id
, call_data
)
1104 widget_value
*wv
= (widget_value
*) call_data
;
1106 help
= wv
? wv
->help
: Qnil
;
1108 /* Determine the frame for the help event. */
1109 f
= menubar_id_to_frame (id
);
1111 show_help_event (f
, widget
, help
);
1116 /* Gtk calls callbacks just because we tell it what item should be
1117 selected in a radio group. If this variable is set to a non-zero
1118 value, we are creating menus and don't want callbacks right now.
1120 static int xg_crazy_callback_abort
;
1122 /* This callback is called from the menu bar pulldown menu
1123 when the user makes a selection.
1124 Figure out what the user chose
1125 and put the appropriate events into the keyboard buffer. */
1127 menubar_selection_callback (widget
, client_data
)
1129 gpointer client_data
;
1131 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1133 if (xg_crazy_callback_abort
)
1136 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
1139 /* For a group of radio buttons, GTK calls the selection callback first
1140 for the item that was active before the selection and then for the one that
1141 is active after the selection. For C-h k this means we get the help on
1142 the deselected item and then the selected item is executed. Prevent that
1143 by ignoring the non-active item. */
1144 if (GTK_IS_RADIO_MENU_ITEM (widget
)
1145 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
1148 /* When a menu is popped down, X generates a focus event (i.e. focus
1149 goes back to the frame below the menu). Since GTK buffers events,
1150 we force it out here before the menu selection event. Otherwise
1151 sit-for will exit at once if the focus event follows the menu selection
1155 while (gtk_events_pending ())
1156 gtk_main_iteration ();
1159 find_and_call_menu_selection (cb_data
->cl_data
->f
,
1160 cb_data
->cl_data
->menu_bar_items_used
,
1161 cb_data
->cl_data
->menu_bar_vector
,
1162 cb_data
->call_data
);
1165 #else /* not USE_GTK */
1167 /* This callback is called from the menu bar pulldown menu
1168 when the user makes a selection.
1169 Figure out what the user chose
1170 and put the appropriate events into the keyboard buffer. */
1172 menubar_selection_callback (widget
, id
, client_data
)
1175 XtPointer client_data
;
1179 f
= menubar_id_to_frame (id
);
1182 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
1183 f
->menu_bar_vector
, client_data
);
1185 #endif /* not USE_GTK */
1187 /* Recompute all the widgets of frame F, when the menu bar has been
1188 changed. Value is non-zero if widgets were updated. */
1191 update_frame_menubar (f
)
1195 return xg_update_frame_menubar (f
);
1200 if (! FRAME_X_P (f
))
1203 x
= f
->output_data
.x
;
1205 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
1209 /* Save the size of the frame because the pane widget doesn't accept
1210 to resize itself. So force it. */
1211 columns
= FRAME_COLS (f
);
1212 rows
= FRAME_LINES (f
);
1214 /* Do the voodoo which means "I'm changing lots of things, don't try
1215 to refigure sizes until I'm done." */
1216 lw_refigure_widget (x
->column_widget
, False
);
1218 /* The order in which children are managed is the top to bottom
1219 order in which they are displayed in the paned window. First,
1220 remove the text-area widget. */
1221 XtUnmanageChild (x
->edit_widget
);
1223 /* Remove the menubar that is there now, and put up the menubar that
1225 XtManageChild (x
->menubar_widget
);
1226 XtMapWidget (x
->menubar_widget
);
1227 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
1229 /* Re-manage the text-area widget, and then thrash the sizes. */
1230 XtManageChild (x
->edit_widget
);
1231 lw_refigure_widget (x
->column_widget
, True
);
1233 /* Force the pane widget to resize itself with the right values. */
1234 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
1240 /* Set the contents of the menubar widgets of frame F.
1241 The argument FIRST_TIME is currently ignored;
1242 it is set the first time this is called, from initialize_frame_menubar. */
1245 set_frame_menubar (f
, first_time
, deep_p
)
1250 xt_or_gtk_widget menubar_widget
;
1251 #ifdef USE_X_TOOLKIT
1255 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1257 int *submenu_start
, *submenu_end
;
1258 int *submenu_top_level_items
, *submenu_n_panes
;
1260 if (! FRAME_X_P (f
))
1263 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1265 XSETFRAME (Vmenu_updating_frame
, f
);
1267 #ifdef USE_X_TOOLKIT
1268 if (f
->output_data
.x
->id
== 0)
1269 f
->output_data
.x
->id
= next_menubar_widget_id
++;
1270 id
= f
->output_data
.x
->id
;
1273 if (! menubar_widget
)
1275 else if (pending_menu_activation
&& !deep_p
)
1277 /* Make the first call for any given frame always go deep. */
1278 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1281 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1282 f
->output_data
.x
->saved_menu_event
->type
= 0;
1286 /* If we have detached menus, we must update deep so detached menus
1287 also gets updated. */
1288 deep_p
= deep_p
|| xg_have_tear_offs ();
1293 /* Make a widget-value tree representing the entire menu trees. */
1295 struct buffer
*prev
= current_buffer
;
1297 int specpdl_count
= SPECPDL_INDEX ();
1298 int previous_menu_items_used
= f
->menu_bar_items_used
;
1299 Lisp_Object
*previous_items
1300 = (Lisp_Object
*) alloca (previous_menu_items_used
1301 * sizeof (Lisp_Object
));
1303 /* If we are making a new widget, its contents are empty,
1304 do always reinitialize them. */
1305 if (! menubar_widget
)
1306 previous_menu_items_used
= 0;
1308 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1309 specbind (Qinhibit_quit
, Qt
);
1310 /* Don't let the debugger step into this code
1311 because it is not reentrant. */
1312 specbind (Qdebug_on_next_call
, Qnil
);
1314 record_unwind_save_match_data ();
1315 if (NILP (Voverriding_local_map_menu_flag
))
1317 specbind (Qoverriding_terminal_local_map
, Qnil
);
1318 specbind (Qoverriding_local_map
, Qnil
);
1321 set_buffer_internal_1 (XBUFFER (buffer
));
1323 /* Run the Lucid hook. */
1324 safe_run_hooks (Qactivate_menubar_hook
);
1326 /* If it has changed current-menubar from previous value,
1327 really recompute the menubar from the value. */
1328 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1329 call0 (Qrecompute_lucid_menubar
);
1330 safe_run_hooks (Qmenu_bar_update_hook
);
1331 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1333 items
= FRAME_MENU_BAR_ITEMS (f
);
1335 /* Save the frame's previous menu bar contents data. */
1336 if (previous_menu_items_used
)
1337 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1338 previous_menu_items_used
* sizeof (Lisp_Object
));
1340 /* Fill in menu_items with the current menu bar contents.
1341 This can evaluate Lisp code. */
1344 menu_items
= f
->menu_bar_vector
;
1345 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1346 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1347 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1348 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1349 submenu_top_level_items
1350 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1352 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1354 Lisp_Object key
, string
, maps
;
1358 key
= XVECTOR (items
)->contents
[i
];
1359 string
= XVECTOR (items
)->contents
[i
+ 1];
1360 maps
= XVECTOR (items
)->contents
[i
+ 2];
1364 submenu_start
[i
] = menu_items_used
;
1366 menu_items_n_panes
= 0;
1367 submenu_top_level_items
[i
]
1368 = parse_single_submenu (key
, string
, maps
);
1369 submenu_n_panes
[i
] = menu_items_n_panes
;
1371 submenu_end
[i
] = menu_items_used
;
1374 finish_menu_items ();
1376 /* Convert menu_items into widget_value trees
1377 to display the menu. This cannot evaluate Lisp code. */
1379 wv
= xmalloc_widget_value ();
1380 wv
->name
= "menubar";
1383 wv
->button_type
= BUTTON_TYPE_NONE
;
1387 for (i
= 0; i
< last_i
; i
+= 4)
1389 menu_items_n_panes
= submenu_n_panes
[i
];
1390 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1391 submenu_top_level_items
[i
]);
1395 first_wv
->contents
= wv
;
1396 /* Don't set wv->name here; GC during the loop might relocate it. */
1398 wv
->button_type
= BUTTON_TYPE_NONE
;
1402 set_buffer_internal_1 (prev
);
1404 /* If there has been no change in the Lisp-level contents
1405 of the menu bar, skip redisplaying it. Just exit. */
1407 /* Compare the new menu items with the ones computed last time. */
1408 for (i
= 0; i
< previous_menu_items_used
; i
++)
1409 if (menu_items_used
== i
1410 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1412 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1414 /* The menu items have not changed. Don't bother updating
1415 the menus in any form, since it would be a no-op. */
1416 free_menubar_widget_value_tree (first_wv
);
1417 discard_menu_items ();
1418 unbind_to (specpdl_count
, Qnil
);
1422 /* The menu items are different, so store them in the frame. */
1423 f
->menu_bar_vector
= menu_items
;
1424 f
->menu_bar_items_used
= menu_items_used
;
1426 /* This undoes save_menu_items. */
1427 unbind_to (specpdl_count
, Qnil
);
1429 /* Now GC cannot happen during the lifetime of the widget_value,
1430 so it's safe to store data from a Lisp_String. */
1431 wv
= first_wv
->contents
;
1432 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1435 string
= XVECTOR (items
)->contents
[i
+ 1];
1438 wv
->name
= (char *) SDATA (string
);
1439 update_submenu_strings (wv
->contents
);
1446 /* Make a widget-value tree containing
1447 just the top level menu bar strings. */
1449 wv
= xmalloc_widget_value ();
1450 wv
->name
= "menubar";
1453 wv
->button_type
= BUTTON_TYPE_NONE
;
1457 items
= FRAME_MENU_BAR_ITEMS (f
);
1458 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1462 string
= XVECTOR (items
)->contents
[i
+ 1];
1466 wv
= xmalloc_widget_value ();
1467 wv
->name
= (char *) SDATA (string
);
1470 wv
->button_type
= BUTTON_TYPE_NONE
;
1472 /* This prevents lwlib from assuming this
1473 menu item is really supposed to be empty. */
1474 /* The EMACS_INT cast avoids a warning.
1475 This value just has to be different from small integers. */
1476 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1481 first_wv
->contents
= wv
;
1485 /* Forget what we thought we knew about what is in the
1486 detailed contents of the menu bar menus.
1487 Changing the top level always destroys the contents. */
1488 f
->menu_bar_items_used
= 0;
1491 /* Create or update the menu bar widget. */
1496 xg_crazy_callback_abort
= 1;
1499 /* The fourth arg is DEEP_P, which says to consider the entire
1500 menu trees we supply, rather than just the menu bar item names. */
1501 xg_modify_menubar_widgets (menubar_widget
,
1505 G_CALLBACK (menubar_selection_callback
),
1506 G_CALLBACK (popup_deactivate_callback
),
1507 G_CALLBACK (menu_highlight_callback
));
1511 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1514 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1515 G_CALLBACK (menubar_selection_callback
),
1516 G_CALLBACK (popup_deactivate_callback
),
1517 G_CALLBACK (menu_highlight_callback
));
1519 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1523 #else /* not USE_GTK */
1526 /* Disable resizing (done for Motif!) */
1527 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1529 /* The third arg is DEEP_P, which says to consider the entire
1530 menu trees we supply, rather than just the menu bar item names. */
1531 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1533 /* Re-enable the edit widget to resize. */
1534 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1538 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1539 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1541 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1542 f
->output_data
.x
->column_widget
,
1544 popup_activate_callback
,
1545 menubar_selection_callback
,
1546 popup_deactivate_callback
,
1547 menu_highlight_callback
);
1548 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1550 /* Make menu pop down on C-g. */
1551 XtOverrideTranslations (menubar_widget
, override
);
1556 = (f
->output_data
.x
->menubar_widget
1557 ? (f
->output_data
.x
->menubar_widget
->core
.height
1558 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1561 #if 1 /* Experimentally, we now get the right results
1562 for -geometry -0-0 without this. 24 Aug 96, rms.
1563 Maybe so, but the menu bar size is missing the pixels so the
1564 WM size hints are off by theses pixel. Jan D, oct 2009. */
1566 if (FRAME_EXTERNAL_MENU_BAR (f
))
1569 XtVaGetValues (f
->output_data
.x
->column_widget
,
1570 XtNinternalBorderWidth
, &ibw
, NULL
);
1571 menubar_size
+= ibw
;
1573 #endif /* USE_LUCID */
1576 f
->output_data
.x
->menubar_height
= menubar_size
;
1578 #endif /* not USE_GTK */
1580 free_menubar_widget_value_tree (first_wv
);
1581 update_frame_menubar (f
);
1584 xg_crazy_callback_abort
= 0;
1590 /* Called from Fx_create_frame to create the initial menubar of a frame
1591 before it is mapped, so that the window is mapped with the menubar already
1592 there instead of us tacking it on later and thrashing the window after it
1596 initialize_frame_menubar (f
)
1599 /* This function is called before the first chance to redisplay
1600 the frame. It has to be, so the frame will have the right size. */
1601 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1602 set_frame_menubar (f
, 1, 1);
1606 /* Get rid of the menu bar of frame F, and free its storage.
1607 This is used when deleting a frame, and when turning off the menu bar.
1608 For GTK this function is in gtkutil.c. */
1612 free_frame_menubar (f
)
1615 Widget menubar_widget
;
1617 if (! FRAME_X_P (f
))
1620 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1622 f
->output_data
.x
->menubar_height
= 0;
1627 /* Removing the menu bar magically changes the shell widget's x
1628 and y position of (0, 0) which, when the menu bar is turned
1629 on again, leads to pull-down menuss appearing in strange
1630 positions near the upper-left corner of the display. This
1631 happens only with some window managers like twm and ctwm,
1632 but not with other like Motif's mwm or kwm, because the
1633 latter generate ConfigureNotify events when the menu bar
1634 is switched off, which fixes the shell position. */
1635 Position x0
, y0
, x1
, y1
;
1641 if (f
->output_data
.x
->widget
)
1642 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1645 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1646 f
->output_data
.x
->menubar_widget
= NULL
;
1649 if (f
->output_data
.x
->widget
)
1651 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1652 if (x1
== 0 && y1
== 0)
1653 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1660 #endif /* not USE_GTK */
1662 #endif /* USE_X_TOOLKIT || USE_GTK */
1664 /* xmenu_show actually displays a menu using the panes and items in menu_items
1665 and returns the value selected from it.
1666 There are two versions of xmenu_show, one for Xt and one for Xlib.
1667 Both assume input is blocked by the caller. */
1669 /* F is the frame the menu is for.
1670 X and Y are the frame-relative specified position,
1671 relative to the inside upper left corner of the frame F.
1672 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1673 KEYMAPS is 1 if this menu was specified with keymaps;
1674 in that case, we return a list containing the chosen item's value
1675 and perhaps also the pane's prefix.
1676 TITLE is the specified menu title.
1677 ERROR is a place to store an error message string in case of failure.
1678 (We return nil on failure, but the value doesn't actually matter.) */
1680 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1682 /* The item selected in the popup menu. */
1683 static Lisp_Object
*volatile menu_item_selection
;
1687 /* Used when position a popup menu. See menu_position_func and
1688 create_and_show_popup_menu below. */
1689 struct next_popup_x_y
1696 /* The menu position function to use if we are not putting a popup
1697 menu where the pointer is.
1698 MENU is the menu to pop up.
1699 X and Y shall on exit contain x/y where the menu shall pop up.
1700 PUSH_IN is not documented in the GTK manual.
1701 USER_DATA is any data passed in when calling gtk_menu_popup.
1702 Here it points to a struct next_popup_x_y where the coordinates
1703 to store in *X and *Y are as well as the frame for the popup.
1705 Here only X and Y are used. */
1707 menu_position_func (menu
, x
, y
, push_in
, user_data
)
1714 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1716 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1717 int disp_width
= x_display_pixel_width (dpyinfo
);
1718 int disp_height
= x_display_pixel_height (dpyinfo
);
1723 /* Check if there is room for the menu. If not, adjust x/y so that
1724 the menu is fully visible. */
1725 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1726 if (data
->x
+ req
.width
> disp_width
)
1727 *x
-= data
->x
+ req
.width
- disp_width
;
1728 if (data
->y
+ req
.height
> disp_height
)
1729 *y
-= data
->y
+ req
.height
- disp_height
;
1733 popup_selection_callback (widget
, client_data
)
1735 gpointer client_data
;
1737 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1739 if (xg_crazy_callback_abort
) return;
1740 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1747 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1749 popup_activated_flag
= 0;
1751 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1756 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1758 menu_item_selection will be set to the selection. */
1760 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1762 widget_value
*first_wv
;
1766 EMACS_UINT timestamp
;
1770 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1771 struct next_popup_x_y popup_x_y
;
1772 int specpdl_count
= SPECPDL_INDEX ();
1774 if (! FRAME_X_P (f
))
1777 xg_crazy_callback_abort
= 1;
1778 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1779 G_CALLBACK (popup_selection_callback
),
1780 G_CALLBACK (popup_deactivate_callback
),
1781 G_CALLBACK (menu_highlight_callback
));
1782 xg_crazy_callback_abort
= 0;
1786 /* Not invoked by a click. pop up at x/y. */
1787 pos_func
= menu_position_func
;
1789 /* Adjust coordinates to be root-window-relative. */
1790 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1791 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1797 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1801 for (i
= 0; i
< 5; i
++)
1802 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1806 /* Display the menu. */
1807 gtk_widget_show_all (menu
);
1808 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1811 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1813 if (GTK_WIDGET_MAPPED (menu
))
1815 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1816 two. show_help_echo uses this to detect popup menus. */
1817 popup_activated_flag
= 1;
1818 /* Process events that apply to the menu. */
1819 popup_widget_loop (1, menu
);
1822 unbind_to (specpdl_count
, Qnil
);
1824 /* Must reset this manually because the button release event is not passed
1825 to Emacs event loop. */
1826 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1829 #else /* not USE_GTK */
1831 /* We need a unique id for each widget handled by the Lucid Widget
1834 For the main windows, and popup menus, we use this counter,
1835 which we increment each time after use. This starts from 1<<16.
1837 For menu bars, we use numbers starting at 0, counted in
1838 next_menubar_widget_id. */
1839 LWLIB_ID widget_id_tick
;
1842 popup_selection_callback (widget
, id
, client_data
)
1845 XtPointer client_data
;
1847 menu_item_selection
= (Lisp_Object
*) client_data
;
1850 /* ARG is the LWLIB ID of the dialog box, represented
1851 as a Lisp object as (HIGHPART . LOWPART). */
1857 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1858 | XINT (XCDR (arg
)));
1861 lw_destroy_all_widgets (id
);
1863 popup_activated_flag
= 0;
1868 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1870 menu_item_selection will be set to the selection. */
1872 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1874 widget_value
*first_wv
;
1878 EMACS_UINT timestamp
;
1883 XButtonPressedEvent dummy
;
1887 if (! FRAME_X_P (f
))
1890 menu_id
= widget_id_tick
++;
1891 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1892 f
->output_data
.x
->widget
, 1, 0,
1893 popup_selection_callback
,
1894 popup_deactivate_callback
,
1895 menu_highlight_callback
);
1897 dummy
.type
= ButtonPress
;
1899 dummy
.send_event
= 0;
1900 dummy
.display
= FRAME_X_DISPLAY (f
);
1901 dummy
.time
= CurrentTime
;
1902 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1903 dummy
.window
= dummy
.root
;
1904 dummy
.subwindow
= dummy
.root
;
1908 /* Adjust coordinates to be root-window-relative. */
1909 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1910 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1917 for (i
= 0; i
< 5; i
++)
1918 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1921 /* Don't allow any geometry request from the user. */
1922 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1923 XtSetValues (menu
, av
, ac
);
1925 /* Display the menu. */
1926 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1927 popup_activated_flag
= 1;
1928 x_activate_timeout_atimer ();
1931 int fact
= 4 * sizeof (LWLIB_ID
);
1932 int specpdl_count
= SPECPDL_INDEX ();
1933 record_unwind_protect (pop_down_menu
,
1934 Fcons (make_number (menu_id
>> (fact
)),
1935 make_number (menu_id
& ~(-1 << (fact
)))));
1937 /* Process events that apply to the menu. */
1938 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1940 unbind_to (specpdl_count
, Qnil
);
1944 #endif /* not USE_GTK */
1947 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
1955 EMACS_UINT timestamp
;
1958 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1959 widget_value
**submenu_stack
1960 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1961 Lisp_Object
*subprefix_stack
1962 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1963 int submenu_depth
= 0;
1967 if (! FRAME_X_P (f
))
1972 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1974 *error
= "Empty menu";
1978 /* Create a tree of widget_value objects
1979 representing the panes and their items. */
1980 wv
= xmalloc_widget_value ();
1984 wv
->button_type
= BUTTON_TYPE_NONE
;
1989 /* Loop over all panes and items, filling in the tree. */
1991 while (i
< menu_items_used
)
1993 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1995 submenu_stack
[submenu_depth
++] = save_wv
;
2001 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2004 save_wv
= submenu_stack
[--submenu_depth
];
2008 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
2009 && submenu_depth
!= 0)
2010 i
+= MENU_ITEMS_PANE_LENGTH
;
2011 /* Ignore a nil in the item list.
2012 It's meaningful only for dialog boxes. */
2013 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2015 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2017 /* Create a new pane. */
2018 Lisp_Object pane_name
, prefix
;
2021 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2022 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2024 #ifndef HAVE_MULTILINGUAL_MENU
2025 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
2027 pane_name
= ENCODE_MENU_STRING (pane_name
);
2028 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
2031 pane_string
= (NILP (pane_name
)
2032 ? "" : (char *) SDATA (pane_name
));
2033 /* If there is just one top-level pane, put all its items directly
2034 under the top-level menu. */
2035 if (menu_items_n_panes
== 1)
2038 /* If the pane has a meaningful name,
2039 make the pane a top-level menu item
2040 with its items as a submenu beneath it. */
2041 if (!keymaps
&& strcmp (pane_string
, ""))
2043 wv
= xmalloc_widget_value ();
2047 first_wv
->contents
= wv
;
2048 wv
->name
= pane_string
;
2049 if (keymaps
&& !NILP (prefix
))
2053 wv
->button_type
= BUTTON_TYPE_NONE
;
2058 else if (first_pane
)
2064 i
+= MENU_ITEMS_PANE_LENGTH
;
2068 /* Create a new item within current pane. */
2069 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
2070 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2071 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2072 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2073 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
2074 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
2075 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
2076 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2078 #ifndef HAVE_MULTILINGUAL_MENU
2079 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
2081 item_name
= ENCODE_MENU_STRING (item_name
);
2082 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
2085 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
2087 descrip
= ENCODE_MENU_STRING (descrip
);
2088 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
2090 #endif /* not HAVE_MULTILINGUAL_MENU */
2092 wv
= xmalloc_widget_value ();
2096 save_wv
->contents
= wv
;
2097 wv
->name
= (char *) SDATA (item_name
);
2098 if (!NILP (descrip
))
2099 wv
->key
= (char *) SDATA (descrip
);
2101 /* If this item has a null value,
2102 make the call_data null so that it won't display a box
2103 when the mouse is on it. */
2105 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
2106 wv
->enabled
= !NILP (enable
);
2109 wv
->button_type
= BUTTON_TYPE_NONE
;
2110 else if (EQ (type
, QCtoggle
))
2111 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
2112 else if (EQ (type
, QCradio
))
2113 wv
->button_type
= BUTTON_TYPE_RADIO
;
2117 wv
->selected
= !NILP (selected
);
2119 if (! STRINGP (help
))
2126 i
+= MENU_ITEMS_ITEM_LENGTH
;
2130 /* Deal with the title, if it is non-nil. */
2133 widget_value
*wv_title
= xmalloc_widget_value ();
2134 widget_value
*wv_sep1
= xmalloc_widget_value ();
2135 widget_value
*wv_sep2
= xmalloc_widget_value ();
2137 wv_sep2
->name
= "--";
2138 wv_sep2
->next
= first_wv
->contents
;
2139 wv_sep2
->help
= Qnil
;
2141 wv_sep1
->name
= "--";
2142 wv_sep1
->next
= wv_sep2
;
2143 wv_sep1
->help
= Qnil
;
2145 #ifndef HAVE_MULTILINGUAL_MENU
2146 if (STRING_MULTIBYTE (title
))
2147 title
= ENCODE_MENU_STRING (title
);
2150 wv_title
->name
= (char *) SDATA (title
);
2151 wv_title
->enabled
= TRUE
;
2152 wv_title
->button_type
= BUTTON_TYPE_NONE
;
2153 wv_title
->help
= Qnil
;
2154 wv_title
->next
= wv_sep1
;
2155 first_wv
->contents
= wv_title
;
2158 /* No selection has been chosen yet. */
2159 menu_item_selection
= 0;
2161 /* Actually create and show the menu until popped down. */
2162 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
2164 /* Free the widget_value objects we used to specify the contents. */
2165 free_menubar_widget_value_tree (first_wv
);
2167 /* Find the selected item, and its pane, to return
2168 the proper value. */
2169 if (menu_item_selection
!= 0)
2171 Lisp_Object prefix
, entry
;
2173 prefix
= entry
= Qnil
;
2175 while (i
< menu_items_used
)
2177 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2179 subprefix_stack
[submenu_depth
++] = prefix
;
2183 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2185 prefix
= subprefix_stack
[--submenu_depth
];
2188 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2191 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2192 i
+= MENU_ITEMS_PANE_LENGTH
;
2194 /* Ignore a nil in the item list.
2195 It's meaningful only for dialog boxes. */
2196 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2201 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2202 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2208 entry
= Fcons (entry
, Qnil
);
2210 entry
= Fcons (prefix
, entry
);
2211 for (j
= submenu_depth
- 1; j
>= 0; j
--)
2212 if (!NILP (subprefix_stack
[j
]))
2213 entry
= Fcons (subprefix_stack
[j
], entry
);
2217 i
+= MENU_ITEMS_ITEM_LENGTH
;
2221 else if (!for_click
)
2222 /* Make "Cancel" equivalent to C-g. */
2223 Fsignal (Qquit
, Qnil
);
2230 dialog_selection_callback (widget
, client_data
)
2232 gpointer client_data
;
2234 /* The EMACS_INT cast avoids a warning. There's no problem
2235 as long as pointers have enough bits to hold small integers. */
2236 if ((int) (EMACS_INT
) client_data
!= -1)
2237 menu_item_selection
= (Lisp_Object
*) client_data
;
2239 popup_activated_flag
= 0;
2242 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2244 menu_item_selection will be set to the selection. */
2246 create_and_show_dialog (f
, first_wv
)
2248 widget_value
*first_wv
;
2252 if (! FRAME_X_P (f
))
2255 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
2256 G_CALLBACK (dialog_selection_callback
),
2257 G_CALLBACK (popup_deactivate_callback
),
2262 int specpdl_count
= SPECPDL_INDEX ();
2263 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
2265 /* Display the menu. */
2266 gtk_widget_show_all (menu
);
2268 /* Process events that apply to the menu. */
2269 popup_widget_loop (1, menu
);
2271 unbind_to (specpdl_count
, Qnil
);
2275 #else /* not USE_GTK */
2277 dialog_selection_callback (widget
, id
, client_data
)
2280 XtPointer client_data
;
2282 /* The EMACS_INT cast avoids a warning. There's no problem
2283 as long as pointers have enough bits to hold small integers. */
2284 if ((int) (EMACS_INT
) client_data
!= -1)
2285 menu_item_selection
= (Lisp_Object
*) client_data
;
2288 lw_destroy_all_widgets (id
);
2290 popup_activated_flag
= 0;
2294 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2296 menu_item_selection will be set to the selection. */
2298 create_and_show_dialog (f
, first_wv
)
2300 widget_value
*first_wv
;
2307 dialog_id
= widget_id_tick
++;
2308 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2309 f
->output_data
.x
->widget
, 1, 0,
2310 dialog_selection_callback
, 0, 0);
2311 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2313 /* Display the dialog box. */
2314 lw_pop_up_all_widgets (dialog_id
);
2315 popup_activated_flag
= 1;
2316 x_activate_timeout_atimer ();
2318 /* Process events that apply to the dialog box.
2319 Also handle timers. */
2321 int count
= SPECPDL_INDEX ();
2322 int fact
= 4 * sizeof (LWLIB_ID
);
2324 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2325 record_unwind_protect (pop_down_menu
,
2326 Fcons (make_number (dialog_id
>> (fact
)),
2327 make_number (dialog_id
& ~(-1 << (fact
)))));
2329 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2332 unbind_to (count
, Qnil
);
2336 #endif /* not USE_GTK */
2338 static char * button_names
[] = {
2339 "button1", "button2", "button3", "button4", "button5",
2340 "button6", "button7", "button8", "button9", "button10" };
2343 xdialog_show (f
, keymaps
, title
, header
, error_name
)
2346 Lisp_Object title
, header
;
2349 int i
, nb_buttons
=0;
2350 char dialog_name
[6];
2352 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2354 /* Number of elements seen so far, before boundary. */
2356 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2357 int boundary_seen
= 0;
2359 if (! FRAME_X_P (f
))
2364 if (menu_items_n_panes
> 1)
2366 *error_name
= "Multiple panes in dialog box";
2370 /* Create a tree of widget_value objects
2371 representing the text label and buttons. */
2373 Lisp_Object pane_name
, prefix
;
2375 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2376 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2377 pane_string
= (NILP (pane_name
)
2378 ? "" : (char *) SDATA (pane_name
));
2379 prev_wv
= xmalloc_widget_value ();
2380 prev_wv
->value
= pane_string
;
2381 if (keymaps
&& !NILP (prefix
))
2383 prev_wv
->enabled
= 1;
2384 prev_wv
->name
= "message";
2385 prev_wv
->help
= Qnil
;
2388 /* Loop over all panes and items, filling in the tree. */
2389 i
= MENU_ITEMS_PANE_LENGTH
;
2390 while (i
< menu_items_used
)
2393 /* Create a new item within current pane. */
2394 Lisp_Object item_name
, enable
, descrip
;
2395 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2396 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2398 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2400 if (NILP (item_name
))
2402 free_menubar_widget_value_tree (first_wv
);
2403 *error_name
= "Submenu in dialog items";
2406 if (EQ (item_name
, Qquote
))
2408 /* This is the boundary between left-side elts
2409 and right-side elts. Stop incrementing right_count. */
2414 if (nb_buttons
>= 9)
2416 free_menubar_widget_value_tree (first_wv
);
2417 *error_name
= "Too many dialog items";
2421 wv
= xmalloc_widget_value ();
2423 wv
->name
= (char *) button_names
[nb_buttons
];
2424 if (!NILP (descrip
))
2425 wv
->key
= (char *) SDATA (descrip
);
2426 wv
->value
= (char *) SDATA (item_name
);
2427 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2428 wv
->enabled
= !NILP (enable
);
2432 if (! boundary_seen
)
2436 i
+= MENU_ITEMS_ITEM_LENGTH
;
2439 /* If the boundary was not specified,
2440 by default put half on the left and half on the right. */
2441 if (! boundary_seen
)
2442 left_count
= nb_buttons
- nb_buttons
/ 2;
2444 wv
= xmalloc_widget_value ();
2445 wv
->name
= dialog_name
;
2448 /* Frame title: 'Q' = Question, 'I' = Information.
2449 Can also have 'E' = Error if, one day, we want
2450 a popup for errors. */
2452 dialog_name
[0] = 'Q';
2454 dialog_name
[0] = 'I';
2456 /* Dialog boxes use a really stupid name encoding
2457 which specifies how many buttons to use
2458 and how many buttons are on the right. */
2459 dialog_name
[1] = '0' + nb_buttons
;
2460 dialog_name
[2] = 'B';
2461 dialog_name
[3] = 'R';
2462 /* Number of buttons to put on the right. */
2463 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2465 wv
->contents
= first_wv
;
2469 /* No selection has been chosen yet. */
2470 menu_item_selection
= 0;
2472 /* Actually create and show the dialog. */
2473 create_and_show_dialog (f
, first_wv
);
2475 /* Free the widget_value objects we used to specify the contents. */
2476 free_menubar_widget_value_tree (first_wv
);
2478 /* Find the selected item, and its pane, to return
2479 the proper value. */
2480 if (menu_item_selection
!= 0)
2486 while (i
< menu_items_used
)
2490 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2493 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2494 i
+= MENU_ITEMS_PANE_LENGTH
;
2496 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2498 /* This is the boundary between left-side elts and
2505 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2506 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2510 entry
= Fcons (entry
, Qnil
);
2512 entry
= Fcons (prefix
, entry
);
2516 i
+= MENU_ITEMS_ITEM_LENGTH
;
2521 /* Make "Cancel" equivalent to C-g. */
2522 Fsignal (Qquit
, Qnil
);
2527 #else /* not USE_X_TOOLKIT && not USE_GTK */
2529 /* The frame of the last activated non-toolkit menu bar.
2530 Used to generate menu help events. */
2532 static struct frame
*menu_help_frame
;
2535 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2537 PANE is the pane number, and ITEM is the menu item number in
2538 the menu (currently not used).
2540 This cannot be done with generating a HELP_EVENT because
2541 XMenuActivate contains a loop that doesn't let Emacs process
2545 menu_help_callback (help_string
, pane
, item
)
2549 extern Lisp_Object Qmenu_item
;
2550 Lisp_Object
*first_item
;
2551 Lisp_Object pane_name
;
2552 Lisp_Object menu_object
;
2554 first_item
= XVECTOR (menu_items
)->contents
;
2555 if (EQ (first_item
[0], Qt
))
2556 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2557 else if (EQ (first_item
[0], Qquote
))
2558 /* This shouldn't happen, see xmenu_show. */
2559 pane_name
= empty_unibyte_string
;
2561 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2563 /* (menu-item MENU-NAME PANE-NUMBER) */
2564 menu_object
= Fcons (Qmenu_item
,
2566 Fcons (make_number (pane
), Qnil
)));
2567 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2568 Qnil
, menu_object
, make_number (item
), 1);
2575 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2576 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2578 FRAME_PTR f
= p1
->pointer
;
2579 XMenu
*menu
= p2
->pointer
;
2583 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2584 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2586 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2588 #ifdef HAVE_X_WINDOWS
2589 /* Assume the mouse has moved out of the X window.
2590 If it has actually moved in, we will get an EnterNotify. */
2591 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2593 /* State that no mouse buttons are now held.
2594 (The oldXMenu code doesn't track this info for us.)
2595 That is not necessarily true, but the fiction leads to reasonable
2596 results, and it is a pain to ask which are actually held now. */
2597 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2599 #endif /* HAVE_X_WINDOWS */
2608 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
2615 EMACS_UINT timestamp
;
2619 int pane
, selidx
, lpane
, status
;
2620 Lisp_Object entry
, pane_prefix
;
2622 int ulx
, uly
, width
, height
;
2623 int dispwidth
, dispheight
;
2624 int i
, j
, lines
, maxlines
;
2627 unsigned int dummy_uint
;
2628 int specpdl_count
= SPECPDL_INDEX ();
2630 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2634 if (menu_items_n_panes
== 0)
2637 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2639 *error
= "Empty menu";
2643 /* Figure out which root window F is on. */
2644 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2645 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2646 &dummy_uint
, &dummy_uint
);
2648 /* Make the menu on that window. */
2649 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2652 *error
= "Can't create menu";
2656 /* Don't GC while we prepare and show the menu,
2657 because we give the oldxmenu library pointers to the
2658 contents of strings. */
2659 inhibit_garbage_collection ();
2661 #ifdef HAVE_X_WINDOWS
2662 /* Adjust coordinates to relative to the outer (window manager) window. */
2663 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2664 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2665 #endif /* HAVE_X_WINDOWS */
2667 /* Adjust coordinates to be root-window-relative. */
2671 /* Create all the necessary panes and their items. */
2672 maxlines
= lines
= i
= 0;
2673 while (i
< menu_items_used
)
2675 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2677 /* Create a new pane. */
2678 Lisp_Object pane_name
, prefix
;
2681 maxlines
= max (maxlines
, lines
);
2683 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2684 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2685 pane_string
= (NILP (pane_name
)
2686 ? "" : (char *) SDATA (pane_name
));
2687 if (keymaps
&& !NILP (prefix
))
2690 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2691 if (lpane
== XM_FAILURE
)
2693 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2694 *error
= "Can't create pane";
2697 i
+= MENU_ITEMS_PANE_LENGTH
;
2699 /* Find the width of the widest item in this pane. */
2702 while (j
< menu_items_used
)
2705 item
= XVECTOR (menu_items
)->contents
[j
];
2713 width
= SBYTES (item
);
2714 if (width
> maxwidth
)
2717 j
+= MENU_ITEMS_ITEM_LENGTH
;
2720 /* Ignore a nil in the item list.
2721 It's meaningful only for dialog boxes. */
2722 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2726 /* Create a new item within current pane. */
2727 Lisp_Object item_name
, enable
, descrip
, help
;
2728 unsigned char *item_data
;
2731 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2732 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2734 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2735 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2736 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2738 if (!NILP (descrip
))
2740 int gap
= maxwidth
- SBYTES (item_name
);
2741 /* if alloca is fast, use that to make the space,
2742 to reduce gc needs. */
2744 = (unsigned char *) alloca (maxwidth
2745 + SBYTES (descrip
) + 1);
2746 bcopy (SDATA (item_name
), item_data
,
2747 SBYTES (item_name
));
2748 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2750 bcopy (SDATA (descrip
), item_data
+ j
,
2752 item_data
[j
+ SBYTES (descrip
)] = 0;
2755 item_data
= SDATA (item_name
);
2757 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2758 menu
, lpane
, 0, item_data
,
2759 !NILP (enable
), help_string
)
2762 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2763 *error
= "Can't add selection to menu";
2766 i
+= MENU_ITEMS_ITEM_LENGTH
;
2771 maxlines
= max (maxlines
, lines
);
2773 /* All set and ready to fly. */
2774 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2775 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2776 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2777 x
= min (x
, dispwidth
);
2778 y
= min (y
, dispheight
);
2781 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2782 &ulx
, &uly
, &width
, &height
);
2783 if (ulx
+width
> dispwidth
)
2785 x
-= (ulx
+ width
) - dispwidth
;
2786 ulx
= dispwidth
- width
;
2788 if (uly
+height
> dispheight
)
2790 y
-= (uly
+ height
) - dispheight
;
2791 uly
= dispheight
- height
;
2793 #ifndef HAVE_X_WINDOWS
2794 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2796 /* Move the menu away of the echo area, to avoid overwriting the
2797 menu with help echo messages or vice versa. */
2798 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2800 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2801 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2810 if (ulx
< 0) x
-= ulx
;
2811 if (uly
< 0) y
-= uly
;
2815 /* If position was not given by a mouse click, adjust so upper left
2816 corner of the menu as a whole ends up at given coordinates. This
2817 is what x-popup-menu says in its documentation. */
2819 y
+= 1.5*height
/(maxlines
+2);
2822 XMenuSetAEQ (menu
, TRUE
);
2823 XMenuSetFreeze (menu
, TRUE
);
2827 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2830 record_unwind_protect (pop_down_menu
,
2831 Fcons (make_save_value (f
, 0),
2832 make_save_value (menu
, 0)));
2834 /* Help display under X won't work because XMenuActivate contains
2835 a loop that doesn't give Emacs a chance to process it. */
2836 menu_help_frame
= f
;
2837 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2838 x
, y
, ButtonReleaseMask
, &datap
,
2839 menu_help_callback
);
2845 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2848 /* Find the item number SELIDX in pane number PANE. */
2850 while (i
< menu_items_used
)
2852 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2856 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2858 i
+= MENU_ITEMS_PANE_LENGTH
;
2867 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2870 entry
= Fcons (entry
, Qnil
);
2871 if (!NILP (pane_prefix
))
2872 entry
= Fcons (pane_prefix
, entry
);
2878 i
+= MENU_ITEMS_ITEM_LENGTH
;
2884 *error
= "Can't activate menu";
2889 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2890 the menu was invoked with a mouse event as POSITION). */
2892 Fsignal (Qquit
, Qnil
);
2897 unbind_to (specpdl_count
, Qnil
);
2902 #endif /* not USE_X_TOOLKIT */
2904 #endif /* HAVE_MENUS */
2906 /* Detect if a dialog or menu has been posted. */
2911 return popup_activated_flag
;
2914 /* The following is used by delayed window autoselection. */
2916 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2917 doc
: /* Return t if a menu or popup dialog is active. */)
2921 return (popup_activated ()) ? Qt
: Qnil
;
2924 #endif /* HAVE_MENUS */
2930 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2931 staticpro (&Qdebug_on_next_call
);
2933 #ifdef USE_X_TOOLKIT
2934 widget_id_tick
= (1<<16);
2935 next_menubar_widget_id
= 1;
2938 defsubr (&Sx_popup_menu
);
2939 defsubr (&Smenu_or_popup_active_p
);
2941 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2942 defsubr (&Sx_menu_bar_open_internal
);
2943 Ffset (intern_c_string ("accelerate-menu"),
2944 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2948 defsubr (&Sx_popup_dialog
);
2952 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2953 (do not change this comment) */