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);
154 /* This is set nonzero after the user activates the menu bar, and set
155 to zero again after the menu bars are redisplayed by prepare_menu_bar.
156 While it is nonzero, all calls to set_frame_menubar go deep.
158 I don't understand why this is needed, but it does seem to be
159 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
161 int pending_menu_activation
;
165 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
167 static struct frame
*
168 menubar_id_to_frame (id
)
171 Lisp_Object tail
, frame
;
174 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
180 if (!FRAME_WINDOW_P (f
))
182 if (f
->output_data
.x
->id
== id
)
190 #ifdef HAVE_X_WINDOWS
191 /* Return the mouse position in *X and *Y. The coordinates are window
192 relative for the edit window in frame F.
193 This is for Fx_popup_menu. The mouse_position_hook can not
194 be used for X, as it returns window relative coordinates
195 for the window where the mouse is in. This could be the menu bar,
196 the scroll bar or the edit window. Fx_popup_menu needs to be
197 sure it is the edit window. */
199 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
201 Window root
, dummy_window
;
209 XQueryPointer (FRAME_X_DISPLAY (f
),
210 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
212 /* The root window which contains the pointer. */
215 /* Window pointer is on, not used */
218 /* The position on that root window. */
221 /* x/y in dummy_window coordinates, not used. */
224 /* Modifier keys and pointer buttons, about which
226 (unsigned int *) &dummy
);
230 /* xmenu_show expects window coordinates, not root window
231 coordinates. Translate. */
232 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
233 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
236 #endif /* HAVE_X_WINDOWS */
240 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
241 doc
: /* Pop up a dialog box and return user's selection.
242 POSITION specifies which frame to use.
243 This is normally a mouse button event or a window or frame.
244 If POSITION is t, it means to use the frame the mouse is on.
245 The dialog box appears in the middle of the specified frame.
247 CONTENTS specifies the alternatives to display in the dialog box.
248 It is a list of the form (DIALOG ITEM1 ITEM2...).
249 Each ITEM is a cons cell (STRING . VALUE).
250 The return value is VALUE from the chosen item.
252 An ITEM may also be just a string--that makes a nonselectable item.
253 An ITEM may also be nil--that means to put all preceding items
254 on the left of the dialog box and all following items on the right.
255 \(By default, approximately half appear on each side.)
257 If HEADER is non-nil, the frame title for the box is "Information",
258 otherwise it is "Question".
260 If the user gets rid of the dialog box without making a valid choice,
261 for instance using the window manager, then this produces a quit and
262 `x-popup-dialog' does not return. */)
263 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
270 /* Decode the first argument: find the window or frame to use. */
271 if (EQ (position
, Qt
)
272 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
273 || EQ (XCAR (position
), Qtool_bar
))))
275 #if 0 /* Using the frame the mouse is on may not be right. */
276 /* Use the mouse's current position. */
277 FRAME_PTR new_f
= SELECTED_FRAME ();
278 Lisp_Object bar_window
;
279 enum scroll_bar_part part
;
283 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
286 XSETFRAME (window
, new_f
);
288 window
= selected_window
;
290 window
= selected_window
;
292 else if (CONSP (position
))
295 tem
= Fcar (position
);
297 window
= Fcar (Fcdr (position
));
300 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
301 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
304 else if (WINDOWP (position
) || FRAMEP (position
))
309 /* Decode where to put the menu. */
313 else if (WINDOWP (window
))
315 CHECK_LIVE_WINDOW (window
);
316 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
319 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
320 but I don't want to make one now. */
321 CHECK_WINDOW (window
);
323 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
324 error ("Can not put X dialog on this terminal");
326 /* Force a redisplay before showing the dialog. If a frame is created
327 just before showing the dialog, its contents may not have been fully
328 drawn, as this depends on timing of events from the X server. Redisplay
329 is not done when a dialog is shown. If redisplay could be done in the
330 X event loop (i.e. the X event loop does not run in a signal handler)
331 this would not be needed.
333 Do this before creating the widget value that points to Lisp
334 string contents, because Fredisplay may GC and relocate them. */
337 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
338 /* Display a menu with these alternatives
339 in the middle of frame F. */
341 Lisp_Object x
, y
, frame
, newpos
;
342 XSETFRAME (frame
, f
);
343 XSETINT (x
, x_pixel_width (f
) / 2);
344 XSETINT (y
, x_pixel_height (f
) / 2);
345 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
347 return Fx_popup_menu (newpos
,
348 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
354 Lisp_Object selection
;
355 int specpdl_count
= SPECPDL_INDEX ();
357 /* Decode the dialog items from what was specified. */
358 title
= Fcar (contents
);
359 CHECK_STRING (title
);
360 record_unwind_protect (unuse_menu_items
, Qnil
);
362 if (NILP (Fcar (Fcdr (contents
))))
363 /* No buttons specified, add an "Ok" button so users can pop down
364 the dialog. Also, the lesstif/motif version crashes if there are
366 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
368 list_of_panes (Fcons (contents
, Qnil
));
370 /* Display them in a dialog box. */
372 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
375 unbind_to (specpdl_count
, Qnil
);
376 discard_menu_items ();
378 if (error_name
) error (error_name
);
387 /* Set menu_items_inuse so no other popup menu or dialog is created. */
390 x_menu_set_in_use (int in_use
)
392 menu_items_inuse
= in_use
? Qt
: Qnil
;
393 popup_activated_flag
= in_use
;
395 if (popup_activated_flag
)
396 x_activate_timeout_atimer ();
400 /* Wait for an X event to arrive or for a timer to expire. */
403 x_menu_wait_for_event (void *data
)
405 /* Another way to do this is to register a timer callback, that can be
406 done in GTK and Xt. But we have to do it like this when using only X
407 anyway, and with callbacks we would have three variants for timer handling
408 instead of the small ifdefs below. */
412 ! XtAppPending (Xt_app_con
)
413 #elif defined USE_GTK
414 ! gtk_events_pending ()
416 ! XPending ((Display
*) data
)
420 EMACS_TIME next_time
= timer_check (1), *ntp
;
421 long secs
= EMACS_SECS (next_time
);
422 long usecs
= EMACS_USECS (next_time
);
423 SELECT_TYPE read_fds
;
424 struct x_display_info
*dpyinfo
;
428 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
430 int fd
= ConnectionNumber (dpyinfo
->display
);
431 FD_SET (fd
, &read_fds
);
433 XFlush (dpyinfo
->display
);
436 if (secs
< 0 && usecs
< 0)
441 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
447 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
451 /* Loop in Xt until the menu pulldown or dialog popup has been
452 popped down (deactivated). This is used for x-popup-menu
453 and x-popup-dialog; it is not used for the menu bar.
455 NOTE: All calls to popup_get_selection should be protected
456 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
459 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
460 XEvent
*initial_event
;
461 struct x_display_info
*dpyinfo
;
467 while (popup_activated_flag
)
471 event
= *initial_event
;
476 if (do_timers
) x_menu_wait_for_event (0);
477 XtAppNextEvent (Xt_app_con
, &event
);
480 /* Make sure we don't consider buttons grabbed after menu goes.
481 And make sure to deactivate for any ButtonRelease,
482 even if XtDispatchEvent doesn't do that. */
483 if (event
.type
== ButtonRelease
484 && dpyinfo
->display
== event
.xbutton
.display
)
486 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
487 #ifdef USE_MOTIF /* Pretending that the event came from a
488 Btn1Down seems the only way to convince Motif to
489 activate its callbacks; setting the XmNmenuPost
490 isn't working. --marcus@sysc.pdx.edu. */
491 event
.xbutton
.button
= 1;
492 /* Motif only pops down menus when no Ctrl, Alt or Mod
493 key is pressed and the button is released. So reset key state
494 so Motif thinks this is the case. */
495 event
.xbutton
.state
= 0;
498 /* Pop down on C-g and Escape. */
499 else if (event
.type
== KeyPress
500 && dpyinfo
->display
== event
.xbutton
.display
)
502 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
504 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
505 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
506 popup_activated_flag
= 0;
509 x_dispatch_event (&event
, event
.xany
.display
);
513 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
514 doc
: /* Start key navigation of the menu bar in FRAME.
515 This initially opens the first menu bar item and you can then navigate with the
516 arrow keys, select a menu entry with the return key or cancel with the
517 escape key. If FRAME has no menu bar this function does nothing.
519 If FRAME is nil or not given, use the selected frame. */)
523 FRAME_PTR f
= check_x_frame (frame
);
527 if (FRAME_EXTERNAL_MENU_BAR (f
))
528 set_frame_menubar (f
, 0, 1);
530 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
536 x_catch_errors (FRAME_X_DISPLAY (f
));
537 memset (&ev
, 0, sizeof ev
);
538 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
539 ev
.xbutton
.window
= XtWindow (menubar
);
540 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
541 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
542 ev
.xbutton
.button
= Button1
;
543 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
544 ev
.xbutton
.same_screen
= True
;
551 XtSetArg (al
[0], XtNchildren
, &list
);
552 XtSetArg (al
[1], XtNnumChildren
, &nr
);
553 XtGetValues (menubar
, al
, 2);
554 ev
.xbutton
.window
= XtWindow (list
[0]);
558 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
559 /* From-window, to-window. */
560 ev
.xbutton
.window
, ev
.xbutton
.root
,
562 /* From-position, to-position. */
563 ev
.xbutton
.x
, ev
.xbutton
.y
,
564 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
568 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
573 ev
.type
= ButtonPress
;
574 ev
.xbutton
.state
= 0;
576 XtDispatchEvent (&ev
);
577 ev
.xbutton
.type
= ButtonRelease
;
578 ev
.xbutton
.state
= Button1Mask
;
579 XtDispatchEvent (&ev
);
587 #endif /* USE_X_TOOLKIT */
591 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
592 doc
: /* Start key navigation of the menu bar in FRAME.
593 This initially opens the first menu bar item and you can then navigate with the
594 arrow keys, select a menu entry with the return key or cancel with the
595 escape key. If FRAME has no menu bar this function does nothing.
597 If FRAME is nil or not given, use the selected frame. */)
603 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
607 f
= check_x_frame (frame
);
609 if (FRAME_EXTERNAL_MENU_BAR (f
))
610 set_frame_menubar (f
, 0, 1);
612 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
615 /* Activate the first menu. */
616 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
620 g_signal_emit_by_name (children
->data
, "activate_item");
621 popup_activated_flag
= 1;
622 g_list_free (children
);
630 /* Loop util popup_activated_flag is set to zero in a callback.
631 Used for popup menus and dialogs. */
634 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
636 ++popup_activated_flag
;
638 /* Process events in the Gtk event loop until done. */
639 while (popup_activated_flag
)
641 if (do_timers
) x_menu_wait_for_event (0);
642 gtk_main_iteration ();
647 /* Activate the menu bar of frame F.
648 This is called from keyboard.c when it gets the
649 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
651 To activate the menu bar, we use the X button-press event
652 that was saved in saved_menu_event.
653 That makes the toolkit do its thing.
655 But first we recompute the menu bar contents (the whole tree).
657 The reason for saving the button event until here, instead of
658 passing it to the toolkit right away, is that we can safely
659 execute Lisp code. */
662 x_activate_menubar (FRAME_PTR f
)
667 if (!f
->output_data
.x
->saved_menu_event
->type
)
671 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
672 f
->output_data
.x
->saved_menu_event
->xany
.window
))
676 set_frame_menubar (f
, 0, 1);
679 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
680 f
->output_data
.x
->saved_menu_event
);
681 popup_activated_flag
= 1;
683 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
687 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
688 pending_menu_activation
= 1;
691 /* Ignore this if we get it a second time. */
692 f
->output_data
.x
->saved_menu_event
->type
= 0;
695 /* This callback is invoked when the user selects a menubar cascade
696 pushbutton, but before the pulldown menu is posted. */
700 popup_activate_callback (widget
, id
, client_data
)
703 XtPointer client_data
;
705 popup_activated_flag
= 1;
707 x_activate_timeout_atimer ();
712 /* This callback is invoked when a dialog or menu is finished being
713 used and has been unposted. */
717 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
719 popup_activated_flag
= 0;
723 popup_deactivate_callback (widget
, id
, client_data
)
726 XtPointer client_data
;
728 popup_activated_flag
= 0;
733 /* Function that finds the frame for WIDGET and shows the HELP text
735 F is the frame if known, or NULL if not known. */
737 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
743 XSETFRAME (frame
, f
);
744 kbd_buffer_store_help_event (frame
, help
);
748 #if 0 /* This code doesn't do anything useful. ++kfs */
749 /* WIDGET is the popup menu. It's parent is the frame's
750 widget. See which frame that is. */
751 xt_or_gtk_widget frame_widget
= XtParent (widget
);
754 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
758 && (f
= XFRAME (frame
),
759 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
763 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
767 /* Callback called when menu items are highlighted/unhighlighted
768 while moving the mouse over them. WIDGET is the menu bar or menu
769 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
770 the data structure for the menu item, or null in case of
775 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
777 xg_menu_item_cb_data
*cb_data
;
780 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
782 if (! cb_data
) return;
784 help
= call_data
? cb_data
->help
: Qnil
;
786 /* If popup_activated_flag is greater than 1 we are in a popup menu.
787 Don't show help for them, they won't appear before the
788 popup is popped down. */
789 if (popup_activated_flag
<= 1)
790 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
794 menu_highlight_callback (widget
, id
, call_data
)
802 widget_value
*wv
= (widget_value
*) call_data
;
804 help
= wv
? wv
->help
: Qnil
;
806 /* Determine the frame for the help event. */
807 f
= menubar_id_to_frame (id
);
809 show_help_event (f
, widget
, help
);
814 /* Gtk calls callbacks just because we tell it what item should be
815 selected in a radio group. If this variable is set to a non-zero
816 value, we are creating menus and don't want callbacks right now.
818 static int xg_crazy_callback_abort
;
820 /* This callback is called from the menu bar pulldown menu
821 when the user makes a selection.
822 Figure out what the user chose
823 and put the appropriate events into the keyboard buffer. */
825 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
827 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
829 if (xg_crazy_callback_abort
)
832 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
835 /* For a group of radio buttons, GTK calls the selection callback first
836 for the item that was active before the selection and then for the one that
837 is active after the selection. For C-h k this means we get the help on
838 the deselected item and then the selected item is executed. Prevent that
839 by ignoring the non-active item. */
840 if (GTK_IS_RADIO_MENU_ITEM (widget
)
841 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
844 /* When a menu is popped down, X generates a focus event (i.e. focus
845 goes back to the frame below the menu). Since GTK buffers events,
846 we force it out here before the menu selection event. Otherwise
847 sit-for will exit at once if the focus event follows the menu selection
851 while (gtk_events_pending ())
852 gtk_main_iteration ();
855 find_and_call_menu_selection (cb_data
->cl_data
->f
,
856 cb_data
->cl_data
->menu_bar_items_used
,
857 cb_data
->cl_data
->menu_bar_vector
,
861 #else /* not USE_GTK */
863 /* This callback is called from the menu bar pulldown menu
864 when the user makes a selection.
865 Figure out what the user chose
866 and put the appropriate events into the keyboard buffer. */
868 menubar_selection_callback (widget
, id
, client_data
)
871 XtPointer client_data
;
875 f
= menubar_id_to_frame (id
);
878 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
879 f
->menu_bar_vector
, client_data
);
881 #endif /* not USE_GTK */
883 /* Recompute all the widgets of frame F, when the menu bar has been
884 changed. Value is non-zero if widgets were updated. */
887 update_frame_menubar (FRAME_PTR f
)
890 return xg_update_frame_menubar (f
);
898 x
= f
->output_data
.x
;
900 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
904 /* Save the size of the frame because the pane widget doesn't accept
905 to resize itself. So force it. */
906 columns
= FRAME_COLS (f
);
907 rows
= FRAME_LINES (f
);
909 /* Do the voodoo which means "I'm changing lots of things, don't try
910 to refigure sizes until I'm done." */
911 lw_refigure_widget (x
->column_widget
, False
);
913 /* The order in which children are managed is the top to bottom
914 order in which they are displayed in the paned window. First,
915 remove the text-area widget. */
916 XtUnmanageChild (x
->edit_widget
);
918 /* Remove the menubar that is there now, and put up the menubar that
920 XtManageChild (x
->menubar_widget
);
921 XtMapWidget (x
->menubar_widget
);
922 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
924 /* Re-manage the text-area widget, and then thrash the sizes. */
925 XtManageChild (x
->edit_widget
);
926 lw_refigure_widget (x
->column_widget
, True
);
928 /* Force the pane widget to resize itself with the right values. */
929 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
937 apply_systemfont_to_dialog (w
)
940 const char *fn
= xsettings_get_system_normal_font ();
943 XrmDatabase db
= XtDatabase (XtDisplay (w
));
945 XrmPutStringResource (&db
, "*dialog.faceName", fn
);
950 apply_systemfont_to_menu (w
)
953 const char *fn
= xsettings_get_system_normal_font ();
958 if (XtIsShell (w
)) /* popup menu */
960 Widget
*childs
= NULL
;
962 XtVaGetValues (w
, XtNchildren
, &childs
, NULL
);
963 if (*childs
) w
= *childs
;
966 /* Only use system font if the default is used for the menu. */
967 XtVaGetValues (w
, XtNdefaultFace
, &defflt
, NULL
);
969 XtVaSetValues (w
, XtNfaceName
, fn
, NULL
);
973 /* Set the contents of the menubar widgets of frame F.
974 The argument FIRST_TIME is currently ignored;
975 it is set the first time this is called, from initialize_frame_menubar. */
978 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
980 xt_or_gtk_widget menubar_widget
;
985 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
987 int *submenu_start
, *submenu_end
;
988 int *submenu_top_level_items
, *submenu_n_panes
;
993 menubar_widget
= f
->output_data
.x
->menubar_widget
;
995 XSETFRAME (Vmenu_updating_frame
, f
);
998 if (f
->output_data
.x
->id
== 0)
999 f
->output_data
.x
->id
= next_menubar_widget_id
++;
1000 id
= f
->output_data
.x
->id
;
1003 if (! menubar_widget
)
1005 else if (pending_menu_activation
&& !deep_p
)
1007 /* Make the first call for any given frame always go deep. */
1008 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1011 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1012 f
->output_data
.x
->saved_menu_event
->type
= 0;
1016 /* If we have detached menus, we must update deep so detached menus
1017 also gets updated. */
1018 deep_p
= deep_p
|| xg_have_tear_offs ();
1023 /* Make a widget-value tree representing the entire menu trees. */
1025 struct buffer
*prev
= current_buffer
;
1027 int specpdl_count
= SPECPDL_INDEX ();
1028 int previous_menu_items_used
= f
->menu_bar_items_used
;
1029 Lisp_Object
*previous_items
1030 = (Lisp_Object
*) alloca (previous_menu_items_used
1031 * sizeof (Lisp_Object
));
1033 /* If we are making a new widget, its contents are empty,
1034 do always reinitialize them. */
1035 if (! menubar_widget
)
1036 previous_menu_items_used
= 0;
1038 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1039 specbind (Qinhibit_quit
, Qt
);
1040 /* Don't let the debugger step into this code
1041 because it is not reentrant. */
1042 specbind (Qdebug_on_next_call
, Qnil
);
1044 record_unwind_save_match_data ();
1045 if (NILP (Voverriding_local_map_menu_flag
))
1047 specbind (Qoverriding_terminal_local_map
, Qnil
);
1048 specbind (Qoverriding_local_map
, Qnil
);
1051 set_buffer_internal_1 (XBUFFER (buffer
));
1053 /* Run the Lucid hook. */
1054 safe_run_hooks (Qactivate_menubar_hook
);
1056 /* If it has changed current-menubar from previous value,
1057 really recompute the menubar from the value. */
1058 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1059 call0 (Qrecompute_lucid_menubar
);
1060 safe_run_hooks (Qmenu_bar_update_hook
);
1061 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1063 items
= FRAME_MENU_BAR_ITEMS (f
);
1065 /* Save the frame's previous menu bar contents data. */
1066 if (previous_menu_items_used
)
1067 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1068 previous_menu_items_used
* sizeof (Lisp_Object
));
1070 /* Fill in menu_items with the current menu bar contents.
1071 This can evaluate Lisp code. */
1074 menu_items
= f
->menu_bar_vector
;
1075 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1076 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1077 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1078 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1079 submenu_top_level_items
1080 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1082 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1084 Lisp_Object key
, string
, maps
;
1088 key
= XVECTOR (items
)->contents
[i
];
1089 string
= XVECTOR (items
)->contents
[i
+ 1];
1090 maps
= XVECTOR (items
)->contents
[i
+ 2];
1094 submenu_start
[i
] = menu_items_used
;
1096 menu_items_n_panes
= 0;
1097 submenu_top_level_items
[i
]
1098 = parse_single_submenu (key
, string
, maps
);
1099 submenu_n_panes
[i
] = menu_items_n_panes
;
1101 submenu_end
[i
] = menu_items_used
;
1104 finish_menu_items ();
1106 /* Convert menu_items into widget_value trees
1107 to display the menu. This cannot evaluate Lisp code. */
1109 wv
= xmalloc_widget_value ();
1110 wv
->name
= "menubar";
1113 wv
->button_type
= BUTTON_TYPE_NONE
;
1117 for (i
= 0; i
< last_i
; i
+= 4)
1119 menu_items_n_panes
= submenu_n_panes
[i
];
1120 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1121 submenu_top_level_items
[i
]);
1125 first_wv
->contents
= wv
;
1126 /* Don't set wv->name here; GC during the loop might relocate it. */
1128 wv
->button_type
= BUTTON_TYPE_NONE
;
1132 set_buffer_internal_1 (prev
);
1134 /* If there has been no change in the Lisp-level contents
1135 of the menu bar, skip redisplaying it. Just exit. */
1137 /* Compare the new menu items with the ones computed last time. */
1138 for (i
= 0; i
< previous_menu_items_used
; i
++)
1139 if (menu_items_used
== i
1140 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1142 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1144 /* The menu items have not changed. Don't bother updating
1145 the menus in any form, since it would be a no-op. */
1146 free_menubar_widget_value_tree (first_wv
);
1147 discard_menu_items ();
1148 unbind_to (specpdl_count
, Qnil
);
1152 /* The menu items are different, so store them in the frame. */
1153 f
->menu_bar_vector
= menu_items
;
1154 f
->menu_bar_items_used
= menu_items_used
;
1156 /* This undoes save_menu_items. */
1157 unbind_to (specpdl_count
, Qnil
);
1159 /* Now GC cannot happen during the lifetime of the widget_value,
1160 so it's safe to store data from a Lisp_String. */
1161 wv
= first_wv
->contents
;
1162 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1165 string
= XVECTOR (items
)->contents
[i
+ 1];
1168 wv
->name
= (char *) SDATA (string
);
1169 update_submenu_strings (wv
->contents
);
1176 /* Make a widget-value tree containing
1177 just the top level menu bar strings. */
1179 wv
= xmalloc_widget_value ();
1180 wv
->name
= "menubar";
1183 wv
->button_type
= BUTTON_TYPE_NONE
;
1187 items
= FRAME_MENU_BAR_ITEMS (f
);
1188 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1192 string
= XVECTOR (items
)->contents
[i
+ 1];
1196 wv
= xmalloc_widget_value ();
1197 wv
->name
= (char *) SDATA (string
);
1200 wv
->button_type
= BUTTON_TYPE_NONE
;
1202 /* This prevents lwlib from assuming this
1203 menu item is really supposed to be empty. */
1204 /* The EMACS_INT cast avoids a warning.
1205 This value just has to be different from small integers. */
1206 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1211 first_wv
->contents
= wv
;
1215 /* Forget what we thought we knew about what is in the
1216 detailed contents of the menu bar menus.
1217 Changing the top level always destroys the contents. */
1218 f
->menu_bar_items_used
= 0;
1221 /* Create or update the menu bar widget. */
1226 xg_crazy_callback_abort
= 1;
1229 /* The fourth arg is DEEP_P, which says to consider the entire
1230 menu trees we supply, rather than just the menu bar item names. */
1231 xg_modify_menubar_widgets (menubar_widget
,
1235 G_CALLBACK (menubar_selection_callback
),
1236 G_CALLBACK (popup_deactivate_callback
),
1237 G_CALLBACK (menu_highlight_callback
));
1241 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1244 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1245 G_CALLBACK (menubar_selection_callback
),
1246 G_CALLBACK (popup_deactivate_callback
),
1247 G_CALLBACK (menu_highlight_callback
));
1249 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1253 #else /* not USE_GTK */
1256 /* Disable resizing (done for Motif!) */
1257 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1259 /* The third arg is DEEP_P, which says to consider the entire
1260 menu trees we supply, rather than just the menu bar item names. */
1261 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1263 /* Re-enable the edit widget to resize. */
1264 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1268 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1269 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1271 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1272 f
->output_data
.x
->column_widget
,
1274 popup_activate_callback
,
1275 menubar_selection_callback
,
1276 popup_deactivate_callback
,
1277 menu_highlight_callback
);
1278 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1280 /* Make menu pop down on C-g. */
1281 XtOverrideTranslations (menubar_widget
, override
);
1283 apply_systemfont_to_menu (menubar_widget
);
1289 = (f
->output_data
.x
->menubar_widget
1290 ? (f
->output_data
.x
->menubar_widget
->core
.height
1291 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1294 #if 1 /* Experimentally, we now get the right results
1295 for -geometry -0-0 without this. 24 Aug 96, rms.
1296 Maybe so, but the menu bar size is missing the pixels so the
1297 WM size hints are off by theses pixel. Jan D, oct 2009. */
1299 if (FRAME_EXTERNAL_MENU_BAR (f
))
1302 XtVaGetValues (f
->output_data
.x
->column_widget
,
1303 XtNinternalBorderWidth
, &ibw
, NULL
);
1304 menubar_size
+= ibw
;
1306 #endif /* USE_LUCID */
1309 f
->output_data
.x
->menubar_height
= menubar_size
;
1311 #endif /* not USE_GTK */
1313 free_menubar_widget_value_tree (first_wv
);
1314 update_frame_menubar (f
);
1317 xg_crazy_callback_abort
= 0;
1323 /* Called from Fx_create_frame to create the initial menubar of a frame
1324 before it is mapped, so that the window is mapped with the menubar already
1325 there instead of us tacking it on later and thrashing the window after it
1329 initialize_frame_menubar (FRAME_PTR f
)
1331 /* This function is called before the first chance to redisplay
1332 the frame. It has to be, so the frame will have the right size. */
1333 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1334 set_frame_menubar (f
, 1, 1);
1338 /* Get rid of the menu bar of frame F, and free its storage.
1339 This is used when deleting a frame, and when turning off the menu bar.
1340 For GTK this function is in gtkutil.c. */
1344 free_frame_menubar (f
)
1347 Widget menubar_widget
;
1349 if (! FRAME_X_P (f
))
1352 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1354 f
->output_data
.x
->menubar_height
= 0;
1359 /* Removing the menu bar magically changes the shell widget's x
1360 and y position of (0, 0) which, when the menu bar is turned
1361 on again, leads to pull-down menuss appearing in strange
1362 positions near the upper-left corner of the display. This
1363 happens only with some window managers like twm and ctwm,
1364 but not with other like Motif's mwm or kwm, because the
1365 latter generate ConfigureNotify events when the menu bar
1366 is switched off, which fixes the shell position. */
1367 Position x0
, y0
, x1
, y1
;
1373 if (f
->output_data
.x
->widget
)
1374 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1377 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1378 f
->output_data
.x
->menubar_widget
= NULL
;
1381 if (f
->output_data
.x
->widget
)
1383 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1384 if (x1
== 0 && y1
== 0)
1385 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1392 #endif /* not USE_GTK */
1394 #endif /* USE_X_TOOLKIT || USE_GTK */
1396 /* xmenu_show actually displays a menu using the panes and items in menu_items
1397 and returns the value selected from it.
1398 There are two versions of xmenu_show, one for Xt and one for Xlib.
1399 Both assume input is blocked by the caller. */
1401 /* F is the frame the menu is for.
1402 X and Y are the frame-relative specified position,
1403 relative to the inside upper left corner of the frame F.
1404 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1405 KEYMAPS is 1 if this menu was specified with keymaps;
1406 in that case, we return a list containing the chosen item's value
1407 and perhaps also the pane's prefix.
1408 TITLE is the specified menu title.
1409 ERROR is a place to store an error message string in case of failure.
1410 (We return nil on failure, but the value doesn't actually matter.) */
1412 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1414 /* The item selected in the popup menu. */
1415 static Lisp_Object
*volatile menu_item_selection
;
1419 /* Used when position a popup menu. See menu_position_func and
1420 create_and_show_popup_menu below. */
1421 struct next_popup_x_y
1428 /* The menu position function to use if we are not putting a popup
1429 menu where the pointer is.
1430 MENU is the menu to pop up.
1431 X and Y shall on exit contain x/y where the menu shall pop up.
1432 PUSH_IN is not documented in the GTK manual.
1433 USER_DATA is any data passed in when calling gtk_menu_popup.
1434 Here it points to a struct next_popup_x_y where the coordinates
1435 to store in *X and *Y are as well as the frame for the popup.
1437 Here only X and Y are used. */
1439 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1441 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1443 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1444 int disp_width
= x_display_pixel_width (dpyinfo
);
1445 int disp_height
= x_display_pixel_height (dpyinfo
);
1450 /* Check if there is room for the menu. If not, adjust x/y so that
1451 the menu is fully visible. */
1452 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1453 if (data
->x
+ req
.width
> disp_width
)
1454 *x
-= data
->x
+ req
.width
- disp_width
;
1455 if (data
->y
+ req
.height
> disp_height
)
1456 *y
-= data
->y
+ req
.height
- disp_height
;
1460 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1462 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1464 if (xg_crazy_callback_abort
) return;
1465 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1469 pop_down_menu (Lisp_Object arg
)
1471 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1473 popup_activated_flag
= 0;
1475 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1480 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1482 menu_item_selection will be set to the selection. */
1484 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1488 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1489 struct next_popup_x_y popup_x_y
;
1490 int specpdl_count
= SPECPDL_INDEX ();
1492 if (! FRAME_X_P (f
))
1495 xg_crazy_callback_abort
= 1;
1496 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1497 G_CALLBACK (popup_selection_callback
),
1498 G_CALLBACK (popup_deactivate_callback
),
1499 G_CALLBACK (menu_highlight_callback
));
1500 xg_crazy_callback_abort
= 0;
1504 /* Not invoked by a click. pop up at x/y. */
1505 pos_func
= menu_position_func
;
1507 /* Adjust coordinates to be root-window-relative. */
1508 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1509 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1515 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1519 for (i
= 0; i
< 5; i
++)
1520 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1524 /* Display the menu. */
1525 gtk_widget_show_all (menu
);
1527 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1528 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1530 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1532 if (gtk_widget_get_mapped (menu
))
1534 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1535 two. show_help_echo uses this to detect popup menus. */
1536 popup_activated_flag
= 1;
1537 /* Process events that apply to the menu. */
1538 popup_widget_loop (1, menu
);
1541 unbind_to (specpdl_count
, Qnil
);
1543 /* Must reset this manually because the button release event is not passed
1544 to Emacs event loop. */
1545 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1548 #else /* not USE_GTK */
1550 /* We need a unique id for each widget handled by the Lucid Widget
1553 For the main windows, and popup menus, we use this counter,
1554 which we increment each time after use. This starts from 1<<16.
1556 For menu bars, we use numbers starting at 0, counted in
1557 next_menubar_widget_id. */
1558 LWLIB_ID widget_id_tick
;
1561 popup_selection_callback (widget
, id
, client_data
)
1564 XtPointer client_data
;
1566 menu_item_selection
= (Lisp_Object
*) client_data
;
1569 /* ARG is the LWLIB ID of the dialog box, represented
1570 as a Lisp object as (HIGHPART . LOWPART). */
1576 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1577 | XINT (XCDR (arg
)));
1580 lw_destroy_all_widgets (id
);
1582 popup_activated_flag
= 0;
1587 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1589 menu_item_selection will be set to the selection. */
1591 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1593 widget_value
*first_wv
;
1597 EMACS_UINT timestamp
;
1602 XButtonPressedEvent dummy
;
1606 if (! FRAME_X_P (f
))
1609 menu_id
= widget_id_tick
++;
1610 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1611 f
->output_data
.x
->widget
, 1, 0,
1612 popup_selection_callback
,
1613 popup_deactivate_callback
,
1614 menu_highlight_callback
);
1617 apply_systemfont_to_menu (menu
);
1620 dummy
.type
= ButtonPress
;
1622 dummy
.send_event
= 0;
1623 dummy
.display
= FRAME_X_DISPLAY (f
);
1624 dummy
.time
= CurrentTime
;
1625 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1626 dummy
.window
= dummy
.root
;
1627 dummy
.subwindow
= dummy
.root
;
1631 /* Adjust coordinates to be root-window-relative. */
1632 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1633 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1640 for (i
= 0; i
< 5; i
++)
1641 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1644 /* Don't allow any geometry request from the user. */
1645 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1646 XtSetValues (menu
, av
, ac
);
1648 /* Display the menu. */
1649 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1650 popup_activated_flag
= 1;
1651 x_activate_timeout_atimer ();
1654 int fact
= 4 * sizeof (LWLIB_ID
);
1655 int specpdl_count
= SPECPDL_INDEX ();
1656 record_unwind_protect (pop_down_menu
,
1657 Fcons (make_number (menu_id
>> (fact
)),
1658 make_number (menu_id
& ~(-1 << (fact
)))));
1660 /* Process events that apply to the menu. */
1661 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1663 unbind_to (specpdl_count
, Qnil
);
1667 #endif /* not USE_GTK */
1670 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1671 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1674 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1675 widget_value
**submenu_stack
1676 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1677 Lisp_Object
*subprefix_stack
1678 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1679 int submenu_depth
= 0;
1683 if (! FRAME_X_P (f
))
1688 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1690 *error
= "Empty menu";
1694 /* Create a tree of widget_value objects
1695 representing the panes and their items. */
1696 wv
= xmalloc_widget_value ();
1700 wv
->button_type
= BUTTON_TYPE_NONE
;
1705 /* Loop over all panes and items, filling in the tree. */
1707 while (i
< menu_items_used
)
1709 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1711 submenu_stack
[submenu_depth
++] = save_wv
;
1717 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1720 save_wv
= submenu_stack
[--submenu_depth
];
1724 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1725 && submenu_depth
!= 0)
1726 i
+= MENU_ITEMS_PANE_LENGTH
;
1727 /* Ignore a nil in the item list.
1728 It's meaningful only for dialog boxes. */
1729 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1731 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1733 /* Create a new pane. */
1734 Lisp_Object pane_name
, prefix
;
1737 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1738 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1740 #ifndef HAVE_MULTILINGUAL_MENU
1741 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1743 pane_name
= ENCODE_MENU_STRING (pane_name
);
1744 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1747 pane_string
= (NILP (pane_name
)
1748 ? "" : (char *) SDATA (pane_name
));
1749 /* If there is just one top-level pane, put all its items directly
1750 under the top-level menu. */
1751 if (menu_items_n_panes
== 1)
1754 /* If the pane has a meaningful name,
1755 make the pane a top-level menu item
1756 with its items as a submenu beneath it. */
1757 if (!keymaps
&& strcmp (pane_string
, ""))
1759 wv
= xmalloc_widget_value ();
1763 first_wv
->contents
= wv
;
1764 wv
->name
= pane_string
;
1765 if (keymaps
&& !NILP (prefix
))
1769 wv
->button_type
= BUTTON_TYPE_NONE
;
1774 else if (first_pane
)
1780 i
+= MENU_ITEMS_PANE_LENGTH
;
1784 /* Create a new item within current pane. */
1785 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1786 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1787 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1788 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1789 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1790 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1791 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1792 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1794 #ifndef HAVE_MULTILINGUAL_MENU
1795 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1797 item_name
= ENCODE_MENU_STRING (item_name
);
1798 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1801 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1803 descrip
= ENCODE_MENU_STRING (descrip
);
1804 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1806 #endif /* not HAVE_MULTILINGUAL_MENU */
1808 wv
= xmalloc_widget_value ();
1812 save_wv
->contents
= wv
;
1813 wv
->name
= (char *) SDATA (item_name
);
1814 if (!NILP (descrip
))
1815 wv
->key
= (char *) SDATA (descrip
);
1817 /* If this item has a null value,
1818 make the call_data null so that it won't display a box
1819 when the mouse is on it. */
1821 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1822 wv
->enabled
= !NILP (enable
);
1825 wv
->button_type
= BUTTON_TYPE_NONE
;
1826 else if (EQ (type
, QCtoggle
))
1827 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1828 else if (EQ (type
, QCradio
))
1829 wv
->button_type
= BUTTON_TYPE_RADIO
;
1833 wv
->selected
= !NILP (selected
);
1835 if (! STRINGP (help
))
1842 i
+= MENU_ITEMS_ITEM_LENGTH
;
1846 /* Deal with the title, if it is non-nil. */
1849 widget_value
*wv_title
= xmalloc_widget_value ();
1850 widget_value
*wv_sep1
= xmalloc_widget_value ();
1851 widget_value
*wv_sep2
= xmalloc_widget_value ();
1853 wv_sep2
->name
= "--";
1854 wv_sep2
->next
= first_wv
->contents
;
1855 wv_sep2
->help
= Qnil
;
1857 wv_sep1
->name
= "--";
1858 wv_sep1
->next
= wv_sep2
;
1859 wv_sep1
->help
= Qnil
;
1861 #ifndef HAVE_MULTILINGUAL_MENU
1862 if (STRING_MULTIBYTE (title
))
1863 title
= ENCODE_MENU_STRING (title
);
1866 wv_title
->name
= (char *) SDATA (title
);
1867 wv_title
->enabled
= TRUE
;
1868 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1869 wv_title
->help
= Qnil
;
1870 wv_title
->next
= wv_sep1
;
1871 first_wv
->contents
= wv_title
;
1874 /* No selection has been chosen yet. */
1875 menu_item_selection
= 0;
1877 /* Actually create and show the menu until popped down. */
1878 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1880 /* Free the widget_value objects we used to specify the contents. */
1881 free_menubar_widget_value_tree (first_wv
);
1883 /* Find the selected item, and its pane, to return
1884 the proper value. */
1885 if (menu_item_selection
!= 0)
1887 Lisp_Object prefix
, entry
;
1889 prefix
= entry
= Qnil
;
1891 while (i
< menu_items_used
)
1893 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1895 subprefix_stack
[submenu_depth
++] = prefix
;
1899 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1901 prefix
= subprefix_stack
[--submenu_depth
];
1904 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1907 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1908 i
+= MENU_ITEMS_PANE_LENGTH
;
1910 /* Ignore a nil in the item list.
1911 It's meaningful only for dialog boxes. */
1912 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1917 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1918 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1924 entry
= Fcons (entry
, Qnil
);
1926 entry
= Fcons (prefix
, entry
);
1927 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1928 if (!NILP (subprefix_stack
[j
]))
1929 entry
= Fcons (subprefix_stack
[j
], entry
);
1933 i
+= MENU_ITEMS_ITEM_LENGTH
;
1937 else if (!for_click
)
1938 /* Make "Cancel" equivalent to C-g. */
1939 Fsignal (Qquit
, Qnil
);
1946 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1948 /* The EMACS_INT cast avoids a warning. There's no problem
1949 as long as pointers have enough bits to hold small integers. */
1950 if ((int) (EMACS_INT
) client_data
!= -1)
1951 menu_item_selection
= (Lisp_Object
*) client_data
;
1953 popup_activated_flag
= 0;
1956 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1958 menu_item_selection will be set to the selection. */
1960 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1964 if (! FRAME_X_P (f
))
1967 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1968 G_CALLBACK (dialog_selection_callback
),
1969 G_CALLBACK (popup_deactivate_callback
),
1974 int specpdl_count
= SPECPDL_INDEX ();
1975 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1977 /* Display the menu. */
1978 gtk_widget_show_all (menu
);
1980 /* Process events that apply to the menu. */
1981 popup_widget_loop (1, menu
);
1983 unbind_to (specpdl_count
, Qnil
);
1987 #else /* not USE_GTK */
1989 dialog_selection_callback (widget
, id
, client_data
)
1992 XtPointer client_data
;
1994 /* The EMACS_INT cast avoids a warning. There's no problem
1995 as long as pointers have enough bits to hold small integers. */
1996 if ((int) (EMACS_INT
) client_data
!= -1)
1997 menu_item_selection
= (Lisp_Object
*) client_data
;
2000 lw_destroy_all_widgets (id
);
2002 popup_activated_flag
= 0;
2006 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2008 menu_item_selection will be set to the selection. */
2010 create_and_show_dialog (f
, first_wv
)
2012 widget_value
*first_wv
;
2019 dialog_id
= widget_id_tick
++;
2021 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
2023 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2024 f
->output_data
.x
->widget
, 1, 0,
2025 dialog_selection_callback
, 0, 0);
2026 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2027 /* Display the dialog box. */
2028 lw_pop_up_all_widgets (dialog_id
);
2029 popup_activated_flag
= 1;
2030 x_activate_timeout_atimer ();
2032 /* Process events that apply to the dialog box.
2033 Also handle timers. */
2035 int count
= SPECPDL_INDEX ();
2036 int fact
= 4 * sizeof (LWLIB_ID
);
2038 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2039 record_unwind_protect (pop_down_menu
,
2040 Fcons (make_number (dialog_id
>> (fact
)),
2041 make_number (dialog_id
& ~(-1 << (fact
)))));
2043 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2046 unbind_to (count
, Qnil
);
2050 #endif /* not USE_GTK */
2052 static char * button_names
[] = {
2053 "button1", "button2", "button3", "button4", "button5",
2054 "button6", "button7", "button8", "button9", "button10" };
2057 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2059 int i
, nb_buttons
=0;
2060 char dialog_name
[6];
2062 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2064 /* Number of elements seen so far, before boundary. */
2066 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2067 int boundary_seen
= 0;
2069 if (! FRAME_X_P (f
))
2074 if (menu_items_n_panes
> 1)
2076 *error_name
= "Multiple panes in dialog box";
2080 /* Create a tree of widget_value objects
2081 representing the text label and buttons. */
2083 Lisp_Object pane_name
, prefix
;
2085 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2086 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2087 pane_string
= (NILP (pane_name
)
2088 ? "" : (char *) SDATA (pane_name
));
2089 prev_wv
= xmalloc_widget_value ();
2090 prev_wv
->value
= pane_string
;
2091 if (keymaps
&& !NILP (prefix
))
2093 prev_wv
->enabled
= 1;
2094 prev_wv
->name
= "message";
2095 prev_wv
->help
= Qnil
;
2098 /* Loop over all panes and items, filling in the tree. */
2099 i
= MENU_ITEMS_PANE_LENGTH
;
2100 while (i
< menu_items_used
)
2103 /* Create a new item within current pane. */
2104 Lisp_Object item_name
, enable
, descrip
;
2105 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2106 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2108 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2110 if (NILP (item_name
))
2112 free_menubar_widget_value_tree (first_wv
);
2113 *error_name
= "Submenu in dialog items";
2116 if (EQ (item_name
, Qquote
))
2118 /* This is the boundary between left-side elts
2119 and right-side elts. Stop incrementing right_count. */
2124 if (nb_buttons
>= 9)
2126 free_menubar_widget_value_tree (first_wv
);
2127 *error_name
= "Too many dialog items";
2131 wv
= xmalloc_widget_value ();
2133 wv
->name
= (char *) button_names
[nb_buttons
];
2134 if (!NILP (descrip
))
2135 wv
->key
= (char *) SDATA (descrip
);
2136 wv
->value
= (char *) SDATA (item_name
);
2137 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2138 wv
->enabled
= !NILP (enable
);
2142 if (! boundary_seen
)
2146 i
+= MENU_ITEMS_ITEM_LENGTH
;
2149 /* If the boundary was not specified,
2150 by default put half on the left and half on the right. */
2151 if (! boundary_seen
)
2152 left_count
= nb_buttons
- nb_buttons
/ 2;
2154 wv
= xmalloc_widget_value ();
2155 wv
->name
= dialog_name
;
2158 /* Frame title: 'Q' = Question, 'I' = Information.
2159 Can also have 'E' = Error if, one day, we want
2160 a popup for errors. */
2162 dialog_name
[0] = 'Q';
2164 dialog_name
[0] = 'I';
2166 /* Dialog boxes use a really stupid name encoding
2167 which specifies how many buttons to use
2168 and how many buttons are on the right. */
2169 dialog_name
[1] = '0' + nb_buttons
;
2170 dialog_name
[2] = 'B';
2171 dialog_name
[3] = 'R';
2172 /* Number of buttons to put on the right. */
2173 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2175 wv
->contents
= first_wv
;
2179 /* No selection has been chosen yet. */
2180 menu_item_selection
= 0;
2182 /* Actually create and show the dialog. */
2183 create_and_show_dialog (f
, first_wv
);
2185 /* Free the widget_value objects we used to specify the contents. */
2186 free_menubar_widget_value_tree (first_wv
);
2188 /* Find the selected item, and its pane, to return
2189 the proper value. */
2190 if (menu_item_selection
!= 0)
2196 while (i
< menu_items_used
)
2200 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2203 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2204 i
+= MENU_ITEMS_PANE_LENGTH
;
2206 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2208 /* This is the boundary between left-side elts and
2215 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2216 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2220 entry
= Fcons (entry
, Qnil
);
2222 entry
= Fcons (prefix
, entry
);
2226 i
+= MENU_ITEMS_ITEM_LENGTH
;
2231 /* Make "Cancel" equivalent to C-g. */
2232 Fsignal (Qquit
, Qnil
);
2237 #else /* not USE_X_TOOLKIT && not USE_GTK */
2239 /* The frame of the last activated non-toolkit menu bar.
2240 Used to generate menu help events. */
2242 static struct frame
*menu_help_frame
;
2245 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2247 PANE is the pane number, and ITEM is the menu item number in
2248 the menu (currently not used).
2250 This cannot be done with generating a HELP_EVENT because
2251 XMenuActivate contains a loop that doesn't let Emacs process
2255 menu_help_callback (help_string
, pane
, item
)
2259 extern Lisp_Object Qmenu_item
;
2260 Lisp_Object
*first_item
;
2261 Lisp_Object pane_name
;
2262 Lisp_Object menu_object
;
2264 first_item
= XVECTOR (menu_items
)->contents
;
2265 if (EQ (first_item
[0], Qt
))
2266 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2267 else if (EQ (first_item
[0], Qquote
))
2268 /* This shouldn't happen, see xmenu_show. */
2269 pane_name
= empty_unibyte_string
;
2271 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2273 /* (menu-item MENU-NAME PANE-NUMBER) */
2274 menu_object
= Fcons (Qmenu_item
,
2276 Fcons (make_number (pane
), Qnil
)));
2277 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2278 Qnil
, menu_object
, make_number (item
), 1);
2285 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2286 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2288 FRAME_PTR f
= p1
->pointer
;
2289 XMenu
*menu
= p2
->pointer
;
2293 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2294 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2296 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2298 #ifdef HAVE_X_WINDOWS
2299 /* Assume the mouse has moved out of the X window.
2300 If it has actually moved in, we will get an EnterNotify. */
2301 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2303 /* State that no mouse buttons are now held.
2304 (The oldXMenu code doesn't track this info for us.)
2305 That is not necessarily true, but the fiction leads to reasonable
2306 results, and it is a pain to ask which are actually held now. */
2307 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2309 #endif /* HAVE_X_WINDOWS */
2318 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
2325 EMACS_UINT timestamp
;
2329 int pane
, selidx
, lpane
, status
;
2330 Lisp_Object entry
, pane_prefix
;
2332 int ulx
, uly
, width
, height
;
2333 int dispwidth
, dispheight
;
2334 int i
, j
, lines
, maxlines
;
2337 unsigned int dummy_uint
;
2338 int specpdl_count
= SPECPDL_INDEX ();
2340 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2344 if (menu_items_n_panes
== 0)
2347 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2349 *error
= "Empty menu";
2353 /* Figure out which root window F is on. */
2354 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2355 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2356 &dummy_uint
, &dummy_uint
);
2358 /* Make the menu on that window. */
2359 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2362 *error
= "Can't create menu";
2366 /* Don't GC while we prepare and show the menu,
2367 because we give the oldxmenu library pointers to the
2368 contents of strings. */
2369 inhibit_garbage_collection ();
2371 #ifdef HAVE_X_WINDOWS
2372 /* Adjust coordinates to relative to the outer (window manager) window. */
2373 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2374 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2375 #endif /* HAVE_X_WINDOWS */
2377 /* Adjust coordinates to be root-window-relative. */
2381 /* Create all the necessary panes and their items. */
2382 maxlines
= lines
= i
= 0;
2383 while (i
< menu_items_used
)
2385 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2387 /* Create a new pane. */
2388 Lisp_Object pane_name
, prefix
;
2391 maxlines
= max (maxlines
, lines
);
2393 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2394 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2395 pane_string
= (NILP (pane_name
)
2396 ? "" : (char *) SDATA (pane_name
));
2397 if (keymaps
&& !NILP (prefix
))
2400 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2401 if (lpane
== XM_FAILURE
)
2403 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2404 *error
= "Can't create pane";
2407 i
+= MENU_ITEMS_PANE_LENGTH
;
2409 /* Find the width of the widest item in this pane. */
2412 while (j
< menu_items_used
)
2415 item
= XVECTOR (menu_items
)->contents
[j
];
2423 width
= SBYTES (item
);
2424 if (width
> maxwidth
)
2427 j
+= MENU_ITEMS_ITEM_LENGTH
;
2430 /* Ignore a nil in the item list.
2431 It's meaningful only for dialog boxes. */
2432 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2436 /* Create a new item within current pane. */
2437 Lisp_Object item_name
, enable
, descrip
, help
;
2438 unsigned char *item_data
;
2441 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2442 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2444 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2445 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2446 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2448 if (!NILP (descrip
))
2450 int gap
= maxwidth
- SBYTES (item_name
);
2451 /* if alloca is fast, use that to make the space,
2452 to reduce gc needs. */
2454 = (unsigned char *) alloca (maxwidth
2455 + SBYTES (descrip
) + 1);
2456 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2457 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2459 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2460 item_data
[j
+ SBYTES (descrip
)] = 0;
2463 item_data
= SDATA (item_name
);
2465 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2466 menu
, lpane
, 0, item_data
,
2467 !NILP (enable
), help_string
)
2470 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2471 *error
= "Can't add selection to menu";
2474 i
+= MENU_ITEMS_ITEM_LENGTH
;
2479 maxlines
= max (maxlines
, lines
);
2481 /* All set and ready to fly. */
2482 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2483 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2484 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2485 x
= min (x
, dispwidth
);
2486 y
= min (y
, dispheight
);
2489 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2490 &ulx
, &uly
, &width
, &height
);
2491 if (ulx
+width
> dispwidth
)
2493 x
-= (ulx
+ width
) - dispwidth
;
2494 ulx
= dispwidth
- width
;
2496 if (uly
+height
> dispheight
)
2498 y
-= (uly
+ height
) - dispheight
;
2499 uly
= dispheight
- height
;
2501 #ifndef HAVE_X_WINDOWS
2502 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2504 /* Move the menu away of the echo area, to avoid overwriting the
2505 menu with help echo messages or vice versa. */
2506 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2508 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2509 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2518 if (ulx
< 0) x
-= ulx
;
2519 if (uly
< 0) y
-= uly
;
2523 /* If position was not given by a mouse click, adjust so upper left
2524 corner of the menu as a whole ends up at given coordinates. This
2525 is what x-popup-menu says in its documentation. */
2527 y
+= 1.5*height
/(maxlines
+2);
2530 XMenuSetAEQ (menu
, TRUE
);
2531 XMenuSetFreeze (menu
, TRUE
);
2535 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2538 record_unwind_protect (pop_down_menu
,
2539 Fcons (make_save_value (f
, 0),
2540 make_save_value (menu
, 0)));
2542 /* Help display under X won't work because XMenuActivate contains
2543 a loop that doesn't give Emacs a chance to process it. */
2544 menu_help_frame
= f
;
2545 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2546 x
, y
, ButtonReleaseMask
, &datap
,
2547 menu_help_callback
);
2553 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2556 /* Find the item number SELIDX in pane number PANE. */
2558 while (i
< menu_items_used
)
2560 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2564 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2566 i
+= MENU_ITEMS_PANE_LENGTH
;
2575 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2578 entry
= Fcons (entry
, Qnil
);
2579 if (!NILP (pane_prefix
))
2580 entry
= Fcons (pane_prefix
, entry
);
2586 i
+= MENU_ITEMS_ITEM_LENGTH
;
2592 *error
= "Can't activate menu";
2597 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2598 the menu was invoked with a mouse event as POSITION). */
2600 Fsignal (Qquit
, Qnil
);
2605 unbind_to (specpdl_count
, Qnil
);
2610 #endif /* not USE_X_TOOLKIT */
2612 #endif /* HAVE_MENUS */
2614 /* Detect if a dialog or menu has been posted. */
2617 popup_activated (void)
2619 return popup_activated_flag
;
2622 /* The following is used by delayed window autoselection. */
2624 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2625 doc
: /* Return t if a menu or popup dialog is active. */)
2629 return (popup_activated ()) ? Qt
: Qnil
;
2632 #endif /* HAVE_MENUS */
2636 syms_of_xmenu (void)
2638 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2639 staticpro (&Qdebug_on_next_call
);
2641 #ifdef USE_X_TOOLKIT
2642 widget_id_tick
= (1<<16);
2643 next_menubar_widget_id
= 1;
2646 defsubr (&Smenu_or_popup_active_p
);
2648 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2649 defsubr (&Sx_menu_bar_open_internal
);
2650 Ffset (intern_c_string ("accelerate-menu"),
2651 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2655 defsubr (&Sx_popup_dialog
);
2659 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2660 (do not change this comment) */