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 (position
, contents
, header
)
264 Lisp_Object position
, contents
, header
;
271 /* Decode the first argument: find the window or frame to use. */
272 if (EQ (position
, Qt
)
273 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
274 || EQ (XCAR (position
), Qtool_bar
))))
276 #if 0 /* Using the frame the mouse is on may not be right. */
277 /* Use the mouse's current position. */
278 FRAME_PTR new_f
= SELECTED_FRAME ();
279 Lisp_Object bar_window
;
280 enum scroll_bar_part part
;
284 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
287 XSETFRAME (window
, new_f
);
289 window
= selected_window
;
291 window
= selected_window
;
293 else if (CONSP (position
))
296 tem
= Fcar (position
);
298 window
= Fcar (Fcdr (position
));
301 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
302 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
305 else if (WINDOWP (position
) || FRAMEP (position
))
310 /* Decode where to put the menu. */
314 else if (WINDOWP (window
))
316 CHECK_LIVE_WINDOW (window
);
317 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
320 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
321 but I don't want to make one now. */
322 CHECK_WINDOW (window
);
324 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
325 error ("Can not put X dialog on this terminal");
327 /* Force a redisplay before showing the dialog. If a frame is created
328 just before showing the dialog, its contents may not have been fully
329 drawn, as this depends on timing of events from the X server. Redisplay
330 is not done when a dialog is shown. If redisplay could be done in the
331 X event loop (i.e. the X event loop does not run in a signal handler)
332 this would not be needed.
334 Do this before creating the widget value that points to Lisp
335 string contents, because Fredisplay may GC and relocate them. */
338 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
339 /* Display a menu with these alternatives
340 in the middle of frame F. */
342 Lisp_Object x
, y
, frame
, newpos
;
343 XSETFRAME (frame
, f
);
344 XSETINT (x
, x_pixel_width (f
) / 2);
345 XSETINT (y
, x_pixel_height (f
) / 2);
346 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
348 return Fx_popup_menu (newpos
,
349 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
355 Lisp_Object selection
;
356 int specpdl_count
= SPECPDL_INDEX ();
358 /* Decode the dialog items from what was specified. */
359 title
= Fcar (contents
);
360 CHECK_STRING (title
);
361 record_unwind_protect (unuse_menu_items
, Qnil
);
363 if (NILP (Fcar (Fcdr (contents
))))
364 /* No buttons specified, add an "Ok" button so users can pop down
365 the dialog. Also, the lesstif/motif version crashes if there are
367 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
369 list_of_panes (Fcons (contents
, Qnil
));
371 /* Display them in a dialog box. */
373 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
376 unbind_to (specpdl_count
, Qnil
);
377 discard_menu_items ();
379 if (error_name
) error (error_name
);
388 /* Set menu_items_inuse so no other popup menu or dialog is created. */
391 x_menu_set_in_use (int in_use
)
393 menu_items_inuse
= in_use
? Qt
: Qnil
;
394 popup_activated_flag
= in_use
;
396 if (popup_activated_flag
)
397 x_activate_timeout_atimer ();
401 /* Wait for an X event to arrive or for a timer to expire. */
404 x_menu_wait_for_event (void *data
)
406 /* Another way to do this is to register a timer callback, that can be
407 done in GTK and Xt. But we have to do it like this when using only X
408 anyway, and with callbacks we would have three variants for timer handling
409 instead of the small ifdefs below. */
413 ! XtAppPending (Xt_app_con
)
414 #elif defined USE_GTK
415 ! gtk_events_pending ()
417 ! XPending ((Display
*) data
)
421 EMACS_TIME next_time
= timer_check (1), *ntp
;
422 long secs
= EMACS_SECS (next_time
);
423 long usecs
= EMACS_USECS (next_time
);
424 SELECT_TYPE read_fds
;
425 struct x_display_info
*dpyinfo
;
429 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
431 int fd
= ConnectionNumber (dpyinfo
->display
);
432 FD_SET (fd
, &read_fds
);
434 XFlush (dpyinfo
->display
);
437 if (secs
< 0 && usecs
< 0)
442 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
448 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
452 /* Loop in Xt until the menu pulldown or dialog popup has been
453 popped down (deactivated). This is used for x-popup-menu
454 and x-popup-dialog; it is not used for the menu bar.
456 NOTE: All calls to popup_get_selection should be protected
457 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
460 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
461 XEvent
*initial_event
;
462 struct x_display_info
*dpyinfo
;
468 while (popup_activated_flag
)
472 event
= *initial_event
;
477 if (do_timers
) x_menu_wait_for_event (0);
478 XtAppNextEvent (Xt_app_con
, &event
);
481 /* Make sure we don't consider buttons grabbed after menu goes.
482 And make sure to deactivate for any ButtonRelease,
483 even if XtDispatchEvent doesn't do that. */
484 if (event
.type
== ButtonRelease
485 && dpyinfo
->display
== event
.xbutton
.display
)
487 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
488 #ifdef USE_MOTIF /* Pretending that the event came from a
489 Btn1Down seems the only way to convince Motif to
490 activate its callbacks; setting the XmNmenuPost
491 isn't working. --marcus@sysc.pdx.edu. */
492 event
.xbutton
.button
= 1;
493 /* Motif only pops down menus when no Ctrl, Alt or Mod
494 key is pressed and the button is released. So reset key state
495 so Motif thinks this is the case. */
496 event
.xbutton
.state
= 0;
499 /* Pop down on C-g and Escape. */
500 else if (event
.type
== KeyPress
501 && dpyinfo
->display
== event
.xbutton
.display
)
503 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
505 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
506 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
507 popup_activated_flag
= 0;
510 x_dispatch_event (&event
, event
.xany
.display
);
514 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
515 doc
: /* Start key navigation of the menu bar in FRAME.
516 This initially opens the first menu bar item and you can then navigate with the
517 arrow keys, select a menu entry with the return key or cancel with the
518 escape key. If FRAME has no menu bar this function does nothing.
520 If FRAME is nil or not given, use the selected frame. */)
525 FRAME_PTR f
= check_x_frame (frame
);
529 if (FRAME_EXTERNAL_MENU_BAR (f
))
530 set_frame_menubar (f
, 0, 1);
532 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
538 x_catch_errors (FRAME_X_DISPLAY (f
));
539 memset (&ev
, 0, sizeof ev
);
540 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
541 ev
.xbutton
.window
= XtWindow (menubar
);
542 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
543 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
544 ev
.xbutton
.button
= Button1
;
545 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
546 ev
.xbutton
.same_screen
= True
;
553 XtSetArg (al
[0], XtNchildren
, &list
);
554 XtSetArg (al
[1], XtNnumChildren
, &nr
);
555 XtGetValues (menubar
, al
, 2);
556 ev
.xbutton
.window
= XtWindow (list
[0]);
560 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
561 /* From-window, to-window. */
562 ev
.xbutton
.window
, ev
.xbutton
.root
,
564 /* From-position, to-position. */
565 ev
.xbutton
.x
, ev
.xbutton
.y
,
566 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
570 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
575 ev
.type
= ButtonPress
;
576 ev
.xbutton
.state
= 0;
578 XtDispatchEvent (&ev
);
579 ev
.xbutton
.type
= ButtonRelease
;
580 ev
.xbutton
.state
= Button1Mask
;
581 XtDispatchEvent (&ev
);
589 #endif /* USE_X_TOOLKIT */
593 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
594 doc
: /* Start key navigation of the menu bar in FRAME.
595 This initially opens the first menu bar item and you can then navigate with the
596 arrow keys, select a menu entry with the return key or cancel with the
597 escape key. If FRAME has no menu bar this function does nothing.
599 If FRAME is nil or not given, use the selected frame. */)
606 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
610 f
= check_x_frame (frame
);
612 if (FRAME_EXTERNAL_MENU_BAR (f
))
613 set_frame_menubar (f
, 0, 1);
615 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
618 /* Activate the first menu. */
619 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
623 g_signal_emit_by_name (children
->data
, "activate_item");
624 popup_activated_flag
= 1;
625 g_list_free (children
);
633 /* Loop util popup_activated_flag is set to zero in a callback.
634 Used for popup menus and dialogs. */
637 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
639 ++popup_activated_flag
;
641 /* Process events in the Gtk event loop until done. */
642 while (popup_activated_flag
)
644 if (do_timers
) x_menu_wait_for_event (0);
645 gtk_main_iteration ();
650 /* Activate the menu bar of frame F.
651 This is called from keyboard.c when it gets the
652 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
654 To activate the menu bar, we use the X button-press event
655 that was saved in saved_menu_event.
656 That makes the toolkit do its thing.
658 But first we recompute the menu bar contents (the whole tree).
660 The reason for saving the button event until here, instead of
661 passing it to the toolkit right away, is that we can safely
662 execute Lisp code. */
665 x_activate_menubar (FRAME_PTR f
)
670 if (!f
->output_data
.x
->saved_menu_event
->type
)
674 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
675 f
->output_data
.x
->saved_menu_event
->xany
.window
))
679 set_frame_menubar (f
, 0, 1);
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
, id
, client_data
)
706 XtPointer client_data
;
708 popup_activated_flag
= 1;
710 x_activate_timeout_atimer ();
715 /* This callback is invoked when a dialog or menu is finished being
716 used and has been unposted. */
720 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
722 popup_activated_flag
= 0;
726 popup_deactivate_callback (widget
, id
, client_data
)
729 XtPointer client_data
;
731 popup_activated_flag
= 0;
736 /* Function that finds the frame for WIDGET and shows the HELP text
738 F is the frame if known, or NULL if not known. */
740 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
746 XSETFRAME (frame
, f
);
747 kbd_buffer_store_help_event (frame
, help
);
751 #if 0 /* This code doesn't do anything useful. ++kfs */
752 /* WIDGET is the popup menu. It's parent is the frame's
753 widget. See which frame that is. */
754 xt_or_gtk_widget frame_widget
= XtParent (widget
);
757 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
761 && (f
= XFRAME (frame
),
762 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
766 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
770 /* Callback called when menu items are highlighted/unhighlighted
771 while moving the mouse over them. WIDGET is the menu bar or menu
772 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
773 the data structure for the menu item, or null in case of
778 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
780 xg_menu_item_cb_data
*cb_data
;
783 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
785 if (! cb_data
) return;
787 help
= call_data
? cb_data
->help
: Qnil
;
789 /* If popup_activated_flag is greater than 1 we are in a popup menu.
790 Don't show help for them, they won't appear before the
791 popup is popped down. */
792 if (popup_activated_flag
<= 1)
793 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
797 menu_highlight_callback (widget
, id
, call_data
)
805 widget_value
*wv
= (widget_value
*) call_data
;
807 help
= wv
? wv
->help
: Qnil
;
809 /* Determine the frame for the help event. */
810 f
= menubar_id_to_frame (id
);
812 show_help_event (f
, widget
, help
);
817 /* Gtk calls callbacks just because we tell it what item should be
818 selected in a radio group. If this variable is set to a non-zero
819 value, we are creating menus and don't want callbacks right now.
821 static int xg_crazy_callback_abort
;
823 /* This callback is called from the menu bar pulldown menu
824 when the user makes a selection.
825 Figure out what the user chose
826 and put the appropriate events into the keyboard buffer. */
828 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
830 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
832 if (xg_crazy_callback_abort
)
835 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
838 /* For a group of radio buttons, GTK calls the selection callback first
839 for the item that was active before the selection and then for the one that
840 is active after the selection. For C-h k this means we get the help on
841 the deselected item and then the selected item is executed. Prevent that
842 by ignoring the non-active item. */
843 if (GTK_IS_RADIO_MENU_ITEM (widget
)
844 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
847 /* When a menu is popped down, X generates a focus event (i.e. focus
848 goes back to the frame below the menu). Since GTK buffers events,
849 we force it out here before the menu selection event. Otherwise
850 sit-for will exit at once if the focus event follows the menu selection
854 while (gtk_events_pending ())
855 gtk_main_iteration ();
858 find_and_call_menu_selection (cb_data
->cl_data
->f
,
859 cb_data
->cl_data
->menu_bar_items_used
,
860 cb_data
->cl_data
->menu_bar_vector
,
864 #else /* not USE_GTK */
866 /* This callback is called from the menu bar pulldown menu
867 when the user makes a selection.
868 Figure out what the user chose
869 and put the appropriate events into the keyboard buffer. */
871 menubar_selection_callback (widget
, id
, client_data
)
874 XtPointer client_data
;
878 f
= menubar_id_to_frame (id
);
881 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
882 f
->menu_bar_vector
, client_data
);
884 #endif /* not USE_GTK */
886 /* Recompute all the widgets of frame F, when the menu bar has been
887 changed. Value is non-zero if widgets were updated. */
890 update_frame_menubar (FRAME_PTR f
)
893 return xg_update_frame_menubar (f
);
901 x
= f
->output_data
.x
;
903 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
907 /* Save the size of the frame because the pane widget doesn't accept
908 to resize itself. So force it. */
909 columns
= FRAME_COLS (f
);
910 rows
= FRAME_LINES (f
);
912 /* Do the voodoo which means "I'm changing lots of things, don't try
913 to refigure sizes until I'm done." */
914 lw_refigure_widget (x
->column_widget
, False
);
916 /* The order in which children are managed is the top to bottom
917 order in which they are displayed in the paned window. First,
918 remove the text-area widget. */
919 XtUnmanageChild (x
->edit_widget
);
921 /* Remove the menubar that is there now, and put up the menubar that
923 XtManageChild (x
->menubar_widget
);
924 XtMapWidget (x
->menubar_widget
);
925 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
927 /* Re-manage the text-area widget, and then thrash the sizes. */
928 XtManageChild (x
->edit_widget
);
929 lw_refigure_widget (x
->column_widget
, True
);
931 /* Force the pane widget to resize itself with the right values. */
932 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
940 apply_systemfont_to_dialog (w
)
943 const char *fn
= xsettings_get_system_normal_font ();
946 XrmDatabase db
= XtDatabase (XtDisplay (w
));
948 XrmPutStringResource (&db
, "*dialog.faceName", fn
);
953 apply_systemfont_to_menu (w
)
956 const char *fn
= xsettings_get_system_normal_font ();
961 if (XtIsShell (w
)) /* popup menu */
963 Widget
*childs
= NULL
;
965 XtVaGetValues (w
, XtNchildren
, &childs
, NULL
);
966 if (*childs
) w
= *childs
;
969 /* Only use system font if the default is used for the menu. */
970 XtVaGetValues (w
, XtNdefaultFace
, &defflt
, NULL
);
972 XtVaSetValues (w
, XtNfaceName
, fn
, NULL
);
976 /* Set the contents of the menubar widgets of frame F.
977 The argument FIRST_TIME is currently ignored;
978 it is set the first time this is called, from initialize_frame_menubar. */
981 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
983 xt_or_gtk_widget menubar_widget
;
988 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
990 int *submenu_start
, *submenu_end
;
991 int *submenu_top_level_items
, *submenu_n_panes
;
996 menubar_widget
= f
->output_data
.x
->menubar_widget
;
998 XSETFRAME (Vmenu_updating_frame
, f
);
1000 #ifdef USE_X_TOOLKIT
1001 if (f
->output_data
.x
->id
== 0)
1002 f
->output_data
.x
->id
= next_menubar_widget_id
++;
1003 id
= f
->output_data
.x
->id
;
1006 if (! menubar_widget
)
1008 else if (pending_menu_activation
&& !deep_p
)
1010 /* Make the first call for any given frame always go deep. */
1011 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1014 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1015 f
->output_data
.x
->saved_menu_event
->type
= 0;
1019 /* If we have detached menus, we must update deep so detached menus
1020 also gets updated. */
1021 deep_p
= deep_p
|| xg_have_tear_offs ();
1026 /* Make a widget-value tree representing the entire menu trees. */
1028 struct buffer
*prev
= current_buffer
;
1030 int specpdl_count
= SPECPDL_INDEX ();
1031 int previous_menu_items_used
= f
->menu_bar_items_used
;
1032 Lisp_Object
*previous_items
1033 = (Lisp_Object
*) alloca (previous_menu_items_used
1034 * sizeof (Lisp_Object
));
1036 /* If we are making a new widget, its contents are empty,
1037 do always reinitialize them. */
1038 if (! menubar_widget
)
1039 previous_menu_items_used
= 0;
1041 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1042 specbind (Qinhibit_quit
, Qt
);
1043 /* Don't let the debugger step into this code
1044 because it is not reentrant. */
1045 specbind (Qdebug_on_next_call
, Qnil
);
1047 record_unwind_save_match_data ();
1048 if (NILP (Voverriding_local_map_menu_flag
))
1050 specbind (Qoverriding_terminal_local_map
, Qnil
);
1051 specbind (Qoverriding_local_map
, Qnil
);
1054 set_buffer_internal_1 (XBUFFER (buffer
));
1056 /* Run the Lucid hook. */
1057 safe_run_hooks (Qactivate_menubar_hook
);
1059 /* If it has changed current-menubar from previous value,
1060 really recompute the menubar from the value. */
1061 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1062 call0 (Qrecompute_lucid_menubar
);
1063 safe_run_hooks (Qmenu_bar_update_hook
);
1064 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1066 items
= FRAME_MENU_BAR_ITEMS (f
);
1068 /* Save the frame's previous menu bar contents data. */
1069 if (previous_menu_items_used
)
1070 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1071 previous_menu_items_used
* sizeof (Lisp_Object
));
1073 /* Fill in menu_items with the current menu bar contents.
1074 This can evaluate Lisp code. */
1077 menu_items
= f
->menu_bar_vector
;
1078 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1079 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1080 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1081 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1082 submenu_top_level_items
1083 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1085 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1087 Lisp_Object key
, string
, maps
;
1091 key
= XVECTOR (items
)->contents
[i
];
1092 string
= XVECTOR (items
)->contents
[i
+ 1];
1093 maps
= XVECTOR (items
)->contents
[i
+ 2];
1097 submenu_start
[i
] = menu_items_used
;
1099 menu_items_n_panes
= 0;
1100 submenu_top_level_items
[i
]
1101 = parse_single_submenu (key
, string
, maps
);
1102 submenu_n_panes
[i
] = menu_items_n_panes
;
1104 submenu_end
[i
] = menu_items_used
;
1107 finish_menu_items ();
1109 /* Convert menu_items into widget_value trees
1110 to display the menu. This cannot evaluate Lisp code. */
1112 wv
= xmalloc_widget_value ();
1113 wv
->name
= "menubar";
1116 wv
->button_type
= BUTTON_TYPE_NONE
;
1120 for (i
= 0; i
< last_i
; i
+= 4)
1122 menu_items_n_panes
= submenu_n_panes
[i
];
1123 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1124 submenu_top_level_items
[i
]);
1128 first_wv
->contents
= wv
;
1129 /* Don't set wv->name here; GC during the loop might relocate it. */
1131 wv
->button_type
= BUTTON_TYPE_NONE
;
1135 set_buffer_internal_1 (prev
);
1137 /* If there has been no change in the Lisp-level contents
1138 of the menu bar, skip redisplaying it. Just exit. */
1140 /* Compare the new menu items with the ones computed last time. */
1141 for (i
= 0; i
< previous_menu_items_used
; i
++)
1142 if (menu_items_used
== i
1143 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1145 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1147 /* The menu items have not changed. Don't bother updating
1148 the menus in any form, since it would be a no-op. */
1149 free_menubar_widget_value_tree (first_wv
);
1150 discard_menu_items ();
1151 unbind_to (specpdl_count
, Qnil
);
1155 /* The menu items are different, so store them in the frame. */
1156 f
->menu_bar_vector
= menu_items
;
1157 f
->menu_bar_items_used
= menu_items_used
;
1159 /* This undoes save_menu_items. */
1160 unbind_to (specpdl_count
, Qnil
);
1162 /* Now GC cannot happen during the lifetime of the widget_value,
1163 so it's safe to store data from a Lisp_String. */
1164 wv
= first_wv
->contents
;
1165 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1168 string
= XVECTOR (items
)->contents
[i
+ 1];
1171 wv
->name
= (char *) SDATA (string
);
1172 update_submenu_strings (wv
->contents
);
1179 /* Make a widget-value tree containing
1180 just the top level menu bar strings. */
1182 wv
= xmalloc_widget_value ();
1183 wv
->name
= "menubar";
1186 wv
->button_type
= BUTTON_TYPE_NONE
;
1190 items
= FRAME_MENU_BAR_ITEMS (f
);
1191 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1195 string
= XVECTOR (items
)->contents
[i
+ 1];
1199 wv
= xmalloc_widget_value ();
1200 wv
->name
= (char *) SDATA (string
);
1203 wv
->button_type
= BUTTON_TYPE_NONE
;
1205 /* This prevents lwlib from assuming this
1206 menu item is really supposed to be empty. */
1207 /* The EMACS_INT cast avoids a warning.
1208 This value just has to be different from small integers. */
1209 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1214 first_wv
->contents
= wv
;
1218 /* Forget what we thought we knew about what is in the
1219 detailed contents of the menu bar menus.
1220 Changing the top level always destroys the contents. */
1221 f
->menu_bar_items_used
= 0;
1224 /* Create or update the menu bar widget. */
1229 xg_crazy_callback_abort
= 1;
1232 /* The fourth arg is DEEP_P, which says to consider the entire
1233 menu trees we supply, rather than just the menu bar item names. */
1234 xg_modify_menubar_widgets (menubar_widget
,
1238 G_CALLBACK (menubar_selection_callback
),
1239 G_CALLBACK (popup_deactivate_callback
),
1240 G_CALLBACK (menu_highlight_callback
));
1244 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1247 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1248 G_CALLBACK (menubar_selection_callback
),
1249 G_CALLBACK (popup_deactivate_callback
),
1250 G_CALLBACK (menu_highlight_callback
));
1252 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1256 #else /* not USE_GTK */
1259 /* Disable resizing (done for Motif!) */
1260 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1262 /* The third arg is DEEP_P, which says to consider the entire
1263 menu trees we supply, rather than just the menu bar item names. */
1264 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1266 /* Re-enable the edit widget to resize. */
1267 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1271 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1272 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1274 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1275 f
->output_data
.x
->column_widget
,
1277 popup_activate_callback
,
1278 menubar_selection_callback
,
1279 popup_deactivate_callback
,
1280 menu_highlight_callback
);
1281 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1283 /* Make menu pop down on C-g. */
1284 XtOverrideTranslations (menubar_widget
, override
);
1285 apply_systemfont_to_menu (menubar_widget
);
1290 = (f
->output_data
.x
->menubar_widget
1291 ? (f
->output_data
.x
->menubar_widget
->core
.height
1292 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1295 #if 1 /* Experimentally, we now get the right results
1296 for -geometry -0-0 without this. 24 Aug 96, rms.
1297 Maybe so, but the menu bar size is missing the pixels so the
1298 WM size hints are off by theses pixel. Jan D, oct 2009. */
1300 if (FRAME_EXTERNAL_MENU_BAR (f
))
1303 XtVaGetValues (f
->output_data
.x
->column_widget
,
1304 XtNinternalBorderWidth
, &ibw
, NULL
);
1305 menubar_size
+= ibw
;
1307 #endif /* USE_LUCID */
1310 f
->output_data
.x
->menubar_height
= menubar_size
;
1312 #endif /* not USE_GTK */
1314 free_menubar_widget_value_tree (first_wv
);
1315 update_frame_menubar (f
);
1318 xg_crazy_callback_abort
= 0;
1324 /* Called from Fx_create_frame to create the initial menubar of a frame
1325 before it is mapped, so that the window is mapped with the menubar already
1326 there instead of us tacking it on later and thrashing the window after it
1330 initialize_frame_menubar (FRAME_PTR f
)
1332 /* This function is called before the first chance to redisplay
1333 the frame. It has to be, so the frame will have the right size. */
1334 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1335 set_frame_menubar (f
, 1, 1);
1339 /* Get rid of the menu bar of frame F, and free its storage.
1340 This is used when deleting a frame, and when turning off the menu bar.
1341 For GTK this function is in gtkutil.c. */
1345 free_frame_menubar (f
)
1348 Widget menubar_widget
;
1350 if (! FRAME_X_P (f
))
1353 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1355 f
->output_data
.x
->menubar_height
= 0;
1360 /* Removing the menu bar magically changes the shell widget's x
1361 and y position of (0, 0) which, when the menu bar is turned
1362 on again, leads to pull-down menuss appearing in strange
1363 positions near the upper-left corner of the display. This
1364 happens only with some window managers like twm and ctwm,
1365 but not with other like Motif's mwm or kwm, because the
1366 latter generate ConfigureNotify events when the menu bar
1367 is switched off, which fixes the shell position. */
1368 Position x0
, y0
, x1
, y1
;
1374 if (f
->output_data
.x
->widget
)
1375 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1378 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1379 f
->output_data
.x
->menubar_widget
= NULL
;
1382 if (f
->output_data
.x
->widget
)
1384 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1385 if (x1
== 0 && y1
== 0)
1386 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1393 #endif /* not USE_GTK */
1395 #endif /* USE_X_TOOLKIT || USE_GTK */
1397 /* xmenu_show actually displays a menu using the panes and items in menu_items
1398 and returns the value selected from it.
1399 There are two versions of xmenu_show, one for Xt and one for Xlib.
1400 Both assume input is blocked by the caller. */
1402 /* F is the frame the menu is for.
1403 X and Y are the frame-relative specified position,
1404 relative to the inside upper left corner of the frame F.
1405 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1406 KEYMAPS is 1 if this menu was specified with keymaps;
1407 in that case, we return a list containing the chosen item's value
1408 and perhaps also the pane's prefix.
1409 TITLE is the specified menu title.
1410 ERROR is a place to store an error message string in case of failure.
1411 (We return nil on failure, but the value doesn't actually matter.) */
1413 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1415 /* The item selected in the popup menu. */
1416 static Lisp_Object
*volatile menu_item_selection
;
1420 /* Used when position a popup menu. See menu_position_func and
1421 create_and_show_popup_menu below. */
1422 struct next_popup_x_y
1429 /* The menu position function to use if we are not putting a popup
1430 menu where the pointer is.
1431 MENU is the menu to pop up.
1432 X and Y shall on exit contain x/y where the menu shall pop up.
1433 PUSH_IN is not documented in the GTK manual.
1434 USER_DATA is any data passed in when calling gtk_menu_popup.
1435 Here it points to a struct next_popup_x_y where the coordinates
1436 to store in *X and *Y are as well as the frame for the popup.
1438 Here only X and Y are used. */
1440 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1442 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1444 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1445 int disp_width
= x_display_pixel_width (dpyinfo
);
1446 int disp_height
= x_display_pixel_height (dpyinfo
);
1451 /* Check if there is room for the menu. If not, adjust x/y so that
1452 the menu is fully visible. */
1453 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1454 if (data
->x
+ req
.width
> disp_width
)
1455 *x
-= data
->x
+ req
.width
- disp_width
;
1456 if (data
->y
+ req
.height
> disp_height
)
1457 *y
-= data
->y
+ req
.height
- disp_height
;
1461 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1463 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1465 if (xg_crazy_callback_abort
) return;
1466 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1470 pop_down_menu (Lisp_Object arg
)
1472 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1474 popup_activated_flag
= 0;
1476 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1481 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1483 menu_item_selection will be set to the selection. */
1485 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1489 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1490 struct next_popup_x_y popup_x_y
;
1491 int specpdl_count
= SPECPDL_INDEX ();
1493 if (! FRAME_X_P (f
))
1496 xg_crazy_callback_abort
= 1;
1497 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1498 G_CALLBACK (popup_selection_callback
),
1499 G_CALLBACK (popup_deactivate_callback
),
1500 G_CALLBACK (menu_highlight_callback
));
1501 xg_crazy_callback_abort
= 0;
1505 /* Not invoked by a click. pop up at x/y. */
1506 pos_func
= menu_position_func
;
1508 /* Adjust coordinates to be root-window-relative. */
1509 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1510 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1516 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1520 for (i
= 0; i
< 5; i
++)
1521 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1525 /* Display the menu. */
1526 gtk_widget_show_all (menu
);
1528 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1529 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1531 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1533 if (gtk_widget_get_mapped (menu
))
1535 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1536 two. show_help_echo uses this to detect popup menus. */
1537 popup_activated_flag
= 1;
1538 /* Process events that apply to the menu. */
1539 popup_widget_loop (1, menu
);
1542 unbind_to (specpdl_count
, Qnil
);
1544 /* Must reset this manually because the button release event is not passed
1545 to Emacs event loop. */
1546 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1549 #else /* not USE_GTK */
1551 /* We need a unique id for each widget handled by the Lucid Widget
1554 For the main windows, and popup menus, we use this counter,
1555 which we increment each time after use. This starts from 1<<16.
1557 For menu bars, we use numbers starting at 0, counted in
1558 next_menubar_widget_id. */
1559 LWLIB_ID widget_id_tick
;
1562 popup_selection_callback (widget
, id
, client_data
)
1565 XtPointer client_data
;
1567 menu_item_selection
= (Lisp_Object
*) client_data
;
1570 /* ARG is the LWLIB ID of the dialog box, represented
1571 as a Lisp object as (HIGHPART . LOWPART). */
1577 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1578 | XINT (XCDR (arg
)));
1581 lw_destroy_all_widgets (id
);
1583 popup_activated_flag
= 0;
1588 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1590 menu_item_selection will be set to the selection. */
1592 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1594 widget_value
*first_wv
;
1598 EMACS_UINT timestamp
;
1603 XButtonPressedEvent dummy
;
1607 if (! FRAME_X_P (f
))
1610 menu_id
= widget_id_tick
++;
1611 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1612 f
->output_data
.x
->widget
, 1, 0,
1613 popup_selection_callback
,
1614 popup_deactivate_callback
,
1615 menu_highlight_callback
);
1617 apply_systemfont_to_menu (menu
);
1619 dummy
.type
= ButtonPress
;
1621 dummy
.send_event
= 0;
1622 dummy
.display
= FRAME_X_DISPLAY (f
);
1623 dummy
.time
= CurrentTime
;
1624 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1625 dummy
.window
= dummy
.root
;
1626 dummy
.subwindow
= dummy
.root
;
1630 /* Adjust coordinates to be root-window-relative. */
1631 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1632 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1639 for (i
= 0; i
< 5; i
++)
1640 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1643 /* Don't allow any geometry request from the user. */
1644 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1645 XtSetValues (menu
, av
, ac
);
1647 /* Display the menu. */
1648 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1649 popup_activated_flag
= 1;
1650 x_activate_timeout_atimer ();
1653 int fact
= 4 * sizeof (LWLIB_ID
);
1654 int specpdl_count
= SPECPDL_INDEX ();
1655 record_unwind_protect (pop_down_menu
,
1656 Fcons (make_number (menu_id
>> (fact
)),
1657 make_number (menu_id
& ~(-1 << (fact
)))));
1659 /* Process events that apply to the menu. */
1660 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1662 unbind_to (specpdl_count
, Qnil
);
1666 #endif /* not USE_GTK */
1669 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1670 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1673 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1674 widget_value
**submenu_stack
1675 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1676 Lisp_Object
*subprefix_stack
1677 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1678 int submenu_depth
= 0;
1682 if (! FRAME_X_P (f
))
1687 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1689 *error
= "Empty menu";
1693 /* Create a tree of widget_value objects
1694 representing the panes and their items. */
1695 wv
= xmalloc_widget_value ();
1699 wv
->button_type
= BUTTON_TYPE_NONE
;
1704 /* Loop over all panes and items, filling in the tree. */
1706 while (i
< menu_items_used
)
1708 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1710 submenu_stack
[submenu_depth
++] = save_wv
;
1716 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1719 save_wv
= submenu_stack
[--submenu_depth
];
1723 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1724 && submenu_depth
!= 0)
1725 i
+= MENU_ITEMS_PANE_LENGTH
;
1726 /* Ignore a nil in the item list.
1727 It's meaningful only for dialog boxes. */
1728 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1730 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1732 /* Create a new pane. */
1733 Lisp_Object pane_name
, prefix
;
1736 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1737 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1739 #ifndef HAVE_MULTILINGUAL_MENU
1740 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1742 pane_name
= ENCODE_MENU_STRING (pane_name
);
1743 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1746 pane_string
= (NILP (pane_name
)
1747 ? "" : (char *) SDATA (pane_name
));
1748 /* If there is just one top-level pane, put all its items directly
1749 under the top-level menu. */
1750 if (menu_items_n_panes
== 1)
1753 /* If the pane has a meaningful name,
1754 make the pane a top-level menu item
1755 with its items as a submenu beneath it. */
1756 if (!keymaps
&& strcmp (pane_string
, ""))
1758 wv
= xmalloc_widget_value ();
1762 first_wv
->contents
= wv
;
1763 wv
->name
= pane_string
;
1764 if (keymaps
&& !NILP (prefix
))
1768 wv
->button_type
= BUTTON_TYPE_NONE
;
1773 else if (first_pane
)
1779 i
+= MENU_ITEMS_PANE_LENGTH
;
1783 /* Create a new item within current pane. */
1784 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1785 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1786 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1787 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1788 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1789 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1790 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1791 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1793 #ifndef HAVE_MULTILINGUAL_MENU
1794 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1796 item_name
= ENCODE_MENU_STRING (item_name
);
1797 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1800 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1802 descrip
= ENCODE_MENU_STRING (descrip
);
1803 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1805 #endif /* not HAVE_MULTILINGUAL_MENU */
1807 wv
= xmalloc_widget_value ();
1811 save_wv
->contents
= wv
;
1812 wv
->name
= (char *) SDATA (item_name
);
1813 if (!NILP (descrip
))
1814 wv
->key
= (char *) SDATA (descrip
);
1816 /* If this item has a null value,
1817 make the call_data null so that it won't display a box
1818 when the mouse is on it. */
1820 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1821 wv
->enabled
= !NILP (enable
);
1824 wv
->button_type
= BUTTON_TYPE_NONE
;
1825 else if (EQ (type
, QCtoggle
))
1826 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1827 else if (EQ (type
, QCradio
))
1828 wv
->button_type
= BUTTON_TYPE_RADIO
;
1832 wv
->selected
= !NILP (selected
);
1834 if (! STRINGP (help
))
1841 i
+= MENU_ITEMS_ITEM_LENGTH
;
1845 /* Deal with the title, if it is non-nil. */
1848 widget_value
*wv_title
= xmalloc_widget_value ();
1849 widget_value
*wv_sep1
= xmalloc_widget_value ();
1850 widget_value
*wv_sep2
= xmalloc_widget_value ();
1852 wv_sep2
->name
= "--";
1853 wv_sep2
->next
= first_wv
->contents
;
1854 wv_sep2
->help
= Qnil
;
1856 wv_sep1
->name
= "--";
1857 wv_sep1
->next
= wv_sep2
;
1858 wv_sep1
->help
= Qnil
;
1860 #ifndef HAVE_MULTILINGUAL_MENU
1861 if (STRING_MULTIBYTE (title
))
1862 title
= ENCODE_MENU_STRING (title
);
1865 wv_title
->name
= (char *) SDATA (title
);
1866 wv_title
->enabled
= TRUE
;
1867 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1868 wv_title
->help
= Qnil
;
1869 wv_title
->next
= wv_sep1
;
1870 first_wv
->contents
= wv_title
;
1873 /* No selection has been chosen yet. */
1874 menu_item_selection
= 0;
1876 /* Actually create and show the menu until popped down. */
1877 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1879 /* Free the widget_value objects we used to specify the contents. */
1880 free_menubar_widget_value_tree (first_wv
);
1882 /* Find the selected item, and its pane, to return
1883 the proper value. */
1884 if (menu_item_selection
!= 0)
1886 Lisp_Object prefix
, entry
;
1888 prefix
= entry
= Qnil
;
1890 while (i
< menu_items_used
)
1892 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1894 subprefix_stack
[submenu_depth
++] = prefix
;
1898 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1900 prefix
= subprefix_stack
[--submenu_depth
];
1903 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1906 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1907 i
+= MENU_ITEMS_PANE_LENGTH
;
1909 /* Ignore a nil in the item list.
1910 It's meaningful only for dialog boxes. */
1911 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1916 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1917 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1923 entry
= Fcons (entry
, Qnil
);
1925 entry
= Fcons (prefix
, entry
);
1926 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1927 if (!NILP (subprefix_stack
[j
]))
1928 entry
= Fcons (subprefix_stack
[j
], entry
);
1932 i
+= MENU_ITEMS_ITEM_LENGTH
;
1936 else if (!for_click
)
1937 /* Make "Cancel" equivalent to C-g. */
1938 Fsignal (Qquit
, Qnil
);
1945 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1947 /* The EMACS_INT cast avoids a warning. There's no problem
1948 as long as pointers have enough bits to hold small integers. */
1949 if ((int) (EMACS_INT
) client_data
!= -1)
1950 menu_item_selection
= (Lisp_Object
*) client_data
;
1952 popup_activated_flag
= 0;
1955 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1957 menu_item_selection will be set to the selection. */
1959 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1963 if (! FRAME_X_P (f
))
1966 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1967 G_CALLBACK (dialog_selection_callback
),
1968 G_CALLBACK (popup_deactivate_callback
),
1973 int specpdl_count
= SPECPDL_INDEX ();
1974 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1976 /* Display the menu. */
1977 gtk_widget_show_all (menu
);
1979 /* Process events that apply to the menu. */
1980 popup_widget_loop (1, menu
);
1982 unbind_to (specpdl_count
, Qnil
);
1986 #else /* not USE_GTK */
1988 dialog_selection_callback (widget
, id
, client_data
)
1991 XtPointer client_data
;
1993 /* The EMACS_INT cast avoids a warning. There's no problem
1994 as long as pointers have enough bits to hold small integers. */
1995 if ((int) (EMACS_INT
) client_data
!= -1)
1996 menu_item_selection
= (Lisp_Object
*) client_data
;
1999 lw_destroy_all_widgets (id
);
2001 popup_activated_flag
= 0;
2005 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2007 menu_item_selection will be set to the selection. */
2009 create_and_show_dialog (f
, first_wv
)
2011 widget_value
*first_wv
;
2018 dialog_id
= widget_id_tick
++;
2020 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
2022 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2023 f
->output_data
.x
->widget
, 1, 0,
2024 dialog_selection_callback
, 0, 0);
2025 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2026 /* Display the dialog box. */
2027 lw_pop_up_all_widgets (dialog_id
);
2028 popup_activated_flag
= 1;
2029 x_activate_timeout_atimer ();
2031 /* Process events that apply to the dialog box.
2032 Also handle timers. */
2034 int count
= SPECPDL_INDEX ();
2035 int fact
= 4 * sizeof (LWLIB_ID
);
2037 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2038 record_unwind_protect (pop_down_menu
,
2039 Fcons (make_number (dialog_id
>> (fact
)),
2040 make_number (dialog_id
& ~(-1 << (fact
)))));
2042 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2045 unbind_to (count
, Qnil
);
2049 #endif /* not USE_GTK */
2051 static char * button_names
[] = {
2052 "button1", "button2", "button3", "button4", "button5",
2053 "button6", "button7", "button8", "button9", "button10" };
2056 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2058 int i
, nb_buttons
=0;
2059 char dialog_name
[6];
2061 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2063 /* Number of elements seen so far, before boundary. */
2065 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2066 int boundary_seen
= 0;
2068 if (! FRAME_X_P (f
))
2073 if (menu_items_n_panes
> 1)
2075 *error_name
= "Multiple panes in dialog box";
2079 /* Create a tree of widget_value objects
2080 representing the text label and buttons. */
2082 Lisp_Object pane_name
, prefix
;
2084 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2085 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2086 pane_string
= (NILP (pane_name
)
2087 ? "" : (char *) SDATA (pane_name
));
2088 prev_wv
= xmalloc_widget_value ();
2089 prev_wv
->value
= pane_string
;
2090 if (keymaps
&& !NILP (prefix
))
2092 prev_wv
->enabled
= 1;
2093 prev_wv
->name
= "message";
2094 prev_wv
->help
= Qnil
;
2097 /* Loop over all panes and items, filling in the tree. */
2098 i
= MENU_ITEMS_PANE_LENGTH
;
2099 while (i
< menu_items_used
)
2102 /* Create a new item within current pane. */
2103 Lisp_Object item_name
, enable
, descrip
;
2104 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2105 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2107 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2109 if (NILP (item_name
))
2111 free_menubar_widget_value_tree (first_wv
);
2112 *error_name
= "Submenu in dialog items";
2115 if (EQ (item_name
, Qquote
))
2117 /* This is the boundary between left-side elts
2118 and right-side elts. Stop incrementing right_count. */
2123 if (nb_buttons
>= 9)
2125 free_menubar_widget_value_tree (first_wv
);
2126 *error_name
= "Too many dialog items";
2130 wv
= xmalloc_widget_value ();
2132 wv
->name
= (char *) button_names
[nb_buttons
];
2133 if (!NILP (descrip
))
2134 wv
->key
= (char *) SDATA (descrip
);
2135 wv
->value
= (char *) SDATA (item_name
);
2136 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2137 wv
->enabled
= !NILP (enable
);
2141 if (! boundary_seen
)
2145 i
+= MENU_ITEMS_ITEM_LENGTH
;
2148 /* If the boundary was not specified,
2149 by default put half on the left and half on the right. */
2150 if (! boundary_seen
)
2151 left_count
= nb_buttons
- nb_buttons
/ 2;
2153 wv
= xmalloc_widget_value ();
2154 wv
->name
= dialog_name
;
2157 /* Frame title: 'Q' = Question, 'I' = Information.
2158 Can also have 'E' = Error if, one day, we want
2159 a popup for errors. */
2161 dialog_name
[0] = 'Q';
2163 dialog_name
[0] = 'I';
2165 /* Dialog boxes use a really stupid name encoding
2166 which specifies how many buttons to use
2167 and how many buttons are on the right. */
2168 dialog_name
[1] = '0' + nb_buttons
;
2169 dialog_name
[2] = 'B';
2170 dialog_name
[3] = 'R';
2171 /* Number of buttons to put on the right. */
2172 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2174 wv
->contents
= first_wv
;
2178 /* No selection has been chosen yet. */
2179 menu_item_selection
= 0;
2181 /* Actually create and show the dialog. */
2182 create_and_show_dialog (f
, first_wv
);
2184 /* Free the widget_value objects we used to specify the contents. */
2185 free_menubar_widget_value_tree (first_wv
);
2187 /* Find the selected item, and its pane, to return
2188 the proper value. */
2189 if (menu_item_selection
!= 0)
2195 while (i
< menu_items_used
)
2199 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2202 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2203 i
+= MENU_ITEMS_PANE_LENGTH
;
2205 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2207 /* This is the boundary between left-side elts and
2214 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2215 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2219 entry
= Fcons (entry
, Qnil
);
2221 entry
= Fcons (prefix
, entry
);
2225 i
+= MENU_ITEMS_ITEM_LENGTH
;
2230 /* Make "Cancel" equivalent to C-g. */
2231 Fsignal (Qquit
, Qnil
);
2236 #else /* not USE_X_TOOLKIT && not USE_GTK */
2238 /* The frame of the last activated non-toolkit menu bar.
2239 Used to generate menu help events. */
2241 static struct frame
*menu_help_frame
;
2244 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2246 PANE is the pane number, and ITEM is the menu item number in
2247 the menu (currently not used).
2249 This cannot be done with generating a HELP_EVENT because
2250 XMenuActivate contains a loop that doesn't let Emacs process
2254 menu_help_callback (help_string
, pane
, item
)
2258 extern Lisp_Object Qmenu_item
;
2259 Lisp_Object
*first_item
;
2260 Lisp_Object pane_name
;
2261 Lisp_Object menu_object
;
2263 first_item
= XVECTOR (menu_items
)->contents
;
2264 if (EQ (first_item
[0], Qt
))
2265 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2266 else if (EQ (first_item
[0], Qquote
))
2267 /* This shouldn't happen, see xmenu_show. */
2268 pane_name
= empty_unibyte_string
;
2270 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2272 /* (menu-item MENU-NAME PANE-NUMBER) */
2273 menu_object
= Fcons (Qmenu_item
,
2275 Fcons (make_number (pane
), Qnil
)));
2276 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2277 Qnil
, menu_object
, make_number (item
), 1);
2284 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2285 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2287 FRAME_PTR f
= p1
->pointer
;
2288 XMenu
*menu
= p2
->pointer
;
2292 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2293 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2295 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2297 #ifdef HAVE_X_WINDOWS
2298 /* Assume the mouse has moved out of the X window.
2299 If it has actually moved in, we will get an EnterNotify. */
2300 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2302 /* State that no mouse buttons are now held.
2303 (The oldXMenu code doesn't track this info for us.)
2304 That is not necessarily true, but the fiction leads to reasonable
2305 results, and it is a pain to ask which are actually held now. */
2306 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2308 #endif /* HAVE_X_WINDOWS */
2317 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
2324 EMACS_UINT timestamp
;
2328 int pane
, selidx
, lpane
, status
;
2329 Lisp_Object entry
, pane_prefix
;
2331 int ulx
, uly
, width
, height
;
2332 int dispwidth
, dispheight
;
2333 int i
, j
, lines
, maxlines
;
2336 unsigned int dummy_uint
;
2337 int specpdl_count
= SPECPDL_INDEX ();
2339 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2343 if (menu_items_n_panes
== 0)
2346 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2348 *error
= "Empty menu";
2352 /* Figure out which root window F is on. */
2353 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2354 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2355 &dummy_uint
, &dummy_uint
);
2357 /* Make the menu on that window. */
2358 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2361 *error
= "Can't create menu";
2365 /* Don't GC while we prepare and show the menu,
2366 because we give the oldxmenu library pointers to the
2367 contents of strings. */
2368 inhibit_garbage_collection ();
2370 #ifdef HAVE_X_WINDOWS
2371 /* Adjust coordinates to relative to the outer (window manager) window. */
2372 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2373 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2374 #endif /* HAVE_X_WINDOWS */
2376 /* Adjust coordinates to be root-window-relative. */
2380 /* Create all the necessary panes and their items. */
2381 maxlines
= lines
= i
= 0;
2382 while (i
< menu_items_used
)
2384 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2386 /* Create a new pane. */
2387 Lisp_Object pane_name
, prefix
;
2390 maxlines
= max (maxlines
, lines
);
2392 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2393 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2394 pane_string
= (NILP (pane_name
)
2395 ? "" : (char *) SDATA (pane_name
));
2396 if (keymaps
&& !NILP (prefix
))
2399 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2400 if (lpane
== XM_FAILURE
)
2402 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2403 *error
= "Can't create pane";
2406 i
+= MENU_ITEMS_PANE_LENGTH
;
2408 /* Find the width of the widest item in this pane. */
2411 while (j
< menu_items_used
)
2414 item
= XVECTOR (menu_items
)->contents
[j
];
2422 width
= SBYTES (item
);
2423 if (width
> maxwidth
)
2426 j
+= MENU_ITEMS_ITEM_LENGTH
;
2429 /* Ignore a nil in the item list.
2430 It's meaningful only for dialog boxes. */
2431 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2435 /* Create a new item within current pane. */
2436 Lisp_Object item_name
, enable
, descrip
, help
;
2437 unsigned char *item_data
;
2440 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2441 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2443 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2444 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2445 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2447 if (!NILP (descrip
))
2449 int gap
= maxwidth
- SBYTES (item_name
);
2450 /* if alloca is fast, use that to make the space,
2451 to reduce gc needs. */
2453 = (unsigned char *) alloca (maxwidth
2454 + SBYTES (descrip
) + 1);
2455 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2456 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2458 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2459 item_data
[j
+ SBYTES (descrip
)] = 0;
2462 item_data
= SDATA (item_name
);
2464 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2465 menu
, lpane
, 0, item_data
,
2466 !NILP (enable
), help_string
)
2469 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2470 *error
= "Can't add selection to menu";
2473 i
+= MENU_ITEMS_ITEM_LENGTH
;
2478 maxlines
= max (maxlines
, lines
);
2480 /* All set and ready to fly. */
2481 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2482 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2483 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2484 x
= min (x
, dispwidth
);
2485 y
= min (y
, dispheight
);
2488 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2489 &ulx
, &uly
, &width
, &height
);
2490 if (ulx
+width
> dispwidth
)
2492 x
-= (ulx
+ width
) - dispwidth
;
2493 ulx
= dispwidth
- width
;
2495 if (uly
+height
> dispheight
)
2497 y
-= (uly
+ height
) - dispheight
;
2498 uly
= dispheight
- height
;
2500 #ifndef HAVE_X_WINDOWS
2501 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2503 /* Move the menu away of the echo area, to avoid overwriting the
2504 menu with help echo messages or vice versa. */
2505 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2507 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2508 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2517 if (ulx
< 0) x
-= ulx
;
2518 if (uly
< 0) y
-= uly
;
2522 /* If position was not given by a mouse click, adjust so upper left
2523 corner of the menu as a whole ends up at given coordinates. This
2524 is what x-popup-menu says in its documentation. */
2526 y
+= 1.5*height
/(maxlines
+2);
2529 XMenuSetAEQ (menu
, TRUE
);
2530 XMenuSetFreeze (menu
, TRUE
);
2534 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2537 record_unwind_protect (pop_down_menu
,
2538 Fcons (make_save_value (f
, 0),
2539 make_save_value (menu
, 0)));
2541 /* Help display under X won't work because XMenuActivate contains
2542 a loop that doesn't give Emacs a chance to process it. */
2543 menu_help_frame
= f
;
2544 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2545 x
, y
, ButtonReleaseMask
, &datap
,
2546 menu_help_callback
);
2552 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2555 /* Find the item number SELIDX in pane number PANE. */
2557 while (i
< menu_items_used
)
2559 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2563 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2565 i
+= MENU_ITEMS_PANE_LENGTH
;
2574 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2577 entry
= Fcons (entry
, Qnil
);
2578 if (!NILP (pane_prefix
))
2579 entry
= Fcons (pane_prefix
, entry
);
2585 i
+= MENU_ITEMS_ITEM_LENGTH
;
2591 *error
= "Can't activate menu";
2596 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2597 the menu was invoked with a mouse event as POSITION). */
2599 Fsignal (Qquit
, Qnil
);
2604 unbind_to (specpdl_count
, Qnil
);
2609 #endif /* not USE_X_TOOLKIT */
2611 #endif /* HAVE_MENUS */
2613 /* Detect if a dialog or menu has been posted. */
2616 popup_activated (void)
2618 return popup_activated_flag
;
2621 /* The following is used by delayed window autoselection. */
2623 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2624 doc
: /* Return t if a menu or popup dialog is active. */)
2628 return (popup_activated ()) ? Qt
: Qnil
;
2631 #endif /* HAVE_MENUS */
2635 syms_of_xmenu (void)
2637 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2638 staticpro (&Qdebug_on_next_call
);
2640 #ifdef USE_X_TOOLKIT
2641 widget_id_tick
= (1<<16);
2642 next_menubar_widget_id
= 1;
2645 defsubr (&Smenu_or_popup_active_p
);
2647 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2648 defsubr (&Sx_menu_bar_open_internal
);
2649 Ffset (intern_c_string ("accelerate-menu"),
2650 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2654 defsubr (&Sx_popup_dialog
);
2658 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2659 (do not change this comment) */