1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2011
4 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
35 #if 0 /* Why was this included? And without syssignal.h? */
36 /* On 4.3 this loses if it comes after xterm.h. */
47 #include "termhooks.h"
49 #include "blockinput.h"
53 #include "sysselect.h"
60 /* This may include sys/types.h, and that somehow loses
61 if this is not done before the other system files. */
65 /* Load sys/types.h if not already loaded.
66 In some systems loading it twice is suicidal. */
68 #include <sys/types.h>
71 #include "dispextern.h"
74 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
75 code accepts the Emacs internal encoding. */
76 #undef HAVE_MULTILINGUAL_MENU
80 #include <X11/IntrinsicP.h>
81 #include <X11/CoreP.h>
82 #include <X11/StringDefs.h>
83 #include <X11/Shell.h>
85 #include "xsettings.h"
86 #include "../lwlib/xlwmenu.h"
88 #include <X11/Xaw3d/Paned.h>
89 #else /* !HAVE_XAW3D */
90 #include <X11/Xaw/Paned.h>
91 #endif /* HAVE_XAW3D */
92 #endif /* USE_LUCID */
94 #include "../lwlib/lwlib.h"
96 #else /* not USE_X_TOOLKIT */
98 #include "../oldXMenu/XMenu.h"
100 #endif /* not USE_X_TOOLKIT */
101 #endif /* HAVE_X_WINDOWS */
113 static Lisp_Object Qdebug_on_next_call
;
115 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
116 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
120 /* Flag which when set indicates a dialog or menu has been posted by
121 Xt on behalf of one of the widget sets. */
122 static int popup_activated_flag
;
127 static int next_menubar_widget_id
;
129 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
131 static struct frame
*
132 menubar_id_to_frame (LWLIB_ID id
)
134 Lisp_Object tail
, frame
;
137 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
143 if (!FRAME_WINDOW_P (f
))
145 if (f
->output_data
.x
->id
== id
)
153 #ifdef HAVE_X_WINDOWS
154 /* Return the mouse position in *X and *Y. The coordinates are window
155 relative for the edit window in frame F.
156 This is for Fx_popup_menu. The mouse_position_hook can not
157 be used for X, as it returns window relative coordinates
158 for the window where the mouse is in. This could be the menu bar,
159 the scroll bar or the edit window. Fx_popup_menu needs to be
160 sure it is the edit window. */
162 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
164 Window root
, dummy_window
;
172 XQueryPointer (FRAME_X_DISPLAY (f
),
173 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
175 /* The root window which contains the pointer. */
178 /* Window pointer is on, not used */
181 /* The position on that root window. */
184 /* x/y in dummy_window coordinates, not used. */
187 /* Modifier keys and pointer buttons, about which
189 (unsigned int *) &dummy
);
193 /* xmenu_show expects window coordinates, not root window
194 coordinates. Translate. */
195 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
196 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
199 #endif /* HAVE_X_WINDOWS */
203 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
204 doc
: /* Pop up a dialog box and return user's selection.
205 POSITION specifies which frame to use.
206 This is normally a mouse button event or a window or frame.
207 If POSITION is t, it means to use the frame the mouse is on.
208 The dialog box appears in the middle of the specified frame.
210 CONTENTS specifies the alternatives to display in the dialog box.
211 It is a list of the form (DIALOG ITEM1 ITEM2...).
212 Each ITEM is a cons cell (STRING . VALUE).
213 The return value is VALUE from the chosen item.
215 An ITEM may also be just a string--that makes a nonselectable item.
216 An ITEM may also be nil--that means to put all preceding items
217 on the left of the dialog box and all following items on the right.
218 \(By default, approximately half appear on each side.)
220 If HEADER is non-nil, the frame title for the box is "Information",
221 otherwise it is "Question".
223 If the user gets rid of the dialog box without making a valid choice,
224 for instance using the window manager, then this produces a quit and
225 `x-popup-dialog' does not return. */)
226 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
233 /* Decode the first argument: find the window or frame to use. */
234 if (EQ (position
, Qt
)
235 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
236 || EQ (XCAR (position
), Qtool_bar
))))
238 #if 0 /* Using the frame the mouse is on may not be right. */
239 /* Use the mouse's current position. */
240 FRAME_PTR new_f
= SELECTED_FRAME ();
241 Lisp_Object bar_window
;
242 enum scroll_bar_part part
;
246 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
249 XSETFRAME (window
, new_f
);
251 window
= selected_window
;
253 window
= selected_window
;
255 else if (CONSP (position
))
258 tem
= Fcar (position
);
260 window
= Fcar (Fcdr (position
));
263 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
264 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
267 else if (WINDOWP (position
) || FRAMEP (position
))
272 /* Decode where to put the menu. */
276 else if (WINDOWP (window
))
278 CHECK_LIVE_WINDOW (window
);
279 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
282 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
283 but I don't want to make one now. */
284 CHECK_WINDOW (window
);
286 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
287 error ("Can not put X dialog on this terminal");
289 /* Force a redisplay before showing the dialog. If a frame is created
290 just before showing the dialog, its contents may not have been fully
291 drawn, as this depends on timing of events from the X server. Redisplay
292 is not done when a dialog is shown. If redisplay could be done in the
293 X event loop (i.e. the X event loop does not run in a signal handler)
294 this would not be needed.
296 Do this before creating the widget value that points to Lisp
297 string contents, because Fredisplay may GC and relocate them. */
300 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
301 /* Display a menu with these alternatives
302 in the middle of frame F. */
304 Lisp_Object x
, y
, frame
, newpos
;
305 XSETFRAME (frame
, f
);
306 XSETINT (x
, x_pixel_width (f
) / 2);
307 XSETINT (y
, x_pixel_height (f
) / 2);
308 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
310 return Fx_popup_menu (newpos
,
311 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
316 const char *error_name
;
317 Lisp_Object selection
;
318 int specpdl_count
= SPECPDL_INDEX ();
320 /* Decode the dialog items from what was specified. */
321 title
= Fcar (contents
);
322 CHECK_STRING (title
);
323 record_unwind_protect (unuse_menu_items
, Qnil
);
325 if (NILP (Fcar (Fcdr (contents
))))
326 /* No buttons specified, add an "Ok" button so users can pop down
327 the dialog. Also, the lesstif/motif version crashes if there are
329 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
331 list_of_panes (Fcons (contents
, Qnil
));
333 /* Display them in a dialog box. */
335 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
338 unbind_to (specpdl_count
, Qnil
);
339 discard_menu_items ();
341 if (error_name
) error ("%s", error_name
);
350 #if defined USE_GTK || defined USE_MOTIF
352 /* Set menu_items_inuse so no other popup menu or dialog is created. */
355 x_menu_set_in_use (int in_use
)
357 menu_items_inuse
= in_use
? Qt
: Qnil
;
358 popup_activated_flag
= in_use
;
359 if (popup_activated_flag
)
360 x_activate_timeout_atimer ();
365 /* Wait for an X event to arrive or for a timer to expire. */
371 x_menu_wait_for_event (void *data
)
373 /* Another way to do this is to register a timer callback, that can be
374 done in GTK and Xt. But we have to do it like this when using only X
375 anyway, and with callbacks we would have three variants for timer handling
376 instead of the small ifdefs below. */
380 ! XtAppPending (Xt_app_con
)
381 #elif defined USE_GTK
382 ! gtk_events_pending ()
384 ! XPending ((Display
*) data
)
388 EMACS_TIME next_time
= timer_check (), *ntp
;
389 long secs
= EMACS_SECS (next_time
);
390 long usecs
= EMACS_USECS (next_time
);
391 SELECT_TYPE read_fds
;
392 struct x_display_info
*dpyinfo
;
396 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
398 int fd
= ConnectionNumber (dpyinfo
->display
);
399 FD_SET (fd
, &read_fds
);
401 XFlush (dpyinfo
->display
);
404 if (secs
< 0 && usecs
< 0)
409 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
415 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
419 /* Loop in Xt until the menu pulldown or dialog popup has been
420 popped down (deactivated). This is used for x-popup-menu
421 and x-popup-dialog; it is not used for the menu bar.
423 NOTE: All calls to popup_get_selection should be protected
424 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
427 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
431 while (popup_activated_flag
)
435 event
= *initial_event
;
440 if (do_timers
) x_menu_wait_for_event (0);
441 XtAppNextEvent (Xt_app_con
, &event
);
444 /* Make sure we don't consider buttons grabbed after menu goes.
445 And make sure to deactivate for any ButtonRelease,
446 even if XtDispatchEvent doesn't do that. */
447 if (event
.type
== ButtonRelease
448 && dpyinfo
->display
== event
.xbutton
.display
)
450 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
451 #ifdef USE_MOTIF /* Pretending that the event came from a
452 Btn1Down seems the only way to convince Motif to
453 activate its callbacks; setting the XmNmenuPost
454 isn't working. --marcus@sysc.pdx.edu. */
455 event
.xbutton
.button
= 1;
456 /* Motif only pops down menus when no Ctrl, Alt or Mod
457 key is pressed and the button is released. So reset key state
458 so Motif thinks this is the case. */
459 event
.xbutton
.state
= 0;
462 /* Pop down on C-g and Escape. */
463 else if (event
.type
== KeyPress
464 && dpyinfo
->display
== event
.xbutton
.display
)
466 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
468 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
469 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
470 popup_activated_flag
= 0;
473 x_dispatch_event (&event
, event
.xany
.display
);
477 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
478 doc
: /* Start key navigation of the menu bar in FRAME.
479 This initially opens the first menu bar item and you can then navigate with the
480 arrow keys, select a menu entry with the return key or cancel with the
481 escape key. If FRAME has no menu bar this function does nothing.
483 If FRAME is nil or not given, use the selected frame. */)
487 FRAME_PTR f
= check_x_frame (frame
);
491 if (FRAME_EXTERNAL_MENU_BAR (f
))
492 set_frame_menubar (f
, 0, 1);
494 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
500 x_catch_errors (FRAME_X_DISPLAY (f
));
501 memset (&ev
, 0, sizeof ev
);
502 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
503 ev
.xbutton
.window
= XtWindow (menubar
);
504 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
505 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
506 ev
.xbutton
.button
= Button1
;
507 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
508 ev
.xbutton
.same_screen
= True
;
515 XtSetArg (al
[0], XtNchildren
, &list
);
516 XtSetArg (al
[1], XtNnumChildren
, &nr
);
517 XtGetValues (menubar
, al
, 2);
518 ev
.xbutton
.window
= XtWindow (list
[0]);
522 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
523 /* From-window, to-window. */
524 ev
.xbutton
.window
, ev
.xbutton
.root
,
526 /* From-position, to-position. */
527 ev
.xbutton
.x
, ev
.xbutton
.y
,
528 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
532 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
537 ev
.type
= ButtonPress
;
538 ev
.xbutton
.state
= 0;
540 XtDispatchEvent (&ev
);
541 ev
.xbutton
.type
= ButtonRelease
;
542 ev
.xbutton
.state
= Button1Mask
;
543 XtDispatchEvent (&ev
);
551 #endif /* USE_X_TOOLKIT */
555 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
556 doc
: /* Start key navigation of the menu bar in FRAME.
557 This initially opens the first menu bar item and you can then navigate with the
558 arrow keys, select a menu entry with the return key or cancel with the
559 escape key. If FRAME has no menu bar this function does nothing.
561 If FRAME is nil or not given, use the selected frame. */)
567 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
571 f
= check_x_frame (frame
);
573 if (FRAME_EXTERNAL_MENU_BAR (f
))
574 set_frame_menubar (f
, 0, 1);
576 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
579 /* Activate the first menu. */
580 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
584 g_signal_emit_by_name (children
->data
, "activate_item");
585 popup_activated_flag
= 1;
586 g_list_free (children
);
594 /* Loop util popup_activated_flag is set to zero in a callback.
595 Used for popup menus and dialogs. */
598 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
600 ++popup_activated_flag
;
602 /* Process events in the Gtk event loop until done. */
603 while (popup_activated_flag
)
605 if (do_timers
) x_menu_wait_for_event (0);
606 gtk_main_iteration ();
611 /* Activate the menu bar of frame F.
612 This is called from keyboard.c when it gets the
613 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
615 To activate the menu bar, we use the X button-press event
616 that was saved in saved_menu_event.
617 That makes the toolkit do its thing.
619 But first we recompute the menu bar contents (the whole tree).
621 The reason for saving the button event until here, instead of
622 passing it to the toolkit right away, is that we can safely
623 execute Lisp code. */
626 x_activate_menubar (FRAME_PTR f
)
631 if (!f
->output_data
.x
->saved_menu_event
->type
)
635 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
636 f
->output_data
.x
->saved_menu_event
->xany
.window
))
640 set_frame_menubar (f
, 0, 1);
642 popup_activated_flag
= 1;
644 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
645 f
->output_data
.x
->saved_menu_event
);
647 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
651 /* Ignore this if we get it a second time. */
652 f
->output_data
.x
->saved_menu_event
->type
= 0;
655 /* This callback is invoked when the user selects a menubar cascade
656 pushbutton, but before the pulldown menu is posted. */
660 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
662 popup_activated_flag
= 1;
664 x_activate_timeout_atimer ();
669 /* This callback is invoked when a dialog or menu is finished being
670 used and has been unposted. */
674 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
676 popup_activated_flag
= 0;
680 popup_deactivate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
682 popup_activated_flag
= 0;
687 /* Function that finds the frame for WIDGET and shows the HELP text
689 F is the frame if known, or NULL if not known. */
691 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
697 XSETFRAME (frame
, f
);
698 kbd_buffer_store_help_event (frame
, help
);
702 #if 0 /* This code doesn't do anything useful. ++kfs */
703 /* WIDGET is the popup menu. It's parent is the frame's
704 widget. See which frame that is. */
705 xt_or_gtk_widget frame_widget
= XtParent (widget
);
708 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
712 && (f
= XFRAME (frame
),
713 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
717 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
721 /* Callback called when menu items are highlighted/unhighlighted
722 while moving the mouse over them. WIDGET is the menu bar or menu
723 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
724 the data structure for the menu item, or null in case of
729 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
731 xg_menu_item_cb_data
*cb_data
;
734 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
736 if (! cb_data
) return;
738 help
= call_data
? cb_data
->help
: Qnil
;
740 /* If popup_activated_flag is greater than 1 we are in a popup menu.
741 Don't show help for them, they won't appear before the
742 popup is popped down. */
743 if (popup_activated_flag
<= 1)
744 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
748 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
753 widget_value
*wv
= (widget_value
*) call_data
;
755 help
= wv
? wv
->help
: Qnil
;
757 /* Determine the frame for the help event. */
758 f
= menubar_id_to_frame (id
);
760 show_help_event (f
, widget
, help
);
765 /* Gtk calls callbacks just because we tell it what item should be
766 selected in a radio group. If this variable is set to a non-zero
767 value, we are creating menus and don't want callbacks right now.
769 static int xg_crazy_callback_abort
;
771 /* This callback is called from the menu bar pulldown menu
772 when the user makes a selection.
773 Figure out what the user chose
774 and put the appropriate events into the keyboard buffer. */
776 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
778 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
780 if (xg_crazy_callback_abort
)
783 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
786 /* For a group of radio buttons, GTK calls the selection callback first
787 for the item that was active before the selection and then for the one that
788 is active after the selection. For C-h k this means we get the help on
789 the deselected item and then the selected item is executed. Prevent that
790 by ignoring the non-active item. */
791 if (GTK_IS_RADIO_MENU_ITEM (widget
)
792 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
795 /* When a menu is popped down, X generates a focus event (i.e. focus
796 goes back to the frame below the menu). Since GTK buffers events,
797 we force it out here before the menu selection event. Otherwise
798 sit-for will exit at once if the focus event follows the menu selection
802 while (gtk_events_pending ())
803 gtk_main_iteration ();
806 find_and_call_menu_selection (cb_data
->cl_data
->f
,
807 cb_data
->cl_data
->menu_bar_items_used
,
808 cb_data
->cl_data
->menu_bar_vector
,
812 #else /* not USE_GTK */
814 /* This callback is called from the menu bar pulldown menu
815 when the user makes a selection.
816 Figure out what the user chose
817 and put the appropriate events into the keyboard buffer. */
819 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
823 f
= menubar_id_to_frame (id
);
826 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
827 f
->menu_bar_vector
, client_data
);
829 #endif /* not USE_GTK */
831 /* Recompute all the widgets of frame F, when the menu bar has been
832 changed. Value is non-zero if widgets were updated. */
835 update_frame_menubar (FRAME_PTR f
)
838 return xg_update_frame_menubar (f
);
846 x
= f
->output_data
.x
;
848 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
852 /* Save the size of the frame because the pane widget doesn't accept
853 to resize itself. So force it. */
854 columns
= FRAME_COLS (f
);
855 rows
= FRAME_LINES (f
);
857 /* Do the voodoo which means "I'm changing lots of things, don't try
858 to refigure sizes until I'm done." */
859 lw_refigure_widget (x
->column_widget
, False
);
861 /* The order in which children are managed is the top to bottom
862 order in which they are displayed in the paned window. First,
863 remove the text-area widget. */
864 XtUnmanageChild (x
->edit_widget
);
866 /* Remove the menubar that is there now, and put up the menubar that
868 XtManageChild (x
->menubar_widget
);
869 XtMapWidget (x
->menubar_widget
);
870 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
872 /* Re-manage the text-area widget, and then thrash the sizes. */
873 XtManageChild (x
->edit_widget
);
874 lw_refigure_widget (x
->column_widget
, True
);
876 /* Force the pane widget to resize itself with the right values. */
877 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
885 apply_systemfont_to_dialog (Widget w
)
887 const char *fn
= xsettings_get_system_normal_font ();
890 XrmDatabase db
= XtDatabase (XtDisplay (w
));
892 XrmPutStringResource (&db
, "*dialog.font", fn
);
897 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
899 const char *fn
= xsettings_get_system_normal_font ();
903 XrmDatabase db
= XtDatabase (XtDisplay (w
));
906 XrmPutStringResource (&db
, "*menubar*font", fn
);
907 XrmPutStringResource (&db
, "*popup*font", fn
);
914 /* Set the contents of the menubar widgets of frame F.
915 The argument FIRST_TIME is currently ignored;
916 it is set the first time this is called, from initialize_frame_menubar. */
919 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
921 xt_or_gtk_widget menubar_widget
;
926 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
928 int *submenu_start
, *submenu_end
;
929 int *submenu_top_level_items
, *submenu_n_panes
;
934 menubar_widget
= f
->output_data
.x
->menubar_widget
;
936 XSETFRAME (Vmenu_updating_frame
, f
);
939 if (f
->output_data
.x
->id
== 0)
940 f
->output_data
.x
->id
= next_menubar_widget_id
++;
941 id
= f
->output_data
.x
->id
;
944 if (! menubar_widget
)
946 /* Make the first call for any given frame always go deep. */
947 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
950 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
951 f
->output_data
.x
->saved_menu_event
->type
= 0;
955 /* If we have detached menus, we must update deep so detached menus
956 also gets updated. */
957 deep_p
= deep_p
|| xg_have_tear_offs ();
962 /* Make a widget-value tree representing the entire menu trees. */
964 struct buffer
*prev
= current_buffer
;
966 int specpdl_count
= SPECPDL_INDEX ();
967 int previous_menu_items_used
= f
->menu_bar_items_used
;
968 Lisp_Object
*previous_items
969 = (Lisp_Object
*) alloca (previous_menu_items_used
970 * sizeof (Lisp_Object
));
973 /* If we are making a new widget, its contents are empty,
974 do always reinitialize them. */
975 if (! menubar_widget
)
976 previous_menu_items_used
= 0;
978 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
979 specbind (Qinhibit_quit
, Qt
);
980 /* Don't let the debugger step into this code
981 because it is not reentrant. */
982 specbind (Qdebug_on_next_call
, Qnil
);
984 record_unwind_save_match_data ();
985 if (NILP (Voverriding_local_map_menu_flag
))
987 specbind (Qoverriding_terminal_local_map
, Qnil
);
988 specbind (Qoverriding_local_map
, Qnil
);
991 set_buffer_internal_1 (XBUFFER (buffer
));
993 /* Run the Lucid hook. */
994 safe_run_hooks (Qactivate_menubar_hook
);
996 /* If it has changed current-menubar from previous value,
997 really recompute the menubar from the value. */
998 if (! NILP (Vlucid_menu_bar_dirty_flag
))
999 call0 (Qrecompute_lucid_menubar
);
1000 safe_run_hooks (Qmenu_bar_update_hook
);
1001 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1003 items
= FRAME_MENU_BAR_ITEMS (f
);
1005 /* Save the frame's previous menu bar contents data. */
1006 if (previous_menu_items_used
)
1007 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1008 previous_menu_items_used
* sizeof (Lisp_Object
));
1010 /* Fill in menu_items with the current menu bar contents.
1011 This can evaluate Lisp code. */
1014 menu_items
= f
->menu_bar_vector
;
1015 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1016 subitems
= ASIZE (items
) / 4;
1017 submenu_start
= (int *) alloca ((subitems
+ 1) * sizeof (int));
1018 submenu_end
= (int *) alloca (subitems
* sizeof (int));
1019 submenu_n_panes
= (int *) alloca (subitems
* sizeof (int));
1020 submenu_top_level_items
= (int *) alloca (subitems
* sizeof (int));
1022 for (i
= 0; i
< subitems
; i
++)
1024 Lisp_Object key
, string
, maps
;
1026 key
= XVECTOR (items
)->contents
[4 * i
];
1027 string
= XVECTOR (items
)->contents
[4 * i
+ 1];
1028 maps
= XVECTOR (items
)->contents
[4 * i
+ 2];
1032 submenu_start
[i
] = menu_items_used
;
1034 menu_items_n_panes
= 0;
1035 submenu_top_level_items
[i
]
1036 = parse_single_submenu (key
, string
, maps
);
1037 submenu_n_panes
[i
] = menu_items_n_panes
;
1039 submenu_end
[i
] = menu_items_used
;
1042 submenu_start
[i
] = -1;
1043 finish_menu_items ();
1045 /* Convert menu_items into widget_value trees
1046 to display the menu. This cannot evaluate Lisp code. */
1048 wv
= xmalloc_widget_value ();
1049 wv
->name
= "menubar";
1052 wv
->button_type
= BUTTON_TYPE_NONE
;
1056 for (i
= 0; 0 <= submenu_start
[i
]; i
++)
1058 menu_items_n_panes
= submenu_n_panes
[i
];
1059 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1060 submenu_top_level_items
[i
]);
1064 first_wv
->contents
= wv
;
1065 /* Don't set wv->name here; GC during the loop might relocate it. */
1067 wv
->button_type
= BUTTON_TYPE_NONE
;
1071 set_buffer_internal_1 (prev
);
1073 /* If there has been no change in the Lisp-level contents
1074 of the menu bar, skip redisplaying it. Just exit. */
1076 /* Compare the new menu items with the ones computed last time. */
1077 for (i
= 0; i
< previous_menu_items_used
; i
++)
1078 if (menu_items_used
== i
1079 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1081 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1083 /* The menu items have not changed. Don't bother updating
1084 the menus in any form, since it would be a no-op. */
1085 free_menubar_widget_value_tree (first_wv
);
1086 discard_menu_items ();
1087 unbind_to (specpdl_count
, Qnil
);
1091 /* The menu items are different, so store them in the frame. */
1092 f
->menu_bar_vector
= menu_items
;
1093 f
->menu_bar_items_used
= menu_items_used
;
1095 /* This undoes save_menu_items. */
1096 unbind_to (specpdl_count
, Qnil
);
1098 /* Now GC cannot happen during the lifetime of the widget_value,
1099 so it's safe to store data from a Lisp_String. */
1100 wv
= first_wv
->contents
;
1101 for (i
= 0; i
< ASIZE (items
); i
+= 4)
1104 string
= XVECTOR (items
)->contents
[i
+ 1];
1107 wv
->name
= SSDATA (string
);
1108 update_submenu_strings (wv
->contents
);
1115 /* Make a widget-value tree containing
1116 just the top level menu bar strings. */
1118 wv
= xmalloc_widget_value ();
1119 wv
->name
= "menubar";
1122 wv
->button_type
= BUTTON_TYPE_NONE
;
1126 items
= FRAME_MENU_BAR_ITEMS (f
);
1127 for (i
= 0; i
< ASIZE (items
); i
+= 4)
1131 string
= XVECTOR (items
)->contents
[i
+ 1];
1135 wv
= xmalloc_widget_value ();
1136 wv
->name
= SSDATA (string
);
1139 wv
->button_type
= BUTTON_TYPE_NONE
;
1141 /* This prevents lwlib from assuming this
1142 menu item is really supposed to be empty. */
1143 /* The intptr_t cast avoids a warning.
1144 This value just has to be different from small integers. */
1145 wv
->call_data
= (void *) (intptr_t) (-1);
1150 first_wv
->contents
= wv
;
1154 /* Forget what we thought we knew about what is in the
1155 detailed contents of the menu bar menus.
1156 Changing the top level always destroys the contents. */
1157 f
->menu_bar_items_used
= 0;
1160 /* Create or update the menu bar widget. */
1165 xg_crazy_callback_abort
= 1;
1168 /* The fourth arg is DEEP_P, which says to consider the entire
1169 menu trees we supply, rather than just the menu bar item names. */
1170 xg_modify_menubar_widgets (menubar_widget
,
1174 G_CALLBACK (menubar_selection_callback
),
1175 G_CALLBACK (popup_deactivate_callback
),
1176 G_CALLBACK (menu_highlight_callback
));
1181 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1182 G_CALLBACK (menubar_selection_callback
),
1183 G_CALLBACK (popup_deactivate_callback
),
1184 G_CALLBACK (menu_highlight_callback
));
1186 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1190 #else /* not USE_GTK */
1193 /* Disable resizing (done for Motif!) */
1194 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1196 /* The third arg is DEEP_P, which says to consider the entire
1197 menu trees we supply, rather than just the menu bar item names. */
1198 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1200 /* Re-enable the edit widget to resize. */
1201 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1205 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1206 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1209 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
1211 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
1213 f
->output_data
.x
->column_widget
,
1215 popup_activate_callback
,
1216 menubar_selection_callback
,
1217 popup_deactivate_callback
,
1218 menu_highlight_callback
);
1219 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1221 /* Make menu pop down on C-g. */
1222 XtOverrideTranslations (menubar_widget
, override
);
1227 if (f
->output_data
.x
->menubar_widget
)
1228 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1231 = (f
->output_data
.x
->menubar_widget
1232 ? (f
->output_data
.x
->menubar_widget
->core
.height
1233 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1236 #if 1 /* Experimentally, we now get the right results
1237 for -geometry -0-0 without this. 24 Aug 96, rms.
1238 Maybe so, but the menu bar size is missing the pixels so the
1239 WM size hints are off by these pixels. Jan D, oct 2009. */
1241 if (FRAME_EXTERNAL_MENU_BAR (f
))
1244 XtVaGetValues (f
->output_data
.x
->column_widget
,
1245 XtNinternalBorderWidth
, &ibw
, NULL
);
1246 menubar_size
+= ibw
;
1248 #endif /* USE_LUCID */
1251 f
->output_data
.x
->menubar_height
= menubar_size
;
1253 #endif /* not USE_GTK */
1255 free_menubar_widget_value_tree (first_wv
);
1256 update_frame_menubar (f
);
1259 xg_crazy_callback_abort
= 0;
1265 /* Called from Fx_create_frame to create the initial menubar of a frame
1266 before it is mapped, so that the window is mapped with the menubar already
1267 there instead of us tacking it on later and thrashing the window after it
1271 initialize_frame_menubar (FRAME_PTR f
)
1273 /* This function is called before the first chance to redisplay
1274 the frame. It has to be, so the frame will have the right size. */
1275 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1276 set_frame_menubar (f
, 1, 1);
1280 /* Get rid of the menu bar of frame F, and free its storage.
1281 This is used when deleting a frame, and when turning off the menu bar.
1282 For GTK this function is in gtkutil.c. */
1286 free_frame_menubar (FRAME_PTR f
)
1288 Widget menubar_widget
;
1290 if (! FRAME_X_P (f
))
1293 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1295 f
->output_data
.x
->menubar_height
= 0;
1300 /* Removing the menu bar magically changes the shell widget's x
1301 and y position of (0, 0) which, when the menu bar is turned
1302 on again, leads to pull-down menuss appearing in strange
1303 positions near the upper-left corner of the display. This
1304 happens only with some window managers like twm and ctwm,
1305 but not with other like Motif's mwm or kwm, because the
1306 latter generate ConfigureNotify events when the menu bar
1307 is switched off, which fixes the shell position. */
1308 Position x0
, y0
, x1
, y1
;
1314 if (f
->output_data
.x
->widget
)
1315 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1318 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1319 f
->output_data
.x
->menubar_widget
= NULL
;
1321 if (f
->output_data
.x
->widget
)
1324 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1325 if (x1
== 0 && y1
== 0)
1326 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1328 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1333 #endif /* not USE_GTK */
1335 #endif /* USE_X_TOOLKIT || USE_GTK */
1337 /* xmenu_show actually displays a menu using the panes and items in menu_items
1338 and returns the value selected from it.
1339 There are two versions of xmenu_show, one for Xt and one for Xlib.
1340 Both assume input is blocked by the caller. */
1342 /* F is the frame the menu is for.
1343 X and Y are the frame-relative specified position,
1344 relative to the inside upper left corner of the frame F.
1345 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1346 KEYMAPS is 1 if this menu was specified with keymaps;
1347 in that case, we return a list containing the chosen item's value
1348 and perhaps also the pane's prefix.
1349 TITLE is the specified menu title.
1350 ERROR is a place to store an error message string in case of failure.
1351 (We return nil on failure, but the value doesn't actually matter.) */
1353 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1355 /* The item selected in the popup menu. */
1356 static Lisp_Object
*volatile menu_item_selection
;
1360 /* Used when position a popup menu. See menu_position_func and
1361 create_and_show_popup_menu below. */
1362 struct next_popup_x_y
1369 /* The menu position function to use if we are not putting a popup
1370 menu where the pointer is.
1371 MENU is the menu to pop up.
1372 X and Y shall on exit contain x/y where the menu shall pop up.
1373 PUSH_IN is not documented in the GTK manual.
1374 USER_DATA is any data passed in when calling gtk_menu_popup.
1375 Here it points to a struct next_popup_x_y where the coordinates
1376 to store in *X and *Y are as well as the frame for the popup.
1378 Here only X and Y are used. */
1380 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1382 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1384 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1385 int disp_width
= x_display_pixel_width (dpyinfo
);
1386 int disp_height
= x_display_pixel_height (dpyinfo
);
1391 /* Check if there is room for the menu. If not, adjust x/y so that
1392 the menu is fully visible. */
1393 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1394 if (data
->x
+ req
.width
> disp_width
)
1395 *x
-= data
->x
+ req
.width
- disp_width
;
1396 if (data
->y
+ req
.height
> disp_height
)
1397 *y
-= data
->y
+ req
.height
- disp_height
;
1401 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1403 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1405 if (xg_crazy_callback_abort
) return;
1406 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1410 pop_down_menu (Lisp_Object arg
)
1412 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1414 popup_activated_flag
= 0;
1416 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1421 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1423 menu_item_selection will be set to the selection. */
1425 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
,
1426 int for_click
, Time timestamp
)
1430 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1431 struct next_popup_x_y popup_x_y
;
1432 int specpdl_count
= SPECPDL_INDEX ();
1434 if (! FRAME_X_P (f
))
1437 xg_crazy_callback_abort
= 1;
1438 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1439 G_CALLBACK (popup_selection_callback
),
1440 G_CALLBACK (popup_deactivate_callback
),
1441 G_CALLBACK (menu_highlight_callback
));
1442 xg_crazy_callback_abort
= 0;
1446 /* Not invoked by a click. pop up at x/y. */
1447 pos_func
= menu_position_func
;
1449 /* Adjust coordinates to be root-window-relative. */
1450 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1451 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1457 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1461 for (i
= 0; i
< 5; i
++)
1462 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1466 /* Display the menu. */
1467 gtk_widget_show_all (menu
);
1469 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1470 timestamp
? timestamp
: gtk_get_current_event_time ());
1472 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1474 if (gtk_widget_get_mapped (menu
))
1476 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1477 two. show_help_echo uses this to detect popup menus. */
1478 popup_activated_flag
= 1;
1479 /* Process events that apply to the menu. */
1480 popup_widget_loop (1, menu
);
1483 unbind_to (specpdl_count
, Qnil
);
1485 /* Must reset this manually because the button release event is not passed
1486 to Emacs event loop. */
1487 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1490 #else /* not USE_GTK */
1492 /* We need a unique id for each widget handled by the Lucid Widget
1495 For the main windows, and popup menus, we use this counter,
1496 which we increment each time after use. This starts from 1<<16.
1498 For menu bars, we use numbers starting at 0, counted in
1499 next_menubar_widget_id. */
1500 LWLIB_ID widget_id_tick
;
1503 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1505 menu_item_selection
= (Lisp_Object
*) client_data
;
1508 /* ARG is the LWLIB ID of the dialog box, represented
1509 as a Lisp object as (HIGHPART . LOWPART). */
1512 pop_down_menu (Lisp_Object arg
)
1514 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1515 | XINT (XCDR (arg
)));
1518 lw_destroy_all_widgets (id
);
1520 popup_activated_flag
= 0;
1525 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1527 menu_item_selection will be set to the selection. */
1529 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
,
1530 int x
, int y
, int for_click
, Time timestamp
)
1536 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1540 if (! FRAME_X_P (f
))
1544 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1547 menu_id
= widget_id_tick
++;
1548 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1549 f
->output_data
.x
->widget
, 1, 0,
1550 popup_selection_callback
,
1551 popup_deactivate_callback
,
1552 menu_highlight_callback
);
1554 event
->type
= ButtonPress
;
1556 event
->send_event
= 0;
1557 event
->display
= FRAME_X_DISPLAY (f
);
1558 event
->time
= CurrentTime
;
1559 event
->root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1560 event
->window
= event
->subwindow
= event
->root
;
1564 /* Adjust coordinates to be root-window-relative. */
1565 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1566 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1573 for (i
= 0; i
< 5; i
++)
1574 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1577 /* Don't allow any geometry request from the user. */
1578 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1579 XtSetValues (menu
, av
, ac
);
1581 /* Display the menu. */
1582 lw_popup_menu (menu
, &dummy
);
1583 popup_activated_flag
= 1;
1584 x_activate_timeout_atimer ();
1587 int fact
= 4 * sizeof (LWLIB_ID
);
1588 int specpdl_count
= SPECPDL_INDEX ();
1589 record_unwind_protect (pop_down_menu
,
1590 Fcons (make_number (menu_id
>> (fact
)),
1591 make_number (menu_id
& ~(-1 << (fact
)))));
1593 /* Process events that apply to the menu. */
1594 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1596 unbind_to (specpdl_count
, Qnil
);
1600 #endif /* not USE_GTK */
1603 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1604 Lisp_Object title
, const char **error_name
, Time timestamp
)
1607 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1608 widget_value
**submenu_stack
1609 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1610 Lisp_Object
*subprefix_stack
1611 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1612 int submenu_depth
= 0;
1616 if (! FRAME_X_P (f
))
1621 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1623 *error_name
= "Empty menu";
1627 /* Create a tree of widget_value objects
1628 representing the panes and their items. */
1629 wv
= xmalloc_widget_value ();
1633 wv
->button_type
= BUTTON_TYPE_NONE
;
1638 /* Loop over all panes and items, filling in the tree. */
1640 while (i
< menu_items_used
)
1642 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1644 submenu_stack
[submenu_depth
++] = save_wv
;
1650 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1653 save_wv
= submenu_stack
[--submenu_depth
];
1657 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1658 && submenu_depth
!= 0)
1659 i
+= MENU_ITEMS_PANE_LENGTH
;
1660 /* Ignore a nil in the item list.
1661 It's meaningful only for dialog boxes. */
1662 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1664 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1666 /* Create a new pane. */
1667 Lisp_Object pane_name
, prefix
;
1668 const char *pane_string
;
1670 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1671 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1673 #ifndef HAVE_MULTILINGUAL_MENU
1674 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1676 pane_name
= ENCODE_MENU_STRING (pane_name
);
1677 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1680 pane_string
= (NILP (pane_name
)
1681 ? "" : SSDATA (pane_name
));
1682 /* If there is just one top-level pane, put all its items directly
1683 under the top-level menu. */
1684 if (menu_items_n_panes
== 1)
1687 /* If the pane has a meaningful name,
1688 make the pane a top-level menu item
1689 with its items as a submenu beneath it. */
1690 if (!keymaps
&& strcmp (pane_string
, ""))
1692 wv
= xmalloc_widget_value ();
1696 first_wv
->contents
= wv
;
1697 wv
->name
= pane_string
;
1698 if (keymaps
&& !NILP (prefix
))
1702 wv
->button_type
= BUTTON_TYPE_NONE
;
1707 else if (first_pane
)
1713 i
+= MENU_ITEMS_PANE_LENGTH
;
1717 /* Create a new item within current pane. */
1718 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1719 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1720 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1721 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1722 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1723 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1724 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1725 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1727 #ifndef HAVE_MULTILINGUAL_MENU
1728 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1730 item_name
= ENCODE_MENU_STRING (item_name
);
1731 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1734 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1736 descrip
= ENCODE_MENU_STRING (descrip
);
1737 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1739 #endif /* not HAVE_MULTILINGUAL_MENU */
1741 wv
= xmalloc_widget_value ();
1745 save_wv
->contents
= wv
;
1746 wv
->name
= SSDATA (item_name
);
1747 if (!NILP (descrip
))
1748 wv
->key
= SSDATA (descrip
);
1750 /* If this item has a null value,
1751 make the call_data null so that it won't display a box
1752 when the mouse is on it. */
1754 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1755 wv
->enabled
= !NILP (enable
);
1758 wv
->button_type
= BUTTON_TYPE_NONE
;
1759 else if (EQ (type
, QCtoggle
))
1760 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1761 else if (EQ (type
, QCradio
))
1762 wv
->button_type
= BUTTON_TYPE_RADIO
;
1766 wv
->selected
= !NILP (selected
);
1768 if (! STRINGP (help
))
1775 i
+= MENU_ITEMS_ITEM_LENGTH
;
1779 /* Deal with the title, if it is non-nil. */
1782 widget_value
*wv_title
= xmalloc_widget_value ();
1783 widget_value
*wv_sep1
= xmalloc_widget_value ();
1784 widget_value
*wv_sep2
= xmalloc_widget_value ();
1786 wv_sep2
->name
= "--";
1787 wv_sep2
->next
= first_wv
->contents
;
1788 wv_sep2
->help
= Qnil
;
1790 wv_sep1
->name
= "--";
1791 wv_sep1
->next
= wv_sep2
;
1792 wv_sep1
->help
= Qnil
;
1794 #ifndef HAVE_MULTILINGUAL_MENU
1795 if (STRING_MULTIBYTE (title
))
1796 title
= ENCODE_MENU_STRING (title
);
1799 wv_title
->name
= SSDATA (title
);
1800 wv_title
->enabled
= TRUE
;
1801 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1802 wv_title
->help
= Qnil
;
1803 wv_title
->next
= wv_sep1
;
1804 first_wv
->contents
= wv_title
;
1807 /* No selection has been chosen yet. */
1808 menu_item_selection
= 0;
1810 /* Actually create and show the menu until popped down. */
1811 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1813 /* Free the widget_value objects we used to specify the contents. */
1814 free_menubar_widget_value_tree (first_wv
);
1816 /* Find the selected item, and its pane, to return
1817 the proper value. */
1818 if (menu_item_selection
!= 0)
1820 Lisp_Object prefix
, entry
;
1822 prefix
= entry
= Qnil
;
1824 while (i
< menu_items_used
)
1826 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1828 subprefix_stack
[submenu_depth
++] = prefix
;
1832 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1834 prefix
= subprefix_stack
[--submenu_depth
];
1837 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1840 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1841 i
+= MENU_ITEMS_PANE_LENGTH
;
1843 /* Ignore a nil in the item list.
1844 It's meaningful only for dialog boxes. */
1845 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1850 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1851 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1857 entry
= Fcons (entry
, Qnil
);
1859 entry
= Fcons (prefix
, entry
);
1860 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1861 if (!NILP (subprefix_stack
[j
]))
1862 entry
= Fcons (subprefix_stack
[j
], entry
);
1866 i
+= MENU_ITEMS_ITEM_LENGTH
;
1870 else if (!for_click
)
1871 /* Make "Cancel" equivalent to C-g. */
1872 Fsignal (Qquit
, Qnil
);
1879 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1881 /* Treat the pointer as an integer. There's no problem
1882 as long as pointers have enough bits to hold small integers. */
1883 if ((intptr_t) client_data
!= -1)
1884 menu_item_selection
= (Lisp_Object
*) client_data
;
1886 popup_activated_flag
= 0;
1889 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1891 menu_item_selection will be set to the selection. */
1893 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1897 if (! FRAME_X_P (f
))
1900 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1901 G_CALLBACK (dialog_selection_callback
),
1902 G_CALLBACK (popup_deactivate_callback
),
1907 int specpdl_count
= SPECPDL_INDEX ();
1908 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1910 /* Display the menu. */
1911 gtk_widget_show_all (menu
);
1913 /* Process events that apply to the menu. */
1914 popup_widget_loop (1, menu
);
1916 unbind_to (specpdl_count
, Qnil
);
1920 #else /* not USE_GTK */
1922 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1924 /* Treat the pointer as an integer. There's no problem
1925 as long as pointers have enough bits to hold small integers. */
1926 if ((intptr_t) client_data
!= -1)
1927 menu_item_selection
= (Lisp_Object
*) client_data
;
1930 lw_destroy_all_widgets (id
);
1932 popup_activated_flag
= 0;
1936 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1938 menu_item_selection will be set to the selection. */
1940 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1947 dialog_id
= widget_id_tick
++;
1949 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1951 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1952 f
->output_data
.x
->widget
, 1, 0,
1953 dialog_selection_callback
, 0, 0);
1954 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1955 /* Display the dialog box. */
1956 lw_pop_up_all_widgets (dialog_id
);
1957 popup_activated_flag
= 1;
1958 x_activate_timeout_atimer ();
1960 /* Process events that apply to the dialog box.
1961 Also handle timers. */
1963 int count
= SPECPDL_INDEX ();
1964 int fact
= 4 * sizeof (LWLIB_ID
);
1966 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1967 record_unwind_protect (pop_down_menu
,
1968 Fcons (make_number (dialog_id
>> (fact
)),
1969 make_number (dialog_id
& ~(-1 << (fact
)))));
1971 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
1974 unbind_to (count
, Qnil
);
1978 #endif /* not USE_GTK */
1980 static const char * button_names
[] = {
1981 "button1", "button2", "button3", "button4", "button5",
1982 "button6", "button7", "button8", "button9", "button10" };
1985 xdialog_show (FRAME_PTR f
,
1989 const char **error_name
)
1991 int i
, nb_buttons
=0;
1992 char dialog_name
[6];
1994 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1996 /* Number of elements seen so far, before boundary. */
1998 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1999 int boundary_seen
= 0;
2001 if (! FRAME_X_P (f
))
2006 if (menu_items_n_panes
> 1)
2008 *error_name
= "Multiple panes in dialog box";
2012 /* Create a tree of widget_value objects
2013 representing the text label and buttons. */
2015 Lisp_Object pane_name
, prefix
;
2016 const char *pane_string
;
2017 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2018 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2019 pane_string
= (NILP (pane_name
)
2020 ? "" : SSDATA (pane_name
));
2021 prev_wv
= xmalloc_widget_value ();
2022 prev_wv
->value
= pane_string
;
2023 if (keymaps
&& !NILP (prefix
))
2025 prev_wv
->enabled
= 1;
2026 prev_wv
->name
= "message";
2027 prev_wv
->help
= Qnil
;
2030 /* Loop over all panes and items, filling in the tree. */
2031 i
= MENU_ITEMS_PANE_LENGTH
;
2032 while (i
< menu_items_used
)
2035 /* Create a new item within current pane. */
2036 Lisp_Object item_name
, enable
, descrip
;
2037 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2038 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2040 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2042 if (NILP (item_name
))
2044 free_menubar_widget_value_tree (first_wv
);
2045 *error_name
= "Submenu in dialog items";
2048 if (EQ (item_name
, Qquote
))
2050 /* This is the boundary between left-side elts
2051 and right-side elts. Stop incrementing right_count. */
2056 if (nb_buttons
>= 9)
2058 free_menubar_widget_value_tree (first_wv
);
2059 *error_name
= "Too many dialog items";
2063 wv
= xmalloc_widget_value ();
2065 wv
->name
= (char *) button_names
[nb_buttons
];
2066 if (!NILP (descrip
))
2067 wv
->key
= SSDATA (descrip
);
2068 wv
->value
= SSDATA (item_name
);
2069 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2070 wv
->enabled
= !NILP (enable
);
2074 if (! boundary_seen
)
2078 i
+= MENU_ITEMS_ITEM_LENGTH
;
2081 /* If the boundary was not specified,
2082 by default put half on the left and half on the right. */
2083 if (! boundary_seen
)
2084 left_count
= nb_buttons
- nb_buttons
/ 2;
2086 wv
= xmalloc_widget_value ();
2087 wv
->name
= dialog_name
;
2090 /* Frame title: 'Q' = Question, 'I' = Information.
2091 Can also have 'E' = Error if, one day, we want
2092 a popup for errors. */
2094 dialog_name
[0] = 'Q';
2096 dialog_name
[0] = 'I';
2098 /* Dialog boxes use a really stupid name encoding
2099 which specifies how many buttons to use
2100 and how many buttons are on the right. */
2101 dialog_name
[1] = '0' + nb_buttons
;
2102 dialog_name
[2] = 'B';
2103 dialog_name
[3] = 'R';
2104 /* Number of buttons to put on the right. */
2105 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2107 wv
->contents
= first_wv
;
2111 /* No selection has been chosen yet. */
2112 menu_item_selection
= 0;
2114 /* Actually create and show the dialog. */
2115 create_and_show_dialog (f
, first_wv
);
2117 /* Free the widget_value objects we used to specify the contents. */
2118 free_menubar_widget_value_tree (first_wv
);
2120 /* Find the selected item, and its pane, to return
2121 the proper value. */
2122 if (menu_item_selection
!= 0)
2128 while (i
< menu_items_used
)
2132 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2135 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2136 i
+= MENU_ITEMS_PANE_LENGTH
;
2138 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2140 /* This is the boundary between left-side elts and
2147 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2148 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2152 entry
= Fcons (entry
, Qnil
);
2154 entry
= Fcons (prefix
, entry
);
2158 i
+= MENU_ITEMS_ITEM_LENGTH
;
2163 /* Make "Cancel" equivalent to C-g. */
2164 Fsignal (Qquit
, Qnil
);
2169 #else /* not USE_X_TOOLKIT && not USE_GTK */
2171 /* The frame of the last activated non-toolkit menu bar.
2172 Used to generate menu help events. */
2174 static struct frame
*menu_help_frame
;
2177 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2179 PANE is the pane number, and ITEM is the menu item number in
2180 the menu (currently not used).
2182 This cannot be done with generating a HELP_EVENT because
2183 XMenuActivate contains a loop that doesn't let Emacs process
2187 menu_help_callback (char const *help_string
, int pane
, int item
)
2189 Lisp_Object
*first_item
;
2190 Lisp_Object pane_name
;
2191 Lisp_Object menu_object
;
2193 first_item
= XVECTOR (menu_items
)->contents
;
2194 if (EQ (first_item
[0], Qt
))
2195 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2196 else if (EQ (first_item
[0], Qquote
))
2197 /* This shouldn't happen, see xmenu_show. */
2198 pane_name
= empty_unibyte_string
;
2200 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2202 /* (menu-item MENU-NAME PANE-NUMBER) */
2203 menu_object
= Fcons (Qmenu_item
,
2205 Fcons (make_number (pane
), Qnil
)));
2206 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2207 Qnil
, menu_object
, make_number (item
));
2211 pop_down_menu (Lisp_Object arg
)
2213 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2214 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2216 FRAME_PTR f
= p1
->pointer
;
2217 XMenu
*menu
= p2
->pointer
;
2221 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2222 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2224 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2226 #ifdef HAVE_X_WINDOWS
2227 /* Assume the mouse has moved out of the X window.
2228 If it has actually moved in, we will get an EnterNotify. */
2229 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2231 /* State that no mouse buttons are now held.
2232 (The oldXMenu code doesn't track this info for us.)
2233 That is not necessarily true, but the fiction leads to reasonable
2234 results, and it is a pain to ask which are actually held now. */
2235 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2237 #endif /* HAVE_X_WINDOWS */
2246 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
2247 Lisp_Object title
, const char **error_name
, Time timestamp
)
2251 int pane
, selidx
, lpane
, status
;
2252 Lisp_Object entry
, pane_prefix
;
2254 int ulx
, uly
, width
, height
;
2255 int dispwidth
, dispheight
;
2256 int i
, j
, lines
, maxlines
;
2259 unsigned int dummy_uint
;
2260 int specpdl_count
= SPECPDL_INDEX ();
2262 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2266 if (menu_items_n_panes
== 0)
2269 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2271 *error_name
= "Empty menu";
2275 /* Figure out which root window F is on. */
2276 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2277 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2278 &dummy_uint
, &dummy_uint
);
2280 /* Make the menu on that window. */
2281 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2284 *error_name
= "Can't create menu";
2288 /* Don't GC while we prepare and show the menu,
2289 because we give the oldxmenu library pointers to the
2290 contents of strings. */
2291 inhibit_garbage_collection ();
2293 #ifdef HAVE_X_WINDOWS
2294 /* Adjust coordinates to relative to the outer (window manager) window. */
2295 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2296 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2297 #endif /* HAVE_X_WINDOWS */
2299 /* Adjust coordinates to be root-window-relative. */
2303 /* Create all the necessary panes and their items. */
2304 maxwidth
= maxlines
= lines
= i
= 0;
2306 while (i
< menu_items_used
)
2308 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2310 /* Create a new pane. */
2311 Lisp_Object pane_name
, prefix
;
2312 const char *pane_string
;
2314 maxlines
= max (maxlines
, lines
);
2316 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2317 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2318 pane_string
= (NILP (pane_name
)
2319 ? "" : SSDATA (pane_name
));
2320 if (keymaps
&& !NILP (prefix
))
2323 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2324 if (lpane
== XM_FAILURE
)
2326 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2327 *error_name
= "Can't create pane";
2330 i
+= MENU_ITEMS_PANE_LENGTH
;
2332 /* Find the width of the widest item in this pane. */
2334 while (j
< menu_items_used
)
2337 item
= XVECTOR (menu_items
)->contents
[j
];
2345 width
= SBYTES (item
);
2346 if (width
> maxwidth
)
2349 j
+= MENU_ITEMS_ITEM_LENGTH
;
2352 /* Ignore a nil in the item list.
2353 It's meaningful only for dialog boxes. */
2354 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2358 /* Create a new item within current pane. */
2359 Lisp_Object item_name
, enable
, descrip
, help
;
2361 char const *help_string
;
2363 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2364 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2366 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2367 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2368 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2370 if (!NILP (descrip
))
2372 /* if alloca is fast, use that to make the space,
2373 to reduce gc needs. */
2374 item_data
= (char *) alloca (maxwidth
+ SBYTES (descrip
) + 1);
2375 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2376 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2378 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2379 item_data
[j
+ SBYTES (descrip
)] = 0;
2382 item_data
= SSDATA (item_name
);
2384 if (lpane
== XM_FAILURE
2385 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2386 menu
, lpane
, 0, item_data
,
2387 !NILP (enable
), help_string
)
2390 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2391 *error_name
= "Can't add selection to menu";
2394 i
+= MENU_ITEMS_ITEM_LENGTH
;
2399 maxlines
= max (maxlines
, lines
);
2401 /* All set and ready to fly. */
2402 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2403 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2404 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2405 x
= min (x
, dispwidth
);
2406 y
= min (y
, dispheight
);
2409 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2410 &ulx
, &uly
, &width
, &height
);
2411 if (ulx
+width
> dispwidth
)
2413 x
-= (ulx
+ width
) - dispwidth
;
2414 ulx
= dispwidth
- width
;
2416 if (uly
+height
> dispheight
)
2418 y
-= (uly
+ height
) - dispheight
;
2419 uly
= dispheight
- height
;
2421 #ifndef HAVE_X_WINDOWS
2422 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2424 /* Move the menu away of the echo area, to avoid overwriting the
2425 menu with help echo messages or vice versa. */
2426 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2428 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2429 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2438 if (ulx
< 0) x
-= ulx
;
2439 if (uly
< 0) y
-= uly
;
2443 /* If position was not given by a mouse click, adjust so upper left
2444 corner of the menu as a whole ends up at given coordinates. This
2445 is what x-popup-menu says in its documentation. */
2447 y
+= 1.5*height
/(maxlines
+2);
2450 XMenuSetAEQ (menu
, TRUE
);
2451 XMenuSetFreeze (menu
, TRUE
);
2455 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2458 record_unwind_protect (pop_down_menu
,
2459 Fcons (make_save_value (f
, 0),
2460 make_save_value (menu
, 0)));
2462 /* Help display under X won't work because XMenuActivate contains
2463 a loop that doesn't give Emacs a chance to process it. */
2464 menu_help_frame
= f
;
2465 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2466 x
, y
, ButtonReleaseMask
, &datap
,
2467 menu_help_callback
);
2468 entry
= pane_prefix
= Qnil
;
2474 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2477 /* Find the item number SELIDX in pane number PANE. */
2479 while (i
< menu_items_used
)
2481 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2485 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2487 i
+= MENU_ITEMS_PANE_LENGTH
;
2496 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2499 entry
= Fcons (entry
, Qnil
);
2500 if (!NILP (pane_prefix
))
2501 entry
= Fcons (pane_prefix
, entry
);
2507 i
+= MENU_ITEMS_ITEM_LENGTH
;
2513 *error_name
= "Can't activate menu";
2517 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2518 the menu was invoked with a mouse event as POSITION). */
2520 Fsignal (Qquit
, Qnil
);
2524 unbind_to (specpdl_count
, Qnil
);
2529 #endif /* not USE_X_TOOLKIT */
2531 #endif /* HAVE_MENUS */
2534 /* Detect if a dialog or menu has been posted. MSDOS has its own
2535 implementation on msdos.c. */
2538 popup_activated (void)
2540 return popup_activated_flag
;
2542 #endif /* not MSDOS */
2544 /* The following is used by delayed window autoselection. */
2546 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2547 doc
: /* Return t if a menu or popup dialog is active. */)
2551 return (popup_activated ()) ? Qt
: Qnil
;
2554 #endif /* HAVE_MENUS */
2558 syms_of_xmenu (void)
2560 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2561 staticpro (&Qdebug_on_next_call
);
2563 #ifdef USE_X_TOOLKIT
2564 widget_id_tick
= (1<<16);
2565 next_menubar_widget_id
= 1;
2568 defsubr (&Smenu_or_popup_active_p
);
2570 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2571 defsubr (&Sx_menu_bar_open_internal
);
2572 Ffset (intern_c_string ("accelerate-menu"),
2573 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2577 defsubr (&Sx_popup_dialog
);