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. */
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 */
108 Lisp_Object Qdebug_on_next_call
;
110 extern Lisp_Object Vmenu_updating_frame
;
112 extern Lisp_Object Qmenu_bar
;
114 extern Lisp_Object QCtoggle
, QCradio
;
116 extern Lisp_Object Voverriding_local_map
;
117 extern Lisp_Object Voverriding_local_map_menu_flag
;
119 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
121 extern Lisp_Object Qmenu_bar_update_hook
;
124 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
125 extern XtAppContext Xt_app_con
;
127 static Lisp_Object xdialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
129 static void popup_get_selection
P_ ((XEvent
*, struct x_display_info
*,
131 #endif /* USE_X_TOOLKIT */
134 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
135 static Lisp_Object xdialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
139 static int update_frame_menubar
P_ ((struct frame
*));
140 static Lisp_Object xmenu_show
P_ ((struct frame
*, int, int, int, int,
141 Lisp_Object
, char **));
143 /* Flag which when set indicates a dialog or menu has been posted by
144 Xt on behalf of one of the widget sets. */
145 static int popup_activated_flag
;
147 static int next_menubar_widget_id
;
149 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
150 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
151 extern widget_value
*xmalloc_widget_value
P_ ((void));
152 extern widget_value
*digest_single_submenu
P_ ((int, int, int));
155 /* This is set nonzero after the user activates the menu bar, and set
156 to zero again after the menu bars are redisplayed by prepare_menu_bar.
157 While it is nonzero, all calls to set_frame_menubar go deep.
159 I don't understand why this is needed, but it does seem to be
160 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
162 int pending_menu_activation
;
166 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
168 static struct frame
*
169 menubar_id_to_frame (id
)
172 Lisp_Object tail
, frame
;
175 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
181 if (!FRAME_WINDOW_P (f
))
183 if (f
->output_data
.x
->id
== id
)
191 #ifdef HAVE_X_WINDOWS
192 /* Return the mouse position in *X and *Y. The coordinates are window
193 relative for the edit window in frame F.
194 This is for Fx_popup_menu. The mouse_position_hook can not
195 be used for X, as it returns window relative coordinates
196 for the window where the mouse is in. This could be the menu bar,
197 the scroll bar or the edit window. Fx_popup_menu needs to be
198 sure it is the edit window. */
200 mouse_position_for_popup (f
, x
, y
)
205 Window root
, dummy_window
;
213 XQueryPointer (FRAME_X_DISPLAY (f
),
214 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
216 /* The root window which contains the pointer. */
219 /* Window pointer is on, not used */
222 /* The position on that root window. */
225 /* x/y in dummy_window coordinates, not used. */
228 /* Modifier keys and pointer buttons, about which
230 (unsigned int *) &dummy
);
234 /* xmenu_show expects window coordinates, not root window
235 coordinates. Translate. */
236 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
237 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
240 #endif /* HAVE_X_WINDOWS */
242 DEFUN ("x-popup-menu", Fx_popup_menu
, Sx_popup_menu
, 2, 2, 0,
243 doc
: /* Pop up a deck-of-cards menu and return user's selection.
244 POSITION is a position specification. This is either a mouse button event
245 or a list ((XOFFSET YOFFSET) WINDOW)
246 where XOFFSET and YOFFSET are positions in pixels from the top left
247 corner of WINDOW. (WINDOW may be a window or a frame object.)
248 This controls the position of the top left of the menu as a whole.
249 If POSITION is t, it means to use the current mouse position.
251 MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
252 The menu items come from key bindings that have a menu string as well as
253 a definition; actually, the "definition" in such a key binding looks like
254 \(STRING . REAL-DEFINITION). To give the menu a title, put a string into
255 the keymap as a top-level element.
257 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
258 Otherwise, REAL-DEFINITION should be a valid key binding definition.
260 You can also use a list of keymaps as MENU.
261 Then each keymap makes a separate pane.
263 When MENU is a keymap or a list of keymaps, the return value is the
264 list of events corresponding to the user's choice. Note that
265 `x-popup-menu' does not actually execute the command bound to that
268 Alternatively, you can specify a menu of multiple panes
269 with a list of the form (TITLE PANE1 PANE2...),
270 where each pane is a list of form (TITLE ITEM1 ITEM2...).
271 Each ITEM is normally a cons cell (STRING . VALUE);
272 but a string can appear as an item--that makes a nonselectable line
274 With this form of menu, the return value is VALUE from the chosen item.
276 If POSITION is nil, don't display the menu at all, just precalculate the
277 cached information about equivalent key sequences.
279 If the user gets rid of the menu without making a valid choice, for
280 instance by clicking the mouse away from a valid choice or by typing
281 keyboard input, then this normally results in a quit and
282 `x-popup-menu' does not return. But if POSITION is a mouse button
283 event (indicating that the user invoked the menu with the mouse) then
284 no quit occurs and `x-popup-menu' returns nil. */)
286 Lisp_Object position
, menu
;
288 Lisp_Object keymap
, tem
;
289 int xpos
= 0, ypos
= 0;
291 char *error_name
= NULL
;
292 Lisp_Object selection
= Qnil
;
294 Lisp_Object x
, y
, window
;
297 int specpdl_count
= SPECPDL_INDEX ();
301 if (! NILP (position
))
303 int get_current_pos_p
= 0;
306 /* Decode the first argument: find the window and the coordinates. */
307 if (EQ (position
, Qt
)
308 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
309 || EQ (XCAR (position
), Qtool_bar
))))
311 get_current_pos_p
= 1;
315 tem
= Fcar (position
);
318 window
= Fcar (Fcdr (position
));
320 y
= Fcar (XCDR (tem
));
325 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
326 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
327 tem
= Fcar (Fcdr (Fcdr (tem
))); /* POSN_WINDOW_POSN (tem) */
332 /* If a click happens in an external tool bar or a detached
333 tool bar, x and y is NIL. In that case, use the current
334 mouse position. This happens for the help button in the
335 tool bar. Ideally popup-menu should pass NIL to
336 this function, but it doesn't. */
337 if (NILP (x
) && NILP (y
))
338 get_current_pos_p
= 1;
341 if (get_current_pos_p
)
343 /* Use the mouse's current position. */
344 FRAME_PTR new_f
= SELECTED_FRAME ();
345 #ifdef HAVE_X_WINDOWS
346 /* Can't use mouse_position_hook for X since it returns
347 coordinates relative to the window the mouse is in,
348 we need coordinates relative to the edit widget always. */
353 mouse_position_for_popup (new_f
, &cur_x
, &cur_y
);
354 /* cur_x/y may be negative, so use make_number. */
355 x
= make_number (cur_x
);
356 y
= make_number (cur_y
);
359 #else /* not HAVE_X_WINDOWS */
360 Lisp_Object bar_window
;
361 enum scroll_bar_part part
;
363 void (*mouse_position_hook
) P_ ((struct frame
**, int,
365 enum scroll_bar_part
*,
369 new_f
->terminal
->mouse_position_hook
;
371 if (mouse_position_hook
)
372 (*mouse_position_hook
) (&new_f
, 1, &bar_window
,
373 &part
, &x
, &y
, &time
);
374 #endif /* not HAVE_X_WINDOWS */
377 XSETFRAME (window
, new_f
);
380 window
= selected_window
;
389 /* Decode where to put the menu. */
397 else if (WINDOWP (window
))
399 CHECK_LIVE_WINDOW (window
);
400 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
402 xpos
= WINDOW_LEFT_EDGE_X (XWINDOW (window
));
403 ypos
= WINDOW_TOP_EDGE_Y (XWINDOW (window
));
406 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
407 but I don't want to make one now. */
408 CHECK_WINDOW (window
);
413 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
414 error ("Can not put X menu on this terminal");
416 XSETFRAME (Vmenu_updating_frame
, f
);
419 Vmenu_updating_frame
= Qnil
;
420 #endif /* HAVE_MENUS */
422 record_unwind_protect (unuse_menu_items
, Qnil
);
426 /* Decode the menu items from what was specified. */
428 keymap
= get_keymap (menu
, 0, 0);
431 /* We were given a keymap. Extract menu info from the keymap. */
434 /* Extract the detailed info to make one pane. */
435 keymap_panes (&menu
, 1, NILP (position
));
437 /* Search for a string appearing directly as an element of the keymap.
438 That string is the title of the menu. */
439 prompt
= Fkeymap_prompt (keymap
);
440 if (NILP (title
) && !NILP (prompt
))
443 /* Make that be the pane title of the first pane. */
444 if (!NILP (prompt
) && menu_items_n_panes
>= 0)
445 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = prompt
;
449 else if (CONSP (menu
) && KEYMAPP (XCAR (menu
)))
451 /* We were given a list of keymaps. */
452 int nmaps
= XFASTINT (Flength (menu
));
454 = (Lisp_Object
*) alloca (nmaps
* sizeof (Lisp_Object
));
459 /* The first keymap that has a prompt string
460 supplies the menu title. */
461 for (tem
= menu
, i
= 0; CONSP (tem
); tem
= XCDR (tem
))
465 maps
[i
++] = keymap
= get_keymap (XCAR (tem
), 1, 0);
467 prompt
= Fkeymap_prompt (keymap
);
468 if (NILP (title
) && !NILP (prompt
))
472 /* Extract the detailed info to make one pane. */
473 keymap_panes (maps
, nmaps
, NILP (position
));
475 /* Make the title be the pane title of the first pane. */
476 if (!NILP (title
) && menu_items_n_panes
>= 0)
477 XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
] = title
;
483 /* We were given an old-fashioned menu. */
485 CHECK_STRING (title
);
487 list_of_panes (Fcdr (menu
));
492 unbind_to (specpdl_count
, Qnil
);
496 discard_menu_items ();
502 /* Display them in a menu. */
505 selection
= xmenu_show (f
, xpos
, ypos
, for_click
,
506 keymaps
, title
, &error_name
);
509 discard_menu_items ();
512 #endif /* HAVE_MENUS */
514 if (error_name
) error (error_name
);
520 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
521 doc
: /* Pop up a dialog box and return user's selection.
522 POSITION specifies which frame to use.
523 This is normally a mouse button event or a window or frame.
524 If POSITION is t, it means to use the frame the mouse is on.
525 The dialog box appears in the middle of the specified frame.
527 CONTENTS specifies the alternatives to display in the dialog box.
528 It is a list of the form (DIALOG ITEM1 ITEM2...).
529 Each ITEM is a cons cell (STRING . VALUE).
530 The return value is VALUE from the chosen item.
532 An ITEM may also be just a string--that makes a nonselectable item.
533 An ITEM may also be nil--that means to put all preceding items
534 on the left of the dialog box and all following items on the right.
535 \(By default, approximately half appear on each side.)
537 If HEADER is non-nil, the frame title for the box is "Information",
538 otherwise it is "Question".
540 If the user gets rid of the dialog box without making a valid choice,
541 for instance using the window manager, then this produces a quit and
542 `x-popup-dialog' does not return. */)
543 (position
, contents
, header
)
544 Lisp_Object position
, contents
, header
;
551 /* Decode the first argument: find the window or frame to use. */
552 if (EQ (position
, Qt
)
553 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
554 || EQ (XCAR (position
), Qtool_bar
))))
556 #if 0 /* Using the frame the mouse is on may not be right. */
557 /* Use the mouse's current position. */
558 FRAME_PTR new_f
= SELECTED_FRAME ();
559 Lisp_Object bar_window
;
560 enum scroll_bar_part part
;
564 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
567 XSETFRAME (window
, new_f
);
569 window
= selected_window
;
571 window
= selected_window
;
573 else if (CONSP (position
))
576 tem
= Fcar (position
);
578 window
= Fcar (Fcdr (position
));
581 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
582 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
585 else if (WINDOWP (position
) || FRAMEP (position
))
590 /* Decode where to put the menu. */
594 else if (WINDOWP (window
))
596 CHECK_LIVE_WINDOW (window
);
597 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
600 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
601 but I don't want to make one now. */
602 CHECK_WINDOW (window
);
604 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
605 error ("Can not put X dialog on this terminal");
607 /* Force a redisplay before showing the dialog. If a frame is created
608 just before showing the dialog, its contents may not have been fully
609 drawn, as this depends on timing of events from the X server. Redisplay
610 is not done when a dialog is shown. If redisplay could be done in the
611 X event loop (i.e. the X event loop does not run in a signal handler)
612 this would not be needed.
614 Do this before creating the widget value that points to Lisp
615 string contents, because Fredisplay may GC and relocate them. */
618 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
619 /* Display a menu with these alternatives
620 in the middle of frame F. */
622 Lisp_Object x
, y
, frame
, newpos
;
623 XSETFRAME (frame
, f
);
624 XSETINT (x
, x_pixel_width (f
) / 2);
625 XSETINT (y
, x_pixel_height (f
) / 2);
626 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
628 return Fx_popup_menu (newpos
,
629 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
635 Lisp_Object selection
;
636 int specpdl_count
= SPECPDL_INDEX ();
638 /* Decode the dialog items from what was specified. */
639 title
= Fcar (contents
);
640 CHECK_STRING (title
);
641 record_unwind_protect (unuse_menu_items
, Qnil
);
643 if (NILP (Fcar (Fcdr (contents
))))
644 /* No buttons specified, add an "Ok" button so users can pop down
645 the dialog. Also, the lesstif/motif version crashes if there are
647 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
649 list_of_panes (Fcons (contents
, Qnil
));
651 /* Display them in a dialog box. */
653 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
656 unbind_to (specpdl_count
, Qnil
);
657 discard_menu_items ();
659 if (error_name
) error (error_name
);
668 /* Set menu_items_inuse so no other popup menu or dialog is created. */
671 x_menu_set_in_use (in_use
)
674 menu_items_inuse
= in_use
? Qt
: Qnil
;
675 popup_activated_flag
= in_use
;
677 if (popup_activated_flag
)
678 x_activate_timeout_atimer ();
682 /* Wait for an X event to arrive or for a timer to expire. */
685 x_menu_wait_for_event (void *data
)
687 extern EMACS_TIME timer_check
P_ ((int));
689 /* Another way to do this is to register a timer callback, that can be
690 done in GTK and Xt. But we have to do it like this when using only X
691 anyway, and with callbacks we would have three variants for timer handling
692 instead of the small ifdefs below. */
696 ! XtAppPending (Xt_app_con
)
697 #elif defined USE_GTK
698 ! gtk_events_pending ()
700 ! XPending ((Display
*) data
)
704 EMACS_TIME next_time
= timer_check (1);
705 long secs
= EMACS_SECS (next_time
);
706 long usecs
= EMACS_USECS (next_time
);
707 SELECT_TYPE read_fds
;
708 struct x_display_info
*dpyinfo
;
712 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
714 int fd
= ConnectionNumber (dpyinfo
->display
);
715 FD_SET (fd
, &read_fds
);
719 if (secs
< 0 || (secs
== 0 && usecs
== 0))
721 /* Sometimes timer_check returns -1 (no timers) even if there are
722 timers. So do a timeout anyway. */
723 EMACS_SET_SECS (next_time
, 1);
724 EMACS_SET_USECS (next_time
, 0);
727 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, &next_time
);
733 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
737 /* Loop in Xt until the menu pulldown or dialog popup has been
738 popped down (deactivated). This is used for x-popup-menu
739 and x-popup-dialog; it is not used for the menu bar.
741 NOTE: All calls to popup_get_selection should be protected
742 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
745 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
746 XEvent
*initial_event
;
747 struct x_display_info
*dpyinfo
;
753 while (popup_activated_flag
)
757 event
= *initial_event
;
762 if (do_timers
) x_menu_wait_for_event (0);
763 XtAppNextEvent (Xt_app_con
, &event
);
766 /* Make sure we don't consider buttons grabbed after menu goes.
767 And make sure to deactivate for any ButtonRelease,
768 even if XtDispatchEvent doesn't do that. */
769 if (event
.type
== ButtonRelease
770 && dpyinfo
->display
== event
.xbutton
.display
)
772 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
773 #ifdef USE_MOTIF /* Pretending that the event came from a
774 Btn1Down seems the only way to convince Motif to
775 activate its callbacks; setting the XmNmenuPost
776 isn't working. --marcus@sysc.pdx.edu. */
777 event
.xbutton
.button
= 1;
778 /* Motif only pops down menus when no Ctrl, Alt or Mod
779 key is pressed and the button is released. So reset key state
780 so Motif thinks this is the case. */
781 event
.xbutton
.state
= 0;
784 /* Pop down on C-g and Escape. */
785 else if (event
.type
== KeyPress
786 && dpyinfo
->display
== event
.xbutton
.display
)
788 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
790 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
791 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
792 popup_activated_flag
= 0;
795 x_dispatch_event (&event
, event
.xany
.display
);
799 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
800 doc
: /* Start key navigation of the menu bar in FRAME.
801 This initially opens the first menu bar item and you can then navigate with the
802 arrow keys, select a menu entry with the return key or cancel with the
803 escape key. If FRAME has no menu bar this function does nothing.
805 If FRAME is nil or not given, use the selected frame. */)
810 FRAME_PTR f
= check_x_frame (frame
);
814 if (FRAME_EXTERNAL_MENU_BAR (f
))
815 set_frame_menubar (f
, 0, 1);
817 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
823 x_catch_errors (FRAME_X_DISPLAY (f
));
824 memset (&ev
, 0, sizeof ev
);
825 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
826 ev
.xbutton
.window
= XtWindow (menubar
);
827 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
828 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
829 ev
.xbutton
.button
= Button1
;
830 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
831 ev
.xbutton
.same_screen
= True
;
838 XtSetArg (al
[0], XtNchildren
, &list
);
839 XtSetArg (al
[1], XtNnumChildren
, &nr
);
840 XtGetValues (menubar
, al
, 2);
841 ev
.xbutton
.window
= XtWindow (list
[0]);
845 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
846 /* From-window, to-window. */
847 ev
.xbutton
.window
, ev
.xbutton
.root
,
849 /* From-position, to-position. */
850 ev
.xbutton
.x
, ev
.xbutton
.y
,
851 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
855 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
860 ev
.type
= ButtonPress
;
861 ev
.xbutton
.state
= 0;
863 XtDispatchEvent (&ev
);
864 ev
.xbutton
.type
= ButtonRelease
;
865 ev
.xbutton
.state
= Button1Mask
;
866 XtDispatchEvent (&ev
);
874 #endif /* USE_X_TOOLKIT */
878 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
879 doc
: /* Start key navigation of the menu bar in FRAME.
880 This initially opens the first menu bar item and you can then navigate with the
881 arrow keys, select a menu entry with the return key or cancel with the
882 escape key. If FRAME has no menu bar this function does nothing.
884 If FRAME is nil or not given, use the selected frame. */)
891 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
895 f
= check_x_frame (frame
);
897 if (FRAME_EXTERNAL_MENU_BAR (f
))
898 set_frame_menubar (f
, 0, 1);
900 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
903 /* Activate the first menu. */
904 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
908 g_signal_emit_by_name (children
->data
, "activate_item");
909 popup_activated_flag
= 1;
910 g_list_free (children
);
918 /* Loop util popup_activated_flag is set to zero in a callback.
919 Used for popup menus and dialogs. */
922 popup_widget_loop (do_timers
, widget
)
926 ++popup_activated_flag
;
928 /* Process events in the Gtk event loop until done. */
929 while (popup_activated_flag
)
931 if (do_timers
) x_menu_wait_for_event (0);
932 gtk_main_iteration ();
937 /* Activate the menu bar of frame F.
938 This is called from keyboard.c when it gets the
939 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
941 To activate the menu bar, we use the X button-press event
942 that was saved in saved_menu_event.
943 That makes the toolkit do its thing.
945 But first we recompute the menu bar contents (the whole tree).
947 The reason for saving the button event until here, instead of
948 passing it to the toolkit right away, is that we can safely
949 execute Lisp code. */
952 x_activate_menubar (f
)
958 if (!f
->output_data
.x
->saved_menu_event
->type
)
962 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
963 f
->output_data
.x
->saved_menu_event
->xany
.window
))
967 set_frame_menubar (f
, 0, 1);
970 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
971 f
->output_data
.x
->saved_menu_event
);
972 popup_activated_flag
= 1;
974 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
978 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
979 pending_menu_activation
= 1;
982 /* Ignore this if we get it a second time. */
983 f
->output_data
.x
->saved_menu_event
->type
= 0;
986 /* This callback is invoked when the user selects a menubar cascade
987 pushbutton, but before the pulldown menu is posted. */
991 popup_activate_callback (widget
, id
, client_data
)
994 XtPointer client_data
;
996 popup_activated_flag
= 1;
998 x_activate_timeout_atimer ();
1003 /* This callback is invoked when a dialog or menu is finished being
1004 used and has been unposted. */
1008 popup_deactivate_callback (widget
, client_data
)
1010 gpointer client_data
;
1012 popup_activated_flag
= 0;
1016 popup_deactivate_callback (widget
, id
, client_data
)
1019 XtPointer client_data
;
1021 popup_activated_flag
= 0;
1026 /* Function that finds the frame for WIDGET and shows the HELP text
1028 F is the frame if known, or NULL if not known. */
1030 show_help_event (f
, widget
, help
)
1032 xt_or_gtk_widget widget
;
1039 XSETFRAME (frame
, f
);
1040 kbd_buffer_store_help_event (frame
, help
);
1044 #if 0 /* This code doesn't do anything useful. ++kfs */
1045 /* WIDGET is the popup menu. It's parent is the frame's
1046 widget. See which frame that is. */
1047 xt_or_gtk_widget frame_widget
= XtParent (widget
);
1050 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
1052 frame
= XCAR (tail
);
1054 && (f
= XFRAME (frame
),
1055 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
1059 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
1063 /* Callback called when menu items are highlighted/unhighlighted
1064 while moving the mouse over them. WIDGET is the menu bar or menu
1065 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
1066 the data structure for the menu item, or null in case of
1071 menu_highlight_callback (widget
, call_data
)
1075 xg_menu_item_cb_data
*cb_data
;
1078 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
1080 if (! cb_data
) return;
1082 help
= call_data
? cb_data
->help
: Qnil
;
1084 /* If popup_activated_flag is greater than 1 we are in a popup menu.
1085 Don't show help for them, they won't appear before the
1086 popup is popped down. */
1087 if (popup_activated_flag
<= 1)
1088 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
1092 menu_highlight_callback (widget
, id
, call_data
)
1100 widget_value
*wv
= (widget_value
*) call_data
;
1102 help
= wv
? wv
->help
: Qnil
;
1104 /* Determine the frame for the help event. */
1105 f
= menubar_id_to_frame (id
);
1107 show_help_event (f
, widget
, help
);
1112 /* Gtk calls callbacks just because we tell it what item should be
1113 selected in a radio group. If this variable is set to a non-zero
1114 value, we are creating menus and don't want callbacks right now.
1116 static int xg_crazy_callback_abort
;
1118 /* This callback is called from the menu bar pulldown menu
1119 when the user makes a selection.
1120 Figure out what the user chose
1121 and put the appropriate events into the keyboard buffer. */
1123 menubar_selection_callback (widget
, client_data
)
1125 gpointer client_data
;
1127 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1129 if (xg_crazy_callback_abort
)
1132 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
1135 /* For a group of radio buttons, GTK calls the selection callback first
1136 for the item that was active before the selection and then for the one that
1137 is active after the selection. For C-h k this means we get the help on
1138 the deselected item and then the selected item is executed. Prevent that
1139 by ignoring the non-active item. */
1140 if (GTK_IS_RADIO_MENU_ITEM (widget
)
1141 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
1144 /* When a menu is popped down, X generates a focus event (i.e. focus
1145 goes back to the frame below the menu). Since GTK buffers events,
1146 we force it out here before the menu selection event. Otherwise
1147 sit-for will exit at once if the focus event follows the menu selection
1151 while (gtk_events_pending ())
1152 gtk_main_iteration ();
1155 find_and_call_menu_selection (cb_data
->cl_data
->f
,
1156 cb_data
->cl_data
->menu_bar_items_used
,
1157 cb_data
->cl_data
->menu_bar_vector
,
1158 cb_data
->call_data
);
1161 #else /* not USE_GTK */
1163 /* This callback is called from the menu bar pulldown menu
1164 when the user makes a selection.
1165 Figure out what the user chose
1166 and put the appropriate events into the keyboard buffer. */
1168 menubar_selection_callback (widget
, id
, client_data
)
1171 XtPointer client_data
;
1175 f
= menubar_id_to_frame (id
);
1178 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
1179 f
->menu_bar_vector
, client_data
);
1181 #endif /* not USE_GTK */
1183 /* Recompute all the widgets of frame F, when the menu bar has been
1184 changed. Value is non-zero if widgets were updated. */
1187 update_frame_menubar (f
)
1191 return xg_update_frame_menubar (f
);
1196 if (! FRAME_X_P (f
))
1199 x
= f
->output_data
.x
;
1201 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
1205 /* Save the size of the frame because the pane widget doesn't accept
1206 to resize itself. So force it. */
1207 columns
= FRAME_COLS (f
);
1208 rows
= FRAME_LINES (f
);
1210 /* Do the voodoo which means "I'm changing lots of things, don't try
1211 to refigure sizes until I'm done." */
1212 lw_refigure_widget (x
->column_widget
, False
);
1214 /* The order in which children are managed is the top to bottom
1215 order in which they are displayed in the paned window. First,
1216 remove the text-area widget. */
1217 XtUnmanageChild (x
->edit_widget
);
1219 /* Remove the menubar that is there now, and put up the menubar that
1221 XtManageChild (x
->menubar_widget
);
1222 XtMapWidget (x
->menubar_widget
);
1223 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
1225 /* Re-manage the text-area widget, and then thrash the sizes. */
1226 XtManageChild (x
->edit_widget
);
1227 lw_refigure_widget (x
->column_widget
, True
);
1229 /* Force the pane widget to resize itself with the right values. */
1230 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
1236 /* Set the contents of the menubar widgets of frame F.
1237 The argument FIRST_TIME is currently ignored;
1238 it is set the first time this is called, from initialize_frame_menubar. */
1241 set_frame_menubar (f
, first_time
, deep_p
)
1246 xt_or_gtk_widget menubar_widget
;
1247 #ifdef USE_X_TOOLKIT
1251 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
1253 int *submenu_start
, *submenu_end
;
1254 int *submenu_top_level_items
, *submenu_n_panes
;
1256 if (! FRAME_X_P (f
))
1259 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1261 XSETFRAME (Vmenu_updating_frame
, f
);
1263 #ifdef USE_X_TOOLKIT
1264 if (f
->output_data
.x
->id
== 0)
1265 f
->output_data
.x
->id
= next_menubar_widget_id
++;
1266 id
= f
->output_data
.x
->id
;
1269 if (! menubar_widget
)
1271 else if (pending_menu_activation
&& !deep_p
)
1273 /* Make the first call for any given frame always go deep. */
1274 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1277 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1278 f
->output_data
.x
->saved_menu_event
->type
= 0;
1282 /* If we have detached menus, we must update deep so detached menus
1283 also gets updated. */
1284 deep_p
= deep_p
|| xg_have_tear_offs ();
1289 /* Make a widget-value tree representing the entire menu trees. */
1291 struct buffer
*prev
= current_buffer
;
1293 int specpdl_count
= SPECPDL_INDEX ();
1294 int previous_menu_items_used
= f
->menu_bar_items_used
;
1295 Lisp_Object
*previous_items
1296 = (Lisp_Object
*) alloca (previous_menu_items_used
1297 * sizeof (Lisp_Object
));
1299 /* If we are making a new widget, its contents are empty,
1300 do always reinitialize them. */
1301 if (! menubar_widget
)
1302 previous_menu_items_used
= 0;
1304 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1305 specbind (Qinhibit_quit
, Qt
);
1306 /* Don't let the debugger step into this code
1307 because it is not reentrant. */
1308 specbind (Qdebug_on_next_call
, Qnil
);
1310 record_unwind_save_match_data ();
1311 if (NILP (Voverriding_local_map_menu_flag
))
1313 specbind (Qoverriding_terminal_local_map
, Qnil
);
1314 specbind (Qoverriding_local_map
, Qnil
);
1317 set_buffer_internal_1 (XBUFFER (buffer
));
1319 /* Run the Lucid hook. */
1320 safe_run_hooks (Qactivate_menubar_hook
);
1322 /* If it has changed current-menubar from previous value,
1323 really recompute the menubar from the value. */
1324 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1325 call0 (Qrecompute_lucid_menubar
);
1326 safe_run_hooks (Qmenu_bar_update_hook
);
1327 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1329 items
= FRAME_MENU_BAR_ITEMS (f
);
1331 /* Save the frame's previous menu bar contents data. */
1332 if (previous_menu_items_used
)
1333 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1334 previous_menu_items_used
* sizeof (Lisp_Object
));
1336 /* Fill in menu_items with the current menu bar contents.
1337 This can evaluate Lisp code. */
1340 menu_items
= f
->menu_bar_vector
;
1341 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1342 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1343 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1344 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1345 submenu_top_level_items
1346 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1348 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1350 Lisp_Object key
, string
, maps
;
1354 key
= XVECTOR (items
)->contents
[i
];
1355 string
= XVECTOR (items
)->contents
[i
+ 1];
1356 maps
= XVECTOR (items
)->contents
[i
+ 2];
1360 submenu_start
[i
] = menu_items_used
;
1362 menu_items_n_panes
= 0;
1363 submenu_top_level_items
[i
]
1364 = parse_single_submenu (key
, string
, maps
);
1365 submenu_n_panes
[i
] = menu_items_n_panes
;
1367 submenu_end
[i
] = menu_items_used
;
1370 finish_menu_items ();
1372 /* Convert menu_items into widget_value trees
1373 to display the menu. This cannot evaluate Lisp code. */
1375 wv
= xmalloc_widget_value ();
1376 wv
->name
= "menubar";
1379 wv
->button_type
= BUTTON_TYPE_NONE
;
1383 for (i
= 0; i
< last_i
; i
+= 4)
1385 menu_items_n_panes
= submenu_n_panes
[i
];
1386 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1387 submenu_top_level_items
[i
]);
1391 first_wv
->contents
= wv
;
1392 /* Don't set wv->name here; GC during the loop might relocate it. */
1394 wv
->button_type
= BUTTON_TYPE_NONE
;
1398 set_buffer_internal_1 (prev
);
1400 /* If there has been no change in the Lisp-level contents
1401 of the menu bar, skip redisplaying it. Just exit. */
1403 /* Compare the new menu items with the ones computed last time. */
1404 for (i
= 0; i
< previous_menu_items_used
; i
++)
1405 if (menu_items_used
== i
1406 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1408 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1410 /* The menu items have not changed. Don't bother updating
1411 the menus in any form, since it would be a no-op. */
1412 free_menubar_widget_value_tree (first_wv
);
1413 discard_menu_items ();
1414 unbind_to (specpdl_count
, Qnil
);
1418 /* The menu items are different, so store them in the frame. */
1419 f
->menu_bar_vector
= menu_items
;
1420 f
->menu_bar_items_used
= menu_items_used
;
1422 /* This undoes save_menu_items. */
1423 unbind_to (specpdl_count
, Qnil
);
1425 /* Now GC cannot happen during the lifetime of the widget_value,
1426 so it's safe to store data from a Lisp_String. */
1427 wv
= first_wv
->contents
;
1428 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1431 string
= XVECTOR (items
)->contents
[i
+ 1];
1434 wv
->name
= (char *) SDATA (string
);
1435 update_submenu_strings (wv
->contents
);
1442 /* Make a widget-value tree containing
1443 just the top level menu bar strings. */
1445 wv
= xmalloc_widget_value ();
1446 wv
->name
= "menubar";
1449 wv
->button_type
= BUTTON_TYPE_NONE
;
1453 items
= FRAME_MENU_BAR_ITEMS (f
);
1454 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1458 string
= XVECTOR (items
)->contents
[i
+ 1];
1462 wv
= xmalloc_widget_value ();
1463 wv
->name
= (char *) SDATA (string
);
1466 wv
->button_type
= BUTTON_TYPE_NONE
;
1468 /* This prevents lwlib from assuming this
1469 menu item is really supposed to be empty. */
1470 /* The EMACS_INT cast avoids a warning.
1471 This value just has to be different from small integers. */
1472 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1477 first_wv
->contents
= wv
;
1481 /* Forget what we thought we knew about what is in the
1482 detailed contents of the menu bar menus.
1483 Changing the top level always destroys the contents. */
1484 f
->menu_bar_items_used
= 0;
1487 /* Create or update the menu bar widget. */
1492 xg_crazy_callback_abort
= 1;
1495 /* The fourth arg is DEEP_P, which says to consider the entire
1496 menu trees we supply, rather than just the menu bar item names. */
1497 xg_modify_menubar_widgets (menubar_widget
,
1501 G_CALLBACK (menubar_selection_callback
),
1502 G_CALLBACK (popup_deactivate_callback
),
1503 G_CALLBACK (menu_highlight_callback
));
1507 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1510 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1511 G_CALLBACK (menubar_selection_callback
),
1512 G_CALLBACK (popup_deactivate_callback
),
1513 G_CALLBACK (menu_highlight_callback
));
1515 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1519 #else /* not USE_GTK */
1522 /* Disable resizing (done for Motif!) */
1523 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1525 /* The third arg is DEEP_P, which says to consider the entire
1526 menu trees we supply, rather than just the menu bar item names. */
1527 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1529 /* Re-enable the edit widget to resize. */
1530 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1534 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1535 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1537 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1538 f
->output_data
.x
->column_widget
,
1540 popup_activate_callback
,
1541 menubar_selection_callback
,
1542 popup_deactivate_callback
,
1543 menu_highlight_callback
);
1544 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1546 /* Make menu pop down on C-g. */
1547 XtOverrideTranslations (menubar_widget
, override
);
1552 = (f
->output_data
.x
->menubar_widget
1553 ? (f
->output_data
.x
->menubar_widget
->core
.height
1554 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1557 #if 0 /* Experimentally, we now get the right results
1558 for -geometry -0-0 without this. 24 Aug 96, rms. */
1560 if (FRAME_EXTERNAL_MENU_BAR (f
))
1563 XtVaGetValues (f
->output_data
.x
->column_widget
,
1564 XtNinternalBorderWidth
, &ibw
, NULL
);
1565 menubar_size
+= ibw
;
1567 #endif /* USE_LUCID */
1570 f
->output_data
.x
->menubar_height
= menubar_size
;
1572 #endif /* not USE_GTK */
1574 free_menubar_widget_value_tree (first_wv
);
1575 update_frame_menubar (f
);
1578 xg_crazy_callback_abort
= 0;
1584 /* Called from Fx_create_frame to create the initial menubar of a frame
1585 before it is mapped, so that the window is mapped with the menubar already
1586 there instead of us tacking it on later and thrashing the window after it
1590 initialize_frame_menubar (f
)
1593 /* This function is called before the first chance to redisplay
1594 the frame. It has to be, so the frame will have the right size. */
1595 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1596 set_frame_menubar (f
, 1, 1);
1600 /* Get rid of the menu bar of frame F, and free its storage.
1601 This is used when deleting a frame, and when turning off the menu bar.
1602 For GTK this function is in gtkutil.c. */
1606 free_frame_menubar (f
)
1609 Widget menubar_widget
;
1611 if (! FRAME_X_P (f
))
1614 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1616 f
->output_data
.x
->menubar_height
= 0;
1621 /* Removing the menu bar magically changes the shell widget's x
1622 and y position of (0, 0) which, when the menu bar is turned
1623 on again, leads to pull-down menuss appearing in strange
1624 positions near the upper-left corner of the display. This
1625 happens only with some window managers like twm and ctwm,
1626 but not with other like Motif's mwm or kwm, because the
1627 latter generate ConfigureNotify events when the menu bar
1628 is switched off, which fixes the shell position. */
1629 Position x0
, y0
, x1
, y1
;
1635 if (f
->output_data
.x
->widget
)
1636 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1639 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1640 f
->output_data
.x
->menubar_widget
= NULL
;
1643 if (f
->output_data
.x
->widget
)
1645 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1646 if (x1
== 0 && y1
== 0)
1647 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1654 #endif /* not USE_GTK */
1656 #endif /* USE_X_TOOLKIT || USE_GTK */
1658 /* xmenu_show actually displays a menu using the panes and items in menu_items
1659 and returns the value selected from it.
1660 There are two versions of xmenu_show, one for Xt and one for Xlib.
1661 Both assume input is blocked by the caller. */
1663 /* F is the frame the menu is for.
1664 X and Y are the frame-relative specified position,
1665 relative to the inside upper left corner of the frame F.
1666 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1667 KEYMAPS is 1 if this menu was specified with keymaps;
1668 in that case, we return a list containing the chosen item's value
1669 and perhaps also the pane's prefix.
1670 TITLE is the specified menu title.
1671 ERROR is a place to store an error message string in case of failure.
1672 (We return nil on failure, but the value doesn't actually matter.) */
1674 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1676 /* The item selected in the popup menu. */
1677 static Lisp_Object
*volatile menu_item_selection
;
1681 /* Used when position a popup menu. See menu_position_func and
1682 create_and_show_popup_menu below. */
1683 struct next_popup_x_y
1690 /* The menu position function to use if we are not putting a popup
1691 menu where the pointer is.
1692 MENU is the menu to pop up.
1693 X and Y shall on exit contain x/y where the menu shall pop up.
1694 PUSH_IN is not documented in the GTK manual.
1695 USER_DATA is any data passed in when calling gtk_menu_popup.
1696 Here it points to a struct next_popup_x_y where the coordinates
1697 to store in *X and *Y are as well as the frame for the popup.
1699 Here only X and Y are used. */
1701 menu_position_func (menu
, x
, y
, push_in
, user_data
)
1708 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1710 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1711 int disp_width
= x_display_pixel_width (dpyinfo
);
1712 int disp_height
= x_display_pixel_height (dpyinfo
);
1717 /* Check if there is room for the menu. If not, adjust x/y so that
1718 the menu is fully visible. */
1719 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1720 if (data
->x
+ req
.width
> disp_width
)
1721 *x
-= data
->x
+ req
.width
- disp_width
;
1722 if (data
->y
+ req
.height
> disp_height
)
1723 *y
-= data
->y
+ req
.height
- disp_height
;
1727 popup_selection_callback (widget
, client_data
)
1729 gpointer client_data
;
1731 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1733 if (xg_crazy_callback_abort
) return;
1734 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1741 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1743 popup_activated_flag
= 0;
1745 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1750 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1752 menu_item_selection will be set to the selection. */
1754 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
1756 widget_value
*first_wv
;
1763 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1764 struct next_popup_x_y popup_x_y
;
1765 int specpdl_count
= SPECPDL_INDEX ();
1767 if (! FRAME_X_P (f
))
1770 xg_crazy_callback_abort
= 1;
1771 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1772 G_CALLBACK (popup_selection_callback
),
1773 G_CALLBACK (popup_deactivate_callback
),
1774 G_CALLBACK (menu_highlight_callback
));
1775 xg_crazy_callback_abort
= 0;
1779 /* Not invoked by a click. pop up at x/y. */
1780 pos_func
= menu_position_func
;
1782 /* Adjust coordinates to be root-window-relative. */
1783 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1784 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1790 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1794 for (i
= 0; i
< 5; i
++)
1795 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1799 /* Display the menu. */
1800 gtk_widget_show_all (menu
);
1801 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
, 0);
1803 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1805 if (GTK_WIDGET_MAPPED (menu
))
1807 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1808 two. show_help_echo uses this to detect popup menus. */
1809 popup_activated_flag
= 1;
1810 /* Process events that apply to the menu. */
1811 popup_widget_loop (1, menu
);
1814 unbind_to (specpdl_count
, Qnil
);
1816 /* Must reset this manually because the button release event is not passed
1817 to Emacs event loop. */
1818 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1821 #else /* not USE_GTK */
1823 /* We need a unique id for each widget handled by the Lucid Widget
1826 For the main windows, and popup menus, we use this counter,
1827 which we increment each time after use. This starts from 1<<16.
1829 For menu bars, we use numbers starting at 0, counted in
1830 next_menubar_widget_id. */
1831 LWLIB_ID widget_id_tick
;
1834 popup_selection_callback (widget
, id
, client_data
)
1837 XtPointer client_data
;
1839 menu_item_selection
= (Lisp_Object
*) client_data
;
1842 /* ARG is the LWLIB ID of the dialog box, represented
1843 as a Lisp object as (HIGHPART . LOWPART). */
1849 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1850 | XINT (XCDR (arg
)));
1853 lw_destroy_all_widgets (id
);
1855 popup_activated_flag
= 0;
1860 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1862 menu_item_selection will be set to the selection. */
1864 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
1866 widget_value
*first_wv
;
1874 XButtonPressedEvent dummy
;
1878 if (! FRAME_X_P (f
))
1881 menu_id
= widget_id_tick
++;
1882 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1883 f
->output_data
.x
->widget
, 1, 0,
1884 popup_selection_callback
,
1885 popup_deactivate_callback
,
1886 menu_highlight_callback
);
1888 dummy
.type
= ButtonPress
;
1890 dummy
.send_event
= 0;
1891 dummy
.display
= FRAME_X_DISPLAY (f
);
1892 dummy
.time
= CurrentTime
;
1893 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1894 dummy
.window
= dummy
.root
;
1895 dummy
.subwindow
= dummy
.root
;
1899 /* Adjust coordinates to be root-window-relative. */
1900 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1901 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1908 for (i
= 0; i
< 5; i
++)
1909 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1912 /* Don't allow any geometry request from the user. */
1913 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1914 XtSetValues (menu
, av
, ac
);
1916 /* Display the menu. */
1917 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1918 popup_activated_flag
= 1;
1919 x_activate_timeout_atimer ();
1922 int fact
= 4 * sizeof (LWLIB_ID
);
1923 int specpdl_count
= SPECPDL_INDEX ();
1924 record_unwind_protect (pop_down_menu
,
1925 Fcons (make_number (menu_id
>> (fact
)),
1926 make_number (menu_id
& ~(-1 << (fact
)))));
1928 /* Process events that apply to the menu. */
1929 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1931 unbind_to (specpdl_count
, Qnil
);
1935 #endif /* not USE_GTK */
1938 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
1948 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1949 widget_value
**submenu_stack
1950 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1951 Lisp_Object
*subprefix_stack
1952 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1953 int submenu_depth
= 0;
1957 if (! FRAME_X_P (f
))
1962 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1964 *error
= "Empty menu";
1968 /* Create a tree of widget_value objects
1969 representing the panes and their items. */
1970 wv
= xmalloc_widget_value ();
1974 wv
->button_type
= BUTTON_TYPE_NONE
;
1979 /* Loop over all panes and items, filling in the tree. */
1981 while (i
< menu_items_used
)
1983 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1985 submenu_stack
[submenu_depth
++] = save_wv
;
1991 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1994 save_wv
= submenu_stack
[--submenu_depth
];
1998 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1999 && submenu_depth
!= 0)
2000 i
+= MENU_ITEMS_PANE_LENGTH
;
2001 /* Ignore a nil in the item list.
2002 It's meaningful only for dialog boxes. */
2003 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2005 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2007 /* Create a new pane. */
2008 Lisp_Object pane_name
, prefix
;
2011 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2012 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2014 #ifndef HAVE_MULTILINGUAL_MENU
2015 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
2017 pane_name
= ENCODE_MENU_STRING (pane_name
);
2018 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
2021 pane_string
= (NILP (pane_name
)
2022 ? "" : (char *) SDATA (pane_name
));
2023 /* If there is just one top-level pane, put all its items directly
2024 under the top-level menu. */
2025 if (menu_items_n_panes
== 1)
2028 /* If the pane has a meaningful name,
2029 make the pane a top-level menu item
2030 with its items as a submenu beneath it. */
2031 if (!keymaps
&& strcmp (pane_string
, ""))
2033 wv
= xmalloc_widget_value ();
2037 first_wv
->contents
= wv
;
2038 wv
->name
= pane_string
;
2039 if (keymaps
&& !NILP (prefix
))
2043 wv
->button_type
= BUTTON_TYPE_NONE
;
2048 else if (first_pane
)
2054 i
+= MENU_ITEMS_PANE_LENGTH
;
2058 /* Create a new item within current pane. */
2059 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
2060 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2061 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2062 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2063 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
2064 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
2065 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
2066 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2068 #ifndef HAVE_MULTILINGUAL_MENU
2069 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
2071 item_name
= ENCODE_MENU_STRING (item_name
);
2072 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
2075 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
2077 descrip
= ENCODE_MENU_STRING (descrip
);
2078 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
2080 #endif /* not HAVE_MULTILINGUAL_MENU */
2082 wv
= xmalloc_widget_value ();
2086 save_wv
->contents
= wv
;
2087 wv
->name
= (char *) SDATA (item_name
);
2088 if (!NILP (descrip
))
2089 wv
->key
= (char *) SDATA (descrip
);
2091 /* If this item has a null value,
2092 make the call_data null so that it won't display a box
2093 when the mouse is on it. */
2095 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
2096 wv
->enabled
= !NILP (enable
);
2099 wv
->button_type
= BUTTON_TYPE_NONE
;
2100 else if (EQ (type
, QCtoggle
))
2101 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
2102 else if (EQ (type
, QCradio
))
2103 wv
->button_type
= BUTTON_TYPE_RADIO
;
2107 wv
->selected
= !NILP (selected
);
2109 if (! STRINGP (help
))
2116 i
+= MENU_ITEMS_ITEM_LENGTH
;
2120 /* Deal with the title, if it is non-nil. */
2123 widget_value
*wv_title
= xmalloc_widget_value ();
2124 widget_value
*wv_sep1
= xmalloc_widget_value ();
2125 widget_value
*wv_sep2
= xmalloc_widget_value ();
2127 wv_sep2
->name
= "--";
2128 wv_sep2
->next
= first_wv
->contents
;
2129 wv_sep2
->help
= Qnil
;
2131 wv_sep1
->name
= "--";
2132 wv_sep1
->next
= wv_sep2
;
2133 wv_sep1
->help
= Qnil
;
2135 #ifndef HAVE_MULTILINGUAL_MENU
2136 if (STRING_MULTIBYTE (title
))
2137 title
= ENCODE_MENU_STRING (title
);
2140 wv_title
->name
= (char *) SDATA (title
);
2141 wv_title
->enabled
= TRUE
;
2142 wv_title
->button_type
= BUTTON_TYPE_NONE
;
2143 wv_title
->help
= Qnil
;
2144 wv_title
->next
= wv_sep1
;
2145 first_wv
->contents
= wv_title
;
2148 /* No selection has been chosen yet. */
2149 menu_item_selection
= 0;
2151 /* Actually create and show the menu until popped down. */
2152 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
);
2154 /* Free the widget_value objects we used to specify the contents. */
2155 free_menubar_widget_value_tree (first_wv
);
2157 /* Find the selected item, and its pane, to return
2158 the proper value. */
2159 if (menu_item_selection
!= 0)
2161 Lisp_Object prefix
, entry
;
2163 prefix
= entry
= Qnil
;
2165 while (i
< menu_items_used
)
2167 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
2169 subprefix_stack
[submenu_depth
++] = prefix
;
2173 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
2175 prefix
= subprefix_stack
[--submenu_depth
];
2178 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2181 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2182 i
+= MENU_ITEMS_PANE_LENGTH
;
2184 /* Ignore a nil in the item list.
2185 It's meaningful only for dialog boxes. */
2186 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2191 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2192 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2198 entry
= Fcons (entry
, Qnil
);
2200 entry
= Fcons (prefix
, entry
);
2201 for (j
= submenu_depth
- 1; j
>= 0; j
--)
2202 if (!NILP (subprefix_stack
[j
]))
2203 entry
= Fcons (subprefix_stack
[j
], entry
);
2207 i
+= MENU_ITEMS_ITEM_LENGTH
;
2211 else if (!for_click
)
2212 /* Make "Cancel" equivalent to C-g. */
2213 Fsignal (Qquit
, Qnil
);
2220 dialog_selection_callback (widget
, client_data
)
2222 gpointer client_data
;
2224 /* The EMACS_INT cast avoids a warning. There's no problem
2225 as long as pointers have enough bits to hold small integers. */
2226 if ((int) (EMACS_INT
) client_data
!= -1)
2227 menu_item_selection
= (Lisp_Object
*) client_data
;
2229 popup_activated_flag
= 0;
2232 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2234 menu_item_selection will be set to the selection. */
2236 create_and_show_dialog (f
, first_wv
)
2238 widget_value
*first_wv
;
2242 if (! FRAME_X_P (f
))
2245 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
2246 G_CALLBACK (dialog_selection_callback
),
2247 G_CALLBACK (popup_deactivate_callback
),
2252 int specpdl_count
= SPECPDL_INDEX ();
2253 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
2255 /* Display the menu. */
2256 gtk_widget_show_all (menu
);
2258 /* Process events that apply to the menu. */
2259 popup_widget_loop (1, menu
);
2261 unbind_to (specpdl_count
, Qnil
);
2265 #else /* not USE_GTK */
2267 dialog_selection_callback (widget
, id
, client_data
)
2270 XtPointer client_data
;
2272 /* The EMACS_INT cast avoids a warning. There's no problem
2273 as long as pointers have enough bits to hold small integers. */
2274 if ((int) (EMACS_INT
) client_data
!= -1)
2275 menu_item_selection
= (Lisp_Object
*) client_data
;
2278 lw_destroy_all_widgets (id
);
2280 popup_activated_flag
= 0;
2284 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2286 menu_item_selection will be set to the selection. */
2288 create_and_show_dialog (f
, first_wv
)
2290 widget_value
*first_wv
;
2297 dialog_id
= widget_id_tick
++;
2298 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2299 f
->output_data
.x
->widget
, 1, 0,
2300 dialog_selection_callback
, 0, 0);
2301 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2303 /* Display the dialog box. */
2304 lw_pop_up_all_widgets (dialog_id
);
2305 popup_activated_flag
= 1;
2306 x_activate_timeout_atimer ();
2308 /* Process events that apply to the dialog box.
2309 Also handle timers. */
2311 int count
= SPECPDL_INDEX ();
2312 int fact
= 4 * sizeof (LWLIB_ID
);
2314 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2315 record_unwind_protect (pop_down_menu
,
2316 Fcons (make_number (dialog_id
>> (fact
)),
2317 make_number (dialog_id
& ~(-1 << (fact
)))));
2319 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2322 unbind_to (count
, Qnil
);
2326 #endif /* not USE_GTK */
2328 static char * button_names
[] = {
2329 "button1", "button2", "button3", "button4", "button5",
2330 "button6", "button7", "button8", "button9", "button10" };
2333 xdialog_show (f
, keymaps
, title
, header
, error_name
)
2336 Lisp_Object title
, header
;
2339 int i
, nb_buttons
=0;
2340 char dialog_name
[6];
2342 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2344 /* Number of elements seen so far, before boundary. */
2346 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2347 int boundary_seen
= 0;
2349 if (! FRAME_X_P (f
))
2354 if (menu_items_n_panes
> 1)
2356 *error_name
= "Multiple panes in dialog box";
2360 /* Create a tree of widget_value objects
2361 representing the text label and buttons. */
2363 Lisp_Object pane_name
, prefix
;
2365 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2366 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2367 pane_string
= (NILP (pane_name
)
2368 ? "" : (char *) SDATA (pane_name
));
2369 prev_wv
= xmalloc_widget_value ();
2370 prev_wv
->value
= pane_string
;
2371 if (keymaps
&& !NILP (prefix
))
2373 prev_wv
->enabled
= 1;
2374 prev_wv
->name
= "message";
2375 prev_wv
->help
= Qnil
;
2378 /* Loop over all panes and items, filling in the tree. */
2379 i
= MENU_ITEMS_PANE_LENGTH
;
2380 while (i
< menu_items_used
)
2383 /* Create a new item within current pane. */
2384 Lisp_Object item_name
, enable
, descrip
;
2385 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2386 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2388 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2390 if (NILP (item_name
))
2392 free_menubar_widget_value_tree (first_wv
);
2393 *error_name
= "Submenu in dialog items";
2396 if (EQ (item_name
, Qquote
))
2398 /* This is the boundary between left-side elts
2399 and right-side elts. Stop incrementing right_count. */
2404 if (nb_buttons
>= 9)
2406 free_menubar_widget_value_tree (first_wv
);
2407 *error_name
= "Too many dialog items";
2411 wv
= xmalloc_widget_value ();
2413 wv
->name
= (char *) button_names
[nb_buttons
];
2414 if (!NILP (descrip
))
2415 wv
->key
= (char *) SDATA (descrip
);
2416 wv
->value
= (char *) SDATA (item_name
);
2417 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2418 wv
->enabled
= !NILP (enable
);
2422 if (! boundary_seen
)
2426 i
+= MENU_ITEMS_ITEM_LENGTH
;
2429 /* If the boundary was not specified,
2430 by default put half on the left and half on the right. */
2431 if (! boundary_seen
)
2432 left_count
= nb_buttons
- nb_buttons
/ 2;
2434 wv
= xmalloc_widget_value ();
2435 wv
->name
= dialog_name
;
2438 /* Frame title: 'Q' = Question, 'I' = Information.
2439 Can also have 'E' = Error if, one day, we want
2440 a popup for errors. */
2442 dialog_name
[0] = 'Q';
2444 dialog_name
[0] = 'I';
2446 /* Dialog boxes use a really stupid name encoding
2447 which specifies how many buttons to use
2448 and how many buttons are on the right. */
2449 dialog_name
[1] = '0' + nb_buttons
;
2450 dialog_name
[2] = 'B';
2451 dialog_name
[3] = 'R';
2452 /* Number of buttons to put on the right. */
2453 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2455 wv
->contents
= first_wv
;
2459 /* No selection has been chosen yet. */
2460 menu_item_selection
= 0;
2462 /* Actually create and show the dialog. */
2463 create_and_show_dialog (f
, first_wv
);
2465 /* Free the widget_value objects we used to specify the contents. */
2466 free_menubar_widget_value_tree (first_wv
);
2468 /* Find the selected item, and its pane, to return
2469 the proper value. */
2470 if (menu_item_selection
!= 0)
2476 while (i
< menu_items_used
)
2480 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2483 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2484 i
+= MENU_ITEMS_PANE_LENGTH
;
2486 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2488 /* This is the boundary between left-side elts and
2495 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2496 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2500 entry
= Fcons (entry
, Qnil
);
2502 entry
= Fcons (prefix
, entry
);
2506 i
+= MENU_ITEMS_ITEM_LENGTH
;
2511 /* Make "Cancel" equivalent to C-g. */
2512 Fsignal (Qquit
, Qnil
);
2517 #else /* not USE_X_TOOLKIT && not USE_GTK */
2519 /* The frame of the last activated non-toolkit menu bar.
2520 Used to generate menu help events. */
2522 static struct frame
*menu_help_frame
;
2525 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2527 PANE is the pane number, and ITEM is the menu item number in
2528 the menu (currently not used).
2530 This cannot be done with generating a HELP_EVENT because
2531 XMenuActivate contains a loop that doesn't let Emacs process
2535 menu_help_callback (help_string
, pane
, item
)
2539 extern Lisp_Object Qmenu_item
;
2540 Lisp_Object
*first_item
;
2541 Lisp_Object pane_name
;
2542 Lisp_Object menu_object
;
2544 first_item
= XVECTOR (menu_items
)->contents
;
2545 if (EQ (first_item
[0], Qt
))
2546 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2547 else if (EQ (first_item
[0], Qquote
))
2548 /* This shouldn't happen, see xmenu_show. */
2549 pane_name
= empty_unibyte_string
;
2551 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2553 /* (menu-item MENU-NAME PANE-NUMBER) */
2554 menu_object
= Fcons (Qmenu_item
,
2556 Fcons (make_number (pane
), Qnil
)));
2557 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2558 Qnil
, menu_object
, make_number (item
), 1);
2565 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2566 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2568 FRAME_PTR f
= p1
->pointer
;
2569 XMenu
*menu
= p2
->pointer
;
2573 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2574 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2576 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2578 #ifdef HAVE_X_WINDOWS
2579 /* Assume the mouse has moved out of the X window.
2580 If it has actually moved in, we will get an EnterNotify. */
2581 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2583 /* State that no mouse buttons are now held.
2584 (The oldXMenu code doesn't track this info for us.)
2585 That is not necessarily true, but the fiction leads to reasonable
2586 results, and it is a pain to ask which are actually held now. */
2587 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2589 #endif /* HAVE_X_WINDOWS */
2598 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
)
2608 int pane
, selidx
, lpane
, status
;
2609 Lisp_Object entry
, pane_prefix
;
2611 int ulx
, uly
, width
, height
;
2612 int dispwidth
, dispheight
;
2613 int i
, j
, lines
, maxlines
;
2616 unsigned int dummy_uint
;
2617 int specpdl_count
= SPECPDL_INDEX ();
2619 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2623 if (menu_items_n_panes
== 0)
2626 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2628 *error
= "Empty menu";
2632 /* Figure out which root window F is on. */
2633 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2634 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2635 &dummy_uint
, &dummy_uint
);
2637 /* Make the menu on that window. */
2638 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2641 *error
= "Can't create menu";
2645 /* Don't GC while we prepare and show the menu,
2646 because we give the oldxmenu library pointers to the
2647 contents of strings. */
2648 inhibit_garbage_collection ();
2650 #ifdef HAVE_X_WINDOWS
2651 /* Adjust coordinates to relative to the outer (window manager) window. */
2652 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2653 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2654 #endif /* HAVE_X_WINDOWS */
2656 /* Adjust coordinates to be root-window-relative. */
2660 /* Create all the necessary panes and their items. */
2661 maxlines
= lines
= i
= 0;
2662 while (i
< menu_items_used
)
2664 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2666 /* Create a new pane. */
2667 Lisp_Object pane_name
, prefix
;
2670 maxlines
= max (maxlines
, lines
);
2672 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2673 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2674 pane_string
= (NILP (pane_name
)
2675 ? "" : (char *) SDATA (pane_name
));
2676 if (keymaps
&& !NILP (prefix
))
2679 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2680 if (lpane
== XM_FAILURE
)
2682 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2683 *error
= "Can't create pane";
2686 i
+= MENU_ITEMS_PANE_LENGTH
;
2688 /* Find the width of the widest item in this pane. */
2691 while (j
< menu_items_used
)
2694 item
= XVECTOR (menu_items
)->contents
[j
];
2702 width
= SBYTES (item
);
2703 if (width
> maxwidth
)
2706 j
+= MENU_ITEMS_ITEM_LENGTH
;
2709 /* Ignore a nil in the item list.
2710 It's meaningful only for dialog boxes. */
2711 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2715 /* Create a new item within current pane. */
2716 Lisp_Object item_name
, enable
, descrip
, help
;
2717 unsigned char *item_data
;
2720 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2721 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2723 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2724 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2725 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2727 if (!NILP (descrip
))
2729 int gap
= maxwidth
- SBYTES (item_name
);
2730 /* if alloca is fast, use that to make the space,
2731 to reduce gc needs. */
2733 = (unsigned char *) alloca (maxwidth
2734 + SBYTES (descrip
) + 1);
2735 bcopy (SDATA (item_name
), item_data
,
2736 SBYTES (item_name
));
2737 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2739 bcopy (SDATA (descrip
), item_data
+ j
,
2741 item_data
[j
+ SBYTES (descrip
)] = 0;
2744 item_data
= SDATA (item_name
);
2746 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2747 menu
, lpane
, 0, item_data
,
2748 !NILP (enable
), help_string
)
2751 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2752 *error
= "Can't add selection to menu";
2755 i
+= MENU_ITEMS_ITEM_LENGTH
;
2760 maxlines
= max (maxlines
, lines
);
2762 /* All set and ready to fly. */
2763 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2764 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2765 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2766 x
= min (x
, dispwidth
);
2767 y
= min (y
, dispheight
);
2770 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2771 &ulx
, &uly
, &width
, &height
);
2772 if (ulx
+width
> dispwidth
)
2774 x
-= (ulx
+ width
) - dispwidth
;
2775 ulx
= dispwidth
- width
;
2777 if (uly
+height
> dispheight
)
2779 y
-= (uly
+ height
) - dispheight
;
2780 uly
= dispheight
- height
;
2782 #ifndef HAVE_X_WINDOWS
2783 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2785 /* Move the menu away of the echo area, to avoid overwriting the
2786 menu with help echo messages or vice versa. */
2787 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2789 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2790 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2799 if (ulx
< 0) x
-= ulx
;
2800 if (uly
< 0) y
-= uly
;
2804 /* If position was not given by a mouse click, adjust so upper left
2805 corner of the menu as a whole ends up at given coordinates. This
2806 is what x-popup-menu says in its documentation. */
2808 y
+= 1.5*height
/(maxlines
+2);
2811 XMenuSetAEQ (menu
, TRUE
);
2812 XMenuSetFreeze (menu
, TRUE
);
2816 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2819 record_unwind_protect (pop_down_menu
,
2820 Fcons (make_save_value (f
, 0),
2821 make_save_value (menu
, 0)));
2823 /* Help display under X won't work because XMenuActivate contains
2824 a loop that doesn't give Emacs a chance to process it. */
2825 menu_help_frame
= f
;
2826 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2827 x
, y
, ButtonReleaseMask
, &datap
,
2828 menu_help_callback
);
2834 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2837 /* Find the item number SELIDX in pane number PANE. */
2839 while (i
< menu_items_used
)
2841 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2845 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2847 i
+= MENU_ITEMS_PANE_LENGTH
;
2856 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2859 entry
= Fcons (entry
, Qnil
);
2860 if (!NILP (pane_prefix
))
2861 entry
= Fcons (pane_prefix
, entry
);
2867 i
+= MENU_ITEMS_ITEM_LENGTH
;
2873 *error
= "Can't activate menu";
2878 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2879 the menu was invoked with a mouse event as POSITION). */
2881 Fsignal (Qquit
, Qnil
);
2886 unbind_to (specpdl_count
, Qnil
);
2891 #endif /* not USE_X_TOOLKIT */
2893 #endif /* HAVE_MENUS */
2895 /* Detect if a dialog or menu has been posted. */
2900 return popup_activated_flag
;
2903 /* The following is used by delayed window autoselection. */
2905 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2906 doc
: /* Return t if a menu or popup dialog is active. */)
2910 return (popup_activated ()) ? Qt
: Qnil
;
2913 #endif /* HAVE_MENUS */
2919 Qdebug_on_next_call
= intern ("debug-on-next-call");
2920 staticpro (&Qdebug_on_next_call
);
2922 #ifdef USE_X_TOOLKIT
2923 widget_id_tick
= (1<<16);
2924 next_menubar_widget_id
= 1;
2927 defsubr (&Sx_popup_menu
);
2928 defsubr (&Smenu_or_popup_active_p
);
2930 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2931 defsubr (&Sx_menu_bar_open_internal
);
2932 Ffset (intern ("accelerate-menu"),
2933 intern (Sx_menu_bar_open_internal
.symbol_name
));
2937 defsubr (&Sx_popup_dialog
);
2941 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2942 (do not change this comment) */