1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2012
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"
50 #include "character.h"
54 #include "sysselect.h"
61 /* This may include sys/types.h, and that somehow loses
62 if this is not done before the other system files. */
66 /* Load sys/types.h if not already loaded.
67 In some systems loading it twice is suicidal. */
69 #include <sys/types.h>
72 #include "dispextern.h"
75 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
76 code accepts the Emacs internal encoding. */
77 #undef HAVE_MULTILINGUAL_MENU
81 #include <X11/IntrinsicP.h>
82 #include <X11/CoreP.h>
83 #include <X11/StringDefs.h>
84 #include <X11/Shell.h>
86 #include "xsettings.h"
87 #include "../lwlib/xlwmenu.h"
89 #include <X11/Xaw3d/Paned.h>
90 #else /* !HAVE_XAW3D */
91 #include <X11/Xaw/Paned.h>
92 #endif /* HAVE_XAW3D */
93 #endif /* USE_LUCID */
95 #include "../lwlib/lwlib.h"
97 #else /* not USE_X_TOOLKIT */
99 #include "../oldXMenu/XMenu.h"
101 #endif /* not USE_X_TOOLKIT */
102 #endif /* HAVE_X_WINDOWS */
107 #include "xgselect.h"
117 static Lisp_Object Qdebug_on_next_call
;
119 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
120 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
124 /* Flag which when set indicates a dialog or menu has been posted by
125 Xt on behalf of one of the widget sets. */
126 static int popup_activated_flag
;
131 static int next_menubar_widget_id
;
133 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
135 static struct frame
*
136 menubar_id_to_frame (LWLIB_ID id
)
138 Lisp_Object tail
, frame
;
141 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
147 if (!FRAME_WINDOW_P (f
))
149 if (f
->output_data
.x
->id
== id
)
157 #ifdef HAVE_X_WINDOWS
158 /* Return the mouse position in *X and *Y. The coordinates are window
159 relative for the edit window in frame F.
160 This is for Fx_popup_menu. The mouse_position_hook can not
161 be used for X, as it returns window relative coordinates
162 for the window where the mouse is in. This could be the menu bar,
163 the scroll bar or the edit window. Fx_popup_menu needs to be
164 sure it is the edit window. */
166 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
168 Window root
, dummy_window
;
176 XQueryPointer (FRAME_X_DISPLAY (f
),
177 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
179 /* The root window which contains the pointer. */
182 /* Window pointer is on, not used */
185 /* The position on that root window. */
188 /* x/y in dummy_window coordinates, not used. */
191 /* Modifier keys and pointer buttons, about which
193 (unsigned int *) &dummy
);
197 /* xmenu_show expects window coordinates, not root window
198 coordinates. Translate. */
199 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
200 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
203 #endif /* HAVE_X_WINDOWS */
207 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
208 doc
: /* Pop up a dialog box and return user's selection.
209 POSITION specifies which frame to use.
210 This is normally a mouse button event or a window or frame.
211 If POSITION is t, it means to use the frame the mouse is on.
212 The dialog box appears in the middle of the specified frame.
214 CONTENTS specifies the alternatives to display in the dialog box.
215 It is a list of the form (DIALOG ITEM1 ITEM2...).
216 Each ITEM is a cons cell (STRING . VALUE).
217 The return value is VALUE from the chosen item.
219 An ITEM may also be just a string--that makes a nonselectable item.
220 An ITEM may also be nil--that means to put all preceding items
221 on the left of the dialog box and all following items on the right.
222 \(By default, approximately half appear on each side.)
224 If HEADER is non-nil, the frame title for the box is "Information",
225 otherwise it is "Question".
227 If the user gets rid of the dialog box without making a valid choice,
228 for instance using the window manager, then this produces a quit and
229 `x-popup-dialog' does not return. */)
230 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
237 /* Decode the first argument: find the window or frame to use. */
238 if (EQ (position
, Qt
)
239 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
240 || EQ (XCAR (position
), Qtool_bar
))))
242 #if 0 /* Using the frame the mouse is on may not be right. */
243 /* Use the mouse's current position. */
244 FRAME_PTR new_f
= SELECTED_FRAME ();
245 Lisp_Object bar_window
;
246 enum scroll_bar_part part
;
250 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
253 XSETFRAME (window
, new_f
);
255 window
= selected_window
;
257 window
= selected_window
;
259 else if (CONSP (position
))
262 tem
= Fcar (position
);
264 window
= Fcar (Fcdr (position
));
267 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
268 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
271 else if (WINDOWP (position
) || FRAMEP (position
))
276 /* Decode where to put the menu. */
280 else if (WINDOWP (window
))
282 CHECK_LIVE_WINDOW (window
);
283 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
286 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
287 but I don't want to make one now. */
288 CHECK_WINDOW (window
);
290 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
291 error ("Can not put X dialog on this terminal");
293 /* Force a redisplay before showing the dialog. If a frame is created
294 just before showing the dialog, its contents may not have been fully
295 drawn, as this depends on timing of events from the X server. Redisplay
296 is not done when a dialog is shown. If redisplay could be done in the
297 X event loop (i.e. the X event loop does not run in a signal handler)
298 this would not be needed.
300 Do this before creating the widget value that points to Lisp
301 string contents, because Fredisplay may GC and relocate them. */
304 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
305 /* Display a menu with these alternatives
306 in the middle of frame F. */
308 Lisp_Object x
, y
, frame
, newpos
;
309 XSETFRAME (frame
, f
);
310 XSETINT (x
, x_pixel_width (f
) / 2);
311 XSETINT (y
, x_pixel_height (f
) / 2);
312 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
314 return Fx_popup_menu (newpos
,
315 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
320 const char *error_name
;
321 Lisp_Object selection
;
322 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
324 /* Decode the dialog items from what was specified. */
325 title
= Fcar (contents
);
326 CHECK_STRING (title
);
327 record_unwind_protect (unuse_menu_items
, Qnil
);
329 if (NILP (Fcar (Fcdr (contents
))))
330 /* No buttons specified, add an "Ok" button so users can pop down
331 the dialog. Also, the lesstif/motif version crashes if there are
333 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
335 list_of_panes (Fcons (contents
, Qnil
));
337 /* Display them in a dialog box. */
339 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
342 unbind_to (specpdl_count
, Qnil
);
343 discard_menu_items ();
345 if (error_name
) error ("%s", error_name
);
354 #if defined USE_GTK || defined USE_MOTIF
356 /* Set menu_items_inuse so no other popup menu or dialog is created. */
359 x_menu_set_in_use (int in_use
)
361 menu_items_inuse
= in_use
? Qt
: Qnil
;
362 popup_activated_flag
= in_use
;
364 if (popup_activated_flag
)
365 x_activate_timeout_atimer ();
371 /* Wait for an X event to arrive or for a timer to expire. */
377 x_menu_wait_for_event (void *data
)
379 /* Another way to do this is to register a timer callback, that can be
380 done in GTK and Xt. But we have to do it like this when using only X
381 anyway, and with callbacks we would have three variants for timer handling
382 instead of the small ifdefs below. */
386 ! XtAppPending (Xt_app_con
)
387 #elif defined USE_GTK
388 ! gtk_events_pending ()
390 ! XPending ((Display
*) data
)
394 EMACS_TIME next_time
= timer_check (), *ntp
;
395 SELECT_TYPE read_fds
;
396 struct x_display_info
*dpyinfo
;
400 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
402 int fd
= ConnectionNumber (dpyinfo
->display
);
403 FD_SET (fd
, &read_fds
);
405 XFlush (dpyinfo
->display
);
408 if (! EMACS_TIME_VALID_P (next_time
))
414 /* Gtk3 have arrows on menus when they don't fit. When the
415 pointer is over an arrow, a timeout scrolls it a bit. Use
416 xg_select so that timeout gets triggered. */
417 xg_select (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
419 pselect (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
426 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
430 /* Loop in Xt until the menu pulldown or dialog popup has been
431 popped down (deactivated). This is used for x-popup-menu
432 and x-popup-dialog; it is not used for the menu bar.
434 NOTE: All calls to popup_get_selection should be protected
435 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
438 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
442 while (popup_activated_flag
)
446 event
= *initial_event
;
451 if (do_timers
) x_menu_wait_for_event (0);
452 XtAppNextEvent (Xt_app_con
, &event
);
455 /* Make sure we don't consider buttons grabbed after menu goes.
456 And make sure to deactivate for any ButtonRelease,
457 even if XtDispatchEvent doesn't do that. */
458 if (event
.type
== ButtonRelease
459 && dpyinfo
->display
== event
.xbutton
.display
)
461 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
462 #ifdef USE_MOTIF /* Pretending that the event came from a
463 Btn1Down seems the only way to convince Motif to
464 activate its callbacks; setting the XmNmenuPost
465 isn't working. --marcus@sysc.pdx.edu. */
466 event
.xbutton
.button
= 1;
467 /* Motif only pops down menus when no Ctrl, Alt or Mod
468 key is pressed and the button is released. So reset key state
469 so Motif thinks this is the case. */
470 event
.xbutton
.state
= 0;
473 /* Pop down on C-g and Escape. */
474 else if (event
.type
== KeyPress
475 && dpyinfo
->display
== event
.xbutton
.display
)
477 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
479 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
480 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
481 popup_activated_flag
= 0;
484 x_dispatch_event (&event
, event
.xany
.display
);
488 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
489 doc
: /* Start key navigation of the menu bar in FRAME.
490 This initially opens the first menu bar item and you can then navigate with the
491 arrow keys, select a menu entry with the return key or cancel with the
492 escape key. If FRAME has no menu bar this function does nothing.
494 If FRAME is nil or not given, use the selected frame. */)
498 FRAME_PTR f
= check_x_frame (frame
);
502 if (FRAME_EXTERNAL_MENU_BAR (f
))
503 set_frame_menubar (f
, 0, 1);
505 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
511 x_catch_errors (FRAME_X_DISPLAY (f
));
512 memset (&ev
, 0, sizeof ev
);
513 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
514 ev
.xbutton
.window
= XtWindow (menubar
);
515 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
516 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
517 ev
.xbutton
.button
= Button1
;
518 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
519 ev
.xbutton
.same_screen
= True
;
526 XtSetArg (al
[0], XtNchildren
, &list
);
527 XtSetArg (al
[1], XtNnumChildren
, &nr
);
528 XtGetValues (menubar
, al
, 2);
529 ev
.xbutton
.window
= XtWindow (list
[0]);
533 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
534 /* From-window, to-window. */
535 ev
.xbutton
.window
, ev
.xbutton
.root
,
537 /* From-position, to-position. */
538 ev
.xbutton
.x
, ev
.xbutton
.y
,
539 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
543 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
548 ev
.type
= ButtonPress
;
549 ev
.xbutton
.state
= 0;
551 XtDispatchEvent (&ev
);
552 ev
.xbutton
.type
= ButtonRelease
;
553 ev
.xbutton
.state
= Button1Mask
;
554 XtDispatchEvent (&ev
);
562 #endif /* USE_X_TOOLKIT */
566 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
567 doc
: /* Start key navigation of the menu bar in FRAME.
568 This initially opens the first menu bar item and you can then navigate with the
569 arrow keys, select a menu entry with the return key or cancel with the
570 escape key. If FRAME has no menu bar this function does nothing.
572 If FRAME is nil or not given, use the selected frame. */)
578 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
582 f
= check_x_frame (frame
);
584 if (FRAME_EXTERNAL_MENU_BAR (f
))
585 set_frame_menubar (f
, 0, 1);
587 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
590 /* Activate the first menu. */
591 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
595 g_signal_emit_by_name (children
->data
, "activate_item");
596 popup_activated_flag
= 1;
597 g_list_free (children
);
605 /* Loop util popup_activated_flag is set to zero in a callback.
606 Used for popup menus and dialogs. */
609 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
611 ++popup_activated_flag
;
613 /* Process events in the Gtk event loop until done. */
614 while (popup_activated_flag
)
616 if (do_timers
) x_menu_wait_for_event (0);
617 gtk_main_iteration ();
622 /* Activate the menu bar of frame F.
623 This is called from keyboard.c when it gets the
624 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
626 To activate the menu bar, we use the X button-press event
627 that was saved in saved_menu_event.
628 That makes the toolkit do its thing.
630 But first we recompute the menu bar contents (the whole tree).
632 The reason for saving the button event until here, instead of
633 passing it to the toolkit right away, is that we can safely
634 execute Lisp code. */
637 x_activate_menubar (FRAME_PTR f
)
642 if (!f
->output_data
.x
->saved_menu_event
->type
)
646 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
647 f
->output_data
.x
->saved_menu_event
->xany
.window
))
651 set_frame_menubar (f
, 0, 1);
653 popup_activated_flag
= 1;
655 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
656 f
->output_data
.x
->saved_menu_event
);
658 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
662 /* Ignore this if we get it a second time. */
663 f
->output_data
.x
->saved_menu_event
->type
= 0;
666 /* This callback is invoked when the user selects a menubar cascade
667 pushbutton, but before the pulldown menu is posted. */
671 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
673 popup_activated_flag
= 1;
675 x_activate_timeout_atimer ();
680 /* This callback is invoked when a dialog or menu is finished being
681 used and has been unposted. */
685 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
687 popup_activated_flag
= 0;
691 popup_deactivate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
693 popup_activated_flag
= 0;
698 /* Function that finds the frame for WIDGET and shows the HELP text
700 F is the frame if known, or NULL if not known. */
702 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
708 XSETFRAME (frame
, f
);
709 kbd_buffer_store_help_event (frame
, help
);
713 #if 0 /* This code doesn't do anything useful. ++kfs */
714 /* WIDGET is the popup menu. It's parent is the frame's
715 widget. See which frame that is. */
716 xt_or_gtk_widget frame_widget
= XtParent (widget
);
719 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
723 && (f
= XFRAME (frame
),
724 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
728 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
732 /* Callback called when menu items are highlighted/unhighlighted
733 while moving the mouse over them. WIDGET is the menu bar or menu
734 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
735 the data structure for the menu item, or null in case of
740 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
742 xg_menu_item_cb_data
*cb_data
;
745 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
747 if (! cb_data
) return;
749 help
= call_data
? cb_data
->help
: Qnil
;
751 /* If popup_activated_flag is greater than 1 we are in a popup menu.
752 Don't pass the frame to show_help_event for those.
753 Passing frame creates an Emacs event. As we are looping in
754 popup_widget_loop, it won't be handled. Passing NULL shows the tip
755 directly without using an Emacs event. This is what the Lucid code
757 show_help_event (popup_activated_flag
<= 1 ? cb_data
->cl_data
->f
: NULL
,
762 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
767 widget_value
*wv
= (widget_value
*) call_data
;
769 help
= wv
? wv
->help
: Qnil
;
771 /* Determine the frame for the help event. */
772 f
= menubar_id_to_frame (id
);
774 show_help_event (f
, widget
, help
);
779 /* Gtk calls callbacks just because we tell it what item should be
780 selected in a radio group. If this variable is set to a non-zero
781 value, we are creating menus and don't want callbacks right now.
783 static int xg_crazy_callback_abort
;
785 /* This callback is called from the menu bar pulldown menu
786 when the user makes a selection.
787 Figure out what the user chose
788 and put the appropriate events into the keyboard buffer. */
790 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
792 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
794 if (xg_crazy_callback_abort
)
797 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
800 /* For a group of radio buttons, GTK calls the selection callback first
801 for the item that was active before the selection and then for the one that
802 is active after the selection. For C-h k this means we get the help on
803 the deselected item and then the selected item is executed. Prevent that
804 by ignoring the non-active item. */
805 if (GTK_IS_RADIO_MENU_ITEM (widget
)
806 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
809 /* When a menu is popped down, X generates a focus event (i.e. focus
810 goes back to the frame below the menu). Since GTK buffers events,
811 we force it out here before the menu selection event. Otherwise
812 sit-for will exit at once if the focus event follows the menu selection
816 while (gtk_events_pending ())
817 gtk_main_iteration ();
820 find_and_call_menu_selection (cb_data
->cl_data
->f
,
821 cb_data
->cl_data
->menu_bar_items_used
,
822 cb_data
->cl_data
->menu_bar_vector
,
826 #else /* not USE_GTK */
828 /* This callback is called from the menu bar pulldown menu
829 when the user makes a selection.
830 Figure out what the user chose
831 and put the appropriate events into the keyboard buffer. */
833 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
837 f
= menubar_id_to_frame (id
);
840 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
841 f
->menu_bar_vector
, client_data
);
843 #endif /* not USE_GTK */
845 /* Recompute all the widgets of frame F, when the menu bar has been
846 changed. Value is non-zero if widgets were updated. */
849 update_frame_menubar (FRAME_PTR f
)
852 return xg_update_frame_menubar (f
);
860 x
= f
->output_data
.x
;
862 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
866 /* Save the size of the frame because the pane widget doesn't accept
867 to resize itself. So force it. */
868 columns
= FRAME_COLS (f
);
869 rows
= FRAME_LINES (f
);
871 /* Do the voodoo which means "I'm changing lots of things, don't try
872 to refigure sizes until I'm done." */
873 lw_refigure_widget (x
->column_widget
, False
);
875 /* The order in which children are managed is the top to bottom
876 order in which they are displayed in the paned window. First,
877 remove the text-area widget. */
878 XtUnmanageChild (x
->edit_widget
);
880 /* Remove the menubar that is there now, and put up the menubar that
882 XtManageChild (x
->menubar_widget
);
883 XtMapWidget (x
->menubar_widget
);
884 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
886 /* Re-manage the text-area widget, and then thrash the sizes. */
887 XtManageChild (x
->edit_widget
);
888 lw_refigure_widget (x
->column_widget
, True
);
890 /* Force the pane widget to resize itself with the right values. */
891 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
899 apply_systemfont_to_dialog (Widget w
)
901 const char *fn
= xsettings_get_system_normal_font ();
904 XrmDatabase db
= XtDatabase (XtDisplay (w
));
906 XrmPutStringResource (&db
, "*dialog.font", fn
);
911 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
913 const char *fn
= xsettings_get_system_normal_font ();
917 XrmDatabase db
= XtDatabase (XtDisplay (w
));
920 XrmPutStringResource (&db
, "*menubar*font", fn
);
921 XrmPutStringResource (&db
, "*popup*font", fn
);
928 /* Set the contents of the menubar widgets of frame F.
929 The argument FIRST_TIME is currently ignored;
930 it is set the first time this is called, from initialize_frame_menubar. */
933 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
935 xt_or_gtk_widget menubar_widget
;
940 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
942 int *submenu_start
, *submenu_end
;
943 int *submenu_top_level_items
, *submenu_n_panes
;
948 menubar_widget
= f
->output_data
.x
->menubar_widget
;
950 XSETFRAME (Vmenu_updating_frame
, f
);
953 if (f
->output_data
.x
->id
== 0)
954 f
->output_data
.x
->id
= next_menubar_widget_id
++;
955 id
= f
->output_data
.x
->id
;
958 if (! menubar_widget
)
960 /* Make the first call for any given frame always go deep. */
961 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
964 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
965 f
->output_data
.x
->saved_menu_event
->type
= 0;
969 /* If we have detached menus, we must update deep so detached menus
970 also gets updated. */
971 deep_p
= deep_p
|| xg_have_tear_offs ();
976 /* Make a widget-value tree representing the entire menu trees. */
978 struct buffer
*prev
= current_buffer
;
980 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
981 int previous_menu_items_used
= f
->menu_bar_items_used
;
982 Lisp_Object
*previous_items
983 = (Lisp_Object
*) alloca (previous_menu_items_used
984 * sizeof (Lisp_Object
));
987 /* If we are making a new widget, its contents are empty,
988 do always reinitialize them. */
989 if (! menubar_widget
)
990 previous_menu_items_used
= 0;
992 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
993 specbind (Qinhibit_quit
, Qt
);
994 /* Don't let the debugger step into this code
995 because it is not reentrant. */
996 specbind (Qdebug_on_next_call
, Qnil
);
998 record_unwind_save_match_data ();
999 if (NILP (Voverriding_local_map_menu_flag
))
1001 specbind (Qoverriding_terminal_local_map
, Qnil
);
1002 specbind (Qoverriding_local_map
, Qnil
);
1005 set_buffer_internal_1 (XBUFFER (buffer
));
1007 /* Run the Lucid hook. */
1008 safe_run_hooks (Qactivate_menubar_hook
);
1010 /* If it has changed current-menubar from previous value,
1011 really recompute the menubar from the value. */
1012 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1013 call0 (Qrecompute_lucid_menubar
);
1014 safe_run_hooks (Qmenu_bar_update_hook
);
1015 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1017 items
= FRAME_MENU_BAR_ITEMS (f
);
1019 /* Save the frame's previous menu bar contents data. */
1020 if (previous_menu_items_used
)
1021 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1022 previous_menu_items_used
* sizeof (Lisp_Object
));
1024 /* Fill in menu_items with the current menu bar contents.
1025 This can evaluate Lisp code. */
1028 menu_items
= f
->menu_bar_vector
;
1029 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1030 subitems
= ASIZE (items
) / 4;
1031 submenu_start
= (int *) alloca ((subitems
+ 1) * sizeof (int));
1032 submenu_end
= (int *) alloca (subitems
* sizeof (int));
1033 submenu_n_panes
= (int *) alloca (subitems
* sizeof (int));
1034 submenu_top_level_items
= (int *) alloca (subitems
* sizeof (int));
1036 for (i
= 0; i
< subitems
; i
++)
1038 Lisp_Object key
, string
, maps
;
1040 key
= AREF (items
, 4 * i
);
1041 string
= AREF (items
, 4 * i
+ 1);
1042 maps
= AREF (items
, 4 * i
+ 2);
1046 submenu_start
[i
] = menu_items_used
;
1048 menu_items_n_panes
= 0;
1049 submenu_top_level_items
[i
]
1050 = parse_single_submenu (key
, string
, maps
);
1051 submenu_n_panes
[i
] = menu_items_n_panes
;
1053 submenu_end
[i
] = menu_items_used
;
1056 submenu_start
[i
] = -1;
1057 finish_menu_items ();
1059 /* Convert menu_items into widget_value trees
1060 to display the menu. This cannot evaluate Lisp code. */
1062 wv
= xmalloc_widget_value ();
1063 wv
->name
= "menubar";
1066 wv
->button_type
= BUTTON_TYPE_NONE
;
1070 for (i
= 0; 0 <= submenu_start
[i
]; i
++)
1072 menu_items_n_panes
= submenu_n_panes
[i
];
1073 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1074 submenu_top_level_items
[i
]);
1078 first_wv
->contents
= wv
;
1079 /* Don't set wv->name here; GC during the loop might relocate it. */
1081 wv
->button_type
= BUTTON_TYPE_NONE
;
1085 set_buffer_internal_1 (prev
);
1087 /* If there has been no change in the Lisp-level contents
1088 of the menu bar, skip redisplaying it. Just exit. */
1090 /* Compare the new menu items with the ones computed last time. */
1091 for (i
= 0; i
< previous_menu_items_used
; i
++)
1092 if (menu_items_used
== i
1093 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
1095 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1097 /* The menu items have not changed. Don't bother updating
1098 the menus in any form, since it would be a no-op. */
1099 free_menubar_widget_value_tree (first_wv
);
1100 discard_menu_items ();
1101 unbind_to (specpdl_count
, Qnil
);
1105 /* The menu items are different, so store them in the frame. */
1106 f
->menu_bar_vector
= menu_items
;
1107 f
->menu_bar_items_used
= menu_items_used
;
1109 /* This undoes save_menu_items. */
1110 unbind_to (specpdl_count
, Qnil
);
1112 /* Now GC cannot happen during the lifetime of the widget_value,
1113 so it's safe to store data from a Lisp_String. */
1114 wv
= first_wv
->contents
;
1115 for (i
= 0; i
< ASIZE (items
); i
+= 4)
1118 string
= AREF (items
, i
+ 1);
1121 wv
->name
= SSDATA (string
);
1122 update_submenu_strings (wv
->contents
);
1129 /* Make a widget-value tree containing
1130 just the top level menu bar strings. */
1132 wv
= xmalloc_widget_value ();
1133 wv
->name
= "menubar";
1136 wv
->button_type
= BUTTON_TYPE_NONE
;
1140 items
= FRAME_MENU_BAR_ITEMS (f
);
1141 for (i
= 0; i
< ASIZE (items
); i
+= 4)
1145 string
= AREF (items
, i
+ 1);
1149 wv
= xmalloc_widget_value ();
1150 wv
->name
= SSDATA (string
);
1153 wv
->button_type
= BUTTON_TYPE_NONE
;
1155 /* This prevents lwlib from assuming this
1156 menu item is really supposed to be empty. */
1157 /* The intptr_t cast avoids a warning.
1158 This value just has to be different from small integers. */
1159 wv
->call_data
= (void *) (intptr_t) (-1);
1164 first_wv
->contents
= wv
;
1168 /* Forget what we thought we knew about what is in the
1169 detailed contents of the menu bar menus.
1170 Changing the top level always destroys the contents. */
1171 f
->menu_bar_items_used
= 0;
1174 /* Create or update the menu bar widget. */
1179 xg_crazy_callback_abort
= 1;
1182 /* The fourth arg is DEEP_P, which says to consider the entire
1183 menu trees we supply, rather than just the menu bar item names. */
1184 xg_modify_menubar_widgets (menubar_widget
,
1188 G_CALLBACK (menubar_selection_callback
),
1189 G_CALLBACK (popup_deactivate_callback
),
1190 G_CALLBACK (menu_highlight_callback
));
1195 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1196 G_CALLBACK (menubar_selection_callback
),
1197 G_CALLBACK (popup_deactivate_callback
),
1198 G_CALLBACK (menu_highlight_callback
));
1200 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1204 #else /* not USE_GTK */
1207 /* Disable resizing (done for Motif!) */
1208 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1210 /* The third arg is DEEP_P, which says to consider the entire
1211 menu trees we supply, rather than just the menu bar item names. */
1212 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1214 /* Re-enable the edit widget to resize. */
1215 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1219 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1220 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1223 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
1225 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
1227 f
->output_data
.x
->column_widget
,
1229 popup_activate_callback
,
1230 menubar_selection_callback
,
1231 popup_deactivate_callback
,
1232 menu_highlight_callback
);
1233 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1235 /* Make menu pop down on C-g. */
1236 XtOverrideTranslations (menubar_widget
, override
);
1241 if (f
->output_data
.x
->menubar_widget
)
1242 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1245 = (f
->output_data
.x
->menubar_widget
1246 ? (f
->output_data
.x
->menubar_widget
->core
.height
1247 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1250 #if 1 /* Experimentally, we now get the right results
1251 for -geometry -0-0 without this. 24 Aug 96, rms.
1252 Maybe so, but the menu bar size is missing the pixels so the
1253 WM size hints are off by these pixels. Jan D, oct 2009. */
1255 if (FRAME_EXTERNAL_MENU_BAR (f
))
1258 XtVaGetValues (f
->output_data
.x
->column_widget
,
1259 XtNinternalBorderWidth
, &ibw
, NULL
);
1260 menubar_size
+= ibw
;
1262 #endif /* USE_LUCID */
1265 f
->output_data
.x
->menubar_height
= menubar_size
;
1267 #endif /* not USE_GTK */
1269 free_menubar_widget_value_tree (first_wv
);
1270 update_frame_menubar (f
);
1273 xg_crazy_callback_abort
= 0;
1279 /* Called from Fx_create_frame to create the initial menubar of a frame
1280 before it is mapped, so that the window is mapped with the menubar already
1281 there instead of us tacking it on later and thrashing the window after it
1285 initialize_frame_menubar (FRAME_PTR f
)
1287 /* This function is called before the first chance to redisplay
1288 the frame. It has to be, so the frame will have the right size. */
1289 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1290 set_frame_menubar (f
, 1, 1);
1294 /* Get rid of the menu bar of frame F, and free its storage.
1295 This is used when deleting a frame, and when turning off the menu bar.
1296 For GTK this function is in gtkutil.c. */
1300 free_frame_menubar (FRAME_PTR f
)
1302 Widget menubar_widget
;
1304 if (! FRAME_X_P (f
))
1307 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1309 f
->output_data
.x
->menubar_height
= 0;
1314 /* Removing the menu bar magically changes the shell widget's x
1315 and y position of (0, 0) which, when the menu bar is turned
1316 on again, leads to pull-down menus appearing in strange
1317 positions near the upper-left corner of the display. This
1318 happens only with some window managers like twm and ctwm,
1319 but not with other like Motif's mwm or kwm, because the
1320 latter generate ConfigureNotify events when the menu bar
1321 is switched off, which fixes the shell position. */
1322 Position x0
, y0
, x1
, y1
;
1328 if (f
->output_data
.x
->widget
)
1329 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1332 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1333 f
->output_data
.x
->menubar_widget
= NULL
;
1335 if (f
->output_data
.x
->widget
)
1338 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1339 if (x1
== 0 && y1
== 0)
1340 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1342 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1347 #endif /* not USE_GTK */
1349 #endif /* USE_X_TOOLKIT || USE_GTK */
1351 /* xmenu_show actually displays a menu using the panes and items in menu_items
1352 and returns the value selected from it.
1353 There are two versions of xmenu_show, one for Xt and one for Xlib.
1354 Both assume input is blocked by the caller. */
1356 /* F is the frame the menu is for.
1357 X and Y are the frame-relative specified position,
1358 relative to the inside upper left corner of the frame F.
1359 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1360 KEYMAPS is 1 if this menu was specified with keymaps;
1361 in that case, we return a list containing the chosen item's value
1362 and perhaps also the pane's prefix.
1363 TITLE is the specified menu title.
1364 ERROR is a place to store an error message string in case of failure.
1365 (We return nil on failure, but the value doesn't actually matter.) */
1367 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1369 /* The item selected in the popup menu. */
1370 static Lisp_Object
*volatile menu_item_selection
;
1374 /* Used when position a popup menu. See menu_position_func and
1375 create_and_show_popup_menu below. */
1376 struct next_popup_x_y
1383 /* The menu position function to use if we are not putting a popup
1384 menu where the pointer is.
1385 MENU is the menu to pop up.
1386 X and Y shall on exit contain x/y where the menu shall pop up.
1387 PUSH_IN is not documented in the GTK manual.
1388 USER_DATA is any data passed in when calling gtk_menu_popup.
1389 Here it points to a struct next_popup_x_y where the coordinates
1390 to store in *X and *Y are as well as the frame for the popup.
1392 Here only X and Y are used. */
1394 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1396 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1398 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1399 int disp_width
= x_display_pixel_width (dpyinfo
);
1400 int disp_height
= x_display_pixel_height (dpyinfo
);
1405 /* Check if there is room for the menu. If not, adjust x/y so that
1406 the menu is fully visible. */
1407 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1408 if (data
->x
+ req
.width
> disp_width
)
1409 *x
-= data
->x
+ req
.width
- disp_width
;
1410 if (data
->y
+ req
.height
> disp_height
)
1411 *y
-= data
->y
+ req
.height
- disp_height
;
1415 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1417 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1419 if (xg_crazy_callback_abort
) return;
1420 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1424 pop_down_menu (Lisp_Object arg
)
1426 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1428 popup_activated_flag
= 0;
1430 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1435 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1437 menu_item_selection will be set to the selection. */
1439 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
,
1440 int for_click
, Time timestamp
)
1444 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1445 struct next_popup_x_y popup_x_y
;
1446 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1447 int use_pos_func
= ! for_click
;
1450 /* Always use position function for Gtk3. Otherwise menus may become
1451 too small to show anything. */
1455 if (! FRAME_X_P (f
))
1458 xg_crazy_callback_abort
= 1;
1459 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1460 G_CALLBACK (popup_selection_callback
),
1461 G_CALLBACK (popup_deactivate_callback
),
1462 G_CALLBACK (menu_highlight_callback
));
1463 xg_crazy_callback_abort
= 0;
1467 /* Not invoked by a click. pop up at x/y. */
1468 pos_func
= menu_position_func
;
1470 /* Adjust coordinates to be root-window-relative. */
1471 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1472 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1478 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1483 for (i
= 0; i
< 5; i
++)
1484 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1488 /* Display the menu. */
1489 gtk_widget_show_all (menu
);
1491 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1492 timestamp
? timestamp
: gtk_get_current_event_time ());
1494 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1496 if (gtk_widget_get_mapped (menu
))
1498 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1499 two. show_help_echo uses this to detect popup menus. */
1500 popup_activated_flag
= 1;
1501 /* Process events that apply to the menu. */
1502 popup_widget_loop (1, menu
);
1505 unbind_to (specpdl_count
, Qnil
);
1507 /* Must reset this manually because the button release event is not passed
1508 to Emacs event loop. */
1509 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1512 #else /* not USE_GTK */
1514 /* We need a unique id for each widget handled by the Lucid Widget
1517 For the main windows, and popup menus, we use this counter,
1518 which we increment each time after use. This starts from 1<<16.
1520 For menu bars, we use numbers starting at 0, counted in
1521 next_menubar_widget_id. */
1522 LWLIB_ID widget_id_tick
;
1525 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1527 menu_item_selection
= (Lisp_Object
*) client_data
;
1530 /* ARG is the LWLIB ID of the dialog box, represented
1531 as a Lisp object as (HIGHPART . LOWPART). */
1534 pop_down_menu (Lisp_Object arg
)
1536 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1537 | XINT (XCDR (arg
)));
1540 lw_destroy_all_widgets (id
);
1542 popup_activated_flag
= 0;
1547 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1549 menu_item_selection will be set to the selection. */
1551 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
,
1552 int x
, int y
, int for_click
, Time timestamp
)
1558 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1562 if (! FRAME_X_P (f
))
1566 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1569 menu_id
= widget_id_tick
++;
1570 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1571 f
->output_data
.x
->widget
, 1, 0,
1572 popup_selection_callback
,
1573 popup_deactivate_callback
,
1574 menu_highlight_callback
);
1576 event
->type
= ButtonPress
;
1578 event
->send_event
= 0;
1579 event
->display
= FRAME_X_DISPLAY (f
);
1580 event
->time
= CurrentTime
;
1581 event
->root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1582 event
->window
= event
->subwindow
= event
->root
;
1586 /* Adjust coordinates to be root-window-relative. */
1587 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1588 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1595 for (i
= 0; i
< 5; i
++)
1596 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1599 /* Don't allow any geometry request from the user. */
1600 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1601 XtSetValues (menu
, av
, ac
);
1603 /* Display the menu. */
1604 lw_popup_menu (menu
, &dummy
);
1605 popup_activated_flag
= 1;
1606 x_activate_timeout_atimer ();
1609 int fact
= 4 * sizeof (LWLIB_ID
);
1610 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1611 record_unwind_protect (pop_down_menu
,
1612 Fcons (make_number (menu_id
>> (fact
)),
1613 make_number (menu_id
& ~(-1 << (fact
)))));
1615 /* Process events that apply to the menu. */
1616 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1618 unbind_to (specpdl_count
, Qnil
);
1622 #endif /* not USE_GTK */
1625 cleanup_widget_value_tree (Lisp_Object arg
)
1627 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1628 widget_value
*wv
= p
->pointer
;
1630 free_menubar_widget_value_tree (wv
);
1636 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1637 Lisp_Object title
, const char **error_name
, Time timestamp
)
1640 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1641 widget_value
**submenu_stack
1642 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1643 Lisp_Object
*subprefix_stack
1644 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1645 int submenu_depth
= 0;
1649 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1651 if (! FRAME_X_P (f
))
1656 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1658 *error_name
= "Empty menu";
1662 /* Create a tree of widget_value objects
1663 representing the panes and their items. */
1664 wv
= xmalloc_widget_value ();
1668 wv
->button_type
= BUTTON_TYPE_NONE
;
1673 /* Loop over all panes and items, filling in the tree. */
1675 while (i
< menu_items_used
)
1677 if (EQ (AREF (menu_items
, i
), Qnil
))
1679 submenu_stack
[submenu_depth
++] = save_wv
;
1685 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1688 save_wv
= submenu_stack
[--submenu_depth
];
1692 else if (EQ (AREF (menu_items
, i
), Qt
)
1693 && submenu_depth
!= 0)
1694 i
+= MENU_ITEMS_PANE_LENGTH
;
1695 /* Ignore a nil in the item list.
1696 It's meaningful only for dialog boxes. */
1697 else if (EQ (AREF (menu_items
, i
), Qquote
))
1699 else if (EQ (AREF (menu_items
, i
), Qt
))
1701 /* Create a new pane. */
1702 Lisp_Object pane_name
, prefix
;
1703 const char *pane_string
;
1705 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1706 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1708 #ifndef HAVE_MULTILINGUAL_MENU
1709 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1711 pane_name
= ENCODE_MENU_STRING (pane_name
);
1712 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1715 pane_string
= (NILP (pane_name
)
1716 ? "" : SSDATA (pane_name
));
1717 /* If there is just one top-level pane, put all its items directly
1718 under the top-level menu. */
1719 if (menu_items_n_panes
== 1)
1722 /* If the pane has a meaningful name,
1723 make the pane a top-level menu item
1724 with its items as a submenu beneath it. */
1725 if (!keymaps
&& strcmp (pane_string
, ""))
1727 wv
= xmalloc_widget_value ();
1731 first_wv
->contents
= wv
;
1732 wv
->name
= (char *) pane_string
;
1733 if (keymaps
&& !NILP (prefix
))
1737 wv
->button_type
= BUTTON_TYPE_NONE
;
1742 else if (first_pane
)
1748 i
+= MENU_ITEMS_PANE_LENGTH
;
1752 /* Create a new item within current pane. */
1753 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1754 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1755 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1756 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1757 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1758 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1759 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1760 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1762 #ifndef HAVE_MULTILINGUAL_MENU
1763 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1765 item_name
= ENCODE_MENU_STRING (item_name
);
1766 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1769 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1771 descrip
= ENCODE_MENU_STRING (descrip
);
1772 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1774 #endif /* not HAVE_MULTILINGUAL_MENU */
1776 wv
= xmalloc_widget_value ();
1780 save_wv
->contents
= wv
;
1781 wv
->name
= SSDATA (item_name
);
1782 if (!NILP (descrip
))
1783 wv
->key
= SSDATA (descrip
);
1785 /* If this item has a null value,
1786 make the call_data null so that it won't display a box
1787 when the mouse is on it. */
1789 = (!NILP (def
) ? (void *) &AREF (menu_items
, i
) : 0);
1790 wv
->enabled
= !NILP (enable
);
1793 wv
->button_type
= BUTTON_TYPE_NONE
;
1794 else if (EQ (type
, QCtoggle
))
1795 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1796 else if (EQ (type
, QCradio
))
1797 wv
->button_type
= BUTTON_TYPE_RADIO
;
1801 wv
->selected
= !NILP (selected
);
1803 if (! STRINGP (help
))
1810 i
+= MENU_ITEMS_ITEM_LENGTH
;
1814 /* Deal with the title, if it is non-nil. */
1817 widget_value
*wv_title
= xmalloc_widget_value ();
1818 widget_value
*wv_sep1
= xmalloc_widget_value ();
1819 widget_value
*wv_sep2
= xmalloc_widget_value ();
1821 wv_sep2
->name
= "--";
1822 wv_sep2
->next
= first_wv
->contents
;
1823 wv_sep2
->help
= Qnil
;
1825 wv_sep1
->name
= "--";
1826 wv_sep1
->next
= wv_sep2
;
1827 wv_sep1
->help
= Qnil
;
1829 #ifndef HAVE_MULTILINGUAL_MENU
1830 if (STRING_MULTIBYTE (title
))
1831 title
= ENCODE_MENU_STRING (title
);
1834 wv_title
->name
= SSDATA (title
);
1835 wv_title
->enabled
= TRUE
;
1836 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1837 wv_title
->help
= Qnil
;
1838 wv_title
->next
= wv_sep1
;
1839 first_wv
->contents
= wv_title
;
1842 /* No selection has been chosen yet. */
1843 menu_item_selection
= 0;
1845 /* Make sure to free the widget_value objects we used to specify the
1846 contents even with longjmp. */
1847 record_unwind_protect (cleanup_widget_value_tree
,
1848 make_save_value (first_wv
, 0));
1850 /* Actually create and show the menu until popped down. */
1851 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1853 unbind_to (specpdl_count
, Qnil
);
1855 /* Find the selected item, and its pane, to return
1856 the proper value. */
1857 if (menu_item_selection
!= 0)
1859 Lisp_Object prefix
, entry
;
1861 prefix
= entry
= Qnil
;
1863 while (i
< menu_items_used
)
1865 if (EQ (AREF (menu_items
, i
), Qnil
))
1867 subprefix_stack
[submenu_depth
++] = prefix
;
1871 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1873 prefix
= subprefix_stack
[--submenu_depth
];
1876 else if (EQ (AREF (menu_items
, i
), Qt
))
1879 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1880 i
+= MENU_ITEMS_PANE_LENGTH
;
1882 /* Ignore a nil in the item list.
1883 It's meaningful only for dialog boxes. */
1884 else if (EQ (AREF (menu_items
, i
), Qquote
))
1889 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1890 if (menu_item_selection
== &AREF (menu_items
, i
))
1896 entry
= Fcons (entry
, Qnil
);
1898 entry
= Fcons (prefix
, entry
);
1899 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1900 if (!NILP (subprefix_stack
[j
]))
1901 entry
= Fcons (subprefix_stack
[j
], entry
);
1905 i
+= MENU_ITEMS_ITEM_LENGTH
;
1909 else if (!for_click
)
1910 /* Make "Cancel" equivalent to C-g. */
1911 Fsignal (Qquit
, Qnil
);
1918 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1920 /* Treat the pointer as an integer. There's no problem
1921 as long as pointers have enough bits to hold small integers. */
1922 if ((intptr_t) client_data
!= -1)
1923 menu_item_selection
= (Lisp_Object
*) client_data
;
1925 popup_activated_flag
= 0;
1928 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1930 menu_item_selection will be set to the selection. */
1932 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1936 if (! FRAME_X_P (f
))
1939 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1940 G_CALLBACK (dialog_selection_callback
),
1941 G_CALLBACK (popup_deactivate_callback
),
1946 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1947 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1949 /* Display the menu. */
1950 gtk_widget_show_all (menu
);
1952 /* Process events that apply to the menu. */
1953 popup_widget_loop (1, menu
);
1955 unbind_to (specpdl_count
, Qnil
);
1959 #else /* not USE_GTK */
1961 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1963 /* Treat the pointer as an integer. There's no problem
1964 as long as pointers have enough bits to hold small integers. */
1965 if ((intptr_t) client_data
!= -1)
1966 menu_item_selection
= (Lisp_Object
*) client_data
;
1969 lw_destroy_all_widgets (id
);
1971 popup_activated_flag
= 0;
1975 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1977 menu_item_selection will be set to the selection. */
1979 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1986 dialog_id
= widget_id_tick
++;
1988 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1990 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1991 f
->output_data
.x
->widget
, 1, 0,
1992 dialog_selection_callback
, 0, 0);
1993 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1994 /* Display the dialog box. */
1995 lw_pop_up_all_widgets (dialog_id
);
1996 popup_activated_flag
= 1;
1997 x_activate_timeout_atimer ();
1999 /* Process events that apply to the dialog box.
2000 Also handle timers. */
2002 ptrdiff_t count
= SPECPDL_INDEX ();
2003 int fact
= 4 * sizeof (LWLIB_ID
);
2005 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2006 record_unwind_protect (pop_down_menu
,
2007 Fcons (make_number (dialog_id
>> (fact
)),
2008 make_number (dialog_id
& ~(-1 << (fact
)))));
2010 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2013 unbind_to (count
, Qnil
);
2017 #endif /* not USE_GTK */
2019 static const char * button_names
[] = {
2020 "button1", "button2", "button3", "button4", "button5",
2021 "button6", "button7", "button8", "button9", "button10" };
2024 xdialog_show (FRAME_PTR f
,
2028 const char **error_name
)
2030 int i
, nb_buttons
=0;
2031 char dialog_name
[6];
2033 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2035 /* Number of elements seen so far, before boundary. */
2037 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2038 int boundary_seen
= 0;
2040 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2042 if (! FRAME_X_P (f
))
2047 if (menu_items_n_panes
> 1)
2049 *error_name
= "Multiple panes in dialog box";
2053 /* Create a tree of widget_value objects
2054 representing the text label and buttons. */
2056 Lisp_Object pane_name
, prefix
;
2057 const char *pane_string
;
2058 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
2059 prefix
= AREF (menu_items
, MENU_ITEMS_PANE_PREFIX
);
2060 pane_string
= (NILP (pane_name
)
2061 ? "" : SSDATA (pane_name
));
2062 prev_wv
= xmalloc_widget_value ();
2063 prev_wv
->value
= (char *) pane_string
;
2064 if (keymaps
&& !NILP (prefix
))
2066 prev_wv
->enabled
= 1;
2067 prev_wv
->name
= "message";
2068 prev_wv
->help
= Qnil
;
2071 /* Loop over all panes and items, filling in the tree. */
2072 i
= MENU_ITEMS_PANE_LENGTH
;
2073 while (i
< menu_items_used
)
2076 /* Create a new item within current pane. */
2077 Lisp_Object item_name
, enable
, descrip
;
2078 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2079 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2081 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2083 if (NILP (item_name
))
2085 free_menubar_widget_value_tree (first_wv
);
2086 *error_name
= "Submenu in dialog items";
2089 if (EQ (item_name
, Qquote
))
2091 /* This is the boundary between left-side elts
2092 and right-side elts. Stop incrementing right_count. */
2097 if (nb_buttons
>= 9)
2099 free_menubar_widget_value_tree (first_wv
);
2100 *error_name
= "Too many dialog items";
2104 wv
= xmalloc_widget_value ();
2106 wv
->name
= (char *) button_names
[nb_buttons
];
2107 if (!NILP (descrip
))
2108 wv
->key
= SSDATA (descrip
);
2109 wv
->value
= SSDATA (item_name
);
2110 wv
->call_data
= (void *) &AREF (menu_items
, i
);
2111 wv
->enabled
= !NILP (enable
);
2115 if (! boundary_seen
)
2119 i
+= MENU_ITEMS_ITEM_LENGTH
;
2122 /* If the boundary was not specified,
2123 by default put half on the left and half on the right. */
2124 if (! boundary_seen
)
2125 left_count
= nb_buttons
- nb_buttons
/ 2;
2127 wv
= xmalloc_widget_value ();
2128 wv
->name
= dialog_name
;
2131 /* Frame title: 'Q' = Question, 'I' = Information.
2132 Can also have 'E' = Error if, one day, we want
2133 a popup for errors. */
2135 dialog_name
[0] = 'Q';
2137 dialog_name
[0] = 'I';
2139 /* Dialog boxes use a really stupid name encoding
2140 which specifies how many buttons to use
2141 and how many buttons are on the right. */
2142 dialog_name
[1] = '0' + nb_buttons
;
2143 dialog_name
[2] = 'B';
2144 dialog_name
[3] = 'R';
2145 /* Number of buttons to put on the right. */
2146 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2148 wv
->contents
= first_wv
;
2152 /* No selection has been chosen yet. */
2153 menu_item_selection
= 0;
2155 /* Make sure to free the widget_value objects we used to specify the
2156 contents even with longjmp. */
2157 record_unwind_protect (cleanup_widget_value_tree
,
2158 make_save_value (first_wv
, 0));
2160 /* Actually create and show the dialog. */
2161 create_and_show_dialog (f
, first_wv
);
2163 unbind_to (specpdl_count
, Qnil
);
2165 /* Find the selected item, and its pane, to return
2166 the proper value. */
2167 if (menu_item_selection
!= 0)
2173 while (i
< menu_items_used
)
2177 if (EQ (AREF (menu_items
, i
), Qt
))
2180 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2181 i
+= MENU_ITEMS_PANE_LENGTH
;
2183 else if (EQ (AREF (menu_items
, i
), Qquote
))
2185 /* This is the boundary between left-side elts and
2192 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2193 if (menu_item_selection
== &AREF (menu_items
, i
))
2197 entry
= Fcons (entry
, Qnil
);
2199 entry
= Fcons (prefix
, entry
);
2203 i
+= MENU_ITEMS_ITEM_LENGTH
;
2208 /* Make "Cancel" equivalent to C-g. */
2209 Fsignal (Qquit
, Qnil
);
2214 #else /* not USE_X_TOOLKIT && not USE_GTK */
2216 /* The frame of the last activated non-toolkit menu bar.
2217 Used to generate menu help events. */
2219 static struct frame
*menu_help_frame
;
2222 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2224 PANE is the pane number, and ITEM is the menu item number in
2225 the menu (currently not used).
2227 This cannot be done with generating a HELP_EVENT because
2228 XMenuActivate contains a loop that doesn't let Emacs process
2232 menu_help_callback (char const *help_string
, int pane
, int item
)
2234 Lisp_Object
*first_item
;
2235 Lisp_Object pane_name
;
2236 Lisp_Object menu_object
;
2238 first_item
= XVECTOR (menu_items
)->contents
;
2239 if (EQ (first_item
[0], Qt
))
2240 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2241 else if (EQ (first_item
[0], Qquote
))
2242 /* This shouldn't happen, see xmenu_show. */
2243 pane_name
= empty_unibyte_string
;
2245 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2247 /* (menu-item MENU-NAME PANE-NUMBER) */
2248 menu_object
= Fcons (Qmenu_item
,
2250 Fcons (make_number (pane
), Qnil
)));
2251 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2252 Qnil
, menu_object
, make_number (item
));
2256 pop_down_menu (Lisp_Object arg
)
2258 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2259 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2261 FRAME_PTR f
= p1
->pointer
;
2262 XMenu
*menu
= p2
->pointer
;
2266 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2267 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2269 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2271 #ifdef HAVE_X_WINDOWS
2272 /* Assume the mouse has moved out of the X window.
2273 If it has actually moved in, we will get an EnterNotify. */
2274 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2276 /* State that no mouse buttons are now held.
2277 (The oldXMenu code doesn't track this info for us.)
2278 That is not necessarily true, but the fiction leads to reasonable
2279 results, and it is a pain to ask which are actually held now. */
2280 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2282 #endif /* HAVE_X_WINDOWS */
2291 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
2292 Lisp_Object title
, const char **error_name
, Time timestamp
)
2296 int pane
, selidx
, lpane
, status
;
2297 Lisp_Object entry
, pane_prefix
;
2299 int ulx
, uly
, width
, height
;
2300 int dispwidth
, dispheight
;
2301 int i
, j
, lines
, maxlines
;
2304 unsigned int dummy_uint
;
2305 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2307 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2311 if (menu_items_n_panes
== 0)
2314 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2316 *error_name
= "Empty menu";
2320 /* Figure out which root window F is on. */
2321 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2322 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2323 &dummy_uint
, &dummy_uint
);
2325 /* Make the menu on that window. */
2326 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2329 *error_name
= "Can't create menu";
2333 /* Don't GC while we prepare and show the menu,
2334 because we give the oldxmenu library pointers to the
2335 contents of strings. */
2336 inhibit_garbage_collection ();
2338 #ifdef HAVE_X_WINDOWS
2339 /* Adjust coordinates to relative to the outer (window manager) window. */
2340 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2341 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2342 #endif /* HAVE_X_WINDOWS */
2344 /* Adjust coordinates to be root-window-relative. */
2348 /* Create all the necessary panes and their items. */
2349 maxwidth
= maxlines
= lines
= i
= 0;
2351 while (i
< menu_items_used
)
2353 if (EQ (AREF (menu_items
, i
), Qt
))
2355 /* Create a new pane. */
2356 Lisp_Object pane_name
, prefix
;
2357 const char *pane_string
;
2359 maxlines
= max (maxlines
, lines
);
2361 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2362 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2363 pane_string
= (NILP (pane_name
)
2364 ? "" : SSDATA (pane_name
));
2365 if (keymaps
&& !NILP (prefix
))
2368 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2369 if (lpane
== XM_FAILURE
)
2371 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2372 *error_name
= "Can't create pane";
2375 i
+= MENU_ITEMS_PANE_LENGTH
;
2377 /* Find the width of the widest item in this pane. */
2379 while (j
< menu_items_used
)
2382 item
= AREF (menu_items
, j
);
2390 width
= SBYTES (item
);
2391 if (width
> maxwidth
)
2394 j
+= MENU_ITEMS_ITEM_LENGTH
;
2397 /* Ignore a nil in the item list.
2398 It's meaningful only for dialog boxes. */
2399 else if (EQ (AREF (menu_items
, i
), Qquote
))
2403 /* Create a new item within current pane. */
2404 Lisp_Object item_name
, enable
, descrip
, help
;
2406 char const *help_string
;
2408 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2409 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2411 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2412 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2413 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2415 if (!NILP (descrip
))
2417 /* if alloca is fast, use that to make the space,
2418 to reduce gc needs. */
2419 item_data
= (char *) alloca (maxwidth
+ SBYTES (descrip
) + 1);
2420 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2421 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2423 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2424 item_data
[j
+ SBYTES (descrip
)] = 0;
2427 item_data
= SSDATA (item_name
);
2429 if (lpane
== XM_FAILURE
2430 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2431 menu
, lpane
, 0, item_data
,
2432 !NILP (enable
), help_string
)
2435 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2436 *error_name
= "Can't add selection to menu";
2439 i
+= MENU_ITEMS_ITEM_LENGTH
;
2444 maxlines
= max (maxlines
, lines
);
2446 /* All set and ready to fly. */
2447 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2448 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2449 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2450 x
= min (x
, dispwidth
);
2451 y
= min (y
, dispheight
);
2454 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2455 &ulx
, &uly
, &width
, &height
);
2456 if (ulx
+width
> dispwidth
)
2458 x
-= (ulx
+ width
) - dispwidth
;
2459 ulx
= dispwidth
- width
;
2461 if (uly
+height
> dispheight
)
2463 y
-= (uly
+ height
) - dispheight
;
2464 uly
= dispheight
- height
;
2466 #ifndef HAVE_X_WINDOWS
2467 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2469 /* Move the menu away of the echo area, to avoid overwriting the
2470 menu with help echo messages or vice versa. */
2471 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2473 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2474 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2483 if (ulx
< 0) x
-= ulx
;
2484 if (uly
< 0) y
-= uly
;
2488 /* If position was not given by a mouse click, adjust so upper left
2489 corner of the menu as a whole ends up at given coordinates. This
2490 is what x-popup-menu says in its documentation. */
2492 y
+= 1.5*height
/(maxlines
+2);
2495 XMenuSetAEQ (menu
, TRUE
);
2496 XMenuSetFreeze (menu
, TRUE
);
2500 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2503 record_unwind_protect (pop_down_menu
,
2504 Fcons (make_save_value (f
, 0),
2505 make_save_value (menu
, 0)));
2507 /* Help display under X won't work because XMenuActivate contains
2508 a loop that doesn't give Emacs a chance to process it. */
2509 menu_help_frame
= f
;
2510 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2511 x
, y
, ButtonReleaseMask
, &datap
,
2512 menu_help_callback
);
2513 entry
= pane_prefix
= Qnil
;
2519 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2522 /* Find the item number SELIDX in pane number PANE. */
2524 while (i
< menu_items_used
)
2526 if (EQ (AREF (menu_items
, i
), Qt
))
2530 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2532 i
+= MENU_ITEMS_PANE_LENGTH
;
2541 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2544 entry
= Fcons (entry
, Qnil
);
2545 if (!NILP (pane_prefix
))
2546 entry
= Fcons (pane_prefix
, entry
);
2552 i
+= MENU_ITEMS_ITEM_LENGTH
;
2558 *error_name
= "Can't activate menu";
2562 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2563 the menu was invoked with a mouse event as POSITION). */
2565 Fsignal (Qquit
, Qnil
);
2569 unbind_to (specpdl_count
, Qnil
);
2574 #endif /* not USE_X_TOOLKIT */
2576 #endif /* HAVE_MENUS */
2579 /* Detect if a dialog or menu has been posted. MSDOS has its own
2580 implementation on msdos.c. */
2583 popup_activated (void)
2585 return popup_activated_flag
;
2587 #endif /* not MSDOS */
2589 /* The following is used by delayed window autoselection. */
2591 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2592 doc
: /* Return t if a menu or popup dialog is active. */)
2596 return (popup_activated ()) ? Qt
: Qnil
;
2599 #endif /* HAVE_MENUS */
2603 syms_of_xmenu (void)
2605 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2607 #ifdef USE_X_TOOLKIT
2608 widget_id_tick
= (1<<16);
2609 next_menubar_widget_id
= 1;
2612 defsubr (&Smenu_or_popup_active_p
);
2614 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2615 defsubr (&Sx_menu_bar_open_internal
);
2616 Ffset (intern_c_string ("accelerate-menu"),
2617 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2621 defsubr (&Sx_popup_dialog
);