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
);
1288 if (f
->output_data
.x
->menubar_widget
)
1289 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1292 = (f
->output_data
.x
->menubar_widget
1293 ? (f
->output_data
.x
->menubar_widget
->core
.height
1294 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1297 #if 1 /* Experimentally, we now get the right results
1298 for -geometry -0-0 without this. 24 Aug 96, rms.
1299 Maybe so, but the menu bar size is missing the pixels so the
1300 WM size hints are off by theses pixel. Jan D, oct 2009. */
1302 if (FRAME_EXTERNAL_MENU_BAR (f
))
1305 XtVaGetValues (f
->output_data
.x
->column_widget
,
1306 XtNinternalBorderWidth
, &ibw
, NULL
);
1307 menubar_size
+= ibw
;
1309 #endif /* USE_LUCID */
1312 f
->output_data
.x
->menubar_height
= menubar_size
;
1314 #endif /* not USE_GTK */
1316 free_menubar_widget_value_tree (first_wv
);
1317 update_frame_menubar (f
);
1320 xg_crazy_callback_abort
= 0;
1326 /* Called from Fx_create_frame to create the initial menubar of a frame
1327 before it is mapped, so that the window is mapped with the menubar already
1328 there instead of us tacking it on later and thrashing the window after it
1332 initialize_frame_menubar (FRAME_PTR f
)
1334 /* This function is called before the first chance to redisplay
1335 the frame. It has to be, so the frame will have the right size. */
1336 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1337 set_frame_menubar (f
, 1, 1);
1341 /* Get rid of the menu bar of frame F, and free its storage.
1342 This is used when deleting a frame, and when turning off the menu bar.
1343 For GTK this function is in gtkutil.c. */
1347 free_frame_menubar (f
)
1350 Widget menubar_widget
;
1352 if (! FRAME_X_P (f
))
1355 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1357 f
->output_data
.x
->menubar_height
= 0;
1362 /* Removing the menu bar magically changes the shell widget's x
1363 and y position of (0, 0) which, when the menu bar is turned
1364 on again, leads to pull-down menuss appearing in strange
1365 positions near the upper-left corner of the display. This
1366 happens only with some window managers like twm and ctwm,
1367 but not with other like Motif's mwm or kwm, because the
1368 latter generate ConfigureNotify events when the menu bar
1369 is switched off, which fixes the shell position. */
1370 Position x0
, y0
, x1
, y1
;
1376 if (f
->output_data
.x
->widget
)
1377 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1380 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1381 f
->output_data
.x
->menubar_widget
= NULL
;
1384 if (f
->output_data
.x
->widget
)
1386 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1387 if (x1
== 0 && y1
== 0)
1388 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1391 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1395 #endif /* not USE_GTK */
1397 #endif /* USE_X_TOOLKIT || USE_GTK */
1399 /* xmenu_show actually displays a menu using the panes and items in menu_items
1400 and returns the value selected from it.
1401 There are two versions of xmenu_show, one for Xt and one for Xlib.
1402 Both assume input is blocked by the caller. */
1404 /* F is the frame the menu is for.
1405 X and Y are the frame-relative specified position,
1406 relative to the inside upper left corner of the frame F.
1407 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1408 KEYMAPS is 1 if this menu was specified with keymaps;
1409 in that case, we return a list containing the chosen item's value
1410 and perhaps also the pane's prefix.
1411 TITLE is the specified menu title.
1412 ERROR is a place to store an error message string in case of failure.
1413 (We return nil on failure, but the value doesn't actually matter.) */
1415 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1417 /* The item selected in the popup menu. */
1418 static Lisp_Object
*volatile menu_item_selection
;
1422 /* Used when position a popup menu. See menu_position_func and
1423 create_and_show_popup_menu below. */
1424 struct next_popup_x_y
1431 /* The menu position function to use if we are not putting a popup
1432 menu where the pointer is.
1433 MENU is the menu to pop up.
1434 X and Y shall on exit contain x/y where the menu shall pop up.
1435 PUSH_IN is not documented in the GTK manual.
1436 USER_DATA is any data passed in when calling gtk_menu_popup.
1437 Here it points to a struct next_popup_x_y where the coordinates
1438 to store in *X and *Y are as well as the frame for the popup.
1440 Here only X and Y are used. */
1442 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1444 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1446 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1447 int disp_width
= x_display_pixel_width (dpyinfo
);
1448 int disp_height
= x_display_pixel_height (dpyinfo
);
1453 /* Check if there is room for the menu. If not, adjust x/y so that
1454 the menu is fully visible. */
1455 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1456 if (data
->x
+ req
.width
> disp_width
)
1457 *x
-= data
->x
+ req
.width
- disp_width
;
1458 if (data
->y
+ req
.height
> disp_height
)
1459 *y
-= data
->y
+ req
.height
- disp_height
;
1463 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1465 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1467 if (xg_crazy_callback_abort
) return;
1468 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1472 pop_down_menu (Lisp_Object arg
)
1474 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1476 popup_activated_flag
= 0;
1478 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1483 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1485 menu_item_selection will be set to the selection. */
1487 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1491 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1492 struct next_popup_x_y popup_x_y
;
1493 int specpdl_count
= SPECPDL_INDEX ();
1495 if (! FRAME_X_P (f
))
1498 xg_crazy_callback_abort
= 1;
1499 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1500 G_CALLBACK (popup_selection_callback
),
1501 G_CALLBACK (popup_deactivate_callback
),
1502 G_CALLBACK (menu_highlight_callback
));
1503 xg_crazy_callback_abort
= 0;
1507 /* Not invoked by a click. pop up at x/y. */
1508 pos_func
= menu_position_func
;
1510 /* Adjust coordinates to be root-window-relative. */
1511 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1512 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1518 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1522 for (i
= 0; i
< 5; i
++)
1523 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1527 /* Display the menu. */
1528 gtk_widget_show_all (menu
);
1530 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1531 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1533 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1535 if (gtk_widget_get_mapped (menu
))
1537 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1538 two. show_help_echo uses this to detect popup menus. */
1539 popup_activated_flag
= 1;
1540 /* Process events that apply to the menu. */
1541 popup_widget_loop (1, menu
);
1544 unbind_to (specpdl_count
, Qnil
);
1546 /* Must reset this manually because the button release event is not passed
1547 to Emacs event loop. */
1548 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1551 #else /* not USE_GTK */
1553 /* We need a unique id for each widget handled by the Lucid Widget
1556 For the main windows, and popup menus, we use this counter,
1557 which we increment each time after use. This starts from 1<<16.
1559 For menu bars, we use numbers starting at 0, counted in
1560 next_menubar_widget_id. */
1561 LWLIB_ID widget_id_tick
;
1564 popup_selection_callback (widget
, id
, client_data
)
1567 XtPointer client_data
;
1569 menu_item_selection
= (Lisp_Object
*) client_data
;
1572 /* ARG is the LWLIB ID of the dialog box, represented
1573 as a Lisp object as (HIGHPART . LOWPART). */
1579 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1580 | XINT (XCDR (arg
)));
1583 lw_destroy_all_widgets (id
);
1585 popup_activated_flag
= 0;
1590 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1592 menu_item_selection will be set to the selection. */
1594 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1596 widget_value
*first_wv
;
1600 EMACS_UINT timestamp
;
1605 XButtonPressedEvent dummy
;
1609 if (! FRAME_X_P (f
))
1612 menu_id
= widget_id_tick
++;
1613 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1614 f
->output_data
.x
->widget
, 1, 0,
1615 popup_selection_callback
,
1616 popup_deactivate_callback
,
1617 menu_highlight_callback
);
1620 apply_systemfont_to_menu (menu
);
1623 dummy
.type
= ButtonPress
;
1625 dummy
.send_event
= 0;
1626 dummy
.display
= FRAME_X_DISPLAY (f
);
1627 dummy
.time
= CurrentTime
;
1628 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1629 dummy
.window
= dummy
.root
;
1630 dummy
.subwindow
= dummy
.root
;
1634 /* Adjust coordinates to be root-window-relative. */
1635 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1636 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1643 for (i
= 0; i
< 5; i
++)
1644 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1647 /* Don't allow any geometry request from the user. */
1648 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1649 XtSetValues (menu
, av
, ac
);
1651 /* Display the menu. */
1652 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1653 popup_activated_flag
= 1;
1654 x_activate_timeout_atimer ();
1657 int fact
= 4 * sizeof (LWLIB_ID
);
1658 int specpdl_count
= SPECPDL_INDEX ();
1659 record_unwind_protect (pop_down_menu
,
1660 Fcons (make_number (menu_id
>> (fact
)),
1661 make_number (menu_id
& ~(-1 << (fact
)))));
1663 /* Process events that apply to the menu. */
1664 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1666 unbind_to (specpdl_count
, Qnil
);
1670 #endif /* not USE_GTK */
1673 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1674 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1677 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1678 widget_value
**submenu_stack
1679 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1680 Lisp_Object
*subprefix_stack
1681 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1682 int submenu_depth
= 0;
1686 if (! FRAME_X_P (f
))
1691 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1693 *error
= "Empty menu";
1697 /* Create a tree of widget_value objects
1698 representing the panes and their items. */
1699 wv
= xmalloc_widget_value ();
1703 wv
->button_type
= BUTTON_TYPE_NONE
;
1708 /* Loop over all panes and items, filling in the tree. */
1710 while (i
< menu_items_used
)
1712 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1714 submenu_stack
[submenu_depth
++] = save_wv
;
1720 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1723 save_wv
= submenu_stack
[--submenu_depth
];
1727 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1728 && submenu_depth
!= 0)
1729 i
+= MENU_ITEMS_PANE_LENGTH
;
1730 /* Ignore a nil in the item list.
1731 It's meaningful only for dialog boxes. */
1732 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1734 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1736 /* Create a new pane. */
1737 Lisp_Object pane_name
, prefix
;
1740 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1741 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1743 #ifndef HAVE_MULTILINGUAL_MENU
1744 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1746 pane_name
= ENCODE_MENU_STRING (pane_name
);
1747 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1750 pane_string
= (NILP (pane_name
)
1751 ? "" : (char *) SDATA (pane_name
));
1752 /* If there is just one top-level pane, put all its items directly
1753 under the top-level menu. */
1754 if (menu_items_n_panes
== 1)
1757 /* If the pane has a meaningful name,
1758 make the pane a top-level menu item
1759 with its items as a submenu beneath it. */
1760 if (!keymaps
&& strcmp (pane_string
, ""))
1762 wv
= xmalloc_widget_value ();
1766 first_wv
->contents
= wv
;
1767 wv
->name
= pane_string
;
1768 if (keymaps
&& !NILP (prefix
))
1772 wv
->button_type
= BUTTON_TYPE_NONE
;
1777 else if (first_pane
)
1783 i
+= MENU_ITEMS_PANE_LENGTH
;
1787 /* Create a new item within current pane. */
1788 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1789 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1790 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1791 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1792 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1793 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1794 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1795 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1797 #ifndef HAVE_MULTILINGUAL_MENU
1798 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1800 item_name
= ENCODE_MENU_STRING (item_name
);
1801 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1804 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1806 descrip
= ENCODE_MENU_STRING (descrip
);
1807 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1809 #endif /* not HAVE_MULTILINGUAL_MENU */
1811 wv
= xmalloc_widget_value ();
1815 save_wv
->contents
= wv
;
1816 wv
->name
= (char *) SDATA (item_name
);
1817 if (!NILP (descrip
))
1818 wv
->key
= (char *) SDATA (descrip
);
1820 /* If this item has a null value,
1821 make the call_data null so that it won't display a box
1822 when the mouse is on it. */
1824 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1825 wv
->enabled
= !NILP (enable
);
1828 wv
->button_type
= BUTTON_TYPE_NONE
;
1829 else if (EQ (type
, QCtoggle
))
1830 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1831 else if (EQ (type
, QCradio
))
1832 wv
->button_type
= BUTTON_TYPE_RADIO
;
1836 wv
->selected
= !NILP (selected
);
1838 if (! STRINGP (help
))
1845 i
+= MENU_ITEMS_ITEM_LENGTH
;
1849 /* Deal with the title, if it is non-nil. */
1852 widget_value
*wv_title
= xmalloc_widget_value ();
1853 widget_value
*wv_sep1
= xmalloc_widget_value ();
1854 widget_value
*wv_sep2
= xmalloc_widget_value ();
1856 wv_sep2
->name
= "--";
1857 wv_sep2
->next
= first_wv
->contents
;
1858 wv_sep2
->help
= Qnil
;
1860 wv_sep1
->name
= "--";
1861 wv_sep1
->next
= wv_sep2
;
1862 wv_sep1
->help
= Qnil
;
1864 #ifndef HAVE_MULTILINGUAL_MENU
1865 if (STRING_MULTIBYTE (title
))
1866 title
= ENCODE_MENU_STRING (title
);
1869 wv_title
->name
= (char *) SDATA (title
);
1870 wv_title
->enabled
= TRUE
;
1871 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1872 wv_title
->help
= Qnil
;
1873 wv_title
->next
= wv_sep1
;
1874 first_wv
->contents
= wv_title
;
1877 /* No selection has been chosen yet. */
1878 menu_item_selection
= 0;
1880 /* Actually create and show the menu until popped down. */
1881 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1883 /* Free the widget_value objects we used to specify the contents. */
1884 free_menubar_widget_value_tree (first_wv
);
1886 /* Find the selected item, and its pane, to return
1887 the proper value. */
1888 if (menu_item_selection
!= 0)
1890 Lisp_Object prefix
, entry
;
1892 prefix
= entry
= Qnil
;
1894 while (i
< menu_items_used
)
1896 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1898 subprefix_stack
[submenu_depth
++] = prefix
;
1902 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1904 prefix
= subprefix_stack
[--submenu_depth
];
1907 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1910 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1911 i
+= MENU_ITEMS_PANE_LENGTH
;
1913 /* Ignore a nil in the item list.
1914 It's meaningful only for dialog boxes. */
1915 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1920 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1921 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1927 entry
= Fcons (entry
, Qnil
);
1929 entry
= Fcons (prefix
, entry
);
1930 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1931 if (!NILP (subprefix_stack
[j
]))
1932 entry
= Fcons (subprefix_stack
[j
], entry
);
1936 i
+= MENU_ITEMS_ITEM_LENGTH
;
1940 else if (!for_click
)
1941 /* Make "Cancel" equivalent to C-g. */
1942 Fsignal (Qquit
, Qnil
);
1949 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1951 /* The EMACS_INT cast avoids a warning. There's no problem
1952 as long as pointers have enough bits to hold small integers. */
1953 if ((int) (EMACS_INT
) client_data
!= -1)
1954 menu_item_selection
= (Lisp_Object
*) client_data
;
1956 popup_activated_flag
= 0;
1959 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1961 menu_item_selection will be set to the selection. */
1963 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1967 if (! FRAME_X_P (f
))
1970 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1971 G_CALLBACK (dialog_selection_callback
),
1972 G_CALLBACK (popup_deactivate_callback
),
1977 int specpdl_count
= SPECPDL_INDEX ();
1978 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1980 /* Display the menu. */
1981 gtk_widget_show_all (menu
);
1983 /* Process events that apply to the menu. */
1984 popup_widget_loop (1, menu
);
1986 unbind_to (specpdl_count
, Qnil
);
1990 #else /* not USE_GTK */
1992 dialog_selection_callback (widget
, id
, client_data
)
1995 XtPointer client_data
;
1997 /* The EMACS_INT cast avoids a warning. There's no problem
1998 as long as pointers have enough bits to hold small integers. */
1999 if ((int) (EMACS_INT
) client_data
!= -1)
2000 menu_item_selection
= (Lisp_Object
*) client_data
;
2003 lw_destroy_all_widgets (id
);
2005 popup_activated_flag
= 0;
2009 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2011 menu_item_selection will be set to the selection. */
2013 create_and_show_dialog (f
, first_wv
)
2015 widget_value
*first_wv
;
2022 dialog_id
= widget_id_tick
++;
2024 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
2026 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2027 f
->output_data
.x
->widget
, 1, 0,
2028 dialog_selection_callback
, 0, 0);
2029 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2030 /* Display the dialog box. */
2031 lw_pop_up_all_widgets (dialog_id
);
2032 popup_activated_flag
= 1;
2033 x_activate_timeout_atimer ();
2035 /* Process events that apply to the dialog box.
2036 Also handle timers. */
2038 int count
= SPECPDL_INDEX ();
2039 int fact
= 4 * sizeof (LWLIB_ID
);
2041 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2042 record_unwind_protect (pop_down_menu
,
2043 Fcons (make_number (dialog_id
>> (fact
)),
2044 make_number (dialog_id
& ~(-1 << (fact
)))));
2046 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2049 unbind_to (count
, Qnil
);
2053 #endif /* not USE_GTK */
2055 static char * button_names
[] = {
2056 "button1", "button2", "button3", "button4", "button5",
2057 "button6", "button7", "button8", "button9", "button10" };
2060 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2062 int i
, nb_buttons
=0;
2063 char dialog_name
[6];
2065 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2067 /* Number of elements seen so far, before boundary. */
2069 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2070 int boundary_seen
= 0;
2072 if (! FRAME_X_P (f
))
2077 if (menu_items_n_panes
> 1)
2079 *error_name
= "Multiple panes in dialog box";
2083 /* Create a tree of widget_value objects
2084 representing the text label and buttons. */
2086 Lisp_Object pane_name
, prefix
;
2088 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2089 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2090 pane_string
= (NILP (pane_name
)
2091 ? "" : (char *) SDATA (pane_name
));
2092 prev_wv
= xmalloc_widget_value ();
2093 prev_wv
->value
= pane_string
;
2094 if (keymaps
&& !NILP (prefix
))
2096 prev_wv
->enabled
= 1;
2097 prev_wv
->name
= "message";
2098 prev_wv
->help
= Qnil
;
2101 /* Loop over all panes and items, filling in the tree. */
2102 i
= MENU_ITEMS_PANE_LENGTH
;
2103 while (i
< menu_items_used
)
2106 /* Create a new item within current pane. */
2107 Lisp_Object item_name
, enable
, descrip
;
2108 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2109 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2111 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2113 if (NILP (item_name
))
2115 free_menubar_widget_value_tree (first_wv
);
2116 *error_name
= "Submenu in dialog items";
2119 if (EQ (item_name
, Qquote
))
2121 /* This is the boundary between left-side elts
2122 and right-side elts. Stop incrementing right_count. */
2127 if (nb_buttons
>= 9)
2129 free_menubar_widget_value_tree (first_wv
);
2130 *error_name
= "Too many dialog items";
2134 wv
= xmalloc_widget_value ();
2136 wv
->name
= (char *) button_names
[nb_buttons
];
2137 if (!NILP (descrip
))
2138 wv
->key
= (char *) SDATA (descrip
);
2139 wv
->value
= (char *) SDATA (item_name
);
2140 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2141 wv
->enabled
= !NILP (enable
);
2145 if (! boundary_seen
)
2149 i
+= MENU_ITEMS_ITEM_LENGTH
;
2152 /* If the boundary was not specified,
2153 by default put half on the left and half on the right. */
2154 if (! boundary_seen
)
2155 left_count
= nb_buttons
- nb_buttons
/ 2;
2157 wv
= xmalloc_widget_value ();
2158 wv
->name
= dialog_name
;
2161 /* Frame title: 'Q' = Question, 'I' = Information.
2162 Can also have 'E' = Error if, one day, we want
2163 a popup for errors. */
2165 dialog_name
[0] = 'Q';
2167 dialog_name
[0] = 'I';
2169 /* Dialog boxes use a really stupid name encoding
2170 which specifies how many buttons to use
2171 and how many buttons are on the right. */
2172 dialog_name
[1] = '0' + nb_buttons
;
2173 dialog_name
[2] = 'B';
2174 dialog_name
[3] = 'R';
2175 /* Number of buttons to put on the right. */
2176 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2178 wv
->contents
= first_wv
;
2182 /* No selection has been chosen yet. */
2183 menu_item_selection
= 0;
2185 /* Actually create and show the dialog. */
2186 create_and_show_dialog (f
, first_wv
);
2188 /* Free the widget_value objects we used to specify the contents. */
2189 free_menubar_widget_value_tree (first_wv
);
2191 /* Find the selected item, and its pane, to return
2192 the proper value. */
2193 if (menu_item_selection
!= 0)
2199 while (i
< menu_items_used
)
2203 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2206 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2207 i
+= MENU_ITEMS_PANE_LENGTH
;
2209 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2211 /* This is the boundary between left-side elts and
2218 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2219 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2223 entry
= Fcons (entry
, Qnil
);
2225 entry
= Fcons (prefix
, entry
);
2229 i
+= MENU_ITEMS_ITEM_LENGTH
;
2234 /* Make "Cancel" equivalent to C-g. */
2235 Fsignal (Qquit
, Qnil
);
2240 #else /* not USE_X_TOOLKIT && not USE_GTK */
2242 /* The frame of the last activated non-toolkit menu bar.
2243 Used to generate menu help events. */
2245 static struct frame
*menu_help_frame
;
2248 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2250 PANE is the pane number, and ITEM is the menu item number in
2251 the menu (currently not used).
2253 This cannot be done with generating a HELP_EVENT because
2254 XMenuActivate contains a loop that doesn't let Emacs process
2258 menu_help_callback (help_string
, pane
, item
)
2262 extern Lisp_Object Qmenu_item
;
2263 Lisp_Object
*first_item
;
2264 Lisp_Object pane_name
;
2265 Lisp_Object menu_object
;
2267 first_item
= XVECTOR (menu_items
)->contents
;
2268 if (EQ (first_item
[0], Qt
))
2269 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2270 else if (EQ (first_item
[0], Qquote
))
2271 /* This shouldn't happen, see xmenu_show. */
2272 pane_name
= empty_unibyte_string
;
2274 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2276 /* (menu-item MENU-NAME PANE-NUMBER) */
2277 menu_object
= Fcons (Qmenu_item
,
2279 Fcons (make_number (pane
), Qnil
)));
2280 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2281 Qnil
, menu_object
, make_number (item
), 1);
2288 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2289 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2291 FRAME_PTR f
= p1
->pointer
;
2292 XMenu
*menu
= p2
->pointer
;
2296 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2297 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2299 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2301 #ifdef HAVE_X_WINDOWS
2302 /* Assume the mouse has moved out of the X window.
2303 If it has actually moved in, we will get an EnterNotify. */
2304 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2306 /* State that no mouse buttons are now held.
2307 (The oldXMenu code doesn't track this info for us.)
2308 That is not necessarily true, but the fiction leads to reasonable
2309 results, and it is a pain to ask which are actually held now. */
2310 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2312 #endif /* HAVE_X_WINDOWS */
2321 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
2328 EMACS_UINT timestamp
;
2332 int pane
, selidx
, lpane
, status
;
2333 Lisp_Object entry
, pane_prefix
;
2335 int ulx
, uly
, width
, height
;
2336 int dispwidth
, dispheight
;
2337 int i
, j
, lines
, maxlines
;
2340 unsigned int dummy_uint
;
2341 int specpdl_count
= SPECPDL_INDEX ();
2343 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2347 if (menu_items_n_panes
== 0)
2350 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2352 *error
= "Empty menu";
2356 /* Figure out which root window F is on. */
2357 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2358 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2359 &dummy_uint
, &dummy_uint
);
2361 /* Make the menu on that window. */
2362 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2365 *error
= "Can't create menu";
2369 /* Don't GC while we prepare and show the menu,
2370 because we give the oldxmenu library pointers to the
2371 contents of strings. */
2372 inhibit_garbage_collection ();
2374 #ifdef HAVE_X_WINDOWS
2375 /* Adjust coordinates to relative to the outer (window manager) window. */
2376 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2377 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2378 #endif /* HAVE_X_WINDOWS */
2380 /* Adjust coordinates to be root-window-relative. */
2384 /* Create all the necessary panes and their items. */
2385 maxlines
= lines
= i
= 0;
2386 while (i
< menu_items_used
)
2388 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2390 /* Create a new pane. */
2391 Lisp_Object pane_name
, prefix
;
2394 maxlines
= max (maxlines
, lines
);
2396 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2397 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2398 pane_string
= (NILP (pane_name
)
2399 ? "" : (char *) SDATA (pane_name
));
2400 if (keymaps
&& !NILP (prefix
))
2403 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2404 if (lpane
== XM_FAILURE
)
2406 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2407 *error
= "Can't create pane";
2410 i
+= MENU_ITEMS_PANE_LENGTH
;
2412 /* Find the width of the widest item in this pane. */
2415 while (j
< menu_items_used
)
2418 item
= XVECTOR (menu_items
)->contents
[j
];
2426 width
= SBYTES (item
);
2427 if (width
> maxwidth
)
2430 j
+= MENU_ITEMS_ITEM_LENGTH
;
2433 /* Ignore a nil in the item list.
2434 It's meaningful only for dialog boxes. */
2435 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2439 /* Create a new item within current pane. */
2440 Lisp_Object item_name
, enable
, descrip
, help
;
2441 unsigned char *item_data
;
2444 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2445 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2447 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2448 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2449 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2451 if (!NILP (descrip
))
2453 int gap
= maxwidth
- SBYTES (item_name
);
2454 /* if alloca is fast, use that to make the space,
2455 to reduce gc needs. */
2457 = (unsigned char *) alloca (maxwidth
2458 + SBYTES (descrip
) + 1);
2459 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2460 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2462 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2463 item_data
[j
+ SBYTES (descrip
)] = 0;
2466 item_data
= SDATA (item_name
);
2468 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2469 menu
, lpane
, 0, item_data
,
2470 !NILP (enable
), help_string
)
2473 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2474 *error
= "Can't add selection to menu";
2477 i
+= MENU_ITEMS_ITEM_LENGTH
;
2482 maxlines
= max (maxlines
, lines
);
2484 /* All set and ready to fly. */
2485 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2486 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2487 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2488 x
= min (x
, dispwidth
);
2489 y
= min (y
, dispheight
);
2492 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2493 &ulx
, &uly
, &width
, &height
);
2494 if (ulx
+width
> dispwidth
)
2496 x
-= (ulx
+ width
) - dispwidth
;
2497 ulx
= dispwidth
- width
;
2499 if (uly
+height
> dispheight
)
2501 y
-= (uly
+ height
) - dispheight
;
2502 uly
= dispheight
- height
;
2504 #ifndef HAVE_X_WINDOWS
2505 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2507 /* Move the menu away of the echo area, to avoid overwriting the
2508 menu with help echo messages or vice versa. */
2509 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2511 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2512 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2521 if (ulx
< 0) x
-= ulx
;
2522 if (uly
< 0) y
-= uly
;
2526 /* If position was not given by a mouse click, adjust so upper left
2527 corner of the menu as a whole ends up at given coordinates. This
2528 is what x-popup-menu says in its documentation. */
2530 y
+= 1.5*height
/(maxlines
+2);
2533 XMenuSetAEQ (menu
, TRUE
);
2534 XMenuSetFreeze (menu
, TRUE
);
2538 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2541 record_unwind_protect (pop_down_menu
,
2542 Fcons (make_save_value (f
, 0),
2543 make_save_value (menu
, 0)));
2545 /* Help display under X won't work because XMenuActivate contains
2546 a loop that doesn't give Emacs a chance to process it. */
2547 menu_help_frame
= f
;
2548 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2549 x
, y
, ButtonReleaseMask
, &datap
,
2550 menu_help_callback
);
2556 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2559 /* Find the item number SELIDX in pane number PANE. */
2561 while (i
< menu_items_used
)
2563 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2567 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2569 i
+= MENU_ITEMS_PANE_LENGTH
;
2578 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2581 entry
= Fcons (entry
, Qnil
);
2582 if (!NILP (pane_prefix
))
2583 entry
= Fcons (pane_prefix
, entry
);
2589 i
+= MENU_ITEMS_ITEM_LENGTH
;
2595 *error
= "Can't activate menu";
2600 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2601 the menu was invoked with a mouse event as POSITION). */
2603 Fsignal (Qquit
, Qnil
);
2608 unbind_to (specpdl_count
, Qnil
);
2613 #endif /* not USE_X_TOOLKIT */
2615 #endif /* HAVE_MENUS */
2617 /* Detect if a dialog or menu has been posted. */
2620 popup_activated (void)
2622 return popup_activated_flag
;
2625 /* The following is used by delayed window autoselection. */
2627 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2628 doc
: /* Return t if a menu or popup dialog is active. */)
2632 return (popup_activated ()) ? Qt
: Qnil
;
2635 #endif /* HAVE_MENUS */
2639 syms_of_xmenu (void)
2641 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2642 staticpro (&Qdebug_on_next_call
);
2644 #ifdef USE_X_TOOLKIT
2645 widget_id_tick
= (1<<16);
2646 next_menubar_widget_id
= 1;
2649 defsubr (&Smenu_or_popup_active_p
);
2651 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2652 defsubr (&Sx_menu_bar_open_internal
);
2653 Ffset (intern_c_string ("accelerate-menu"),
2654 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2658 defsubr (&Sx_popup_dialog
);
2662 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2663 (do not change this comment) */