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 (LWLIB_ID id
)
170 Lisp_Object tail
, frame
;
173 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
179 if (!FRAME_WINDOW_P (f
))
181 if (f
->output_data
.x
->id
== id
)
189 #ifdef HAVE_X_WINDOWS
190 /* Return the mouse position in *X and *Y. The coordinates are window
191 relative for the edit window in frame F.
192 This is for Fx_popup_menu. The mouse_position_hook can not
193 be used for X, as it returns window relative coordinates
194 for the window where the mouse is in. This could be the menu bar,
195 the scroll bar or the edit window. Fx_popup_menu needs to be
196 sure it is the edit window. */
198 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
200 Window root
, dummy_window
;
208 XQueryPointer (FRAME_X_DISPLAY (f
),
209 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
211 /* The root window which contains the pointer. */
214 /* Window pointer is on, not used */
217 /* The position on that root window. */
220 /* x/y in dummy_window coordinates, not used. */
223 /* Modifier keys and pointer buttons, about which
225 (unsigned int *) &dummy
);
229 /* xmenu_show expects window coordinates, not root window
230 coordinates. Translate. */
231 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
232 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
235 #endif /* HAVE_X_WINDOWS */
239 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
240 doc
: /* Pop up a dialog box and return user's selection.
241 POSITION specifies which frame to use.
242 This is normally a mouse button event or a window or frame.
243 If POSITION is t, it means to use the frame the mouse is on.
244 The dialog box appears in the middle of the specified frame.
246 CONTENTS specifies the alternatives to display in the dialog box.
247 It is a list of the form (DIALOG ITEM1 ITEM2...).
248 Each ITEM is a cons cell (STRING . VALUE).
249 The return value is VALUE from the chosen item.
251 An ITEM may also be just a string--that makes a nonselectable item.
252 An ITEM may also be nil--that means to put all preceding items
253 on the left of the dialog box and all following items on the right.
254 \(By default, approximately half appear on each side.)
256 If HEADER is non-nil, the frame title for the box is "Information",
257 otherwise it is "Question".
259 If the user gets rid of the dialog box without making a valid choice,
260 for instance using the window manager, then this produces a quit and
261 `x-popup-dialog' does not return. */)
262 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
269 /* Decode the first argument: find the window or frame to use. */
270 if (EQ (position
, Qt
)
271 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
272 || EQ (XCAR (position
), Qtool_bar
))))
274 #if 0 /* Using the frame the mouse is on may not be right. */
275 /* Use the mouse's current position. */
276 FRAME_PTR new_f
= SELECTED_FRAME ();
277 Lisp_Object bar_window
;
278 enum scroll_bar_part part
;
282 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
285 XSETFRAME (window
, new_f
);
287 window
= selected_window
;
289 window
= selected_window
;
291 else if (CONSP (position
))
294 tem
= Fcar (position
);
296 window
= Fcar (Fcdr (position
));
299 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
300 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
303 else if (WINDOWP (position
) || FRAMEP (position
))
308 /* Decode where to put the menu. */
312 else if (WINDOWP (window
))
314 CHECK_LIVE_WINDOW (window
);
315 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
318 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
319 but I don't want to make one now. */
320 CHECK_WINDOW (window
);
322 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
323 error ("Can not put X dialog on this terminal");
325 /* Force a redisplay before showing the dialog. If a frame is created
326 just before showing the dialog, its contents may not have been fully
327 drawn, as this depends on timing of events from the X server. Redisplay
328 is not done when a dialog is shown. If redisplay could be done in the
329 X event loop (i.e. the X event loop does not run in a signal handler)
330 this would not be needed.
332 Do this before creating the widget value that points to Lisp
333 string contents, because Fredisplay may GC and relocate them. */
336 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
337 /* Display a menu with these alternatives
338 in the middle of frame F. */
340 Lisp_Object x
, y
, frame
, newpos
;
341 XSETFRAME (frame
, f
);
342 XSETINT (x
, x_pixel_width (f
) / 2);
343 XSETINT (y
, x_pixel_height (f
) / 2);
344 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
346 return Fx_popup_menu (newpos
,
347 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
353 Lisp_Object selection
;
354 int specpdl_count
= SPECPDL_INDEX ();
356 /* Decode the dialog items from what was specified. */
357 title
= Fcar (contents
);
358 CHECK_STRING (title
);
359 record_unwind_protect (unuse_menu_items
, Qnil
);
361 if (NILP (Fcar (Fcdr (contents
))))
362 /* No buttons specified, add an "Ok" button so users can pop down
363 the dialog. Also, the lesstif/motif version crashes if there are
365 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
367 list_of_panes (Fcons (contents
, Qnil
));
369 /* Display them in a dialog box. */
371 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
374 unbind_to (specpdl_count
, Qnil
);
375 discard_menu_items ();
377 if (error_name
) error (error_name
);
386 /* Set menu_items_inuse so no other popup menu or dialog is created. */
389 x_menu_set_in_use (int in_use
)
391 menu_items_inuse
= in_use
? Qt
: Qnil
;
392 popup_activated_flag
= in_use
;
394 if (popup_activated_flag
)
395 x_activate_timeout_atimer ();
399 /* Wait for an X event to arrive or for a timer to expire. */
402 x_menu_wait_for_event (void *data
)
404 /* Another way to do this is to register a timer callback, that can be
405 done in GTK and Xt. But we have to do it like this when using only X
406 anyway, and with callbacks we would have three variants for timer handling
407 instead of the small ifdefs below. */
411 ! XtAppPending (Xt_app_con
)
412 #elif defined USE_GTK
413 ! gtk_events_pending ()
415 ! XPending ((Display
*) data
)
419 EMACS_TIME next_time
= timer_check (1), *ntp
;
420 long secs
= EMACS_SECS (next_time
);
421 long usecs
= EMACS_USECS (next_time
);
422 SELECT_TYPE read_fds
;
423 struct x_display_info
*dpyinfo
;
427 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
429 int fd
= ConnectionNumber (dpyinfo
->display
);
430 FD_SET (fd
, &read_fds
);
432 XFlush (dpyinfo
->display
);
435 if (secs
< 0 && usecs
< 0)
440 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
446 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
450 /* Loop in Xt until the menu pulldown or dialog popup has been
451 popped down (deactivated). This is used for x-popup-menu
452 and x-popup-dialog; it is not used for the menu bar.
454 NOTE: All calls to popup_get_selection should be protected
455 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
458 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
462 while (popup_activated_flag
)
466 event
= *initial_event
;
471 if (do_timers
) x_menu_wait_for_event (0);
472 XtAppNextEvent (Xt_app_con
, &event
);
475 /* Make sure we don't consider buttons grabbed after menu goes.
476 And make sure to deactivate for any ButtonRelease,
477 even if XtDispatchEvent doesn't do that. */
478 if (event
.type
== ButtonRelease
479 && dpyinfo
->display
== event
.xbutton
.display
)
481 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
482 #ifdef USE_MOTIF /* Pretending that the event came from a
483 Btn1Down seems the only way to convince Motif to
484 activate its callbacks; setting the XmNmenuPost
485 isn't working. --marcus@sysc.pdx.edu. */
486 event
.xbutton
.button
= 1;
487 /* Motif only pops down menus when no Ctrl, Alt or Mod
488 key is pressed and the button is released. So reset key state
489 so Motif thinks this is the case. */
490 event
.xbutton
.state
= 0;
493 /* Pop down on C-g and Escape. */
494 else if (event
.type
== KeyPress
495 && dpyinfo
->display
== event
.xbutton
.display
)
497 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
499 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
500 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
501 popup_activated_flag
= 0;
504 x_dispatch_event (&event
, event
.xany
.display
);
508 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
509 doc
: /* Start key navigation of the menu bar in FRAME.
510 This initially opens the first menu bar item and you can then navigate with the
511 arrow keys, select a menu entry with the return key or cancel with the
512 escape key. If FRAME has no menu bar this function does nothing.
514 If FRAME is nil or not given, use the selected frame. */)
518 FRAME_PTR f
= check_x_frame (frame
);
522 if (FRAME_EXTERNAL_MENU_BAR (f
))
523 set_frame_menubar (f
, 0, 1);
525 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
531 x_catch_errors (FRAME_X_DISPLAY (f
));
532 memset (&ev
, 0, sizeof ev
);
533 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
534 ev
.xbutton
.window
= XtWindow (menubar
);
535 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
536 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
537 ev
.xbutton
.button
= Button1
;
538 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
539 ev
.xbutton
.same_screen
= True
;
546 XtSetArg (al
[0], XtNchildren
, &list
);
547 XtSetArg (al
[1], XtNnumChildren
, &nr
);
548 XtGetValues (menubar
, al
, 2);
549 ev
.xbutton
.window
= XtWindow (list
[0]);
553 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
554 /* From-window, to-window. */
555 ev
.xbutton
.window
, ev
.xbutton
.root
,
557 /* From-position, to-position. */
558 ev
.xbutton
.x
, ev
.xbutton
.y
,
559 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
563 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
568 ev
.type
= ButtonPress
;
569 ev
.xbutton
.state
= 0;
571 XtDispatchEvent (&ev
);
572 ev
.xbutton
.type
= ButtonRelease
;
573 ev
.xbutton
.state
= Button1Mask
;
574 XtDispatchEvent (&ev
);
582 #endif /* USE_X_TOOLKIT */
586 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
587 doc
: /* Start key navigation of the menu bar in FRAME.
588 This initially opens the first menu bar item and you can then navigate with the
589 arrow keys, select a menu entry with the return key or cancel with the
590 escape key. If FRAME has no menu bar this function does nothing.
592 If FRAME is nil or not given, use the selected frame. */)
598 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
602 f
= check_x_frame (frame
);
604 if (FRAME_EXTERNAL_MENU_BAR (f
))
605 set_frame_menubar (f
, 0, 1);
607 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
610 /* Activate the first menu. */
611 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
615 g_signal_emit_by_name (children
->data
, "activate_item");
616 popup_activated_flag
= 1;
617 g_list_free (children
);
625 /* Loop util popup_activated_flag is set to zero in a callback.
626 Used for popup menus and dialogs. */
629 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
631 ++popup_activated_flag
;
633 /* Process events in the Gtk event loop until done. */
634 while (popup_activated_flag
)
636 if (do_timers
) x_menu_wait_for_event (0);
637 gtk_main_iteration ();
642 /* Activate the menu bar of frame F.
643 This is called from keyboard.c when it gets the
644 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
646 To activate the menu bar, we use the X button-press event
647 that was saved in saved_menu_event.
648 That makes the toolkit do its thing.
650 But first we recompute the menu bar contents (the whole tree).
652 The reason for saving the button event until here, instead of
653 passing it to the toolkit right away, is that we can safely
654 execute Lisp code. */
657 x_activate_menubar (FRAME_PTR f
)
662 if (!f
->output_data
.x
->saved_menu_event
->type
)
666 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
667 f
->output_data
.x
->saved_menu_event
->xany
.window
))
671 set_frame_menubar (f
, 0, 1);
674 /* If we click outside any menu item, the menu bar still grabs.
675 So we send Press and the Release. If outside, grab is released.
676 If on a menu item, it is popped up normally.
677 PutBack is like a stack, so we put back in reverse order. */
678 f
->output_data
.x
->saved_menu_event
->type
= ButtonRelease
;
679 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
680 f
->output_data
.x
->saved_menu_event
);
681 f
->output_data
.x
->saved_menu_event
->type
= ButtonPress
;
682 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
683 f
->output_data
.x
->saved_menu_event
);
684 popup_activated_flag
= 1;
686 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
690 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
691 pending_menu_activation
= 1;
694 /* Ignore this if we get it a second time. */
695 f
->output_data
.x
->saved_menu_event
->type
= 0;
698 /* This callback is invoked when the user selects a menubar cascade
699 pushbutton, but before the pulldown menu is posted. */
703 popup_activate_callback (Widget widget
, LWLIB_ID id
, 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 widget
, LWLIB_ID id
, XtPointer client_data
)
725 popup_activated_flag
= 0;
730 /* Function that finds the frame for WIDGET and shows the HELP text
732 F is the frame if known, or NULL if not known. */
734 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
740 XSETFRAME (frame
, f
);
741 kbd_buffer_store_help_event (frame
, help
);
745 #if 0 /* This code doesn't do anything useful. ++kfs */
746 /* WIDGET is the popup menu. It's parent is the frame's
747 widget. See which frame that is. */
748 xt_or_gtk_widget frame_widget
= XtParent (widget
);
751 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
755 && (f
= XFRAME (frame
),
756 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
760 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
764 /* Callback called when menu items are highlighted/unhighlighted
765 while moving the mouse over them. WIDGET is the menu bar or menu
766 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
767 the data structure for the menu item, or null in case of
772 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
774 xg_menu_item_cb_data
*cb_data
;
777 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
779 if (! cb_data
) return;
781 help
= call_data
? cb_data
->help
: Qnil
;
783 /* If popup_activated_flag is greater than 1 we are in a popup menu.
784 Don't show help for them, they won't appear before the
785 popup is popped down. */
786 if (popup_activated_flag
<= 1)
787 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
791 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
796 widget_value
*wv
= (widget_value
*) call_data
;
798 help
= wv
? wv
->help
: Qnil
;
800 /* Determine the frame for the help event. */
801 f
= menubar_id_to_frame (id
);
803 show_help_event (f
, widget
, help
);
808 /* Gtk calls callbacks just because we tell it what item should be
809 selected in a radio group. If this variable is set to a non-zero
810 value, we are creating menus and don't want callbacks right now.
812 static int xg_crazy_callback_abort
;
814 /* This callback is called from the menu bar pulldown menu
815 when the user makes a selection.
816 Figure out what the user chose
817 and put the appropriate events into the keyboard buffer. */
819 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
821 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
823 if (xg_crazy_callback_abort
)
826 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
829 /* For a group of radio buttons, GTK calls the selection callback first
830 for the item that was active before the selection and then for the one that
831 is active after the selection. For C-h k this means we get the help on
832 the deselected item and then the selected item is executed. Prevent that
833 by ignoring the non-active item. */
834 if (GTK_IS_RADIO_MENU_ITEM (widget
)
835 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
838 /* When a menu is popped down, X generates a focus event (i.e. focus
839 goes back to the frame below the menu). Since GTK buffers events,
840 we force it out here before the menu selection event. Otherwise
841 sit-for will exit at once if the focus event follows the menu selection
845 while (gtk_events_pending ())
846 gtk_main_iteration ();
849 find_and_call_menu_selection (cb_data
->cl_data
->f
,
850 cb_data
->cl_data
->menu_bar_items_used
,
851 cb_data
->cl_data
->menu_bar_vector
,
855 #else /* not USE_GTK */
857 /* This callback is called from the menu bar pulldown menu
858 when the user makes a selection.
859 Figure out what the user chose
860 and put the appropriate events into the keyboard buffer. */
862 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
866 f
= menubar_id_to_frame (id
);
869 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
870 f
->menu_bar_vector
, client_data
);
872 #endif /* not USE_GTK */
874 /* Recompute all the widgets of frame F, when the menu bar has been
875 changed. Value is non-zero if widgets were updated. */
878 update_frame_menubar (FRAME_PTR f
)
881 return xg_update_frame_menubar (f
);
889 x
= f
->output_data
.x
;
891 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
895 /* Save the size of the frame because the pane widget doesn't accept
896 to resize itself. So force it. */
897 columns
= FRAME_COLS (f
);
898 rows
= FRAME_LINES (f
);
900 /* Do the voodoo which means "I'm changing lots of things, don't try
901 to refigure sizes until I'm done." */
902 lw_refigure_widget (x
->column_widget
, False
);
904 /* The order in which children are managed is the top to bottom
905 order in which they are displayed in the paned window. First,
906 remove the text-area widget. */
907 XtUnmanageChild (x
->edit_widget
);
909 /* Remove the menubar that is there now, and put up the menubar that
911 XtManageChild (x
->menubar_widget
);
912 XtMapWidget (x
->menubar_widget
);
913 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
915 /* Re-manage the text-area widget, and then thrash the sizes. */
916 XtManageChild (x
->edit_widget
);
917 lw_refigure_widget (x
->column_widget
, True
);
919 /* Force the pane widget to resize itself with the right values. */
920 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
928 apply_systemfont_to_dialog (Widget w
)
930 const char *fn
= xsettings_get_system_normal_font ();
933 XrmDatabase db
= XtDatabase (XtDisplay (w
));
935 XrmPutStringResource (&db
, "*dialog.faceName", fn
);
940 apply_systemfont_to_menu (Widget w
)
942 const char *fn
= xsettings_get_system_normal_font ();
947 if (XtIsShell (w
)) /* popup menu */
949 Widget
*childs
= NULL
;
951 XtVaGetValues (w
, XtNchildren
, &childs
, NULL
);
952 if (*childs
) w
= *childs
;
955 /* Only use system font if the default is used for the menu. */
956 XtVaGetValues (w
, XtNdefaultFace
, &defflt
, NULL
);
958 XtVaSetValues (w
, XtNfaceName
, fn
, NULL
);
962 /* Set the contents of the menubar widgets of frame F.
963 The argument FIRST_TIME is currently ignored;
964 it is set the first time this is called, from initialize_frame_menubar. */
967 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
969 xt_or_gtk_widget menubar_widget
;
974 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
976 int *submenu_start
, *submenu_end
;
977 int *submenu_top_level_items
, *submenu_n_panes
;
982 menubar_widget
= f
->output_data
.x
->menubar_widget
;
984 XSETFRAME (Vmenu_updating_frame
, f
);
987 if (f
->output_data
.x
->id
== 0)
988 f
->output_data
.x
->id
= next_menubar_widget_id
++;
989 id
= f
->output_data
.x
->id
;
992 if (! menubar_widget
)
994 else if (pending_menu_activation
&& !deep_p
)
996 /* Make the first call for any given frame always go deep. */
997 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1000 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1001 f
->output_data
.x
->saved_menu_event
->type
= 0;
1005 /* If we have detached menus, we must update deep so detached menus
1006 also gets updated. */
1007 deep_p
= deep_p
|| xg_have_tear_offs ();
1012 /* Make a widget-value tree representing the entire menu trees. */
1014 struct buffer
*prev
= current_buffer
;
1016 int specpdl_count
= SPECPDL_INDEX ();
1017 int previous_menu_items_used
= f
->menu_bar_items_used
;
1018 Lisp_Object
*previous_items
1019 = (Lisp_Object
*) alloca (previous_menu_items_used
1020 * sizeof (Lisp_Object
));
1022 /* If we are making a new widget, its contents are empty,
1023 do always reinitialize them. */
1024 if (! menubar_widget
)
1025 previous_menu_items_used
= 0;
1027 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1028 specbind (Qinhibit_quit
, Qt
);
1029 /* Don't let the debugger step into this code
1030 because it is not reentrant. */
1031 specbind (Qdebug_on_next_call
, Qnil
);
1033 record_unwind_save_match_data ();
1034 if (NILP (Voverriding_local_map_menu_flag
))
1036 specbind (Qoverriding_terminal_local_map
, Qnil
);
1037 specbind (Qoverriding_local_map
, Qnil
);
1040 set_buffer_internal_1 (XBUFFER (buffer
));
1042 /* Run the Lucid hook. */
1043 safe_run_hooks (Qactivate_menubar_hook
);
1045 /* If it has changed current-menubar from previous value,
1046 really recompute the menubar from the value. */
1047 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1048 call0 (Qrecompute_lucid_menubar
);
1049 safe_run_hooks (Qmenu_bar_update_hook
);
1050 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1052 items
= FRAME_MENU_BAR_ITEMS (f
);
1054 /* Save the frame's previous menu bar contents data. */
1055 if (previous_menu_items_used
)
1056 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1057 previous_menu_items_used
* sizeof (Lisp_Object
));
1059 /* Fill in menu_items with the current menu bar contents.
1060 This can evaluate Lisp code. */
1063 menu_items
= f
->menu_bar_vector
;
1064 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1065 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1066 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1067 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1068 submenu_top_level_items
1069 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1071 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1073 Lisp_Object key
, string
, maps
;
1077 key
= XVECTOR (items
)->contents
[i
];
1078 string
= XVECTOR (items
)->contents
[i
+ 1];
1079 maps
= XVECTOR (items
)->contents
[i
+ 2];
1083 submenu_start
[i
] = menu_items_used
;
1085 menu_items_n_panes
= 0;
1086 submenu_top_level_items
[i
]
1087 = parse_single_submenu (key
, string
, maps
);
1088 submenu_n_panes
[i
] = menu_items_n_panes
;
1090 submenu_end
[i
] = menu_items_used
;
1093 finish_menu_items ();
1095 /* Convert menu_items into widget_value trees
1096 to display the menu. This cannot evaluate Lisp code. */
1098 wv
= xmalloc_widget_value ();
1099 wv
->name
= "menubar";
1102 wv
->button_type
= BUTTON_TYPE_NONE
;
1106 for (i
= 0; i
< last_i
; i
+= 4)
1108 menu_items_n_panes
= submenu_n_panes
[i
];
1109 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1110 submenu_top_level_items
[i
]);
1114 first_wv
->contents
= wv
;
1115 /* Don't set wv->name here; GC during the loop might relocate it. */
1117 wv
->button_type
= BUTTON_TYPE_NONE
;
1121 set_buffer_internal_1 (prev
);
1123 /* If there has been no change in the Lisp-level contents
1124 of the menu bar, skip redisplaying it. Just exit. */
1126 /* Compare the new menu items with the ones computed last time. */
1127 for (i
= 0; i
< previous_menu_items_used
; i
++)
1128 if (menu_items_used
== i
1129 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1131 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1133 /* The menu items have not changed. Don't bother updating
1134 the menus in any form, since it would be a no-op. */
1135 free_menubar_widget_value_tree (first_wv
);
1136 discard_menu_items ();
1137 unbind_to (specpdl_count
, Qnil
);
1141 /* The menu items are different, so store them in the frame. */
1142 f
->menu_bar_vector
= menu_items
;
1143 f
->menu_bar_items_used
= menu_items_used
;
1145 /* This undoes save_menu_items. */
1146 unbind_to (specpdl_count
, Qnil
);
1148 /* Now GC cannot happen during the lifetime of the widget_value,
1149 so it's safe to store data from a Lisp_String. */
1150 wv
= first_wv
->contents
;
1151 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1154 string
= XVECTOR (items
)->contents
[i
+ 1];
1157 wv
->name
= (char *) SDATA (string
);
1158 update_submenu_strings (wv
->contents
);
1165 /* Make a widget-value tree containing
1166 just the top level menu bar strings. */
1168 wv
= xmalloc_widget_value ();
1169 wv
->name
= "menubar";
1172 wv
->button_type
= BUTTON_TYPE_NONE
;
1176 items
= FRAME_MENU_BAR_ITEMS (f
);
1177 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1181 string
= XVECTOR (items
)->contents
[i
+ 1];
1185 wv
= xmalloc_widget_value ();
1186 wv
->name
= (char *) SDATA (string
);
1189 wv
->button_type
= BUTTON_TYPE_NONE
;
1191 /* This prevents lwlib from assuming this
1192 menu item is really supposed to be empty. */
1193 /* The EMACS_INT cast avoids a warning.
1194 This value just has to be different from small integers. */
1195 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1200 first_wv
->contents
= wv
;
1204 /* Forget what we thought we knew about what is in the
1205 detailed contents of the menu bar menus.
1206 Changing the top level always destroys the contents. */
1207 f
->menu_bar_items_used
= 0;
1210 /* Create or update the menu bar widget. */
1215 xg_crazy_callback_abort
= 1;
1218 /* The fourth arg is DEEP_P, which says to consider the entire
1219 menu trees we supply, rather than just the menu bar item names. */
1220 xg_modify_menubar_widgets (menubar_widget
,
1224 G_CALLBACK (menubar_selection_callback
),
1225 G_CALLBACK (popup_deactivate_callback
),
1226 G_CALLBACK (menu_highlight_callback
));
1230 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1233 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1234 G_CALLBACK (menubar_selection_callback
),
1235 G_CALLBACK (popup_deactivate_callback
),
1236 G_CALLBACK (menu_highlight_callback
));
1238 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1242 #else /* not USE_GTK */
1245 /* Disable resizing (done for Motif!) */
1246 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1248 /* The third arg is DEEP_P, which says to consider the entire
1249 menu trees we supply, rather than just the menu bar item names. */
1250 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1252 /* Re-enable the edit widget to resize. */
1253 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1257 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1258 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1260 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1261 f
->output_data
.x
->column_widget
,
1263 popup_activate_callback
,
1264 menubar_selection_callback
,
1265 popup_deactivate_callback
,
1266 menu_highlight_callback
);
1267 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1269 /* Make menu pop down on C-g. */
1270 XtOverrideTranslations (menubar_widget
, override
);
1272 apply_systemfont_to_menu (menubar_widget
);
1277 if (f
->output_data
.x
->menubar_widget
)
1278 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1281 = (f
->output_data
.x
->menubar_widget
1282 ? (f
->output_data
.x
->menubar_widget
->core
.height
1283 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1286 #if 1 /* Experimentally, we now get the right results
1287 for -geometry -0-0 without this. 24 Aug 96, rms.
1288 Maybe so, but the menu bar size is missing the pixels so the
1289 WM size hints are off by theses pixel. Jan D, oct 2009. */
1291 if (FRAME_EXTERNAL_MENU_BAR (f
))
1294 XtVaGetValues (f
->output_data
.x
->column_widget
,
1295 XtNinternalBorderWidth
, &ibw
, NULL
);
1296 menubar_size
+= ibw
;
1298 #endif /* USE_LUCID */
1301 f
->output_data
.x
->menubar_height
= menubar_size
;
1303 #endif /* not USE_GTK */
1305 free_menubar_widget_value_tree (first_wv
);
1306 update_frame_menubar (f
);
1309 xg_crazy_callback_abort
= 0;
1315 /* Called from Fx_create_frame to create the initial menubar of a frame
1316 before it is mapped, so that the window is mapped with the menubar already
1317 there instead of us tacking it on later and thrashing the window after it
1321 initialize_frame_menubar (FRAME_PTR f
)
1323 /* This function is called before the first chance to redisplay
1324 the frame. It has to be, so the frame will have the right size. */
1325 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1326 set_frame_menubar (f
, 1, 1);
1330 /* Get rid of the menu bar of frame F, and free its storage.
1331 This is used when deleting a frame, and when turning off the menu bar.
1332 For GTK this function is in gtkutil.c. */
1336 free_frame_menubar (FRAME_PTR f
)
1338 Widget menubar_widget
;
1340 if (! FRAME_X_P (f
))
1343 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1345 f
->output_data
.x
->menubar_height
= 0;
1350 /* Removing the menu bar magically changes the shell widget's x
1351 and y position of (0, 0) which, when the menu bar is turned
1352 on again, leads to pull-down menuss appearing in strange
1353 positions near the upper-left corner of the display. This
1354 happens only with some window managers like twm and ctwm,
1355 but not with other like Motif's mwm or kwm, because the
1356 latter generate ConfigureNotify events when the menu bar
1357 is switched off, which fixes the shell position. */
1358 Position x0
, y0
, x1
, y1
;
1364 if (f
->output_data
.x
->widget
)
1365 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1368 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1369 f
->output_data
.x
->menubar_widget
= NULL
;
1372 if (f
->output_data
.x
->widget
)
1374 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1375 if (x1
== 0 && y1
== 0)
1376 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1379 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1383 #endif /* not USE_GTK */
1385 #endif /* USE_X_TOOLKIT || USE_GTK */
1387 /* xmenu_show actually displays a menu using the panes and items in menu_items
1388 and returns the value selected from it.
1389 There are two versions of xmenu_show, one for Xt and one for Xlib.
1390 Both assume input is blocked by the caller. */
1392 /* F is the frame the menu is for.
1393 X and Y are the frame-relative specified position,
1394 relative to the inside upper left corner of the frame F.
1395 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1396 KEYMAPS is 1 if this menu was specified with keymaps;
1397 in that case, we return a list containing the chosen item's value
1398 and perhaps also the pane's prefix.
1399 TITLE is the specified menu title.
1400 ERROR is a place to store an error message string in case of failure.
1401 (We return nil on failure, but the value doesn't actually matter.) */
1403 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1405 /* The item selected in the popup menu. */
1406 static Lisp_Object
*volatile menu_item_selection
;
1410 /* Used when position a popup menu. See menu_position_func and
1411 create_and_show_popup_menu below. */
1412 struct next_popup_x_y
1419 /* The menu position function to use if we are not putting a popup
1420 menu where the pointer is.
1421 MENU is the menu to pop up.
1422 X and Y shall on exit contain x/y where the menu shall pop up.
1423 PUSH_IN is not documented in the GTK manual.
1424 USER_DATA is any data passed in when calling gtk_menu_popup.
1425 Here it points to a struct next_popup_x_y where the coordinates
1426 to store in *X and *Y are as well as the frame for the popup.
1428 Here only X and Y are used. */
1430 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1432 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1434 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1435 int disp_width
= x_display_pixel_width (dpyinfo
);
1436 int disp_height
= x_display_pixel_height (dpyinfo
);
1441 /* Check if there is room for the menu. If not, adjust x/y so that
1442 the menu is fully visible. */
1443 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1444 if (data
->x
+ req
.width
> disp_width
)
1445 *x
-= data
->x
+ req
.width
- disp_width
;
1446 if (data
->y
+ req
.height
> disp_height
)
1447 *y
-= data
->y
+ req
.height
- disp_height
;
1451 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1453 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1455 if (xg_crazy_callback_abort
) return;
1456 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1460 pop_down_menu (Lisp_Object arg
)
1462 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1464 popup_activated_flag
= 0;
1466 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1471 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1473 menu_item_selection will be set to the selection. */
1475 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1479 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1480 struct next_popup_x_y popup_x_y
;
1481 int specpdl_count
= SPECPDL_INDEX ();
1483 if (! FRAME_X_P (f
))
1486 xg_crazy_callback_abort
= 1;
1487 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1488 G_CALLBACK (popup_selection_callback
),
1489 G_CALLBACK (popup_deactivate_callback
),
1490 G_CALLBACK (menu_highlight_callback
));
1491 xg_crazy_callback_abort
= 0;
1495 /* Not invoked by a click. pop up at x/y. */
1496 pos_func
= menu_position_func
;
1498 /* Adjust coordinates to be root-window-relative. */
1499 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1500 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1506 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1510 for (i
= 0; i
< 5; i
++)
1511 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1515 /* Display the menu. */
1516 gtk_widget_show_all (menu
);
1518 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1519 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1521 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1523 if (gtk_widget_get_mapped (menu
))
1525 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1526 two. show_help_echo uses this to detect popup menus. */
1527 popup_activated_flag
= 1;
1528 /* Process events that apply to the menu. */
1529 popup_widget_loop (1, menu
);
1532 unbind_to (specpdl_count
, Qnil
);
1534 /* Must reset this manually because the button release event is not passed
1535 to Emacs event loop. */
1536 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1539 #else /* not USE_GTK */
1541 /* We need a unique id for each widget handled by the Lucid Widget
1544 For the main windows, and popup menus, we use this counter,
1545 which we increment each time after use. This starts from 1<<16.
1547 For menu bars, we use numbers starting at 0, counted in
1548 next_menubar_widget_id. */
1549 LWLIB_ID widget_id_tick
;
1552 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1554 menu_item_selection
= (Lisp_Object
*) client_data
;
1557 /* ARG is the LWLIB ID of the dialog box, represented
1558 as a Lisp object as (HIGHPART . LOWPART). */
1561 pop_down_menu (Lisp_Object arg
)
1563 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1564 | XINT (XCDR (arg
)));
1567 lw_destroy_all_widgets (id
);
1569 popup_activated_flag
= 0;
1574 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1576 menu_item_selection will be set to the selection. */
1578 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, unsigned int timestamp
)
1583 XButtonPressedEvent dummy
;
1587 if (! FRAME_X_P (f
))
1590 menu_id
= widget_id_tick
++;
1591 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1592 f
->output_data
.x
->widget
, 1, 0,
1593 popup_selection_callback
,
1594 popup_deactivate_callback
,
1595 menu_highlight_callback
);
1598 apply_systemfont_to_menu (menu
);
1601 dummy
.type
= ButtonPress
;
1603 dummy
.send_event
= 0;
1604 dummy
.display
= FRAME_X_DISPLAY (f
);
1605 dummy
.time
= CurrentTime
;
1606 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1607 dummy
.window
= dummy
.root
;
1608 dummy
.subwindow
= dummy
.root
;
1612 /* Adjust coordinates to be root-window-relative. */
1613 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1614 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1621 for (i
= 0; i
< 5; i
++)
1622 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1625 /* Don't allow any geometry request from the user. */
1626 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1627 XtSetValues (menu
, av
, ac
);
1629 /* Display the menu. */
1630 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1631 popup_activated_flag
= 1;
1632 x_activate_timeout_atimer ();
1635 int fact
= 4 * sizeof (LWLIB_ID
);
1636 int specpdl_count
= SPECPDL_INDEX ();
1637 record_unwind_protect (pop_down_menu
,
1638 Fcons (make_number (menu_id
>> (fact
)),
1639 make_number (menu_id
& ~(-1 << (fact
)))));
1641 /* Process events that apply to the menu. */
1642 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1644 unbind_to (specpdl_count
, Qnil
);
1648 #endif /* not USE_GTK */
1651 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1652 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1655 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1656 widget_value
**submenu_stack
1657 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1658 Lisp_Object
*subprefix_stack
1659 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1660 int submenu_depth
= 0;
1664 if (! FRAME_X_P (f
))
1669 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1671 *error
= "Empty menu";
1675 /* Create a tree of widget_value objects
1676 representing the panes and their items. */
1677 wv
= xmalloc_widget_value ();
1681 wv
->button_type
= BUTTON_TYPE_NONE
;
1686 /* Loop over all panes and items, filling in the tree. */
1688 while (i
< menu_items_used
)
1690 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1692 submenu_stack
[submenu_depth
++] = save_wv
;
1698 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1701 save_wv
= submenu_stack
[--submenu_depth
];
1705 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1706 && submenu_depth
!= 0)
1707 i
+= MENU_ITEMS_PANE_LENGTH
;
1708 /* Ignore a nil in the item list.
1709 It's meaningful only for dialog boxes. */
1710 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1712 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1714 /* Create a new pane. */
1715 Lisp_Object pane_name
, prefix
;
1718 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1719 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1721 #ifndef HAVE_MULTILINGUAL_MENU
1722 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1724 pane_name
= ENCODE_MENU_STRING (pane_name
);
1725 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1728 pane_string
= (NILP (pane_name
)
1729 ? "" : (char *) SDATA (pane_name
));
1730 /* If there is just one top-level pane, put all its items directly
1731 under the top-level menu. */
1732 if (menu_items_n_panes
== 1)
1735 /* If the pane has a meaningful name,
1736 make the pane a top-level menu item
1737 with its items as a submenu beneath it. */
1738 if (!keymaps
&& strcmp (pane_string
, ""))
1740 wv
= xmalloc_widget_value ();
1744 first_wv
->contents
= wv
;
1745 wv
->name
= pane_string
;
1746 if (keymaps
&& !NILP (prefix
))
1750 wv
->button_type
= BUTTON_TYPE_NONE
;
1755 else if (first_pane
)
1761 i
+= MENU_ITEMS_PANE_LENGTH
;
1765 /* Create a new item within current pane. */
1766 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1767 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1768 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1769 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1770 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1771 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1772 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1773 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1775 #ifndef HAVE_MULTILINGUAL_MENU
1776 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1778 item_name
= ENCODE_MENU_STRING (item_name
);
1779 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1782 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1784 descrip
= ENCODE_MENU_STRING (descrip
);
1785 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1787 #endif /* not HAVE_MULTILINGUAL_MENU */
1789 wv
= xmalloc_widget_value ();
1793 save_wv
->contents
= wv
;
1794 wv
->name
= (char *) SDATA (item_name
);
1795 if (!NILP (descrip
))
1796 wv
->key
= (char *) SDATA (descrip
);
1798 /* If this item has a null value,
1799 make the call_data null so that it won't display a box
1800 when the mouse is on it. */
1802 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1803 wv
->enabled
= !NILP (enable
);
1806 wv
->button_type
= BUTTON_TYPE_NONE
;
1807 else if (EQ (type
, QCtoggle
))
1808 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1809 else if (EQ (type
, QCradio
))
1810 wv
->button_type
= BUTTON_TYPE_RADIO
;
1814 wv
->selected
= !NILP (selected
);
1816 if (! STRINGP (help
))
1823 i
+= MENU_ITEMS_ITEM_LENGTH
;
1827 /* Deal with the title, if it is non-nil. */
1830 widget_value
*wv_title
= xmalloc_widget_value ();
1831 widget_value
*wv_sep1
= xmalloc_widget_value ();
1832 widget_value
*wv_sep2
= xmalloc_widget_value ();
1834 wv_sep2
->name
= "--";
1835 wv_sep2
->next
= first_wv
->contents
;
1836 wv_sep2
->help
= Qnil
;
1838 wv_sep1
->name
= "--";
1839 wv_sep1
->next
= wv_sep2
;
1840 wv_sep1
->help
= Qnil
;
1842 #ifndef HAVE_MULTILINGUAL_MENU
1843 if (STRING_MULTIBYTE (title
))
1844 title
= ENCODE_MENU_STRING (title
);
1847 wv_title
->name
= (char *) SDATA (title
);
1848 wv_title
->enabled
= TRUE
;
1849 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1850 wv_title
->help
= Qnil
;
1851 wv_title
->next
= wv_sep1
;
1852 first_wv
->contents
= wv_title
;
1855 /* No selection has been chosen yet. */
1856 menu_item_selection
= 0;
1858 /* Actually create and show the menu until popped down. */
1859 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1861 /* Free the widget_value objects we used to specify the contents. */
1862 free_menubar_widget_value_tree (first_wv
);
1864 /* Find the selected item, and its pane, to return
1865 the proper value. */
1866 if (menu_item_selection
!= 0)
1868 Lisp_Object prefix
, entry
;
1870 prefix
= entry
= Qnil
;
1872 while (i
< menu_items_used
)
1874 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1876 subprefix_stack
[submenu_depth
++] = prefix
;
1880 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1882 prefix
= subprefix_stack
[--submenu_depth
];
1885 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1888 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1889 i
+= MENU_ITEMS_PANE_LENGTH
;
1891 /* Ignore a nil in the item list.
1892 It's meaningful only for dialog boxes. */
1893 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1898 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1899 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1905 entry
= Fcons (entry
, Qnil
);
1907 entry
= Fcons (prefix
, entry
);
1908 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1909 if (!NILP (subprefix_stack
[j
]))
1910 entry
= Fcons (subprefix_stack
[j
], entry
);
1914 i
+= MENU_ITEMS_ITEM_LENGTH
;
1918 else if (!for_click
)
1919 /* Make "Cancel" equivalent to C-g. */
1920 Fsignal (Qquit
, Qnil
);
1927 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1929 /* The EMACS_INT cast avoids a warning. There's no problem
1930 as long as pointers have enough bits to hold small integers. */
1931 if ((int) (EMACS_INT
) client_data
!= -1)
1932 menu_item_selection
= (Lisp_Object
*) client_data
;
1934 popup_activated_flag
= 0;
1937 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1939 menu_item_selection will be set to the selection. */
1941 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1945 if (! FRAME_X_P (f
))
1948 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1949 G_CALLBACK (dialog_selection_callback
),
1950 G_CALLBACK (popup_deactivate_callback
),
1955 int specpdl_count
= SPECPDL_INDEX ();
1956 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1958 /* Display the menu. */
1959 gtk_widget_show_all (menu
);
1961 /* Process events that apply to the menu. */
1962 popup_widget_loop (1, menu
);
1964 unbind_to (specpdl_count
, Qnil
);
1968 #else /* not USE_GTK */
1970 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1972 /* The EMACS_INT cast avoids a warning. There's no problem
1973 as long as pointers have enough bits to hold small integers. */
1974 if ((int) (EMACS_INT
) client_data
!= -1)
1975 menu_item_selection
= (Lisp_Object
*) client_data
;
1978 lw_destroy_all_widgets (id
);
1980 popup_activated_flag
= 0;
1984 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1986 menu_item_selection will be set to the selection. */
1988 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1995 dialog_id
= widget_id_tick
++;
1997 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1999 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2000 f
->output_data
.x
->widget
, 1, 0,
2001 dialog_selection_callback
, 0, 0);
2002 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2003 /* Display the dialog box. */
2004 lw_pop_up_all_widgets (dialog_id
);
2005 popup_activated_flag
= 1;
2006 x_activate_timeout_atimer ();
2008 /* Process events that apply to the dialog box.
2009 Also handle timers. */
2011 int count
= SPECPDL_INDEX ();
2012 int fact
= 4 * sizeof (LWLIB_ID
);
2014 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2015 record_unwind_protect (pop_down_menu
,
2016 Fcons (make_number (dialog_id
>> (fact
)),
2017 make_number (dialog_id
& ~(-1 << (fact
)))));
2019 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2022 unbind_to (count
, Qnil
);
2026 #endif /* not USE_GTK */
2028 static char * button_names
[] = {
2029 "button1", "button2", "button3", "button4", "button5",
2030 "button6", "button7", "button8", "button9", "button10" };
2033 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2035 int i
, nb_buttons
=0;
2036 char dialog_name
[6];
2038 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2040 /* Number of elements seen so far, before boundary. */
2042 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2043 int boundary_seen
= 0;
2045 if (! FRAME_X_P (f
))
2050 if (menu_items_n_panes
> 1)
2052 *error_name
= "Multiple panes in dialog box";
2056 /* Create a tree of widget_value objects
2057 representing the text label and buttons. */
2059 Lisp_Object pane_name
, prefix
;
2061 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2062 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2063 pane_string
= (NILP (pane_name
)
2064 ? "" : (char *) SDATA (pane_name
));
2065 prev_wv
= xmalloc_widget_value ();
2066 prev_wv
->value
= pane_string
;
2067 if (keymaps
&& !NILP (prefix
))
2069 prev_wv
->enabled
= 1;
2070 prev_wv
->name
= "message";
2071 prev_wv
->help
= Qnil
;
2074 /* Loop over all panes and items, filling in the tree. */
2075 i
= MENU_ITEMS_PANE_LENGTH
;
2076 while (i
< menu_items_used
)
2079 /* Create a new item within current pane. */
2080 Lisp_Object item_name
, enable
, descrip
;
2081 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2082 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2084 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2086 if (NILP (item_name
))
2088 free_menubar_widget_value_tree (first_wv
);
2089 *error_name
= "Submenu in dialog items";
2092 if (EQ (item_name
, Qquote
))
2094 /* This is the boundary between left-side elts
2095 and right-side elts. Stop incrementing right_count. */
2100 if (nb_buttons
>= 9)
2102 free_menubar_widget_value_tree (first_wv
);
2103 *error_name
= "Too many dialog items";
2107 wv
= xmalloc_widget_value ();
2109 wv
->name
= (char *) button_names
[nb_buttons
];
2110 if (!NILP (descrip
))
2111 wv
->key
= (char *) SDATA (descrip
);
2112 wv
->value
= (char *) SDATA (item_name
);
2113 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2114 wv
->enabled
= !NILP (enable
);
2118 if (! boundary_seen
)
2122 i
+= MENU_ITEMS_ITEM_LENGTH
;
2125 /* If the boundary was not specified,
2126 by default put half on the left and half on the right. */
2127 if (! boundary_seen
)
2128 left_count
= nb_buttons
- nb_buttons
/ 2;
2130 wv
= xmalloc_widget_value ();
2131 wv
->name
= dialog_name
;
2134 /* Frame title: 'Q' = Question, 'I' = Information.
2135 Can also have 'E' = Error if, one day, we want
2136 a popup for errors. */
2138 dialog_name
[0] = 'Q';
2140 dialog_name
[0] = 'I';
2142 /* Dialog boxes use a really stupid name encoding
2143 which specifies how many buttons to use
2144 and how many buttons are on the right. */
2145 dialog_name
[1] = '0' + nb_buttons
;
2146 dialog_name
[2] = 'B';
2147 dialog_name
[3] = 'R';
2148 /* Number of buttons to put on the right. */
2149 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2151 wv
->contents
= first_wv
;
2155 /* No selection has been chosen yet. */
2156 menu_item_selection
= 0;
2158 /* Actually create and show the dialog. */
2159 create_and_show_dialog (f
, first_wv
);
2161 /* Free the widget_value objects we used to specify the contents. */
2162 free_menubar_widget_value_tree (first_wv
);
2164 /* Find the selected item, and its pane, to return
2165 the proper value. */
2166 if (menu_item_selection
!= 0)
2172 while (i
< menu_items_used
)
2176 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2179 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2180 i
+= MENU_ITEMS_PANE_LENGTH
;
2182 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2184 /* This is the boundary between left-side elts and
2191 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2192 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2196 entry
= Fcons (entry
, Qnil
);
2198 entry
= Fcons (prefix
, entry
);
2202 i
+= MENU_ITEMS_ITEM_LENGTH
;
2207 /* Make "Cancel" equivalent to C-g. */
2208 Fsignal (Qquit
, Qnil
);
2213 #else /* not USE_X_TOOLKIT && not USE_GTK */
2215 /* The frame of the last activated non-toolkit menu bar.
2216 Used to generate menu help events. */
2218 static struct frame
*menu_help_frame
;
2221 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2223 PANE is the pane number, and ITEM is the menu item number in
2224 the menu (currently not used).
2226 This cannot be done with generating a HELP_EVENT because
2227 XMenuActivate contains a loop that doesn't let Emacs process
2231 menu_help_callback (char *help_string
, int pane
, int item
)
2233 extern Lisp_Object Qmenu_item
;
2234 Lisp_Object
*first_item
;
2235 Lisp_Object pane_name
;
2236 Lisp_Object menu_object
;
2238 first_item
= XVECTOR (menu_items
)->contents
;
2239 if (EQ (first_item
[0], Qt
))
2240 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2241 else if (EQ (first_item
[0], Qquote
))
2242 /* This shouldn't happen, see xmenu_show. */
2243 pane_name
= empty_unibyte_string
;
2245 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2247 /* (menu-item MENU-NAME PANE-NUMBER) */
2248 menu_object
= Fcons (Qmenu_item
,
2250 Fcons (make_number (pane
), Qnil
)));
2251 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2252 Qnil
, menu_object
, make_number (item
), 1);
2256 pop_down_menu (Lisp_Object arg
)
2258 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2259 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2261 FRAME_PTR f
= p1
->pointer
;
2262 XMenu
*menu
= p2
->pointer
;
2266 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2267 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2269 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2271 #ifdef HAVE_X_WINDOWS
2272 /* Assume the mouse has moved out of the X window.
2273 If it has actually moved in, we will get an EnterNotify. */
2274 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2276 /* State that no mouse buttons are now held.
2277 (The oldXMenu code doesn't track this info for us.)
2278 That is not necessarily true, but the fiction leads to reasonable
2279 results, and it is a pain to ask which are actually held now. */
2280 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2282 #endif /* HAVE_X_WINDOWS */
2291 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
, Lisp_Object title
, char **error
, unsigned int timestamp
)
2295 int pane
, selidx
, lpane
, status
;
2296 Lisp_Object entry
, pane_prefix
;
2298 int ulx
, uly
, width
, height
;
2299 int dispwidth
, dispheight
;
2300 int i
, j
, lines
, maxlines
;
2303 unsigned int dummy_uint
;
2304 int specpdl_count
= SPECPDL_INDEX ();
2306 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2310 if (menu_items_n_panes
== 0)
2313 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2315 *error
= "Empty menu";
2319 /* Figure out which root window F is on. */
2320 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2321 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2322 &dummy_uint
, &dummy_uint
);
2324 /* Make the menu on that window. */
2325 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2328 *error
= "Can't create menu";
2332 /* Don't GC while we prepare and show the menu,
2333 because we give the oldxmenu library pointers to the
2334 contents of strings. */
2335 inhibit_garbage_collection ();
2337 #ifdef HAVE_X_WINDOWS
2338 /* Adjust coordinates to relative to the outer (window manager) window. */
2339 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2340 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2341 #endif /* HAVE_X_WINDOWS */
2343 /* Adjust coordinates to be root-window-relative. */
2347 /* Create all the necessary panes and their items. */
2348 maxlines
= lines
= i
= 0;
2349 while (i
< menu_items_used
)
2351 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2353 /* Create a new pane. */
2354 Lisp_Object pane_name
, prefix
;
2357 maxlines
= max (maxlines
, lines
);
2359 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2360 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2361 pane_string
= (NILP (pane_name
)
2362 ? "" : (char *) SDATA (pane_name
));
2363 if (keymaps
&& !NILP (prefix
))
2366 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2367 if (lpane
== XM_FAILURE
)
2369 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2370 *error
= "Can't create pane";
2373 i
+= MENU_ITEMS_PANE_LENGTH
;
2375 /* Find the width of the widest item in this pane. */
2378 while (j
< menu_items_used
)
2381 item
= XVECTOR (menu_items
)->contents
[j
];
2389 width
= SBYTES (item
);
2390 if (width
> maxwidth
)
2393 j
+= MENU_ITEMS_ITEM_LENGTH
;
2396 /* Ignore a nil in the item list.
2397 It's meaningful only for dialog boxes. */
2398 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2402 /* Create a new item within current pane. */
2403 Lisp_Object item_name
, enable
, descrip
, help
;
2404 unsigned char *item_data
;
2407 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2408 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2410 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2411 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2412 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2414 if (!NILP (descrip
))
2416 int gap
= maxwidth
- SBYTES (item_name
);
2417 /* if alloca is fast, use that to make the space,
2418 to reduce gc needs. */
2420 = (unsigned char *) alloca (maxwidth
2421 + SBYTES (descrip
) + 1);
2422 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2423 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2425 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2426 item_data
[j
+ SBYTES (descrip
)] = 0;
2429 item_data
= SDATA (item_name
);
2431 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2432 menu
, lpane
, 0, item_data
,
2433 !NILP (enable
), help_string
)
2436 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2437 *error
= "Can't add selection to menu";
2440 i
+= MENU_ITEMS_ITEM_LENGTH
;
2445 maxlines
= max (maxlines
, lines
);
2447 /* All set and ready to fly. */
2448 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2449 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2450 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2451 x
= min (x
, dispwidth
);
2452 y
= min (y
, dispheight
);
2455 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2456 &ulx
, &uly
, &width
, &height
);
2457 if (ulx
+width
> dispwidth
)
2459 x
-= (ulx
+ width
) - dispwidth
;
2460 ulx
= dispwidth
- width
;
2462 if (uly
+height
> dispheight
)
2464 y
-= (uly
+ height
) - dispheight
;
2465 uly
= dispheight
- height
;
2467 #ifndef HAVE_X_WINDOWS
2468 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2470 /* Move the menu away of the echo area, to avoid overwriting the
2471 menu with help echo messages or vice versa. */
2472 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2474 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2475 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2484 if (ulx
< 0) x
-= ulx
;
2485 if (uly
< 0) y
-= uly
;
2489 /* If position was not given by a mouse click, adjust so upper left
2490 corner of the menu as a whole ends up at given coordinates. This
2491 is what x-popup-menu says in its documentation. */
2493 y
+= 1.5*height
/(maxlines
+2);
2496 XMenuSetAEQ (menu
, TRUE
);
2497 XMenuSetFreeze (menu
, TRUE
);
2501 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2504 record_unwind_protect (pop_down_menu
,
2505 Fcons (make_save_value (f
, 0),
2506 make_save_value (menu
, 0)));
2508 /* Help display under X won't work because XMenuActivate contains
2509 a loop that doesn't give Emacs a chance to process it. */
2510 menu_help_frame
= f
;
2511 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2512 x
, y
, ButtonReleaseMask
, &datap
,
2513 menu_help_callback
);
2519 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2522 /* Find the item number SELIDX in pane number PANE. */
2524 while (i
< menu_items_used
)
2526 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2530 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2532 i
+= MENU_ITEMS_PANE_LENGTH
;
2541 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2544 entry
= Fcons (entry
, Qnil
);
2545 if (!NILP (pane_prefix
))
2546 entry
= Fcons (pane_prefix
, entry
);
2552 i
+= MENU_ITEMS_ITEM_LENGTH
;
2558 *error
= "Can't activate menu";
2563 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2564 the menu was invoked with a mouse event as POSITION). */
2566 Fsignal (Qquit
, Qnil
);
2571 unbind_to (specpdl_count
, Qnil
);
2576 #endif /* not USE_X_TOOLKIT */
2578 #endif /* HAVE_MENUS */
2580 /* Detect if a dialog or menu has been posted. */
2583 popup_activated (void)
2585 return popup_activated_flag
;
2588 /* The following is used by delayed window autoselection. */
2590 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2591 doc
: /* Return t if a menu or popup dialog is active. */)
2595 return (popup_activated ()) ? Qt
: Qnil
;
2598 #endif /* HAVE_MENUS */
2602 syms_of_xmenu (void)
2604 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2605 staticpro (&Qdebug_on_next_call
);
2607 #ifdef USE_X_TOOLKIT
2608 widget_id_tick
= (1<<16);
2609 next_menubar_widget_id
= 1;
2612 defsubr (&Smenu_or_popup_active_p
);
2614 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2615 defsubr (&Sx_menu_bar_open_internal
);
2616 Ffset (intern_c_string ("accelerate-menu"),
2617 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2621 defsubr (&Sx_popup_dialog
);
2625 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2626 (do not change this comment) */