1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
27 /* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
30 /* Rewritten for clarity and GC protection by rms in Feb 94. */
34 #if 0 /* Why was this included? And without syssignal.h? */
35 /* On 4.3 this loses if it comes after xterm.h. */
46 #include "termhooks.h"
48 #include "blockinput.h"
52 #include "sysselect.h"
59 /* This may include sys/types.h, and that somehow loses
60 if this is not done before the other system files. */
64 /* Load sys/types.h if not already loaded.
65 In some systems loading it twice is suicidal. */
67 #include <sys/types.h>
70 #include "dispextern.h"
73 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
74 code accepts the Emacs internal encoding. */
75 #undef HAVE_MULTILINGUAL_MENU
79 #include <X11/IntrinsicP.h>
80 #include <X11/CoreP.h>
81 #include <X11/StringDefs.h>
82 #include <X11/Shell.h>
84 #include "xsettings.h"
85 #include "../lwlib/xlwmenu.h"
87 #include <X11/Xaw3d/Paned.h>
88 #else /* !HAVE_XAW3D */
89 #include <X11/Xaw/Paned.h>
90 #endif /* HAVE_XAW3D */
91 #endif /* USE_LUCID */
92 #include "../lwlib/lwlib.h"
93 #else /* not USE_X_TOOLKIT */
95 #include "../oldXMenu/XMenu.h"
97 #endif /* not USE_X_TOOLKIT */
98 #endif /* HAVE_X_WINDOWS */
111 Lisp_Object Qdebug_on_next_call
;
113 extern Lisp_Object Qmenu_bar
;
115 extern Lisp_Object QCtoggle
, QCradio
;
117 extern Lisp_Object Voverriding_local_map
;
118 extern Lisp_Object Voverriding_local_map_menu_flag
;
120 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
122 extern Lisp_Object Qmenu_bar_update_hook
;
125 extern void set_frame_menubar (FRAME_PTR
, int, int);
126 extern XtAppContext Xt_app_con
;
128 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
130 static void popup_get_selection (XEvent
*, struct x_display_info
*,
132 #endif /* USE_X_TOOLKIT */
135 extern void set_frame_menubar (FRAME_PTR
, int, int);
136 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
140 static int update_frame_menubar (struct frame
*);
142 /* Flag which when set indicates a dialog or menu has been posted by
143 Xt on behalf of one of the widget sets. */
144 static int popup_activated_flag
;
146 static int next_menubar_widget_id
;
148 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
149 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
150 extern widget_value
*xmalloc_widget_value (void);
151 extern widget_value
*digest_single_submenu (int, int, int);
157 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
159 static struct frame
*
160 menubar_id_to_frame (LWLIB_ID id
)
162 Lisp_Object tail
, frame
;
165 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
171 if (!FRAME_WINDOW_P (f
))
173 if (f
->output_data
.x
->id
== id
)
181 #ifdef HAVE_X_WINDOWS
182 /* Return the mouse position in *X and *Y. The coordinates are window
183 relative for the edit window in frame F.
184 This is for Fx_popup_menu. The mouse_position_hook can not
185 be used for X, as it returns window relative coordinates
186 for the window where the mouse is in. This could be the menu bar,
187 the scroll bar or the edit window. Fx_popup_menu needs to be
188 sure it is the edit window. */
190 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
192 Window root
, dummy_window
;
200 XQueryPointer (FRAME_X_DISPLAY (f
),
201 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
203 /* The root window which contains the pointer. */
206 /* Window pointer is on, not used */
209 /* The position on that root window. */
212 /* x/y in dummy_window coordinates, not used. */
215 /* Modifier keys and pointer buttons, about which
217 (unsigned int *) &dummy
);
221 /* xmenu_show expects window coordinates, not root window
222 coordinates. Translate. */
223 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
224 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
227 #endif /* HAVE_X_WINDOWS */
231 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
232 doc
: /* Pop up a dialog box and return user's selection.
233 POSITION specifies which frame to use.
234 This is normally a mouse button event or a window or frame.
235 If POSITION is t, it means to use the frame the mouse is on.
236 The dialog box appears in the middle of the specified frame.
238 CONTENTS specifies the alternatives to display in the dialog box.
239 It is a list of the form (DIALOG ITEM1 ITEM2...).
240 Each ITEM is a cons cell (STRING . VALUE).
241 The return value is VALUE from the chosen item.
243 An ITEM may also be just a string--that makes a nonselectable item.
244 An ITEM may also be nil--that means to put all preceding items
245 on the left of the dialog box and all following items on the right.
246 \(By default, approximately half appear on each side.)
248 If HEADER is non-nil, the frame title for the box is "Information",
249 otherwise it is "Question".
251 If the user gets rid of the dialog box without making a valid choice,
252 for instance using the window manager, then this produces a quit and
253 `x-popup-dialog' does not return. */)
254 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
261 /* Decode the first argument: find the window or frame to use. */
262 if (EQ (position
, Qt
)
263 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
264 || EQ (XCAR (position
), Qtool_bar
))))
266 #if 0 /* Using the frame the mouse is on may not be right. */
267 /* Use the mouse's current position. */
268 FRAME_PTR new_f
= SELECTED_FRAME ();
269 Lisp_Object bar_window
;
270 enum scroll_bar_part part
;
274 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
277 XSETFRAME (window
, new_f
);
279 window
= selected_window
;
281 window
= selected_window
;
283 else if (CONSP (position
))
286 tem
= Fcar (position
);
288 window
= Fcar (Fcdr (position
));
291 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
292 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
295 else if (WINDOWP (position
) || FRAMEP (position
))
300 /* Decode where to put the menu. */
304 else if (WINDOWP (window
))
306 CHECK_LIVE_WINDOW (window
);
307 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
310 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
311 but I don't want to make one now. */
312 CHECK_WINDOW (window
);
314 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
315 error ("Can not put X dialog on this terminal");
317 /* Force a redisplay before showing the dialog. If a frame is created
318 just before showing the dialog, its contents may not have been fully
319 drawn, as this depends on timing of events from the X server. Redisplay
320 is not done when a dialog is shown. If redisplay could be done in the
321 X event loop (i.e. the X event loop does not run in a signal handler)
322 this would not be needed.
324 Do this before creating the widget value that points to Lisp
325 string contents, because Fredisplay may GC and relocate them. */
328 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
329 /* Display a menu with these alternatives
330 in the middle of frame F. */
332 Lisp_Object x
, y
, frame
, newpos
;
333 XSETFRAME (frame
, f
);
334 XSETINT (x
, x_pixel_width (f
) / 2);
335 XSETINT (y
, x_pixel_height (f
) / 2);
336 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
338 return Fx_popup_menu (newpos
,
339 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
345 Lisp_Object selection
;
346 int specpdl_count
= SPECPDL_INDEX ();
348 /* Decode the dialog items from what was specified. */
349 title
= Fcar (contents
);
350 CHECK_STRING (title
);
351 record_unwind_protect (unuse_menu_items
, Qnil
);
353 if (NILP (Fcar (Fcdr (contents
))))
354 /* No buttons specified, add an "Ok" button so users can pop down
355 the dialog. Also, the lesstif/motif version crashes if there are
357 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
359 list_of_panes (Fcons (contents
, Qnil
));
361 /* Display them in a dialog box. */
363 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
366 unbind_to (specpdl_count
, Qnil
);
367 discard_menu_items ();
369 if (error_name
) error (error_name
);
378 /* Set menu_items_inuse so no other popup menu or dialog is created. */
381 x_menu_set_in_use (int in_use
)
383 menu_items_inuse
= in_use
? Qt
: Qnil
;
384 popup_activated_flag
= in_use
;
386 if (popup_activated_flag
)
387 x_activate_timeout_atimer ();
391 /* Wait for an X event to arrive or for a timer to expire. */
394 x_menu_wait_for_event (void *data
)
396 /* Another way to do this is to register a timer callback, that can be
397 done in GTK and Xt. But we have to do it like this when using only X
398 anyway, and with callbacks we would have three variants for timer handling
399 instead of the small ifdefs below. */
403 ! XtAppPending (Xt_app_con
)
404 #elif defined USE_GTK
405 ! gtk_events_pending ()
407 ! XPending ((Display
*) data
)
411 EMACS_TIME next_time
= timer_check (1), *ntp
;
412 long secs
= EMACS_SECS (next_time
);
413 long usecs
= EMACS_USECS (next_time
);
414 SELECT_TYPE read_fds
;
415 struct x_display_info
*dpyinfo
;
419 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
421 int fd
= ConnectionNumber (dpyinfo
->display
);
422 FD_SET (fd
, &read_fds
);
424 XFlush (dpyinfo
->display
);
427 if (secs
< 0 && usecs
< 0)
432 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
438 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
442 /* Loop in Xt until the menu pulldown or dialog popup has been
443 popped down (deactivated). This is used for x-popup-menu
444 and x-popup-dialog; it is not used for the menu bar.
446 NOTE: All calls to popup_get_selection should be protected
447 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
450 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
454 while (popup_activated_flag
)
458 event
= *initial_event
;
463 if (do_timers
) x_menu_wait_for_event (0);
464 XtAppNextEvent (Xt_app_con
, &event
);
467 /* Make sure we don't consider buttons grabbed after menu goes.
468 And make sure to deactivate for any ButtonRelease,
469 even if XtDispatchEvent doesn't do that. */
470 if (event
.type
== ButtonRelease
471 && dpyinfo
->display
== event
.xbutton
.display
)
473 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
474 #ifdef USE_MOTIF /* Pretending that the event came from a
475 Btn1Down seems the only way to convince Motif to
476 activate its callbacks; setting the XmNmenuPost
477 isn't working. --marcus@sysc.pdx.edu. */
478 event
.xbutton
.button
= 1;
479 /* Motif only pops down menus when no Ctrl, Alt or Mod
480 key is pressed and the button is released. So reset key state
481 so Motif thinks this is the case. */
482 event
.xbutton
.state
= 0;
485 /* Pop down on C-g and Escape. */
486 else if (event
.type
== KeyPress
487 && dpyinfo
->display
== event
.xbutton
.display
)
489 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
491 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
492 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
493 popup_activated_flag
= 0;
496 x_dispatch_event (&event
, event
.xany
.display
);
500 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
501 doc
: /* Start key navigation of the menu bar in FRAME.
502 This initially opens the first menu bar item and you can then navigate with the
503 arrow keys, select a menu entry with the return key or cancel with the
504 escape key. If FRAME has no menu bar this function does nothing.
506 If FRAME is nil or not given, use the selected frame. */)
510 FRAME_PTR f
= check_x_frame (frame
);
514 if (FRAME_EXTERNAL_MENU_BAR (f
))
515 set_frame_menubar (f
, 0, 1);
517 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
523 x_catch_errors (FRAME_X_DISPLAY (f
));
524 memset (&ev
, 0, sizeof ev
);
525 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
526 ev
.xbutton
.window
= XtWindow (menubar
);
527 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
528 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
529 ev
.xbutton
.button
= Button1
;
530 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
531 ev
.xbutton
.same_screen
= True
;
538 XtSetArg (al
[0], XtNchildren
, &list
);
539 XtSetArg (al
[1], XtNnumChildren
, &nr
);
540 XtGetValues (menubar
, al
, 2);
541 ev
.xbutton
.window
= XtWindow (list
[0]);
545 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
546 /* From-window, to-window. */
547 ev
.xbutton
.window
, ev
.xbutton
.root
,
549 /* From-position, to-position. */
550 ev
.xbutton
.x
, ev
.xbutton
.y
,
551 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
555 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
560 ev
.type
= ButtonPress
;
561 ev
.xbutton
.state
= 0;
563 XtDispatchEvent (&ev
);
564 ev
.xbutton
.type
= ButtonRelease
;
565 ev
.xbutton
.state
= Button1Mask
;
566 XtDispatchEvent (&ev
);
574 #endif /* USE_X_TOOLKIT */
578 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
579 doc
: /* Start key navigation of the menu bar in FRAME.
580 This initially opens the first menu bar item and you can then navigate with the
581 arrow keys, select a menu entry with the return key or cancel with the
582 escape key. If FRAME has no menu bar this function does nothing.
584 If FRAME is nil or not given, use the selected frame. */)
590 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
594 f
= check_x_frame (frame
);
596 if (FRAME_EXTERNAL_MENU_BAR (f
))
597 set_frame_menubar (f
, 0, 1);
599 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
602 /* Activate the first menu. */
603 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
607 g_signal_emit_by_name (children
->data
, "activate_item");
608 popup_activated_flag
= 1;
609 g_list_free (children
);
617 /* Loop util popup_activated_flag is set to zero in a callback.
618 Used for popup menus and dialogs. */
621 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
623 ++popup_activated_flag
;
625 /* Process events in the Gtk event loop until done. */
626 while (popup_activated_flag
)
628 if (do_timers
) x_menu_wait_for_event (0);
629 gtk_main_iteration ();
634 /* Activate the menu bar of frame F.
635 This is called from keyboard.c when it gets the
636 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
638 To activate the menu bar, we use the X button-press event
639 that was saved in saved_menu_event.
640 That makes the toolkit do its thing.
642 But first we recompute the menu bar contents (the whole tree).
644 The reason for saving the button event until here, instead of
645 passing it to the toolkit right away, is that we can safely
646 execute Lisp code. */
649 x_activate_menubar (FRAME_PTR f
)
654 if (!f
->output_data
.x
->saved_menu_event
->type
)
658 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
659 f
->output_data
.x
->saved_menu_event
->xany
.window
))
663 set_frame_menubar (f
, 0, 1);
665 popup_activated_flag
= 1;
667 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
668 f
->output_data
.x
->saved_menu_event
);
670 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
674 /* Ignore this if we get it a second time. */
675 f
->output_data
.x
->saved_menu_event
->type
= 0;
678 /* This callback is invoked when the user selects a menubar cascade
679 pushbutton, but before the pulldown menu is posted. */
683 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
685 popup_activated_flag
= 1;
687 x_activate_timeout_atimer ();
692 /* This callback is invoked when a dialog or menu is finished being
693 used and has been unposted. */
697 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
699 popup_activated_flag
= 0;
703 popup_deactivate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
705 popup_activated_flag
= 0;
710 /* Function that finds the frame for WIDGET and shows the HELP text
712 F is the frame if known, or NULL if not known. */
714 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
720 XSETFRAME (frame
, f
);
721 kbd_buffer_store_help_event (frame
, help
);
725 #if 0 /* This code doesn't do anything useful. ++kfs */
726 /* WIDGET is the popup menu. It's parent is the frame's
727 widget. See which frame that is. */
728 xt_or_gtk_widget frame_widget
= XtParent (widget
);
731 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
735 && (f
= XFRAME (frame
),
736 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
740 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
744 /* Callback called when menu items are highlighted/unhighlighted
745 while moving the mouse over them. WIDGET is the menu bar or menu
746 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
747 the data structure for the menu item, or null in case of
752 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
754 xg_menu_item_cb_data
*cb_data
;
757 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
759 if (! cb_data
) return;
761 help
= call_data
? cb_data
->help
: Qnil
;
763 /* If popup_activated_flag is greater than 1 we are in a popup menu.
764 Don't show help for them, they won't appear before the
765 popup is popped down. */
766 if (popup_activated_flag
<= 1)
767 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
771 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
776 widget_value
*wv
= (widget_value
*) call_data
;
778 help
= wv
? wv
->help
: Qnil
;
780 /* Determine the frame for the help event. */
781 f
= menubar_id_to_frame (id
);
783 show_help_event (f
, widget
, help
);
788 /* Gtk calls callbacks just because we tell it what item should be
789 selected in a radio group. If this variable is set to a non-zero
790 value, we are creating menus and don't want callbacks right now.
792 static int xg_crazy_callback_abort
;
794 /* This callback is called from the menu bar pulldown menu
795 when the user makes a selection.
796 Figure out what the user chose
797 and put the appropriate events into the keyboard buffer. */
799 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
801 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
803 if (xg_crazy_callback_abort
)
806 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
809 /* For a group of radio buttons, GTK calls the selection callback first
810 for the item that was active before the selection and then for the one that
811 is active after the selection. For C-h k this means we get the help on
812 the deselected item and then the selected item is executed. Prevent that
813 by ignoring the non-active item. */
814 if (GTK_IS_RADIO_MENU_ITEM (widget
)
815 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
818 /* When a menu is popped down, X generates a focus event (i.e. focus
819 goes back to the frame below the menu). Since GTK buffers events,
820 we force it out here before the menu selection event. Otherwise
821 sit-for will exit at once if the focus event follows the menu selection
825 while (gtk_events_pending ())
826 gtk_main_iteration ();
829 find_and_call_menu_selection (cb_data
->cl_data
->f
,
830 cb_data
->cl_data
->menu_bar_items_used
,
831 cb_data
->cl_data
->menu_bar_vector
,
835 #else /* not USE_GTK */
837 /* This callback is called from the menu bar pulldown menu
838 when the user makes a selection.
839 Figure out what the user chose
840 and put the appropriate events into the keyboard buffer. */
842 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
846 f
= menubar_id_to_frame (id
);
849 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
850 f
->menu_bar_vector
, client_data
);
852 #endif /* not USE_GTK */
854 /* Recompute all the widgets of frame F, when the menu bar has been
855 changed. Value is non-zero if widgets were updated. */
858 update_frame_menubar (FRAME_PTR f
)
861 return xg_update_frame_menubar (f
);
869 x
= f
->output_data
.x
;
871 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
875 /* Save the size of the frame because the pane widget doesn't accept
876 to resize itself. So force it. */
877 columns
= FRAME_COLS (f
);
878 rows
= FRAME_LINES (f
);
880 /* Do the voodoo which means "I'm changing lots of things, don't try
881 to refigure sizes until I'm done." */
882 lw_refigure_widget (x
->column_widget
, False
);
884 /* The order in which children are managed is the top to bottom
885 order in which they are displayed in the paned window. First,
886 remove the text-area widget. */
887 XtUnmanageChild (x
->edit_widget
);
889 /* Remove the menubar that is there now, and put up the menubar that
891 XtManageChild (x
->menubar_widget
);
892 XtMapWidget (x
->menubar_widget
);
893 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
895 /* Re-manage the text-area widget, and then thrash the sizes. */
896 XtManageChild (x
->edit_widget
);
897 lw_refigure_widget (x
->column_widget
, True
);
899 /* Force the pane widget to resize itself with the right values. */
900 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
908 apply_systemfont_to_dialog (Widget w
)
910 const char *fn
= xsettings_get_system_normal_font ();
913 XrmDatabase db
= XtDatabase (XtDisplay (w
));
915 XrmPutStringResource (&db
, "*dialog.faceName", fn
);
920 apply_systemfont_to_menu (Widget w
)
922 const char *fn
= xsettings_get_system_normal_font ();
927 if (XtIsShell (w
)) /* popup menu */
929 Widget
*childs
= NULL
;
931 XtVaGetValues (w
, XtNchildren
, &childs
, NULL
);
932 if (*childs
) w
= *childs
;
935 /* Only use system font if the default is used for the menu. */
936 XtVaGetValues (w
, XtNdefaultFace
, &defflt
, NULL
);
938 XtVaSetValues (w
, XtNfaceName
, fn
, NULL
);
942 /* Set the contents of the menubar widgets of frame F.
943 The argument FIRST_TIME is currently ignored;
944 it is set the first time this is called, from initialize_frame_menubar. */
947 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
949 xt_or_gtk_widget menubar_widget
;
954 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
956 int *submenu_start
, *submenu_end
;
957 int *submenu_top_level_items
, *submenu_n_panes
;
962 menubar_widget
= f
->output_data
.x
->menubar_widget
;
964 XSETFRAME (Vmenu_updating_frame
, f
);
967 if (f
->output_data
.x
->id
== 0)
968 f
->output_data
.x
->id
= next_menubar_widget_id
++;
969 id
= f
->output_data
.x
->id
;
972 if (! menubar_widget
)
974 /* Make the first call for any given frame always go deep. */
975 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
978 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
979 f
->output_data
.x
->saved_menu_event
->type
= 0;
983 /* If we have detached menus, we must update deep so detached menus
984 also gets updated. */
985 deep_p
= deep_p
|| xg_have_tear_offs ();
990 /* Make a widget-value tree representing the entire menu trees. */
992 struct buffer
*prev
= current_buffer
;
994 int specpdl_count
= SPECPDL_INDEX ();
995 int previous_menu_items_used
= f
->menu_bar_items_used
;
996 Lisp_Object
*previous_items
997 = (Lisp_Object
*) alloca (previous_menu_items_used
998 * sizeof (Lisp_Object
));
1000 /* If we are making a new widget, its contents are empty,
1001 do always reinitialize them. */
1002 if (! menubar_widget
)
1003 previous_menu_items_used
= 0;
1005 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1006 specbind (Qinhibit_quit
, Qt
);
1007 /* Don't let the debugger step into this code
1008 because it is not reentrant. */
1009 specbind (Qdebug_on_next_call
, Qnil
);
1011 record_unwind_save_match_data ();
1012 if (NILP (Voverriding_local_map_menu_flag
))
1014 specbind (Qoverriding_terminal_local_map
, Qnil
);
1015 specbind (Qoverriding_local_map
, Qnil
);
1018 set_buffer_internal_1 (XBUFFER (buffer
));
1020 /* Run the Lucid hook. */
1021 safe_run_hooks (Qactivate_menubar_hook
);
1023 /* If it has changed current-menubar from previous value,
1024 really recompute the menubar from the value. */
1025 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1026 call0 (Qrecompute_lucid_menubar
);
1027 safe_run_hooks (Qmenu_bar_update_hook
);
1028 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1030 items
= FRAME_MENU_BAR_ITEMS (f
);
1032 /* Save the frame's previous menu bar contents data. */
1033 if (previous_menu_items_used
)
1034 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1035 previous_menu_items_used
* sizeof (Lisp_Object
));
1037 /* Fill in menu_items with the current menu bar contents.
1038 This can evaluate Lisp code. */
1041 menu_items
= f
->menu_bar_vector
;
1042 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1043 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1044 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1045 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1046 submenu_top_level_items
1047 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1049 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1051 Lisp_Object key
, string
, maps
;
1055 key
= XVECTOR (items
)->contents
[i
];
1056 string
= XVECTOR (items
)->contents
[i
+ 1];
1057 maps
= XVECTOR (items
)->contents
[i
+ 2];
1061 submenu_start
[i
] = menu_items_used
;
1063 menu_items_n_panes
= 0;
1064 submenu_top_level_items
[i
]
1065 = parse_single_submenu (key
, string
, maps
);
1066 submenu_n_panes
[i
] = menu_items_n_panes
;
1068 submenu_end
[i
] = menu_items_used
;
1071 finish_menu_items ();
1073 /* Convert menu_items into widget_value trees
1074 to display the menu. This cannot evaluate Lisp code. */
1076 wv
= xmalloc_widget_value ();
1077 wv
->name
= "menubar";
1080 wv
->button_type
= BUTTON_TYPE_NONE
;
1084 for (i
= 0; i
< last_i
; i
+= 4)
1086 menu_items_n_panes
= submenu_n_panes
[i
];
1087 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1088 submenu_top_level_items
[i
]);
1092 first_wv
->contents
= wv
;
1093 /* Don't set wv->name here; GC during the loop might relocate it. */
1095 wv
->button_type
= BUTTON_TYPE_NONE
;
1099 set_buffer_internal_1 (prev
);
1101 /* If there has been no change in the Lisp-level contents
1102 of the menu bar, skip redisplaying it. Just exit. */
1104 /* Compare the new menu items with the ones computed last time. */
1105 for (i
= 0; i
< previous_menu_items_used
; i
++)
1106 if (menu_items_used
== i
1107 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1109 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1111 /* The menu items have not changed. Don't bother updating
1112 the menus in any form, since it would be a no-op. */
1113 free_menubar_widget_value_tree (first_wv
);
1114 discard_menu_items ();
1115 unbind_to (specpdl_count
, Qnil
);
1119 /* The menu items are different, so store them in the frame. */
1120 f
->menu_bar_vector
= menu_items
;
1121 f
->menu_bar_items_used
= menu_items_used
;
1123 /* This undoes save_menu_items. */
1124 unbind_to (specpdl_count
, Qnil
);
1126 /* Now GC cannot happen during the lifetime of the widget_value,
1127 so it's safe to store data from a Lisp_String. */
1128 wv
= first_wv
->contents
;
1129 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1132 string
= XVECTOR (items
)->contents
[i
+ 1];
1135 wv
->name
= (char *) SDATA (string
);
1136 update_submenu_strings (wv
->contents
);
1143 /* Make a widget-value tree containing
1144 just the top level menu bar strings. */
1146 wv
= xmalloc_widget_value ();
1147 wv
->name
= "menubar";
1150 wv
->button_type
= BUTTON_TYPE_NONE
;
1154 items
= FRAME_MENU_BAR_ITEMS (f
);
1155 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1159 string
= XVECTOR (items
)->contents
[i
+ 1];
1163 wv
= xmalloc_widget_value ();
1164 wv
->name
= (char *) SDATA (string
);
1167 wv
->button_type
= BUTTON_TYPE_NONE
;
1169 /* This prevents lwlib from assuming this
1170 menu item is really supposed to be empty. */
1171 /* The EMACS_INT cast avoids a warning.
1172 This value just has to be different from small integers. */
1173 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1178 first_wv
->contents
= wv
;
1182 /* Forget what we thought we knew about what is in the
1183 detailed contents of the menu bar menus.
1184 Changing the top level always destroys the contents. */
1185 f
->menu_bar_items_used
= 0;
1188 /* Create or update the menu bar widget. */
1193 xg_crazy_callback_abort
= 1;
1196 /* The fourth arg is DEEP_P, which says to consider the entire
1197 menu trees we supply, rather than just the menu bar item names. */
1198 xg_modify_menubar_widgets (menubar_widget
,
1202 G_CALLBACK (menubar_selection_callback
),
1203 G_CALLBACK (popup_deactivate_callback
),
1204 G_CALLBACK (menu_highlight_callback
));
1208 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1211 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1212 G_CALLBACK (menubar_selection_callback
),
1213 G_CALLBACK (popup_deactivate_callback
),
1214 G_CALLBACK (menu_highlight_callback
));
1216 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1220 #else /* not USE_GTK */
1223 /* Disable resizing (done for Motif!) */
1224 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1226 /* The third arg is DEEP_P, which says to consider the entire
1227 menu trees we supply, rather than just the menu bar item names. */
1228 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1230 /* Re-enable the edit widget to resize. */
1231 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1235 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1236 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1238 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1239 f
->output_data
.x
->column_widget
,
1241 popup_activate_callback
,
1242 menubar_selection_callback
,
1243 popup_deactivate_callback
,
1244 menu_highlight_callback
);
1245 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1247 /* Make menu pop down on C-g. */
1248 XtOverrideTranslations (menubar_widget
, override
);
1250 apply_systemfont_to_menu (menubar_widget
);
1256 if (f
->output_data
.x
->menubar_widget
)
1257 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1260 = (f
->output_data
.x
->menubar_widget
1261 ? (f
->output_data
.x
->menubar_widget
->core
.height
1262 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1265 #if 1 /* Experimentally, we now get the right results
1266 for -geometry -0-0 without this. 24 Aug 96, rms.
1267 Maybe so, but the menu bar size is missing the pixels so the
1268 WM size hints are off by these pixels. Jan D, oct 2009. */
1270 if (FRAME_EXTERNAL_MENU_BAR (f
))
1273 XtVaGetValues (f
->output_data
.x
->column_widget
,
1274 XtNinternalBorderWidth
, &ibw
, NULL
);
1275 menubar_size
+= ibw
;
1277 #endif /* USE_LUCID */
1280 f
->output_data
.x
->menubar_height
= menubar_size
;
1282 #endif /* not USE_GTK */
1284 free_menubar_widget_value_tree (first_wv
);
1285 update_frame_menubar (f
);
1288 xg_crazy_callback_abort
= 0;
1294 /* Called from Fx_create_frame to create the initial menubar of a frame
1295 before it is mapped, so that the window is mapped with the menubar already
1296 there instead of us tacking it on later and thrashing the window after it
1300 initialize_frame_menubar (FRAME_PTR f
)
1302 /* This function is called before the first chance to redisplay
1303 the frame. It has to be, so the frame will have the right size. */
1304 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1305 set_frame_menubar (f
, 1, 1);
1309 /* Get rid of the menu bar of frame F, and free its storage.
1310 This is used when deleting a frame, and when turning off the menu bar.
1311 For GTK this function is in gtkutil.c. */
1315 free_frame_menubar (FRAME_PTR f
)
1317 Widget menubar_widget
;
1319 if (! FRAME_X_P (f
))
1322 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1324 f
->output_data
.x
->menubar_height
= 0;
1329 /* Removing the menu bar magically changes the shell widget's x
1330 and y position of (0, 0) which, when the menu bar is turned
1331 on again, leads to pull-down menuss appearing in strange
1332 positions near the upper-left corner of the display. This
1333 happens only with some window managers like twm and ctwm,
1334 but not with other like Motif's mwm or kwm, because the
1335 latter generate ConfigureNotify events when the menu bar
1336 is switched off, which fixes the shell position. */
1337 Position x0
, y0
, x1
, y1
;
1343 if (f
->output_data
.x
->widget
)
1344 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1347 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1348 f
->output_data
.x
->menubar_widget
= NULL
;
1350 if (f
->output_data
.x
->widget
)
1353 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1354 if (x1
== 0 && y1
== 0)
1355 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1357 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1362 #endif /* not USE_GTK */
1364 #endif /* USE_X_TOOLKIT || USE_GTK */
1366 /* xmenu_show actually displays a menu using the panes and items in menu_items
1367 and returns the value selected from it.
1368 There are two versions of xmenu_show, one for Xt and one for Xlib.
1369 Both assume input is blocked by the caller. */
1371 /* F is the frame the menu is for.
1372 X and Y are the frame-relative specified position,
1373 relative to the inside upper left corner of the frame F.
1374 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1375 KEYMAPS is 1 if this menu was specified with keymaps;
1376 in that case, we return a list containing the chosen item's value
1377 and perhaps also the pane's prefix.
1378 TITLE is the specified menu title.
1379 ERROR is a place to store an error message string in case of failure.
1380 (We return nil on failure, but the value doesn't actually matter.) */
1382 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1384 /* The item selected in the popup menu. */
1385 static Lisp_Object
*volatile menu_item_selection
;
1389 /* Used when position a popup menu. See menu_position_func and
1390 create_and_show_popup_menu below. */
1391 struct next_popup_x_y
1398 /* The menu position function to use if we are not putting a popup
1399 menu where the pointer is.
1400 MENU is the menu to pop up.
1401 X and Y shall on exit contain x/y where the menu shall pop up.
1402 PUSH_IN is not documented in the GTK manual.
1403 USER_DATA is any data passed in when calling gtk_menu_popup.
1404 Here it points to a struct next_popup_x_y where the coordinates
1405 to store in *X and *Y are as well as the frame for the popup.
1407 Here only X and Y are used. */
1409 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1411 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1413 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1414 int disp_width
= x_display_pixel_width (dpyinfo
);
1415 int disp_height
= x_display_pixel_height (dpyinfo
);
1420 /* Check if there is room for the menu. If not, adjust x/y so that
1421 the menu is fully visible. */
1422 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1423 if (data
->x
+ req
.width
> disp_width
)
1424 *x
-= data
->x
+ req
.width
- disp_width
;
1425 if (data
->y
+ req
.height
> disp_height
)
1426 *y
-= data
->y
+ req
.height
- disp_height
;
1430 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1432 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1434 if (xg_crazy_callback_abort
) return;
1435 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1439 pop_down_menu (Lisp_Object arg
)
1441 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1443 popup_activated_flag
= 0;
1445 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1450 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1452 menu_item_selection will be set to the selection. */
1454 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1458 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1459 struct next_popup_x_y popup_x_y
;
1460 int specpdl_count
= SPECPDL_INDEX ();
1462 if (! FRAME_X_P (f
))
1465 xg_crazy_callback_abort
= 1;
1466 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1467 G_CALLBACK (popup_selection_callback
),
1468 G_CALLBACK (popup_deactivate_callback
),
1469 G_CALLBACK (menu_highlight_callback
));
1470 xg_crazy_callback_abort
= 0;
1474 /* Not invoked by a click. pop up at x/y. */
1475 pos_func
= menu_position_func
;
1477 /* Adjust coordinates to be root-window-relative. */
1478 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1479 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1485 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1489 for (i
= 0; i
< 5; i
++)
1490 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1494 /* Display the menu. */
1495 gtk_widget_show_all (menu
);
1497 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1498 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1500 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1502 if (gtk_widget_get_mapped (menu
))
1504 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1505 two. show_help_echo uses this to detect popup menus. */
1506 popup_activated_flag
= 1;
1507 /* Process events that apply to the menu. */
1508 popup_widget_loop (1, menu
);
1511 unbind_to (specpdl_count
, Qnil
);
1513 /* Must reset this manually because the button release event is not passed
1514 to Emacs event loop. */
1515 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1518 #else /* not USE_GTK */
1520 /* We need a unique id for each widget handled by the Lucid Widget
1523 For the main windows, and popup menus, we use this counter,
1524 which we increment each time after use. This starts from 1<<16.
1526 For menu bars, we use numbers starting at 0, counted in
1527 next_menubar_widget_id. */
1528 LWLIB_ID widget_id_tick
;
1531 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1533 menu_item_selection
= (Lisp_Object
*) client_data
;
1536 /* ARG is the LWLIB ID of the dialog box, represented
1537 as a Lisp object as (HIGHPART . LOWPART). */
1540 pop_down_menu (Lisp_Object arg
)
1542 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1543 | XINT (XCDR (arg
)));
1546 lw_destroy_all_widgets (id
);
1548 popup_activated_flag
= 0;
1553 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1555 menu_item_selection will be set to the selection. */
1557 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
,
1558 int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1563 XButtonPressedEvent dummy
;
1567 if (! FRAME_X_P (f
))
1570 menu_id
= widget_id_tick
++;
1571 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1572 f
->output_data
.x
->widget
, 1, 0,
1573 popup_selection_callback
,
1574 popup_deactivate_callback
,
1575 menu_highlight_callback
);
1578 apply_systemfont_to_menu (menu
);
1581 dummy
.type
= ButtonPress
;
1583 dummy
.send_event
= 0;
1584 dummy
.display
= FRAME_X_DISPLAY (f
);
1585 dummy
.time
= CurrentTime
;
1586 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1587 dummy
.window
= dummy
.root
;
1588 dummy
.subwindow
= dummy
.root
;
1592 /* Adjust coordinates to be root-window-relative. */
1593 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1594 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1601 for (i
= 0; i
< 5; i
++)
1602 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1605 /* Don't allow any geometry request from the user. */
1606 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1607 XtSetValues (menu
, av
, ac
);
1609 /* Display the menu. */
1610 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1611 popup_activated_flag
= 1;
1612 x_activate_timeout_atimer ();
1615 int fact
= 4 * sizeof (LWLIB_ID
);
1616 int specpdl_count
= SPECPDL_INDEX ();
1617 record_unwind_protect (pop_down_menu
,
1618 Fcons (make_number (menu_id
>> (fact
)),
1619 make_number (menu_id
& ~(-1 << (fact
)))));
1621 /* Process events that apply to the menu. */
1622 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1624 unbind_to (specpdl_count
, Qnil
);
1628 #endif /* not USE_GTK */
1631 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1632 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1635 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1636 widget_value
**submenu_stack
1637 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1638 Lisp_Object
*subprefix_stack
1639 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1640 int submenu_depth
= 0;
1644 if (! FRAME_X_P (f
))
1649 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1651 *error
= "Empty menu";
1655 /* Create a tree of widget_value objects
1656 representing the panes and their items. */
1657 wv
= xmalloc_widget_value ();
1661 wv
->button_type
= BUTTON_TYPE_NONE
;
1666 /* Loop over all panes and items, filling in the tree. */
1668 while (i
< menu_items_used
)
1670 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1672 submenu_stack
[submenu_depth
++] = save_wv
;
1678 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1681 save_wv
= submenu_stack
[--submenu_depth
];
1685 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1686 && submenu_depth
!= 0)
1687 i
+= MENU_ITEMS_PANE_LENGTH
;
1688 /* Ignore a nil in the item list.
1689 It's meaningful only for dialog boxes. */
1690 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1692 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1694 /* Create a new pane. */
1695 Lisp_Object pane_name
, prefix
;
1698 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1699 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1701 #ifndef HAVE_MULTILINGUAL_MENU
1702 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1704 pane_name
= ENCODE_MENU_STRING (pane_name
);
1705 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1708 pane_string
= (NILP (pane_name
)
1709 ? "" : (char *) SDATA (pane_name
));
1710 /* If there is just one top-level pane, put all its items directly
1711 under the top-level menu. */
1712 if (menu_items_n_panes
== 1)
1715 /* If the pane has a meaningful name,
1716 make the pane a top-level menu item
1717 with its items as a submenu beneath it. */
1718 if (!keymaps
&& strcmp (pane_string
, ""))
1720 wv
= xmalloc_widget_value ();
1724 first_wv
->contents
= wv
;
1725 wv
->name
= pane_string
;
1726 if (keymaps
&& !NILP (prefix
))
1730 wv
->button_type
= BUTTON_TYPE_NONE
;
1735 else if (first_pane
)
1741 i
+= MENU_ITEMS_PANE_LENGTH
;
1745 /* Create a new item within current pane. */
1746 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1747 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1748 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1749 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1750 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1751 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1752 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1753 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1755 #ifndef HAVE_MULTILINGUAL_MENU
1756 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1758 item_name
= ENCODE_MENU_STRING (item_name
);
1759 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1762 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1764 descrip
= ENCODE_MENU_STRING (descrip
);
1765 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1767 #endif /* not HAVE_MULTILINGUAL_MENU */
1769 wv
= xmalloc_widget_value ();
1773 save_wv
->contents
= wv
;
1774 wv
->name
= (char *) SDATA (item_name
);
1775 if (!NILP (descrip
))
1776 wv
->key
= (char *) SDATA (descrip
);
1778 /* If this item has a null value,
1779 make the call_data null so that it won't display a box
1780 when the mouse is on it. */
1782 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1783 wv
->enabled
= !NILP (enable
);
1786 wv
->button_type
= BUTTON_TYPE_NONE
;
1787 else if (EQ (type
, QCtoggle
))
1788 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1789 else if (EQ (type
, QCradio
))
1790 wv
->button_type
= BUTTON_TYPE_RADIO
;
1794 wv
->selected
= !NILP (selected
);
1796 if (! STRINGP (help
))
1803 i
+= MENU_ITEMS_ITEM_LENGTH
;
1807 /* Deal with the title, if it is non-nil. */
1810 widget_value
*wv_title
= xmalloc_widget_value ();
1811 widget_value
*wv_sep1
= xmalloc_widget_value ();
1812 widget_value
*wv_sep2
= xmalloc_widget_value ();
1814 wv_sep2
->name
= "--";
1815 wv_sep2
->next
= first_wv
->contents
;
1816 wv_sep2
->help
= Qnil
;
1818 wv_sep1
->name
= "--";
1819 wv_sep1
->next
= wv_sep2
;
1820 wv_sep1
->help
= Qnil
;
1822 #ifndef HAVE_MULTILINGUAL_MENU
1823 if (STRING_MULTIBYTE (title
))
1824 title
= ENCODE_MENU_STRING (title
);
1827 wv_title
->name
= (char *) SDATA (title
);
1828 wv_title
->enabled
= TRUE
;
1829 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1830 wv_title
->help
= Qnil
;
1831 wv_title
->next
= wv_sep1
;
1832 first_wv
->contents
= wv_title
;
1835 /* No selection has been chosen yet. */
1836 menu_item_selection
= 0;
1838 /* Actually create and show the menu until popped down. */
1839 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1841 /* Free the widget_value objects we used to specify the contents. */
1842 free_menubar_widget_value_tree (first_wv
);
1844 /* Find the selected item, and its pane, to return
1845 the proper value. */
1846 if (menu_item_selection
!= 0)
1848 Lisp_Object prefix
, entry
;
1850 prefix
= entry
= Qnil
;
1852 while (i
< menu_items_used
)
1854 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1856 subprefix_stack
[submenu_depth
++] = prefix
;
1860 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1862 prefix
= subprefix_stack
[--submenu_depth
];
1865 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1868 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1869 i
+= MENU_ITEMS_PANE_LENGTH
;
1871 /* Ignore a nil in the item list.
1872 It's meaningful only for dialog boxes. */
1873 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1878 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1879 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1885 entry
= Fcons (entry
, Qnil
);
1887 entry
= Fcons (prefix
, entry
);
1888 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1889 if (!NILP (subprefix_stack
[j
]))
1890 entry
= Fcons (subprefix_stack
[j
], entry
);
1894 i
+= MENU_ITEMS_ITEM_LENGTH
;
1898 else if (!for_click
)
1899 /* Make "Cancel" equivalent to C-g. */
1900 Fsignal (Qquit
, Qnil
);
1907 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1909 /* The EMACS_INT cast avoids a warning. There's no problem
1910 as long as pointers have enough bits to hold small integers. */
1911 if ((int) (EMACS_INT
) client_data
!= -1)
1912 menu_item_selection
= (Lisp_Object
*) client_data
;
1914 popup_activated_flag
= 0;
1917 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1919 menu_item_selection will be set to the selection. */
1921 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1925 if (! FRAME_X_P (f
))
1928 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1929 G_CALLBACK (dialog_selection_callback
),
1930 G_CALLBACK (popup_deactivate_callback
),
1935 int specpdl_count
= SPECPDL_INDEX ();
1936 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1938 /* Display the menu. */
1939 gtk_widget_show_all (menu
);
1941 /* Process events that apply to the menu. */
1942 popup_widget_loop (1, menu
);
1944 unbind_to (specpdl_count
, Qnil
);
1948 #else /* not USE_GTK */
1950 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1952 /* The EMACS_INT cast avoids a warning. There's no problem
1953 as long as pointers have enough bits to hold small integers. */
1954 if ((int) (EMACS_INT
) client_data
!= -1)
1955 menu_item_selection
= (Lisp_Object
*) client_data
;
1958 lw_destroy_all_widgets (id
);
1960 popup_activated_flag
= 0;
1964 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1966 menu_item_selection will be set to the selection. */
1968 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1975 dialog_id
= widget_id_tick
++;
1977 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1979 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1980 f
->output_data
.x
->widget
, 1, 0,
1981 dialog_selection_callback
, 0, 0);
1982 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1983 /* Display the dialog box. */
1984 lw_pop_up_all_widgets (dialog_id
);
1985 popup_activated_flag
= 1;
1986 x_activate_timeout_atimer ();
1988 /* Process events that apply to the dialog box.
1989 Also handle timers. */
1991 int count
= SPECPDL_INDEX ();
1992 int fact
= 4 * sizeof (LWLIB_ID
);
1994 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1995 record_unwind_protect (pop_down_menu
,
1996 Fcons (make_number (dialog_id
>> (fact
)),
1997 make_number (dialog_id
& ~(-1 << (fact
)))));
1999 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2002 unbind_to (count
, Qnil
);
2006 #endif /* not USE_GTK */
2008 static char * button_names
[] = {
2009 "button1", "button2", "button3", "button4", "button5",
2010 "button6", "button7", "button8", "button9", "button10" };
2013 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2015 int i
, nb_buttons
=0;
2016 char dialog_name
[6];
2018 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2020 /* Number of elements seen so far, before boundary. */
2022 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2023 int boundary_seen
= 0;
2025 if (! FRAME_X_P (f
))
2030 if (menu_items_n_panes
> 1)
2032 *error_name
= "Multiple panes in dialog box";
2036 /* Create a tree of widget_value objects
2037 representing the text label and buttons. */
2039 Lisp_Object pane_name
, prefix
;
2041 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2042 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2043 pane_string
= (NILP (pane_name
)
2044 ? "" : (char *) SDATA (pane_name
));
2045 prev_wv
= xmalloc_widget_value ();
2046 prev_wv
->value
= pane_string
;
2047 if (keymaps
&& !NILP (prefix
))
2049 prev_wv
->enabled
= 1;
2050 prev_wv
->name
= "message";
2051 prev_wv
->help
= Qnil
;
2054 /* Loop over all panes and items, filling in the tree. */
2055 i
= MENU_ITEMS_PANE_LENGTH
;
2056 while (i
< menu_items_used
)
2059 /* Create a new item within current pane. */
2060 Lisp_Object item_name
, enable
, descrip
;
2061 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2062 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2064 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2066 if (NILP (item_name
))
2068 free_menubar_widget_value_tree (first_wv
);
2069 *error_name
= "Submenu in dialog items";
2072 if (EQ (item_name
, Qquote
))
2074 /* This is the boundary between left-side elts
2075 and right-side elts. Stop incrementing right_count. */
2080 if (nb_buttons
>= 9)
2082 free_menubar_widget_value_tree (first_wv
);
2083 *error_name
= "Too many dialog items";
2087 wv
= xmalloc_widget_value ();
2089 wv
->name
= (char *) button_names
[nb_buttons
];
2090 if (!NILP (descrip
))
2091 wv
->key
= (char *) SDATA (descrip
);
2092 wv
->value
= (char *) SDATA (item_name
);
2093 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2094 wv
->enabled
= !NILP (enable
);
2098 if (! boundary_seen
)
2102 i
+= MENU_ITEMS_ITEM_LENGTH
;
2105 /* If the boundary was not specified,
2106 by default put half on the left and half on the right. */
2107 if (! boundary_seen
)
2108 left_count
= nb_buttons
- nb_buttons
/ 2;
2110 wv
= xmalloc_widget_value ();
2111 wv
->name
= dialog_name
;
2114 /* Frame title: 'Q' = Question, 'I' = Information.
2115 Can also have 'E' = Error if, one day, we want
2116 a popup for errors. */
2118 dialog_name
[0] = 'Q';
2120 dialog_name
[0] = 'I';
2122 /* Dialog boxes use a really stupid name encoding
2123 which specifies how many buttons to use
2124 and how many buttons are on the right. */
2125 dialog_name
[1] = '0' + nb_buttons
;
2126 dialog_name
[2] = 'B';
2127 dialog_name
[3] = 'R';
2128 /* Number of buttons to put on the right. */
2129 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2131 wv
->contents
= first_wv
;
2135 /* No selection has been chosen yet. */
2136 menu_item_selection
= 0;
2138 /* Actually create and show the dialog. */
2139 create_and_show_dialog (f
, first_wv
);
2141 /* Free the widget_value objects we used to specify the contents. */
2142 free_menubar_widget_value_tree (first_wv
);
2144 /* Find the selected item, and its pane, to return
2145 the proper value. */
2146 if (menu_item_selection
!= 0)
2152 while (i
< menu_items_used
)
2156 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2159 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2160 i
+= MENU_ITEMS_PANE_LENGTH
;
2162 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2164 /* This is the boundary between left-side elts and
2171 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2172 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2176 entry
= Fcons (entry
, Qnil
);
2178 entry
= Fcons (prefix
, entry
);
2182 i
+= MENU_ITEMS_ITEM_LENGTH
;
2187 /* Make "Cancel" equivalent to C-g. */
2188 Fsignal (Qquit
, Qnil
);
2193 #else /* not USE_X_TOOLKIT && not USE_GTK */
2195 /* The frame of the last activated non-toolkit menu bar.
2196 Used to generate menu help events. */
2198 static struct frame
*menu_help_frame
;
2201 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2203 PANE is the pane number, and ITEM is the menu item number in
2204 the menu (currently not used).
2206 This cannot be done with generating a HELP_EVENT because
2207 XMenuActivate contains a loop that doesn't let Emacs process
2211 menu_help_callback (char *help_string
, int pane
, int item
)
2213 extern Lisp_Object Qmenu_item
;
2214 Lisp_Object
*first_item
;
2215 Lisp_Object pane_name
;
2216 Lisp_Object menu_object
;
2218 first_item
= XVECTOR (menu_items
)->contents
;
2219 if (EQ (first_item
[0], Qt
))
2220 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2221 else if (EQ (first_item
[0], Qquote
))
2222 /* This shouldn't happen, see xmenu_show. */
2223 pane_name
= empty_unibyte_string
;
2225 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2227 /* (menu-item MENU-NAME PANE-NUMBER) */
2228 menu_object
= Fcons (Qmenu_item
,
2230 Fcons (make_number (pane
), Qnil
)));
2231 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2232 Qnil
, menu_object
, make_number (item
), 1);
2236 pop_down_menu (Lisp_Object arg
)
2238 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2239 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2241 FRAME_PTR f
= p1
->pointer
;
2242 XMenu
*menu
= p2
->pointer
;
2246 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2247 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2249 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2251 #ifdef HAVE_X_WINDOWS
2252 /* Assume the mouse has moved out of the X window.
2253 If it has actually moved in, we will get an EnterNotify. */
2254 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2256 /* State that no mouse buttons are now held.
2257 (The oldXMenu code doesn't track this info for us.)
2258 That is not necessarily true, but the fiction leads to reasonable
2259 results, and it is a pain to ask which are actually held now. */
2260 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2262 #endif /* HAVE_X_WINDOWS */
2271 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
2272 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
2276 int pane
, selidx
, lpane
, status
;
2277 Lisp_Object entry
, pane_prefix
;
2279 int ulx
, uly
, width
, height
;
2280 int dispwidth
, dispheight
;
2281 int i
, j
, lines
, maxlines
;
2284 unsigned int dummy_uint
;
2285 int specpdl_count
= SPECPDL_INDEX ();
2287 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2291 if (menu_items_n_panes
== 0)
2294 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2296 *error
= "Empty menu";
2300 /* Figure out which root window F is on. */
2301 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2302 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2303 &dummy_uint
, &dummy_uint
);
2305 /* Make the menu on that window. */
2306 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2309 *error
= "Can't create menu";
2313 /* Don't GC while we prepare and show the menu,
2314 because we give the oldxmenu library pointers to the
2315 contents of strings. */
2316 inhibit_garbage_collection ();
2318 #ifdef HAVE_X_WINDOWS
2319 /* Adjust coordinates to relative to the outer (window manager) window. */
2320 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2321 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2322 #endif /* HAVE_X_WINDOWS */
2324 /* Adjust coordinates to be root-window-relative. */
2328 /* Create all the necessary panes and their items. */
2329 maxlines
= lines
= i
= 0;
2330 while (i
< menu_items_used
)
2332 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2334 /* Create a new pane. */
2335 Lisp_Object pane_name
, prefix
;
2338 maxlines
= max (maxlines
, lines
);
2340 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2341 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2342 pane_string
= (NILP (pane_name
)
2343 ? "" : (char *) SDATA (pane_name
));
2344 if (keymaps
&& !NILP (prefix
))
2347 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2348 if (lpane
== XM_FAILURE
)
2350 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2351 *error
= "Can't create pane";
2354 i
+= MENU_ITEMS_PANE_LENGTH
;
2356 /* Find the width of the widest item in this pane. */
2359 while (j
< menu_items_used
)
2362 item
= XVECTOR (menu_items
)->contents
[j
];
2370 width
= SBYTES (item
);
2371 if (width
> maxwidth
)
2374 j
+= MENU_ITEMS_ITEM_LENGTH
;
2377 /* Ignore a nil in the item list.
2378 It's meaningful only for dialog boxes. */
2379 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2383 /* Create a new item within current pane. */
2384 Lisp_Object item_name
, enable
, descrip
, help
;
2385 unsigned char *item_data
;
2388 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2389 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2391 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2392 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2393 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2395 if (!NILP (descrip
))
2397 int gap
= maxwidth
- SBYTES (item_name
);
2398 /* if alloca is fast, use that to make the space,
2399 to reduce gc needs. */
2401 = (unsigned char *) alloca (maxwidth
2402 + SBYTES (descrip
) + 1);
2403 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2404 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2406 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2407 item_data
[j
+ SBYTES (descrip
)] = 0;
2410 item_data
= SDATA (item_name
);
2412 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2413 menu
, lpane
, 0, item_data
,
2414 !NILP (enable
), help_string
)
2417 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2418 *error
= "Can't add selection to menu";
2421 i
+= MENU_ITEMS_ITEM_LENGTH
;
2426 maxlines
= max (maxlines
, lines
);
2428 /* All set and ready to fly. */
2429 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2430 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2431 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2432 x
= min (x
, dispwidth
);
2433 y
= min (y
, dispheight
);
2436 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2437 &ulx
, &uly
, &width
, &height
);
2438 if (ulx
+width
> dispwidth
)
2440 x
-= (ulx
+ width
) - dispwidth
;
2441 ulx
= dispwidth
- width
;
2443 if (uly
+height
> dispheight
)
2445 y
-= (uly
+ height
) - dispheight
;
2446 uly
= dispheight
- height
;
2448 #ifndef HAVE_X_WINDOWS
2449 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2451 /* Move the menu away of the echo area, to avoid overwriting the
2452 menu with help echo messages or vice versa. */
2453 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2455 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2456 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2465 if (ulx
< 0) x
-= ulx
;
2466 if (uly
< 0) y
-= uly
;
2470 /* If position was not given by a mouse click, adjust so upper left
2471 corner of the menu as a whole ends up at given coordinates. This
2472 is what x-popup-menu says in its documentation. */
2474 y
+= 1.5*height
/(maxlines
+2);
2477 XMenuSetAEQ (menu
, TRUE
);
2478 XMenuSetFreeze (menu
, TRUE
);
2482 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2485 record_unwind_protect (pop_down_menu
,
2486 Fcons (make_save_value (f
, 0),
2487 make_save_value (menu
, 0)));
2489 /* Help display under X won't work because XMenuActivate contains
2490 a loop that doesn't give Emacs a chance to process it. */
2491 menu_help_frame
= f
;
2492 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2493 x
, y
, ButtonReleaseMask
, &datap
,
2494 menu_help_callback
);
2500 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2503 /* Find the item number SELIDX in pane number PANE. */
2505 while (i
< menu_items_used
)
2507 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2511 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2513 i
+= MENU_ITEMS_PANE_LENGTH
;
2522 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2525 entry
= Fcons (entry
, Qnil
);
2526 if (!NILP (pane_prefix
))
2527 entry
= Fcons (pane_prefix
, entry
);
2533 i
+= MENU_ITEMS_ITEM_LENGTH
;
2539 *error
= "Can't activate menu";
2544 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2545 the menu was invoked with a mouse event as POSITION). */
2547 Fsignal (Qquit
, Qnil
);
2552 unbind_to (specpdl_count
, Qnil
);
2557 #endif /* not USE_X_TOOLKIT */
2559 #endif /* HAVE_MENUS */
2561 /* Detect if a dialog or menu has been posted. */
2564 popup_activated (void)
2566 return popup_activated_flag
;
2569 /* The following is used by delayed window autoselection. */
2571 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2572 doc
: /* Return t if a menu or popup dialog is active. */)
2576 return (popup_activated ()) ? Qt
: Qnil
;
2579 #endif /* HAVE_MENUS */
2583 syms_of_xmenu (void)
2585 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2586 staticpro (&Qdebug_on_next_call
);
2588 #ifdef USE_X_TOOLKIT
2589 widget_id_tick
= (1<<16);
2590 next_menubar_widget_id
= 1;
2593 defsubr (&Smenu_or_popup_active_p
);
2595 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2596 defsubr (&Sx_menu_bar_open_internal
);
2597 Ffset (intern_c_string ("accelerate-menu"),
2598 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2602 defsubr (&Sx_popup_dialog
);
2606 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2607 (do not change this comment) */