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 Qmenu_bar
;
113 extern Lisp_Object QCtoggle
, QCradio
;
115 extern Lisp_Object Voverriding_local_map
;
116 extern Lisp_Object Voverriding_local_map_menu_flag
;
118 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
120 extern Lisp_Object Qmenu_bar_update_hook
;
123 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
124 extern XtAppContext Xt_app_con
;
126 static Lisp_Object xdialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
128 static void popup_get_selection
P_ ((XEvent
*, struct x_display_info
*,
130 #endif /* USE_X_TOOLKIT */
133 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
134 static Lisp_Object xdialog_show
P_ ((FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
138 static int update_frame_menubar
P_ ((struct frame
*));
140 /* Flag which when set indicates a dialog or menu has been posted by
141 Xt on behalf of one of the widget sets. */
142 static int popup_activated_flag
;
144 static int next_menubar_widget_id
;
146 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
147 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
148 extern widget_value
*xmalloc_widget_value
P_ ((void));
149 extern widget_value
*digest_single_submenu
P_ ((int, int, int));
152 /* This is set nonzero after the user activates the menu bar, and set
153 to zero again after the menu bars are redisplayed by prepare_menu_bar.
154 While it is nonzero, all calls to set_frame_menubar go deep.
156 I don't understand why this is needed, but it does seem to be
157 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
159 int pending_menu_activation
;
163 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
165 static struct frame
*
166 menubar_id_to_frame (id
)
169 Lisp_Object tail
, frame
;
172 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
178 if (!FRAME_WINDOW_P (f
))
180 if (f
->output_data
.x
->id
== id
)
188 #ifdef HAVE_X_WINDOWS
189 /* Return the mouse position in *X and *Y. The coordinates are window
190 relative for the edit window in frame F.
191 This is for Fx_popup_menu. The mouse_position_hook can not
192 be used for X, as it returns window relative coordinates
193 for the window where the mouse is in. This could be the menu bar,
194 the scroll bar or the edit window. Fx_popup_menu needs to be
195 sure it is the edit window. */
197 mouse_position_for_popup (f
, x
, y
)
202 Window root
, dummy_window
;
210 XQueryPointer (FRAME_X_DISPLAY (f
),
211 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
213 /* The root window which contains the pointer. */
216 /* Window pointer is on, not used */
219 /* The position on that root window. */
222 /* x/y in dummy_window coordinates, not used. */
225 /* Modifier keys and pointer buttons, about which
227 (unsigned int *) &dummy
);
231 /* xmenu_show expects window coordinates, not root window
232 coordinates. Translate. */
233 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
234 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
237 #endif /* HAVE_X_WINDOWS */
241 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
242 doc
: /* Pop up a dialog box and return user's selection.
243 POSITION specifies which frame to use.
244 This is normally a mouse button event or a window or frame.
245 If POSITION is t, it means to use the frame the mouse is on.
246 The dialog box appears in the middle of the specified frame.
248 CONTENTS specifies the alternatives to display in the dialog box.
249 It is a list of the form (DIALOG ITEM1 ITEM2...).
250 Each ITEM is a cons cell (STRING . VALUE).
251 The return value is VALUE from the chosen item.
253 An ITEM may also be just a string--that makes a nonselectable item.
254 An ITEM may also be nil--that means to put all preceding items
255 on the left of the dialog box and all following items on the right.
256 \(By default, approximately half appear on each side.)
258 If HEADER is non-nil, the frame title for the box is "Information",
259 otherwise it is "Question".
261 If the user gets rid of the dialog box without making a valid choice,
262 for instance using the window manager, then this produces a quit and
263 `x-popup-dialog' does not return. */)
264 (position
, contents
, header
)
265 Lisp_Object position
, contents
, header
;
272 /* Decode the first argument: find the window or frame to use. */
273 if (EQ (position
, Qt
)
274 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
275 || EQ (XCAR (position
), Qtool_bar
))))
277 #if 0 /* Using the frame the mouse is on may not be right. */
278 /* Use the mouse's current position. */
279 FRAME_PTR new_f
= SELECTED_FRAME ();
280 Lisp_Object bar_window
;
281 enum scroll_bar_part part
;
285 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
288 XSETFRAME (window
, new_f
);
290 window
= selected_window
;
292 window
= selected_window
;
294 else if (CONSP (position
))
297 tem
= Fcar (position
);
299 window
= Fcar (Fcdr (position
));
302 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
303 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
306 else if (WINDOWP (position
) || FRAMEP (position
))
311 /* Decode where to put the menu. */
315 else if (WINDOWP (window
))
317 CHECK_LIVE_WINDOW (window
);
318 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
321 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
322 but I don't want to make one now. */
323 CHECK_WINDOW (window
);
325 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
326 error ("Can not put X dialog on this terminal");
328 /* Force a redisplay before showing the dialog. If a frame is created
329 just before showing the dialog, its contents may not have been fully
330 drawn, as this depends on timing of events from the X server. Redisplay
331 is not done when a dialog is shown. If redisplay could be done in the
332 X event loop (i.e. the X event loop does not run in a signal handler)
333 this would not be needed.
335 Do this before creating the widget value that points to Lisp
336 string contents, because Fredisplay may GC and relocate them. */
339 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
340 /* Display a menu with these alternatives
341 in the middle of frame F. */
343 Lisp_Object x
, y
, frame
, newpos
;
344 XSETFRAME (frame
, f
);
345 XSETINT (x
, x_pixel_width (f
) / 2);
346 XSETINT (y
, x_pixel_height (f
) / 2);
347 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
349 return Fx_popup_menu (newpos
,
350 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
356 Lisp_Object selection
;
357 int specpdl_count
= SPECPDL_INDEX ();
359 /* Decode the dialog items from what was specified. */
360 title
= Fcar (contents
);
361 CHECK_STRING (title
);
362 record_unwind_protect (unuse_menu_items
, Qnil
);
364 if (NILP (Fcar (Fcdr (contents
))))
365 /* No buttons specified, add an "Ok" button so users can pop down
366 the dialog. Also, the lesstif/motif version crashes if there are
368 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
370 list_of_panes (Fcons (contents
, Qnil
));
372 /* Display them in a dialog box. */
374 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
377 unbind_to (specpdl_count
, Qnil
);
378 discard_menu_items ();
380 if (error_name
) error (error_name
);
389 /* Set menu_items_inuse so no other popup menu or dialog is created. */
392 x_menu_set_in_use (in_use
)
395 menu_items_inuse
= in_use
? Qt
: Qnil
;
396 popup_activated_flag
= in_use
;
398 if (popup_activated_flag
)
399 x_activate_timeout_atimer ();
403 /* Wait for an X event to arrive or for a timer to expire. */
406 x_menu_wait_for_event (void *data
)
408 extern EMACS_TIME timer_check
P_ ((int));
410 /* Another way to do this is to register a timer callback, that can be
411 done in GTK and Xt. But we have to do it like this when using only X
412 anyway, and with callbacks we would have three variants for timer handling
413 instead of the small ifdefs below. */
417 ! XtAppPending (Xt_app_con
)
418 #elif defined USE_GTK
419 ! gtk_events_pending ()
421 ! XPending ((Display
*) data
)
425 EMACS_TIME next_time
= timer_check (1);
426 long secs
= EMACS_SECS (next_time
);
427 long usecs
= EMACS_USECS (next_time
);
428 SELECT_TYPE read_fds
;
429 struct x_display_info
*dpyinfo
;
433 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
435 int fd
= ConnectionNumber (dpyinfo
->display
);
436 FD_SET (fd
, &read_fds
);
440 if (secs
< 0 || (secs
== 0 && usecs
== 0))
442 /* Sometimes timer_check returns -1 (no timers) even if there are
443 timers. So do a timeout anyway. */
444 EMACS_SET_SECS (next_time
, 1);
445 EMACS_SET_USECS (next_time
, 0);
448 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, &next_time
);
454 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
458 /* Loop in Xt until the menu pulldown or dialog popup has been
459 popped down (deactivated). This is used for x-popup-menu
460 and x-popup-dialog; it is not used for the menu bar.
462 NOTE: All calls to popup_get_selection should be protected
463 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
466 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
467 XEvent
*initial_event
;
468 struct x_display_info
*dpyinfo
;
474 while (popup_activated_flag
)
478 event
= *initial_event
;
483 if (do_timers
) x_menu_wait_for_event (0);
484 XtAppNextEvent (Xt_app_con
, &event
);
487 /* Make sure we don't consider buttons grabbed after menu goes.
488 And make sure to deactivate for any ButtonRelease,
489 even if XtDispatchEvent doesn't do that. */
490 if (event
.type
== ButtonRelease
491 && dpyinfo
->display
== event
.xbutton
.display
)
493 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
494 #ifdef USE_MOTIF /* Pretending that the event came from a
495 Btn1Down seems the only way to convince Motif to
496 activate its callbacks; setting the XmNmenuPost
497 isn't working. --marcus@sysc.pdx.edu. */
498 event
.xbutton
.button
= 1;
499 /* Motif only pops down menus when no Ctrl, Alt or Mod
500 key is pressed and the button is released. So reset key state
501 so Motif thinks this is the case. */
502 event
.xbutton
.state
= 0;
505 /* Pop down on C-g and Escape. */
506 else if (event
.type
== KeyPress
507 && dpyinfo
->display
== event
.xbutton
.display
)
509 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
511 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
512 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
513 popup_activated_flag
= 0;
516 x_dispatch_event (&event
, event
.xany
.display
);
520 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
521 doc
: /* Start key navigation of the menu bar in FRAME.
522 This initially opens the first menu bar item and you can then navigate with the
523 arrow keys, select a menu entry with the return key or cancel with the
524 escape key. If FRAME has no menu bar this function does nothing.
526 If FRAME is nil or not given, use the selected frame. */)
531 FRAME_PTR f
= check_x_frame (frame
);
535 if (FRAME_EXTERNAL_MENU_BAR (f
))
536 set_frame_menubar (f
, 0, 1);
538 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
544 x_catch_errors (FRAME_X_DISPLAY (f
));
545 memset (&ev
, 0, sizeof ev
);
546 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
547 ev
.xbutton
.window
= XtWindow (menubar
);
548 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
549 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
550 ev
.xbutton
.button
= Button1
;
551 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
552 ev
.xbutton
.same_screen
= True
;
559 XtSetArg (al
[0], XtNchildren
, &list
);
560 XtSetArg (al
[1], XtNnumChildren
, &nr
);
561 XtGetValues (menubar
, al
, 2);
562 ev
.xbutton
.window
= XtWindow (list
[0]);
566 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
567 /* From-window, to-window. */
568 ev
.xbutton
.window
, ev
.xbutton
.root
,
570 /* From-position, to-position. */
571 ev
.xbutton
.x
, ev
.xbutton
.y
,
572 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
576 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
581 ev
.type
= ButtonPress
;
582 ev
.xbutton
.state
= 0;
584 XtDispatchEvent (&ev
);
585 ev
.xbutton
.type
= ButtonRelease
;
586 ev
.xbutton
.state
= Button1Mask
;
587 XtDispatchEvent (&ev
);
595 #endif /* USE_X_TOOLKIT */
599 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
600 doc
: /* Start key navigation of the menu bar in FRAME.
601 This initially opens the first menu bar item and you can then navigate with the
602 arrow keys, select a menu entry with the return key or cancel with the
603 escape key. If FRAME has no menu bar this function does nothing.
605 If FRAME is nil or not given, use the selected frame. */)
612 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
616 f
= check_x_frame (frame
);
618 if (FRAME_EXTERNAL_MENU_BAR (f
))
619 set_frame_menubar (f
, 0, 1);
621 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
624 /* Activate the first menu. */
625 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
629 g_signal_emit_by_name (children
->data
, "activate_item");
630 popup_activated_flag
= 1;
631 g_list_free (children
);
639 /* Loop util popup_activated_flag is set to zero in a callback.
640 Used for popup menus and dialogs. */
643 popup_widget_loop (do_timers
, widget
)
647 ++popup_activated_flag
;
649 /* Process events in the Gtk event loop until done. */
650 while (popup_activated_flag
)
652 if (do_timers
) x_menu_wait_for_event (0);
653 gtk_main_iteration ();
658 /* Activate the menu bar of frame F.
659 This is called from keyboard.c when it gets the
660 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
662 To activate the menu bar, we use the X button-press event
663 that was saved in saved_menu_event.
664 That makes the toolkit do its thing.
666 But first we recompute the menu bar contents (the whole tree).
668 The reason for saving the button event until here, instead of
669 passing it to the toolkit right away, is that we can safely
670 execute Lisp code. */
673 x_activate_menubar (f
)
679 if (!f
->output_data
.x
->saved_menu_event
->type
)
683 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
684 f
->output_data
.x
->saved_menu_event
->xany
.window
))
688 set_frame_menubar (f
, 0, 1);
691 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
692 f
->output_data
.x
->saved_menu_event
);
693 popup_activated_flag
= 1;
695 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
699 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
700 pending_menu_activation
= 1;
703 /* Ignore this if we get it a second time. */
704 f
->output_data
.x
->saved_menu_event
->type
= 0;
707 /* This callback is invoked when the user selects a menubar cascade
708 pushbutton, but before the pulldown menu is posted. */
712 popup_activate_callback (widget
, id
, client_data
)
715 XtPointer client_data
;
717 popup_activated_flag
= 1;
719 x_activate_timeout_atimer ();
724 /* This callback is invoked when a dialog or menu is finished being
725 used and has been unposted. */
729 popup_deactivate_callback (widget
, client_data
)
731 gpointer client_data
;
733 popup_activated_flag
= 0;
737 popup_deactivate_callback (widget
, id
, client_data
)
740 XtPointer client_data
;
742 popup_activated_flag
= 0;
747 /* Function that finds the frame for WIDGET and shows the HELP text
749 F is the frame if known, or NULL if not known. */
751 show_help_event (f
, widget
, help
)
753 xt_or_gtk_widget widget
;
760 XSETFRAME (frame
, f
);
761 kbd_buffer_store_help_event (frame
, help
);
765 #if 0 /* This code doesn't do anything useful. ++kfs */
766 /* WIDGET is the popup menu. It's parent is the frame's
767 widget. See which frame that is. */
768 xt_or_gtk_widget frame_widget
= XtParent (widget
);
771 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
775 && (f
= XFRAME (frame
),
776 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
780 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
784 /* Callback called when menu items are highlighted/unhighlighted
785 while moving the mouse over them. WIDGET is the menu bar or menu
786 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
787 the data structure for the menu item, or null in case of
792 menu_highlight_callback (widget
, call_data
)
796 xg_menu_item_cb_data
*cb_data
;
799 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
801 if (! cb_data
) return;
803 help
= call_data
? cb_data
->help
: Qnil
;
805 /* If popup_activated_flag is greater than 1 we are in a popup menu.
806 Don't show help for them, they won't appear before the
807 popup is popped down. */
808 if (popup_activated_flag
<= 1)
809 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
813 menu_highlight_callback (widget
, id
, call_data
)
821 widget_value
*wv
= (widget_value
*) call_data
;
823 help
= wv
? wv
->help
: Qnil
;
825 /* Determine the frame for the help event. */
826 f
= menubar_id_to_frame (id
);
828 show_help_event (f
, widget
, help
);
833 /* Gtk calls callbacks just because we tell it what item should be
834 selected in a radio group. If this variable is set to a non-zero
835 value, we are creating menus and don't want callbacks right now.
837 static int xg_crazy_callback_abort
;
839 /* This callback is called from the menu bar pulldown menu
840 when the user makes a selection.
841 Figure out what the user chose
842 and put the appropriate events into the keyboard buffer. */
844 menubar_selection_callback (widget
, client_data
)
846 gpointer client_data
;
848 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
850 if (xg_crazy_callback_abort
)
853 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
856 /* For a group of radio buttons, GTK calls the selection callback first
857 for the item that was active before the selection and then for the one that
858 is active after the selection. For C-h k this means we get the help on
859 the deselected item and then the selected item is executed. Prevent that
860 by ignoring the non-active item. */
861 if (GTK_IS_RADIO_MENU_ITEM (widget
)
862 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
865 /* When a menu is popped down, X generates a focus event (i.e. focus
866 goes back to the frame below the menu). Since GTK buffers events,
867 we force it out here before the menu selection event. Otherwise
868 sit-for will exit at once if the focus event follows the menu selection
872 while (gtk_events_pending ())
873 gtk_main_iteration ();
876 find_and_call_menu_selection (cb_data
->cl_data
->f
,
877 cb_data
->cl_data
->menu_bar_items_used
,
878 cb_data
->cl_data
->menu_bar_vector
,
882 #else /* not USE_GTK */
884 /* This callback is called from the menu bar pulldown menu
885 when the user makes a selection.
886 Figure out what the user chose
887 and put the appropriate events into the keyboard buffer. */
889 menubar_selection_callback (widget
, id
, client_data
)
892 XtPointer client_data
;
896 f
= menubar_id_to_frame (id
);
899 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
900 f
->menu_bar_vector
, client_data
);
902 #endif /* not USE_GTK */
904 /* Recompute all the widgets of frame F, when the menu bar has been
905 changed. Value is non-zero if widgets were updated. */
908 update_frame_menubar (f
)
912 return xg_update_frame_menubar (f
);
920 x
= f
->output_data
.x
;
922 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
926 /* Save the size of the frame because the pane widget doesn't accept
927 to resize itself. So force it. */
928 columns
= FRAME_COLS (f
);
929 rows
= FRAME_LINES (f
);
931 /* Do the voodoo which means "I'm changing lots of things, don't try
932 to refigure sizes until I'm done." */
933 lw_refigure_widget (x
->column_widget
, False
);
935 /* The order in which children are managed is the top to bottom
936 order in which they are displayed in the paned window. First,
937 remove the text-area widget. */
938 XtUnmanageChild (x
->edit_widget
);
940 /* Remove the menubar that is there now, and put up the menubar that
942 XtManageChild (x
->menubar_widget
);
943 XtMapWidget (x
->menubar_widget
);
944 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
946 /* Re-manage the text-area widget, and then thrash the sizes. */
947 XtManageChild (x
->edit_widget
);
948 lw_refigure_widget (x
->column_widget
, True
);
950 /* Force the pane widget to resize itself with the right values. */
951 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
957 /* Set the contents of the menubar widgets of frame F.
958 The argument FIRST_TIME is currently ignored;
959 it is set the first time this is called, from initialize_frame_menubar. */
962 set_frame_menubar (f
, first_time
, deep_p
)
967 xt_or_gtk_widget menubar_widget
;
972 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
974 int *submenu_start
, *submenu_end
;
975 int *submenu_top_level_items
, *submenu_n_panes
;
980 menubar_widget
= f
->output_data
.x
->menubar_widget
;
982 XSETFRAME (Vmenu_updating_frame
, f
);
985 if (f
->output_data
.x
->id
== 0)
986 f
->output_data
.x
->id
= next_menubar_widget_id
++;
987 id
= f
->output_data
.x
->id
;
990 if (! menubar_widget
)
992 else if (pending_menu_activation
&& !deep_p
)
994 /* Make the first call for any given frame always go deep. */
995 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
998 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
999 f
->output_data
.x
->saved_menu_event
->type
= 0;
1003 /* If we have detached menus, we must update deep so detached menus
1004 also gets updated. */
1005 deep_p
= deep_p
|| xg_have_tear_offs ();
1010 /* Make a widget-value tree representing the entire menu trees. */
1012 struct buffer
*prev
= current_buffer
;
1014 int specpdl_count
= SPECPDL_INDEX ();
1015 int previous_menu_items_used
= f
->menu_bar_items_used
;
1016 Lisp_Object
*previous_items
1017 = (Lisp_Object
*) alloca (previous_menu_items_used
1018 * sizeof (Lisp_Object
));
1020 /* If we are making a new widget, its contents are empty,
1021 do always reinitialize them. */
1022 if (! menubar_widget
)
1023 previous_menu_items_used
= 0;
1025 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1026 specbind (Qinhibit_quit
, Qt
);
1027 /* Don't let the debugger step into this code
1028 because it is not reentrant. */
1029 specbind (Qdebug_on_next_call
, Qnil
);
1031 record_unwind_save_match_data ();
1032 if (NILP (Voverriding_local_map_menu_flag
))
1034 specbind (Qoverriding_terminal_local_map
, Qnil
);
1035 specbind (Qoverriding_local_map
, Qnil
);
1038 set_buffer_internal_1 (XBUFFER (buffer
));
1040 /* Run the Lucid hook. */
1041 safe_run_hooks (Qactivate_menubar_hook
);
1043 /* If it has changed current-menubar from previous value,
1044 really recompute the menubar from the value. */
1045 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1046 call0 (Qrecompute_lucid_menubar
);
1047 safe_run_hooks (Qmenu_bar_update_hook
);
1048 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1050 items
= FRAME_MENU_BAR_ITEMS (f
);
1052 /* Save the frame's previous menu bar contents data. */
1053 if (previous_menu_items_used
)
1054 bcopy (XVECTOR (f
->menu_bar_vector
)->contents
, previous_items
,
1055 previous_menu_items_used
* sizeof (Lisp_Object
));
1057 /* Fill in menu_items with the current menu bar contents.
1058 This can evaluate Lisp code. */
1061 menu_items
= f
->menu_bar_vector
;
1062 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1063 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1064 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1065 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1066 submenu_top_level_items
1067 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1069 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1071 Lisp_Object key
, string
, maps
;
1075 key
= XVECTOR (items
)->contents
[i
];
1076 string
= XVECTOR (items
)->contents
[i
+ 1];
1077 maps
= XVECTOR (items
)->contents
[i
+ 2];
1081 submenu_start
[i
] = menu_items_used
;
1083 menu_items_n_panes
= 0;
1084 submenu_top_level_items
[i
]
1085 = parse_single_submenu (key
, string
, maps
);
1086 submenu_n_panes
[i
] = menu_items_n_panes
;
1088 submenu_end
[i
] = menu_items_used
;
1091 finish_menu_items ();
1093 /* Convert menu_items into widget_value trees
1094 to display the menu. This cannot evaluate Lisp code. */
1096 wv
= xmalloc_widget_value ();
1097 wv
->name
= "menubar";
1100 wv
->button_type
= BUTTON_TYPE_NONE
;
1104 for (i
= 0; i
< last_i
; i
+= 4)
1106 menu_items_n_panes
= submenu_n_panes
[i
];
1107 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1108 submenu_top_level_items
[i
]);
1112 first_wv
->contents
= wv
;
1113 /* Don't set wv->name here; GC during the loop might relocate it. */
1115 wv
->button_type
= BUTTON_TYPE_NONE
;
1119 set_buffer_internal_1 (prev
);
1121 /* If there has been no change in the Lisp-level contents
1122 of the menu bar, skip redisplaying it. Just exit. */
1124 /* Compare the new menu items with the ones computed last time. */
1125 for (i
= 0; i
< previous_menu_items_used
; i
++)
1126 if (menu_items_used
== i
1127 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1129 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1131 /* The menu items have not changed. Don't bother updating
1132 the menus in any form, since it would be a no-op. */
1133 free_menubar_widget_value_tree (first_wv
);
1134 discard_menu_items ();
1135 unbind_to (specpdl_count
, Qnil
);
1139 /* The menu items are different, so store them in the frame. */
1140 f
->menu_bar_vector
= menu_items
;
1141 f
->menu_bar_items_used
= menu_items_used
;
1143 /* This undoes save_menu_items. */
1144 unbind_to (specpdl_count
, Qnil
);
1146 /* Now GC cannot happen during the lifetime of the widget_value,
1147 so it's safe to store data from a Lisp_String. */
1148 wv
= first_wv
->contents
;
1149 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1152 string
= XVECTOR (items
)->contents
[i
+ 1];
1155 wv
->name
= (char *) SDATA (string
);
1156 update_submenu_strings (wv
->contents
);
1163 /* Make a widget-value tree containing
1164 just the top level menu bar strings. */
1166 wv
= xmalloc_widget_value ();
1167 wv
->name
= "menubar";
1170 wv
->button_type
= BUTTON_TYPE_NONE
;
1174 items
= FRAME_MENU_BAR_ITEMS (f
);
1175 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1179 string
= XVECTOR (items
)->contents
[i
+ 1];
1183 wv
= xmalloc_widget_value ();
1184 wv
->name
= (char *) SDATA (string
);
1187 wv
->button_type
= BUTTON_TYPE_NONE
;
1189 /* This prevents lwlib from assuming this
1190 menu item is really supposed to be empty. */
1191 /* The EMACS_INT cast avoids a warning.
1192 This value just has to be different from small integers. */
1193 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1198 first_wv
->contents
= wv
;
1202 /* Forget what we thought we knew about what is in the
1203 detailed contents of the menu bar menus.
1204 Changing the top level always destroys the contents. */
1205 f
->menu_bar_items_used
= 0;
1208 /* Create or update the menu bar widget. */
1213 xg_crazy_callback_abort
= 1;
1216 /* The fourth arg is DEEP_P, which says to consider the entire
1217 menu trees we supply, rather than just the menu bar item names. */
1218 xg_modify_menubar_widgets (menubar_widget
,
1222 G_CALLBACK (menubar_selection_callback
),
1223 G_CALLBACK (popup_deactivate_callback
),
1224 G_CALLBACK (menu_highlight_callback
));
1228 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1231 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1232 G_CALLBACK (menubar_selection_callback
),
1233 G_CALLBACK (popup_deactivate_callback
),
1234 G_CALLBACK (menu_highlight_callback
));
1236 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1240 #else /* not USE_GTK */
1243 /* Disable resizing (done for Motif!) */
1244 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1246 /* The third arg is DEEP_P, which says to consider the entire
1247 menu trees we supply, rather than just the menu bar item names. */
1248 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1250 /* Re-enable the edit widget to resize. */
1251 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1255 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1256 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1258 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1259 f
->output_data
.x
->column_widget
,
1261 popup_activate_callback
,
1262 menubar_selection_callback
,
1263 popup_deactivate_callback
,
1264 menu_highlight_callback
);
1265 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1267 /* Make menu pop down on C-g. */
1268 XtOverrideTranslations (menubar_widget
, override
);
1273 = (f
->output_data
.x
->menubar_widget
1274 ? (f
->output_data
.x
->menubar_widget
->core
.height
1275 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1278 #if 1 /* Experimentally, we now get the right results
1279 for -geometry -0-0 without this. 24 Aug 96, rms.
1280 Maybe so, but the menu bar size is missing the pixels so the
1281 WM size hints are off by theses pixel. Jan D, oct 2009. */
1283 if (FRAME_EXTERNAL_MENU_BAR (f
))
1286 XtVaGetValues (f
->output_data
.x
->column_widget
,
1287 XtNinternalBorderWidth
, &ibw
, NULL
);
1288 menubar_size
+= ibw
;
1290 #endif /* USE_LUCID */
1293 f
->output_data
.x
->menubar_height
= menubar_size
;
1295 #endif /* not USE_GTK */
1297 free_menubar_widget_value_tree (first_wv
);
1298 update_frame_menubar (f
);
1301 xg_crazy_callback_abort
= 0;
1307 /* Called from Fx_create_frame to create the initial menubar of a frame
1308 before it is mapped, so that the window is mapped with the menubar already
1309 there instead of us tacking it on later and thrashing the window after it
1313 initialize_frame_menubar (f
)
1316 /* This function is called before the first chance to redisplay
1317 the frame. It has to be, so the frame will have the right size. */
1318 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1319 set_frame_menubar (f
, 1, 1);
1323 /* Get rid of the menu bar of frame F, and free its storage.
1324 This is used when deleting a frame, and when turning off the menu bar.
1325 For GTK this function is in gtkutil.c. */
1329 free_frame_menubar (f
)
1332 Widget menubar_widget
;
1334 if (! FRAME_X_P (f
))
1337 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1339 f
->output_data
.x
->menubar_height
= 0;
1344 /* Removing the menu bar magically changes the shell widget's x
1345 and y position of (0, 0) which, when the menu bar is turned
1346 on again, leads to pull-down menuss appearing in strange
1347 positions near the upper-left corner of the display. This
1348 happens only with some window managers like twm and ctwm,
1349 but not with other like Motif's mwm or kwm, because the
1350 latter generate ConfigureNotify events when the menu bar
1351 is switched off, which fixes the shell position. */
1352 Position x0
, y0
, x1
, y1
;
1358 if (f
->output_data
.x
->widget
)
1359 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1362 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1363 f
->output_data
.x
->menubar_widget
= NULL
;
1366 if (f
->output_data
.x
->widget
)
1368 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1369 if (x1
== 0 && y1
== 0)
1370 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1377 #endif /* not USE_GTK */
1379 #endif /* USE_X_TOOLKIT || USE_GTK */
1381 /* xmenu_show actually displays a menu using the panes and items in menu_items
1382 and returns the value selected from it.
1383 There are two versions of xmenu_show, one for Xt and one for Xlib.
1384 Both assume input is blocked by the caller. */
1386 /* F is the frame the menu is for.
1387 X and Y are the frame-relative specified position,
1388 relative to the inside upper left corner of the frame F.
1389 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1390 KEYMAPS is 1 if this menu was specified with keymaps;
1391 in that case, we return a list containing the chosen item's value
1392 and perhaps also the pane's prefix.
1393 TITLE is the specified menu title.
1394 ERROR is a place to store an error message string in case of failure.
1395 (We return nil on failure, but the value doesn't actually matter.) */
1397 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1399 /* The item selected in the popup menu. */
1400 static Lisp_Object
*volatile menu_item_selection
;
1404 /* Used when position a popup menu. See menu_position_func and
1405 create_and_show_popup_menu below. */
1406 struct next_popup_x_y
1413 /* The menu position function to use if we are not putting a popup
1414 menu where the pointer is.
1415 MENU is the menu to pop up.
1416 X and Y shall on exit contain x/y where the menu shall pop up.
1417 PUSH_IN is not documented in the GTK manual.
1418 USER_DATA is any data passed in when calling gtk_menu_popup.
1419 Here it points to a struct next_popup_x_y where the coordinates
1420 to store in *X and *Y are as well as the frame for the popup.
1422 Here only X and Y are used. */
1424 menu_position_func (menu
, x
, y
, push_in
, user_data
)
1431 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1433 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1434 int disp_width
= x_display_pixel_width (dpyinfo
);
1435 int disp_height
= x_display_pixel_height (dpyinfo
);
1440 /* Check if there is room for the menu. If not, adjust x/y so that
1441 the menu is fully visible. */
1442 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1443 if (data
->x
+ req
.width
> disp_width
)
1444 *x
-= data
->x
+ req
.width
- disp_width
;
1445 if (data
->y
+ req
.height
> disp_height
)
1446 *y
-= data
->y
+ req
.height
- disp_height
;
1450 popup_selection_callback (widget
, client_data
)
1452 gpointer client_data
;
1454 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1456 if (xg_crazy_callback_abort
) return;
1457 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1464 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1466 popup_activated_flag
= 0;
1468 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1473 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1475 menu_item_selection will be set to the selection. */
1477 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1479 widget_value
*first_wv
;
1483 EMACS_UINT timestamp
;
1487 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1488 struct next_popup_x_y popup_x_y
;
1489 int specpdl_count
= SPECPDL_INDEX ();
1491 if (! FRAME_X_P (f
))
1494 xg_crazy_callback_abort
= 1;
1495 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1496 G_CALLBACK (popup_selection_callback
),
1497 G_CALLBACK (popup_deactivate_callback
),
1498 G_CALLBACK (menu_highlight_callback
));
1499 xg_crazy_callback_abort
= 0;
1503 /* Not invoked by a click. pop up at x/y. */
1504 pos_func
= menu_position_func
;
1506 /* Adjust coordinates to be root-window-relative. */
1507 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1508 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1514 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1518 for (i
= 0; i
< 5; i
++)
1519 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1523 /* Display the menu. */
1524 gtk_widget_show_all (menu
);
1526 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1527 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1529 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1531 if (GTK_WIDGET_MAPPED (menu
))
1533 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1534 two. show_help_echo uses this to detect popup menus. */
1535 popup_activated_flag
= 1;
1536 /* Process events that apply to the menu. */
1537 popup_widget_loop (1, menu
);
1540 unbind_to (specpdl_count
, Qnil
);
1542 /* Must reset this manually because the button release event is not passed
1543 to Emacs event loop. */
1544 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1547 #else /* not USE_GTK */
1549 /* We need a unique id for each widget handled by the Lucid Widget
1552 For the main windows, and popup menus, we use this counter,
1553 which we increment each time after use. This starts from 1<<16.
1555 For menu bars, we use numbers starting at 0, counted in
1556 next_menubar_widget_id. */
1557 LWLIB_ID widget_id_tick
;
1560 popup_selection_callback (widget
, id
, client_data
)
1563 XtPointer client_data
;
1565 menu_item_selection
= (Lisp_Object
*) client_data
;
1568 /* ARG is the LWLIB ID of the dialog box, represented
1569 as a Lisp object as (HIGHPART . LOWPART). */
1575 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1576 | XINT (XCDR (arg
)));
1579 lw_destroy_all_widgets (id
);
1581 popup_activated_flag
= 0;
1586 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1588 menu_item_selection will be set to the selection. */
1590 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1592 widget_value
*first_wv
;
1596 EMACS_UINT timestamp
;
1601 XButtonPressedEvent dummy
;
1605 if (! FRAME_X_P (f
))
1608 menu_id
= widget_id_tick
++;
1609 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1610 f
->output_data
.x
->widget
, 1, 0,
1611 popup_selection_callback
,
1612 popup_deactivate_callback
,
1613 menu_highlight_callback
);
1615 dummy
.type
= ButtonPress
;
1617 dummy
.send_event
= 0;
1618 dummy
.display
= FRAME_X_DISPLAY (f
);
1619 dummy
.time
= CurrentTime
;
1620 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1621 dummy
.window
= dummy
.root
;
1622 dummy
.subwindow
= dummy
.root
;
1626 /* Adjust coordinates to be root-window-relative. */
1627 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1628 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1635 for (i
= 0; i
< 5; i
++)
1636 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1639 /* Don't allow any geometry request from the user. */
1640 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1641 XtSetValues (menu
, av
, ac
);
1643 /* Display the menu. */
1644 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1645 popup_activated_flag
= 1;
1646 x_activate_timeout_atimer ();
1649 int fact
= 4 * sizeof (LWLIB_ID
);
1650 int specpdl_count
= SPECPDL_INDEX ();
1651 record_unwind_protect (pop_down_menu
,
1652 Fcons (make_number (menu_id
>> (fact
)),
1653 make_number (menu_id
& ~(-1 << (fact
)))));
1655 /* Process events that apply to the menu. */
1656 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1658 unbind_to (specpdl_count
, Qnil
);
1662 #endif /* not USE_GTK */
1665 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1666 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1669 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1670 widget_value
**submenu_stack
1671 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1672 Lisp_Object
*subprefix_stack
1673 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1674 int submenu_depth
= 0;
1678 if (! FRAME_X_P (f
))
1683 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1685 *error
= "Empty menu";
1689 /* Create a tree of widget_value objects
1690 representing the panes and their items. */
1691 wv
= xmalloc_widget_value ();
1695 wv
->button_type
= BUTTON_TYPE_NONE
;
1700 /* Loop over all panes and items, filling in the tree. */
1702 while (i
< menu_items_used
)
1704 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1706 submenu_stack
[submenu_depth
++] = save_wv
;
1712 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1715 save_wv
= submenu_stack
[--submenu_depth
];
1719 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1720 && submenu_depth
!= 0)
1721 i
+= MENU_ITEMS_PANE_LENGTH
;
1722 /* Ignore a nil in the item list.
1723 It's meaningful only for dialog boxes. */
1724 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1726 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1728 /* Create a new pane. */
1729 Lisp_Object pane_name
, prefix
;
1732 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1733 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1735 #ifndef HAVE_MULTILINGUAL_MENU
1736 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1738 pane_name
= ENCODE_MENU_STRING (pane_name
);
1739 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1742 pane_string
= (NILP (pane_name
)
1743 ? "" : (char *) SDATA (pane_name
));
1744 /* If there is just one top-level pane, put all its items directly
1745 under the top-level menu. */
1746 if (menu_items_n_panes
== 1)
1749 /* If the pane has a meaningful name,
1750 make the pane a top-level menu item
1751 with its items as a submenu beneath it. */
1752 if (!keymaps
&& strcmp (pane_string
, ""))
1754 wv
= xmalloc_widget_value ();
1758 first_wv
->contents
= wv
;
1759 wv
->name
= pane_string
;
1760 if (keymaps
&& !NILP (prefix
))
1764 wv
->button_type
= BUTTON_TYPE_NONE
;
1769 else if (first_pane
)
1775 i
+= MENU_ITEMS_PANE_LENGTH
;
1779 /* Create a new item within current pane. */
1780 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1781 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1782 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1783 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1784 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1785 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1786 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1787 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1789 #ifndef HAVE_MULTILINGUAL_MENU
1790 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1792 item_name
= ENCODE_MENU_STRING (item_name
);
1793 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1796 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1798 descrip
= ENCODE_MENU_STRING (descrip
);
1799 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1801 #endif /* not HAVE_MULTILINGUAL_MENU */
1803 wv
= xmalloc_widget_value ();
1807 save_wv
->contents
= wv
;
1808 wv
->name
= (char *) SDATA (item_name
);
1809 if (!NILP (descrip
))
1810 wv
->key
= (char *) SDATA (descrip
);
1812 /* If this item has a null value,
1813 make the call_data null so that it won't display a box
1814 when the mouse is on it. */
1816 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1817 wv
->enabled
= !NILP (enable
);
1820 wv
->button_type
= BUTTON_TYPE_NONE
;
1821 else if (EQ (type
, QCtoggle
))
1822 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1823 else if (EQ (type
, QCradio
))
1824 wv
->button_type
= BUTTON_TYPE_RADIO
;
1828 wv
->selected
= !NILP (selected
);
1830 if (! STRINGP (help
))
1837 i
+= MENU_ITEMS_ITEM_LENGTH
;
1841 /* Deal with the title, if it is non-nil. */
1844 widget_value
*wv_title
= xmalloc_widget_value ();
1845 widget_value
*wv_sep1
= xmalloc_widget_value ();
1846 widget_value
*wv_sep2
= xmalloc_widget_value ();
1848 wv_sep2
->name
= "--";
1849 wv_sep2
->next
= first_wv
->contents
;
1850 wv_sep2
->help
= Qnil
;
1852 wv_sep1
->name
= "--";
1853 wv_sep1
->next
= wv_sep2
;
1854 wv_sep1
->help
= Qnil
;
1856 #ifndef HAVE_MULTILINGUAL_MENU
1857 if (STRING_MULTIBYTE (title
))
1858 title
= ENCODE_MENU_STRING (title
);
1861 wv_title
->name
= (char *) SDATA (title
);
1862 wv_title
->enabled
= TRUE
;
1863 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1864 wv_title
->help
= Qnil
;
1865 wv_title
->next
= wv_sep1
;
1866 first_wv
->contents
= wv_title
;
1869 /* No selection has been chosen yet. */
1870 menu_item_selection
= 0;
1872 /* Actually create and show the menu until popped down. */
1873 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1875 /* Free the widget_value objects we used to specify the contents. */
1876 free_menubar_widget_value_tree (first_wv
);
1878 /* Find the selected item, and its pane, to return
1879 the proper value. */
1880 if (menu_item_selection
!= 0)
1882 Lisp_Object prefix
, entry
;
1884 prefix
= entry
= Qnil
;
1886 while (i
< menu_items_used
)
1888 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1890 subprefix_stack
[submenu_depth
++] = prefix
;
1894 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1896 prefix
= subprefix_stack
[--submenu_depth
];
1899 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1902 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1903 i
+= MENU_ITEMS_PANE_LENGTH
;
1905 /* Ignore a nil in the item list.
1906 It's meaningful only for dialog boxes. */
1907 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1912 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1913 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1919 entry
= Fcons (entry
, Qnil
);
1921 entry
= Fcons (prefix
, entry
);
1922 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1923 if (!NILP (subprefix_stack
[j
]))
1924 entry
= Fcons (subprefix_stack
[j
], entry
);
1928 i
+= MENU_ITEMS_ITEM_LENGTH
;
1932 else if (!for_click
)
1933 /* Make "Cancel" equivalent to C-g. */
1934 Fsignal (Qquit
, Qnil
);
1941 dialog_selection_callback (widget
, client_data
)
1943 gpointer client_data
;
1945 /* The EMACS_INT cast avoids a warning. There's no problem
1946 as long as pointers have enough bits to hold small integers. */
1947 if ((int) (EMACS_INT
) client_data
!= -1)
1948 menu_item_selection
= (Lisp_Object
*) client_data
;
1950 popup_activated_flag
= 0;
1953 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1955 menu_item_selection will be set to the selection. */
1957 create_and_show_dialog (f
, first_wv
)
1959 widget_value
*first_wv
;
1963 if (! FRAME_X_P (f
))
1966 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1967 G_CALLBACK (dialog_selection_callback
),
1968 G_CALLBACK (popup_deactivate_callback
),
1973 int specpdl_count
= SPECPDL_INDEX ();
1974 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1976 /* Display the menu. */
1977 gtk_widget_show_all (menu
);
1979 /* Process events that apply to the menu. */
1980 popup_widget_loop (1, menu
);
1982 unbind_to (specpdl_count
, Qnil
);
1986 #else /* not USE_GTK */
1988 dialog_selection_callback (widget
, id
, client_data
)
1991 XtPointer client_data
;
1993 /* The EMACS_INT cast avoids a warning. There's no problem
1994 as long as pointers have enough bits to hold small integers. */
1995 if ((int) (EMACS_INT
) client_data
!= -1)
1996 menu_item_selection
= (Lisp_Object
*) client_data
;
1999 lw_destroy_all_widgets (id
);
2001 popup_activated_flag
= 0;
2005 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2007 menu_item_selection will be set to the selection. */
2009 create_and_show_dialog (f
, first_wv
)
2011 widget_value
*first_wv
;
2018 dialog_id
= widget_id_tick
++;
2019 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2020 f
->output_data
.x
->widget
, 1, 0,
2021 dialog_selection_callback
, 0, 0);
2022 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2024 /* Display the dialog box. */
2025 lw_pop_up_all_widgets (dialog_id
);
2026 popup_activated_flag
= 1;
2027 x_activate_timeout_atimer ();
2029 /* Process events that apply to the dialog box.
2030 Also handle timers. */
2032 int count
= SPECPDL_INDEX ();
2033 int fact
= 4 * sizeof (LWLIB_ID
);
2035 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2036 record_unwind_protect (pop_down_menu
,
2037 Fcons (make_number (dialog_id
>> (fact
)),
2038 make_number (dialog_id
& ~(-1 << (fact
)))));
2040 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2043 unbind_to (count
, Qnil
);
2047 #endif /* not USE_GTK */
2049 static char * button_names
[] = {
2050 "button1", "button2", "button3", "button4", "button5",
2051 "button6", "button7", "button8", "button9", "button10" };
2054 xdialog_show (f
, keymaps
, title
, header
, error_name
)
2057 Lisp_Object title
, header
;
2060 int i
, nb_buttons
=0;
2061 char dialog_name
[6];
2063 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2065 /* Number of elements seen so far, before boundary. */
2067 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2068 int boundary_seen
= 0;
2070 if (! FRAME_X_P (f
))
2075 if (menu_items_n_panes
> 1)
2077 *error_name
= "Multiple panes in dialog box";
2081 /* Create a tree of widget_value objects
2082 representing the text label and buttons. */
2084 Lisp_Object pane_name
, prefix
;
2086 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2087 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2088 pane_string
= (NILP (pane_name
)
2089 ? "" : (char *) SDATA (pane_name
));
2090 prev_wv
= xmalloc_widget_value ();
2091 prev_wv
->value
= pane_string
;
2092 if (keymaps
&& !NILP (prefix
))
2094 prev_wv
->enabled
= 1;
2095 prev_wv
->name
= "message";
2096 prev_wv
->help
= Qnil
;
2099 /* Loop over all panes and items, filling in the tree. */
2100 i
= MENU_ITEMS_PANE_LENGTH
;
2101 while (i
< menu_items_used
)
2104 /* Create a new item within current pane. */
2105 Lisp_Object item_name
, enable
, descrip
;
2106 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2107 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2109 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2111 if (NILP (item_name
))
2113 free_menubar_widget_value_tree (first_wv
);
2114 *error_name
= "Submenu in dialog items";
2117 if (EQ (item_name
, Qquote
))
2119 /* This is the boundary between left-side elts
2120 and right-side elts. Stop incrementing right_count. */
2125 if (nb_buttons
>= 9)
2127 free_menubar_widget_value_tree (first_wv
);
2128 *error_name
= "Too many dialog items";
2132 wv
= xmalloc_widget_value ();
2134 wv
->name
= (char *) button_names
[nb_buttons
];
2135 if (!NILP (descrip
))
2136 wv
->key
= (char *) SDATA (descrip
);
2137 wv
->value
= (char *) SDATA (item_name
);
2138 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2139 wv
->enabled
= !NILP (enable
);
2143 if (! boundary_seen
)
2147 i
+= MENU_ITEMS_ITEM_LENGTH
;
2150 /* If the boundary was not specified,
2151 by default put half on the left and half on the right. */
2152 if (! boundary_seen
)
2153 left_count
= nb_buttons
- nb_buttons
/ 2;
2155 wv
= xmalloc_widget_value ();
2156 wv
->name
= dialog_name
;
2159 /* Frame title: 'Q' = Question, 'I' = Information.
2160 Can also have 'E' = Error if, one day, we want
2161 a popup for errors. */
2163 dialog_name
[0] = 'Q';
2165 dialog_name
[0] = 'I';
2167 /* Dialog boxes use a really stupid name encoding
2168 which specifies how many buttons to use
2169 and how many buttons are on the right. */
2170 dialog_name
[1] = '0' + nb_buttons
;
2171 dialog_name
[2] = 'B';
2172 dialog_name
[3] = 'R';
2173 /* Number of buttons to put on the right. */
2174 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2176 wv
->contents
= first_wv
;
2180 /* No selection has been chosen yet. */
2181 menu_item_selection
= 0;
2183 /* Actually create and show the dialog. */
2184 create_and_show_dialog (f
, first_wv
);
2186 /* Free the widget_value objects we used to specify the contents. */
2187 free_menubar_widget_value_tree (first_wv
);
2189 /* Find the selected item, and its pane, to return
2190 the proper value. */
2191 if (menu_item_selection
!= 0)
2197 while (i
< menu_items_used
)
2201 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2204 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2205 i
+= MENU_ITEMS_PANE_LENGTH
;
2207 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2209 /* This is the boundary between left-side elts and
2216 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2217 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2221 entry
= Fcons (entry
, Qnil
);
2223 entry
= Fcons (prefix
, entry
);
2227 i
+= MENU_ITEMS_ITEM_LENGTH
;
2232 /* Make "Cancel" equivalent to C-g. */
2233 Fsignal (Qquit
, Qnil
);
2238 #else /* not USE_X_TOOLKIT && not USE_GTK */
2240 /* The frame of the last activated non-toolkit menu bar.
2241 Used to generate menu help events. */
2243 static struct frame
*menu_help_frame
;
2246 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2248 PANE is the pane number, and ITEM is the menu item number in
2249 the menu (currently not used).
2251 This cannot be done with generating a HELP_EVENT because
2252 XMenuActivate contains a loop that doesn't let Emacs process
2256 menu_help_callback (help_string
, pane
, item
)
2260 extern Lisp_Object Qmenu_item
;
2261 Lisp_Object
*first_item
;
2262 Lisp_Object pane_name
;
2263 Lisp_Object menu_object
;
2265 first_item
= XVECTOR (menu_items
)->contents
;
2266 if (EQ (first_item
[0], Qt
))
2267 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2268 else if (EQ (first_item
[0], Qquote
))
2269 /* This shouldn't happen, see xmenu_show. */
2270 pane_name
= empty_unibyte_string
;
2272 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2274 /* (menu-item MENU-NAME PANE-NUMBER) */
2275 menu_object
= Fcons (Qmenu_item
,
2277 Fcons (make_number (pane
), Qnil
)));
2278 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2279 Qnil
, menu_object
, make_number (item
), 1);
2286 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2287 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2289 FRAME_PTR f
= p1
->pointer
;
2290 XMenu
*menu
= p2
->pointer
;
2294 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2295 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2297 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2299 #ifdef HAVE_X_WINDOWS
2300 /* Assume the mouse has moved out of the X window.
2301 If it has actually moved in, we will get an EnterNotify. */
2302 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2304 /* State that no mouse buttons are now held.
2305 (The oldXMenu code doesn't track this info for us.)
2306 That is not necessarily true, but the fiction leads to reasonable
2307 results, and it is a pain to ask which are actually held now. */
2308 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2310 #endif /* HAVE_X_WINDOWS */
2319 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
2326 EMACS_UINT timestamp
;
2330 int pane
, selidx
, lpane
, status
;
2331 Lisp_Object entry
, pane_prefix
;
2333 int ulx
, uly
, width
, height
;
2334 int dispwidth
, dispheight
;
2335 int i
, j
, lines
, maxlines
;
2338 unsigned int dummy_uint
;
2339 int specpdl_count
= SPECPDL_INDEX ();
2341 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2345 if (menu_items_n_panes
== 0)
2348 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2350 *error
= "Empty menu";
2354 /* Figure out which root window F is on. */
2355 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2356 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2357 &dummy_uint
, &dummy_uint
);
2359 /* Make the menu on that window. */
2360 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2363 *error
= "Can't create menu";
2367 /* Don't GC while we prepare and show the menu,
2368 because we give the oldxmenu library pointers to the
2369 contents of strings. */
2370 inhibit_garbage_collection ();
2372 #ifdef HAVE_X_WINDOWS
2373 /* Adjust coordinates to relative to the outer (window manager) window. */
2374 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2375 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2376 #endif /* HAVE_X_WINDOWS */
2378 /* Adjust coordinates to be root-window-relative. */
2382 /* Create all the necessary panes and their items. */
2383 maxlines
= lines
= i
= 0;
2384 while (i
< menu_items_used
)
2386 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2388 /* Create a new pane. */
2389 Lisp_Object pane_name
, prefix
;
2392 maxlines
= max (maxlines
, lines
);
2394 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2395 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2396 pane_string
= (NILP (pane_name
)
2397 ? "" : (char *) SDATA (pane_name
));
2398 if (keymaps
&& !NILP (prefix
))
2401 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2402 if (lpane
== XM_FAILURE
)
2404 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2405 *error
= "Can't create pane";
2408 i
+= MENU_ITEMS_PANE_LENGTH
;
2410 /* Find the width of the widest item in this pane. */
2413 while (j
< menu_items_used
)
2416 item
= XVECTOR (menu_items
)->contents
[j
];
2424 width
= SBYTES (item
);
2425 if (width
> maxwidth
)
2428 j
+= MENU_ITEMS_ITEM_LENGTH
;
2431 /* Ignore a nil in the item list.
2432 It's meaningful only for dialog boxes. */
2433 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2437 /* Create a new item within current pane. */
2438 Lisp_Object item_name
, enable
, descrip
, help
;
2439 unsigned char *item_data
;
2442 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2443 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2445 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2446 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2447 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2449 if (!NILP (descrip
))
2451 int gap
= maxwidth
- SBYTES (item_name
);
2452 /* if alloca is fast, use that to make the space,
2453 to reduce gc needs. */
2455 = (unsigned char *) alloca (maxwidth
2456 + SBYTES (descrip
) + 1);
2457 bcopy (SDATA (item_name
), item_data
,
2458 SBYTES (item_name
));
2459 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2461 bcopy (SDATA (descrip
), item_data
+ j
,
2463 item_data
[j
+ SBYTES (descrip
)] = 0;
2466 item_data
= SDATA (item_name
);
2468 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2469 menu
, lpane
, 0, item_data
,
2470 !NILP (enable
), help_string
)
2473 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2474 *error
= "Can't add selection to menu";
2477 i
+= MENU_ITEMS_ITEM_LENGTH
;
2482 maxlines
= max (maxlines
, lines
);
2484 /* All set and ready to fly. */
2485 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2486 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2487 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2488 x
= min (x
, dispwidth
);
2489 y
= min (y
, dispheight
);
2492 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2493 &ulx
, &uly
, &width
, &height
);
2494 if (ulx
+width
> dispwidth
)
2496 x
-= (ulx
+ width
) - dispwidth
;
2497 ulx
= dispwidth
- width
;
2499 if (uly
+height
> dispheight
)
2501 y
-= (uly
+ height
) - dispheight
;
2502 uly
= dispheight
- height
;
2504 #ifndef HAVE_X_WINDOWS
2505 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2507 /* Move the menu away of the echo area, to avoid overwriting the
2508 menu with help echo messages or vice versa. */
2509 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2511 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2512 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2521 if (ulx
< 0) x
-= ulx
;
2522 if (uly
< 0) y
-= uly
;
2526 /* If position was not given by a mouse click, adjust so upper left
2527 corner of the menu as a whole ends up at given coordinates. This
2528 is what x-popup-menu says in its documentation. */
2530 y
+= 1.5*height
/(maxlines
+2);
2533 XMenuSetAEQ (menu
, TRUE
);
2534 XMenuSetFreeze (menu
, TRUE
);
2538 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2541 record_unwind_protect (pop_down_menu
,
2542 Fcons (make_save_value (f
, 0),
2543 make_save_value (menu
, 0)));
2545 /* Help display under X won't work because XMenuActivate contains
2546 a loop that doesn't give Emacs a chance to process it. */
2547 menu_help_frame
= f
;
2548 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2549 x
, y
, ButtonReleaseMask
, &datap
,
2550 menu_help_callback
);
2556 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2559 /* Find the item number SELIDX in pane number PANE. */
2561 while (i
< menu_items_used
)
2563 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2567 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2569 i
+= MENU_ITEMS_PANE_LENGTH
;
2578 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2581 entry
= Fcons (entry
, Qnil
);
2582 if (!NILP (pane_prefix
))
2583 entry
= Fcons (pane_prefix
, entry
);
2589 i
+= MENU_ITEMS_ITEM_LENGTH
;
2595 *error
= "Can't activate menu";
2600 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2601 the menu was invoked with a mouse event as POSITION). */
2603 Fsignal (Qquit
, Qnil
);
2608 unbind_to (specpdl_count
, Qnil
);
2613 #endif /* not USE_X_TOOLKIT */
2615 #endif /* HAVE_MENUS */
2617 /* Detect if a dialog or menu has been posted. */
2622 return popup_activated_flag
;
2625 /* The following is used by delayed window autoselection. */
2627 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2628 doc
: /* Return t if a menu or popup dialog is active. */)
2632 return (popup_activated ()) ? Qt
: Qnil
;
2635 #endif /* HAVE_MENUS */
2641 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2642 staticpro (&Qdebug_on_next_call
);
2644 #ifdef USE_X_TOOLKIT
2645 widget_id_tick
= (1<<16);
2646 next_menubar_widget_id
= 1;
2649 defsubr (&Smenu_or_popup_active_p
);
2651 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2652 defsubr (&Sx_menu_bar_open_internal
);
2653 Ffset (intern_c_string ("accelerate-menu"),
2654 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2658 defsubr (&Sx_popup_dialog
);
2662 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2663 (do not change this comment) */