1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
27 /* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
30 /* Rewritten for clarity and GC protection by rms in Feb 94. */
34 #if 0 /* Why was this included? And without syssignal.h? */
35 /* On 4.3 this loses if it comes after xterm.h. */
46 #include "termhooks.h"
48 #include "blockinput.h"
52 #include "sysselect.h"
59 /* This may include sys/types.h, and that somehow loses
60 if this is not done before the other system files. */
64 /* Load sys/types.h if not already loaded.
65 In some systems loading it twice is suicidal. */
67 #include <sys/types.h>
70 #include "dispextern.h"
73 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
74 code accepts the Emacs internal encoding. */
75 #undef HAVE_MULTILINGUAL_MENU
79 #include <X11/IntrinsicP.h>
80 #include <X11/CoreP.h>
81 #include <X11/StringDefs.h>
82 #include <X11/Shell.h>
84 #include "xsettings.h"
85 #include "../lwlib/xlwmenu.h"
87 #include <X11/Xaw3d/Paned.h>
88 #else /* !HAVE_XAW3D */
89 #include <X11/Xaw/Paned.h>
90 #endif /* HAVE_XAW3D */
91 #endif /* USE_LUCID */
92 #include "../lwlib/lwlib.h"
93 #else /* not USE_X_TOOLKIT */
95 #include "../oldXMenu/XMenu.h"
97 #endif /* not USE_X_TOOLKIT */
98 #endif /* HAVE_X_WINDOWS */
111 Lisp_Object Qdebug_on_next_call
;
113 extern Lisp_Object Qmenu_bar
;
115 extern Lisp_Object QCtoggle
, QCradio
;
117 extern Lisp_Object Voverriding_local_map
;
118 extern Lisp_Object Voverriding_local_map_menu_flag
;
120 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
122 extern Lisp_Object Qmenu_bar_update_hook
;
125 extern void set_frame_menubar (FRAME_PTR
, int, int);
126 extern XtAppContext Xt_app_con
;
128 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
130 static void popup_get_selection (XEvent
*, struct x_display_info
*,
132 #endif /* USE_X_TOOLKIT */
135 extern void set_frame_menubar (FRAME_PTR
, int, int);
136 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
140 static int update_frame_menubar (struct frame
*);
142 /* Flag which when set indicates a dialog or menu has been posted by
143 Xt on behalf of one of the widget sets. */
144 static int popup_activated_flag
;
146 static int next_menubar_widget_id
;
148 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
149 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
150 extern widget_value
*xmalloc_widget_value (void);
151 extern widget_value
*digest_single_submenu (int, int, int);
154 /* This is set nonzero after the user activates the menu bar, and set
155 to zero again after the menu bars are redisplayed by prepare_menu_bar.
156 While it is nonzero, all calls to set_frame_menubar go deep.
158 I don't understand why this is needed, but it does seem to be
159 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
161 int pending_menu_activation
;
165 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
167 static struct frame
*
168 menubar_id_to_frame (id
)
171 Lisp_Object tail
, frame
;
174 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
180 if (!FRAME_WINDOW_P (f
))
182 if (f
->output_data
.x
->id
== id
)
190 #ifdef HAVE_X_WINDOWS
191 /* Return the mouse position in *X and *Y. The coordinates are window
192 relative for the edit window in frame F.
193 This is for Fx_popup_menu. The mouse_position_hook can not
194 be used for X, as it returns window relative coordinates
195 for the window where the mouse is in. This could be the menu bar,
196 the scroll bar or the edit window. Fx_popup_menu needs to be
197 sure it is the edit window. */
199 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
201 Window root
, dummy_window
;
209 XQueryPointer (FRAME_X_DISPLAY (f
),
210 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
212 /* The root window which contains the pointer. */
215 /* Window pointer is on, not used */
218 /* The position on that root window. */
221 /* x/y in dummy_window coordinates, not used. */
224 /* Modifier keys and pointer buttons, about which
226 (unsigned int *) &dummy
);
230 /* xmenu_show expects window coordinates, not root window
231 coordinates. Translate. */
232 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
233 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
236 #endif /* HAVE_X_WINDOWS */
240 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
241 doc
: /* Pop up a dialog box and return user's selection.
242 POSITION specifies which frame to use.
243 This is normally a mouse button event or a window or frame.
244 If POSITION is t, it means to use the frame the mouse is on.
245 The dialog box appears in the middle of the specified frame.
247 CONTENTS specifies the alternatives to display in the dialog box.
248 It is a list of the form (DIALOG ITEM1 ITEM2...).
249 Each ITEM is a cons cell (STRING . VALUE).
250 The return value is VALUE from the chosen item.
252 An ITEM may also be just a string--that makes a nonselectable item.
253 An ITEM may also be nil--that means to put all preceding items
254 on the left of the dialog box and all following items on the right.
255 \(By default, approximately half appear on each side.)
257 If HEADER is non-nil, the frame title for the box is "Information",
258 otherwise it is "Question".
260 If the user gets rid of the dialog box without making a valid choice,
261 for instance using the window manager, then this produces a quit and
262 `x-popup-dialog' does not return. */)
263 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
270 /* Decode the first argument: find the window or frame to use. */
271 if (EQ (position
, Qt
)
272 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
273 || EQ (XCAR (position
), Qtool_bar
))))
275 #if 0 /* Using the frame the mouse is on may not be right. */
276 /* Use the mouse's current position. */
277 FRAME_PTR new_f
= SELECTED_FRAME ();
278 Lisp_Object bar_window
;
279 enum scroll_bar_part part
;
283 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
286 XSETFRAME (window
, new_f
);
288 window
= selected_window
;
290 window
= selected_window
;
292 else if (CONSP (position
))
295 tem
= Fcar (position
);
297 window
= Fcar (Fcdr (position
));
300 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
301 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
304 else if (WINDOWP (position
) || FRAMEP (position
))
309 /* Decode where to put the menu. */
313 else if (WINDOWP (window
))
315 CHECK_LIVE_WINDOW (window
);
316 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
319 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
320 but I don't want to make one now. */
321 CHECK_WINDOW (window
);
323 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
324 error ("Can not put X dialog on this terminal");
326 /* Force a redisplay before showing the dialog. If a frame is created
327 just before showing the dialog, its contents may not have been fully
328 drawn, as this depends on timing of events from the X server. Redisplay
329 is not done when a dialog is shown. If redisplay could be done in the
330 X event loop (i.e. the X event loop does not run in a signal handler)
331 this would not be needed.
333 Do this before creating the widget value that points to Lisp
334 string contents, because Fredisplay may GC and relocate them. */
337 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
338 /* Display a menu with these alternatives
339 in the middle of frame F. */
341 Lisp_Object x
, y
, frame
, newpos
;
342 XSETFRAME (frame
, f
);
343 XSETINT (x
, x_pixel_width (f
) / 2);
344 XSETINT (y
, x_pixel_height (f
) / 2);
345 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
347 return Fx_popup_menu (newpos
,
348 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
354 Lisp_Object selection
;
355 int specpdl_count
= SPECPDL_INDEX ();
357 /* Decode the dialog items from what was specified. */
358 title
= Fcar (contents
);
359 CHECK_STRING (title
);
360 record_unwind_protect (unuse_menu_items
, Qnil
);
362 if (NILP (Fcar (Fcdr (contents
))))
363 /* No buttons specified, add an "Ok" button so users can pop down
364 the dialog. Also, the lesstif/motif version crashes if there are
366 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
368 list_of_panes (Fcons (contents
, Qnil
));
370 /* Display them in a dialog box. */
372 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
375 unbind_to (specpdl_count
, Qnil
);
376 discard_menu_items ();
378 if (error_name
) error (error_name
);
387 /* Set menu_items_inuse so no other popup menu or dialog is created. */
390 x_menu_set_in_use (int in_use
)
392 menu_items_inuse
= in_use
? Qt
: Qnil
;
393 popup_activated_flag
= in_use
;
395 if (popup_activated_flag
)
396 x_activate_timeout_atimer ();
400 /* Wait for an X event to arrive or for a timer to expire. */
403 x_menu_wait_for_event (void *data
)
405 /* Another way to do this is to register a timer callback, that can be
406 done in GTK and Xt. But we have to do it like this when using only X
407 anyway, and with callbacks we would have three variants for timer handling
408 instead of the small ifdefs below. */
412 ! XtAppPending (Xt_app_con
)
413 #elif defined USE_GTK
414 ! gtk_events_pending ()
416 ! XPending ((Display
*) data
)
420 EMACS_TIME next_time
= timer_check (1), *ntp
;
421 long secs
= EMACS_SECS (next_time
);
422 long usecs
= EMACS_USECS (next_time
);
423 SELECT_TYPE read_fds
;
424 struct x_display_info
*dpyinfo
;
428 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
430 int fd
= ConnectionNumber (dpyinfo
->display
);
431 FD_SET (fd
, &read_fds
);
433 XFlush (dpyinfo
->display
);
436 if (secs
< 0 && usecs
< 0)
441 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
447 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
451 /* Loop in Xt until the menu pulldown or dialog popup has been
452 popped down (deactivated). This is used for x-popup-menu
453 and x-popup-dialog; it is not used for the menu bar.
455 NOTE: All calls to popup_get_selection should be protected
456 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
459 popup_get_selection (initial_event
, dpyinfo
, id
, do_timers
)
460 XEvent
*initial_event
;
461 struct x_display_info
*dpyinfo
;
467 while (popup_activated_flag
)
471 event
= *initial_event
;
476 if (do_timers
) x_menu_wait_for_event (0);
477 XtAppNextEvent (Xt_app_con
, &event
);
480 /* Make sure we don't consider buttons grabbed after menu goes.
481 And make sure to deactivate for any ButtonRelease,
482 even if XtDispatchEvent doesn't do that. */
483 if (event
.type
== ButtonRelease
484 && dpyinfo
->display
== event
.xbutton
.display
)
486 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
487 #ifdef USE_MOTIF /* Pretending that the event came from a
488 Btn1Down seems the only way to convince Motif to
489 activate its callbacks; setting the XmNmenuPost
490 isn't working. --marcus@sysc.pdx.edu. */
491 event
.xbutton
.button
= 1;
492 /* Motif only pops down menus when no Ctrl, Alt or Mod
493 key is pressed and the button is released. So reset key state
494 so Motif thinks this is the case. */
495 event
.xbutton
.state
= 0;
498 /* Pop down on C-g and Escape. */
499 else if (event
.type
== KeyPress
500 && dpyinfo
->display
== event
.xbutton
.display
)
502 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
504 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
505 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
506 popup_activated_flag
= 0;
509 x_dispatch_event (&event
, event
.xany
.display
);
513 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
514 doc
: /* Start key navigation of the menu bar in FRAME.
515 This initially opens the first menu bar item and you can then navigate with the
516 arrow keys, select a menu entry with the return key or cancel with the
517 escape key. If FRAME has no menu bar this function does nothing.
519 If FRAME is nil or not given, use the selected frame. */)
523 FRAME_PTR f
= check_x_frame (frame
);
527 if (FRAME_EXTERNAL_MENU_BAR (f
))
528 set_frame_menubar (f
, 0, 1);
530 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
536 x_catch_errors (FRAME_X_DISPLAY (f
));
537 memset (&ev
, 0, sizeof ev
);
538 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
539 ev
.xbutton
.window
= XtWindow (menubar
);
540 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
541 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
542 ev
.xbutton
.button
= Button1
;
543 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
544 ev
.xbutton
.same_screen
= True
;
551 XtSetArg (al
[0], XtNchildren
, &list
);
552 XtSetArg (al
[1], XtNnumChildren
, &nr
);
553 XtGetValues (menubar
, al
, 2);
554 ev
.xbutton
.window
= XtWindow (list
[0]);
558 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
559 /* From-window, to-window. */
560 ev
.xbutton
.window
, ev
.xbutton
.root
,
562 /* From-position, to-position. */
563 ev
.xbutton
.x
, ev
.xbutton
.y
,
564 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
568 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
573 ev
.type
= ButtonPress
;
574 ev
.xbutton
.state
= 0;
576 XtDispatchEvent (&ev
);
577 ev
.xbutton
.type
= ButtonRelease
;
578 ev
.xbutton
.state
= Button1Mask
;
579 XtDispatchEvent (&ev
);
587 #endif /* USE_X_TOOLKIT */
591 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
592 doc
: /* Start key navigation of the menu bar in FRAME.
593 This initially opens the first menu bar item and you can then navigate with the
594 arrow keys, select a menu entry with the return key or cancel with the
595 escape key. If FRAME has no menu bar this function does nothing.
597 If FRAME is nil or not given, use the selected frame. */)
603 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
607 f
= check_x_frame (frame
);
609 if (FRAME_EXTERNAL_MENU_BAR (f
))
610 set_frame_menubar (f
, 0, 1);
612 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
615 /* Activate the first menu. */
616 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
620 g_signal_emit_by_name (children
->data
, "activate_item");
621 popup_activated_flag
= 1;
622 g_list_free (children
);
630 /* Loop util popup_activated_flag is set to zero in a callback.
631 Used for popup menus and dialogs. */
634 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
636 ++popup_activated_flag
;
638 /* Process events in the Gtk event loop until done. */
639 while (popup_activated_flag
)
641 if (do_timers
) x_menu_wait_for_event (0);
642 gtk_main_iteration ();
647 /* Activate the menu bar of frame F.
648 This is called from keyboard.c when it gets the
649 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
651 To activate the menu bar, we use the X button-press event
652 that was saved in saved_menu_event.
653 That makes the toolkit do its thing.
655 But first we recompute the menu bar contents (the whole tree).
657 The reason for saving the button event until here, instead of
658 passing it to the toolkit right away, is that we can safely
659 execute Lisp code. */
662 x_activate_menubar (FRAME_PTR f
)
667 if (!f
->output_data
.x
->saved_menu_event
->type
)
671 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
672 f
->output_data
.x
->saved_menu_event
->xany
.window
))
676 set_frame_menubar (f
, 0, 1);
679 /* If we click outside any menu item, the menu bar still grabs.
680 So we send Press and the Release. If outside, grab is released.
681 If on a menu item, it is popped up normally.
682 PutBack is like a stack, so we put back in reverse order. */
683 f
->output_data
.x
->saved_menu_event
->type
= ButtonRelease
;
684 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
685 f
->output_data
.x
->saved_menu_event
);
686 f
->output_data
.x
->saved_menu_event
->type
= ButtonPress
;
687 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
688 f
->output_data
.x
->saved_menu_event
);
689 popup_activated_flag
= 1;
691 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
695 if (f
->output_data
.x
->saved_menu_event
->type
== ButtonRelease
)
696 pending_menu_activation
= 1;
699 /* Ignore this if we get it a second time. */
700 f
->output_data
.x
->saved_menu_event
->type
= 0;
703 /* This callback is invoked when the user selects a menubar cascade
704 pushbutton, but before the pulldown menu is posted. */
708 popup_activate_callback (widget
, id
, client_data
)
711 XtPointer client_data
;
713 popup_activated_flag
= 1;
715 x_activate_timeout_atimer ();
720 /* This callback is invoked when a dialog or menu is finished being
721 used and has been unposted. */
725 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
727 popup_activated_flag
= 0;
731 popup_deactivate_callback (widget
, id
, client_data
)
734 XtPointer client_data
;
736 popup_activated_flag
= 0;
741 /* Function that finds the frame for WIDGET and shows the HELP text
743 F is the frame if known, or NULL if not known. */
745 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
751 XSETFRAME (frame
, f
);
752 kbd_buffer_store_help_event (frame
, help
);
756 #if 0 /* This code doesn't do anything useful. ++kfs */
757 /* WIDGET is the popup menu. It's parent is the frame's
758 widget. See which frame that is. */
759 xt_or_gtk_widget frame_widget
= XtParent (widget
);
762 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
766 && (f
= XFRAME (frame
),
767 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
771 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
775 /* Callback called when menu items are highlighted/unhighlighted
776 while moving the mouse over them. WIDGET is the menu bar or menu
777 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
778 the data structure for the menu item, or null in case of
783 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
785 xg_menu_item_cb_data
*cb_data
;
788 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
790 if (! cb_data
) return;
792 help
= call_data
? cb_data
->help
: Qnil
;
794 /* If popup_activated_flag is greater than 1 we are in a popup menu.
795 Don't show help for them, they won't appear before the
796 popup is popped down. */
797 if (popup_activated_flag
<= 1)
798 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
802 menu_highlight_callback (widget
, id
, call_data
)
810 widget_value
*wv
= (widget_value
*) call_data
;
812 help
= wv
? wv
->help
: Qnil
;
814 /* Determine the frame for the help event. */
815 f
= menubar_id_to_frame (id
);
817 show_help_event (f
, widget
, help
);
822 /* Gtk calls callbacks just because we tell it what item should be
823 selected in a radio group. If this variable is set to a non-zero
824 value, we are creating menus and don't want callbacks right now.
826 static int xg_crazy_callback_abort
;
828 /* This callback is called from the menu bar pulldown menu
829 when the user makes a selection.
830 Figure out what the user chose
831 and put the appropriate events into the keyboard buffer. */
833 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
835 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
837 if (xg_crazy_callback_abort
)
840 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
843 /* For a group of radio buttons, GTK calls the selection callback first
844 for the item that was active before the selection and then for the one that
845 is active after the selection. For C-h k this means we get the help on
846 the deselected item and then the selected item is executed. Prevent that
847 by ignoring the non-active item. */
848 if (GTK_IS_RADIO_MENU_ITEM (widget
)
849 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
852 /* When a menu is popped down, X generates a focus event (i.e. focus
853 goes back to the frame below the menu). Since GTK buffers events,
854 we force it out here before the menu selection event. Otherwise
855 sit-for will exit at once if the focus event follows the menu selection
859 while (gtk_events_pending ())
860 gtk_main_iteration ();
863 find_and_call_menu_selection (cb_data
->cl_data
->f
,
864 cb_data
->cl_data
->menu_bar_items_used
,
865 cb_data
->cl_data
->menu_bar_vector
,
869 #else /* not USE_GTK */
871 /* This callback is called from the menu bar pulldown menu
872 when the user makes a selection.
873 Figure out what the user chose
874 and put the appropriate events into the keyboard buffer. */
876 menubar_selection_callback (widget
, id
, client_data
)
879 XtPointer client_data
;
883 f
= menubar_id_to_frame (id
);
886 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
887 f
->menu_bar_vector
, client_data
);
889 #endif /* not USE_GTK */
891 /* Recompute all the widgets of frame F, when the menu bar has been
892 changed. Value is non-zero if widgets were updated. */
895 update_frame_menubar (FRAME_PTR f
)
898 return xg_update_frame_menubar (f
);
906 x
= f
->output_data
.x
;
908 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
912 /* Save the size of the frame because the pane widget doesn't accept
913 to resize itself. So force it. */
914 columns
= FRAME_COLS (f
);
915 rows
= FRAME_LINES (f
);
917 /* Do the voodoo which means "I'm changing lots of things, don't try
918 to refigure sizes until I'm done." */
919 lw_refigure_widget (x
->column_widget
, False
);
921 /* The order in which children are managed is the top to bottom
922 order in which they are displayed in the paned window. First,
923 remove the text-area widget. */
924 XtUnmanageChild (x
->edit_widget
);
926 /* Remove the menubar that is there now, and put up the menubar that
928 XtManageChild (x
->menubar_widget
);
929 XtMapWidget (x
->menubar_widget
);
930 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
932 /* Re-manage the text-area widget, and then thrash the sizes. */
933 XtManageChild (x
->edit_widget
);
934 lw_refigure_widget (x
->column_widget
, True
);
936 /* Force the pane widget to resize itself with the right values. */
937 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
945 apply_systemfont_to_dialog (w
)
948 const char *fn
= xsettings_get_system_normal_font ();
951 XrmDatabase db
= XtDatabase (XtDisplay (w
));
953 XrmPutStringResource (&db
, "*dialog.faceName", fn
);
958 apply_systemfont_to_menu (w
)
961 const char *fn
= xsettings_get_system_normal_font ();
966 if (XtIsShell (w
)) /* popup menu */
968 Widget
*childs
= NULL
;
970 XtVaGetValues (w
, XtNchildren
, &childs
, NULL
);
971 if (*childs
) w
= *childs
;
974 /* Only use system font if the default is used for the menu. */
975 XtVaGetValues (w
, XtNdefaultFace
, &defflt
, NULL
);
977 XtVaSetValues (w
, XtNfaceName
, fn
, NULL
);
981 /* Set the contents of the menubar widgets of frame F.
982 The argument FIRST_TIME is currently ignored;
983 it is set the first time this is called, from initialize_frame_menubar. */
986 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
988 xt_or_gtk_widget menubar_widget
;
993 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
995 int *submenu_start
, *submenu_end
;
996 int *submenu_top_level_items
, *submenu_n_panes
;
1001 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1003 XSETFRAME (Vmenu_updating_frame
, f
);
1005 #ifdef USE_X_TOOLKIT
1006 if (f
->output_data
.x
->id
== 0)
1007 f
->output_data
.x
->id
= next_menubar_widget_id
++;
1008 id
= f
->output_data
.x
->id
;
1011 if (! menubar_widget
)
1013 else if (pending_menu_activation
&& !deep_p
)
1015 /* Make the first call for any given frame always go deep. */
1016 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
1019 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
1020 f
->output_data
.x
->saved_menu_event
->type
= 0;
1024 /* If we have detached menus, we must update deep so detached menus
1025 also gets updated. */
1026 deep_p
= deep_p
|| xg_have_tear_offs ();
1031 /* Make a widget-value tree representing the entire menu trees. */
1033 struct buffer
*prev
= current_buffer
;
1035 int specpdl_count
= SPECPDL_INDEX ();
1036 int previous_menu_items_used
= f
->menu_bar_items_used
;
1037 Lisp_Object
*previous_items
1038 = (Lisp_Object
*) alloca (previous_menu_items_used
1039 * sizeof (Lisp_Object
));
1041 /* If we are making a new widget, its contents are empty,
1042 do always reinitialize them. */
1043 if (! menubar_widget
)
1044 previous_menu_items_used
= 0;
1046 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1047 specbind (Qinhibit_quit
, Qt
);
1048 /* Don't let the debugger step into this code
1049 because it is not reentrant. */
1050 specbind (Qdebug_on_next_call
, Qnil
);
1052 record_unwind_save_match_data ();
1053 if (NILP (Voverriding_local_map_menu_flag
))
1055 specbind (Qoverriding_terminal_local_map
, Qnil
);
1056 specbind (Qoverriding_local_map
, Qnil
);
1059 set_buffer_internal_1 (XBUFFER (buffer
));
1061 /* Run the Lucid hook. */
1062 safe_run_hooks (Qactivate_menubar_hook
);
1064 /* If it has changed current-menubar from previous value,
1065 really recompute the menubar from the value. */
1066 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1067 call0 (Qrecompute_lucid_menubar
);
1068 safe_run_hooks (Qmenu_bar_update_hook
);
1069 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1071 items
= FRAME_MENU_BAR_ITEMS (f
);
1073 /* Save the frame's previous menu bar contents data. */
1074 if (previous_menu_items_used
)
1075 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1076 previous_menu_items_used
* sizeof (Lisp_Object
));
1078 /* Fill in menu_items with the current menu bar contents.
1079 This can evaluate Lisp code. */
1082 menu_items
= f
->menu_bar_vector
;
1083 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1084 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1085 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1086 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1087 submenu_top_level_items
1088 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1090 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1092 Lisp_Object key
, string
, maps
;
1096 key
= XVECTOR (items
)->contents
[i
];
1097 string
= XVECTOR (items
)->contents
[i
+ 1];
1098 maps
= XVECTOR (items
)->contents
[i
+ 2];
1102 submenu_start
[i
] = menu_items_used
;
1104 menu_items_n_panes
= 0;
1105 submenu_top_level_items
[i
]
1106 = parse_single_submenu (key
, string
, maps
);
1107 submenu_n_panes
[i
] = menu_items_n_panes
;
1109 submenu_end
[i
] = menu_items_used
;
1112 finish_menu_items ();
1114 /* Convert menu_items into widget_value trees
1115 to display the menu. This cannot evaluate Lisp code. */
1117 wv
= xmalloc_widget_value ();
1118 wv
->name
= "menubar";
1121 wv
->button_type
= BUTTON_TYPE_NONE
;
1125 for (i
= 0; i
< last_i
; i
+= 4)
1127 menu_items_n_panes
= submenu_n_panes
[i
];
1128 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1129 submenu_top_level_items
[i
]);
1133 first_wv
->contents
= wv
;
1134 /* Don't set wv->name here; GC during the loop might relocate it. */
1136 wv
->button_type
= BUTTON_TYPE_NONE
;
1140 set_buffer_internal_1 (prev
);
1142 /* If there has been no change in the Lisp-level contents
1143 of the menu bar, skip redisplaying it. Just exit. */
1145 /* Compare the new menu items with the ones computed last time. */
1146 for (i
= 0; i
< previous_menu_items_used
; i
++)
1147 if (menu_items_used
== i
1148 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1150 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1152 /* The menu items have not changed. Don't bother updating
1153 the menus in any form, since it would be a no-op. */
1154 free_menubar_widget_value_tree (first_wv
);
1155 discard_menu_items ();
1156 unbind_to (specpdl_count
, Qnil
);
1160 /* The menu items are different, so store them in the frame. */
1161 f
->menu_bar_vector
= menu_items
;
1162 f
->menu_bar_items_used
= menu_items_used
;
1164 /* This undoes save_menu_items. */
1165 unbind_to (specpdl_count
, Qnil
);
1167 /* Now GC cannot happen during the lifetime of the widget_value,
1168 so it's safe to store data from a Lisp_String. */
1169 wv
= first_wv
->contents
;
1170 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1173 string
= XVECTOR (items
)->contents
[i
+ 1];
1176 wv
->name
= (char *) SDATA (string
);
1177 update_submenu_strings (wv
->contents
);
1184 /* Make a widget-value tree containing
1185 just the top level menu bar strings. */
1187 wv
= xmalloc_widget_value ();
1188 wv
->name
= "menubar";
1191 wv
->button_type
= BUTTON_TYPE_NONE
;
1195 items
= FRAME_MENU_BAR_ITEMS (f
);
1196 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1200 string
= XVECTOR (items
)->contents
[i
+ 1];
1204 wv
= xmalloc_widget_value ();
1205 wv
->name
= (char *) SDATA (string
);
1208 wv
->button_type
= BUTTON_TYPE_NONE
;
1210 /* This prevents lwlib from assuming this
1211 menu item is really supposed to be empty. */
1212 /* The EMACS_INT cast avoids a warning.
1213 This value just has to be different from small integers. */
1214 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1219 first_wv
->contents
= wv
;
1223 /* Forget what we thought we knew about what is in the
1224 detailed contents of the menu bar menus.
1225 Changing the top level always destroys the contents. */
1226 f
->menu_bar_items_used
= 0;
1229 /* Create or update the menu bar widget. */
1234 xg_crazy_callback_abort
= 1;
1237 /* The fourth arg is DEEP_P, which says to consider the entire
1238 menu trees we supply, rather than just the menu bar item names. */
1239 xg_modify_menubar_widgets (menubar_widget
,
1243 G_CALLBACK (menubar_selection_callback
),
1244 G_CALLBACK (popup_deactivate_callback
),
1245 G_CALLBACK (menu_highlight_callback
));
1249 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1252 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1253 G_CALLBACK (menubar_selection_callback
),
1254 G_CALLBACK (popup_deactivate_callback
),
1255 G_CALLBACK (menu_highlight_callback
));
1257 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1261 #else /* not USE_GTK */
1264 /* Disable resizing (done for Motif!) */
1265 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1267 /* The third arg is DEEP_P, which says to consider the entire
1268 menu trees we supply, rather than just the menu bar item names. */
1269 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1271 /* Re-enable the edit widget to resize. */
1272 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1276 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1277 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1279 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1280 f
->output_data
.x
->column_widget
,
1282 popup_activate_callback
,
1283 menubar_selection_callback
,
1284 popup_deactivate_callback
,
1285 menu_highlight_callback
);
1286 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1288 /* Make menu pop down on C-g. */
1289 XtOverrideTranslations (menubar_widget
, override
);
1291 apply_systemfont_to_menu (menubar_widget
);
1296 if (f
->output_data
.x
->menubar_widget
)
1297 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1300 = (f
->output_data
.x
->menubar_widget
1301 ? (f
->output_data
.x
->menubar_widget
->core
.height
1302 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1305 #if 1 /* Experimentally, we now get the right results
1306 for -geometry -0-0 without this. 24 Aug 96, rms.
1307 Maybe so, but the menu bar size is missing the pixels so the
1308 WM size hints are off by theses pixel. Jan D, oct 2009. */
1310 if (FRAME_EXTERNAL_MENU_BAR (f
))
1313 XtVaGetValues (f
->output_data
.x
->column_widget
,
1314 XtNinternalBorderWidth
, &ibw
, NULL
);
1315 menubar_size
+= ibw
;
1317 #endif /* USE_LUCID */
1320 f
->output_data
.x
->menubar_height
= menubar_size
;
1322 #endif /* not USE_GTK */
1324 free_menubar_widget_value_tree (first_wv
);
1325 update_frame_menubar (f
);
1328 xg_crazy_callback_abort
= 0;
1334 /* Called from Fx_create_frame to create the initial menubar of a frame
1335 before it is mapped, so that the window is mapped with the menubar already
1336 there instead of us tacking it on later and thrashing the window after it
1340 initialize_frame_menubar (FRAME_PTR f
)
1342 /* This function is called before the first chance to redisplay
1343 the frame. It has to be, so the frame will have the right size. */
1344 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1345 set_frame_menubar (f
, 1, 1);
1349 /* Get rid of the menu bar of frame F, and free its storage.
1350 This is used when deleting a frame, and when turning off the menu bar.
1351 For GTK this function is in gtkutil.c. */
1355 free_frame_menubar (f
)
1358 Widget menubar_widget
;
1360 if (! FRAME_X_P (f
))
1363 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1365 f
->output_data
.x
->menubar_height
= 0;
1370 /* Removing the menu bar magically changes the shell widget's x
1371 and y position of (0, 0) which, when the menu bar is turned
1372 on again, leads to pull-down menuss appearing in strange
1373 positions near the upper-left corner of the display. This
1374 happens only with some window managers like twm and ctwm,
1375 but not with other like Motif's mwm or kwm, because the
1376 latter generate ConfigureNotify events when the menu bar
1377 is switched off, which fixes the shell position. */
1378 Position x0
, y0
, x1
, y1
;
1384 if (f
->output_data
.x
->widget
)
1385 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1388 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1389 f
->output_data
.x
->menubar_widget
= NULL
;
1392 if (f
->output_data
.x
->widget
)
1394 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1395 if (x1
== 0 && y1
== 0)
1396 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1399 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1403 #endif /* not USE_GTK */
1405 #endif /* USE_X_TOOLKIT || USE_GTK */
1407 /* xmenu_show actually displays a menu using the panes and items in menu_items
1408 and returns the value selected from it.
1409 There are two versions of xmenu_show, one for Xt and one for Xlib.
1410 Both assume input is blocked by the caller. */
1412 /* F is the frame the menu is for.
1413 X and Y are the frame-relative specified position,
1414 relative to the inside upper left corner of the frame F.
1415 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1416 KEYMAPS is 1 if this menu was specified with keymaps;
1417 in that case, we return a list containing the chosen item's value
1418 and perhaps also the pane's prefix.
1419 TITLE is the specified menu title.
1420 ERROR is a place to store an error message string in case of failure.
1421 (We return nil on failure, but the value doesn't actually matter.) */
1423 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1425 /* The item selected in the popup menu. */
1426 static Lisp_Object
*volatile menu_item_selection
;
1430 /* Used when position a popup menu. See menu_position_func and
1431 create_and_show_popup_menu below. */
1432 struct next_popup_x_y
1439 /* The menu position function to use if we are not putting a popup
1440 menu where the pointer is.
1441 MENU is the menu to pop up.
1442 X and Y shall on exit contain x/y where the menu shall pop up.
1443 PUSH_IN is not documented in the GTK manual.
1444 USER_DATA is any data passed in when calling gtk_menu_popup.
1445 Here it points to a struct next_popup_x_y where the coordinates
1446 to store in *X and *Y are as well as the frame for the popup.
1448 Here only X and Y are used. */
1450 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1452 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1454 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1455 int disp_width
= x_display_pixel_width (dpyinfo
);
1456 int disp_height
= x_display_pixel_height (dpyinfo
);
1461 /* Check if there is room for the menu. If not, adjust x/y so that
1462 the menu is fully visible. */
1463 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1464 if (data
->x
+ req
.width
> disp_width
)
1465 *x
-= data
->x
+ req
.width
- disp_width
;
1466 if (data
->y
+ req
.height
> disp_height
)
1467 *y
-= data
->y
+ req
.height
- disp_height
;
1471 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1473 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1475 if (xg_crazy_callback_abort
) return;
1476 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1480 pop_down_menu (Lisp_Object arg
)
1482 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1484 popup_activated_flag
= 0;
1486 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1491 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1493 menu_item_selection will be set to the selection. */
1495 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1499 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1500 struct next_popup_x_y popup_x_y
;
1501 int specpdl_count
= SPECPDL_INDEX ();
1503 if (! FRAME_X_P (f
))
1506 xg_crazy_callback_abort
= 1;
1507 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1508 G_CALLBACK (popup_selection_callback
),
1509 G_CALLBACK (popup_deactivate_callback
),
1510 G_CALLBACK (menu_highlight_callback
));
1511 xg_crazy_callback_abort
= 0;
1515 /* Not invoked by a click. pop up at x/y. */
1516 pos_func
= menu_position_func
;
1518 /* Adjust coordinates to be root-window-relative. */
1519 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1520 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1526 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1530 for (i
= 0; i
< 5; i
++)
1531 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1535 /* Display the menu. */
1536 gtk_widget_show_all (menu
);
1538 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1539 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1541 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1543 if (gtk_widget_get_mapped (menu
))
1545 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1546 two. show_help_echo uses this to detect popup menus. */
1547 popup_activated_flag
= 1;
1548 /* Process events that apply to the menu. */
1549 popup_widget_loop (1, menu
);
1552 unbind_to (specpdl_count
, Qnil
);
1554 /* Must reset this manually because the button release event is not passed
1555 to Emacs event loop. */
1556 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1559 #else /* not USE_GTK */
1561 /* We need a unique id for each widget handled by the Lucid Widget
1564 For the main windows, and popup menus, we use this counter,
1565 which we increment each time after use. This starts from 1<<16.
1567 For menu bars, we use numbers starting at 0, counted in
1568 next_menubar_widget_id. */
1569 LWLIB_ID widget_id_tick
;
1572 popup_selection_callback (widget
, id
, client_data
)
1575 XtPointer client_data
;
1577 menu_item_selection
= (Lisp_Object
*) client_data
;
1580 /* ARG is the LWLIB ID of the dialog box, represented
1581 as a Lisp object as (HIGHPART . LOWPART). */
1587 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1588 | XINT (XCDR (arg
)));
1591 lw_destroy_all_widgets (id
);
1593 popup_activated_flag
= 0;
1598 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1600 menu_item_selection will be set to the selection. */
1602 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
)
1604 widget_value
*first_wv
;
1608 EMACS_UINT timestamp
;
1613 XButtonPressedEvent dummy
;
1617 if (! FRAME_X_P (f
))
1620 menu_id
= widget_id_tick
++;
1621 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1622 f
->output_data
.x
->widget
, 1, 0,
1623 popup_selection_callback
,
1624 popup_deactivate_callback
,
1625 menu_highlight_callback
);
1628 apply_systemfont_to_menu (menu
);
1631 dummy
.type
= ButtonPress
;
1633 dummy
.send_event
= 0;
1634 dummy
.display
= FRAME_X_DISPLAY (f
);
1635 dummy
.time
= CurrentTime
;
1636 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1637 dummy
.window
= dummy
.root
;
1638 dummy
.subwindow
= dummy
.root
;
1642 /* Adjust coordinates to be root-window-relative. */
1643 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1644 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1651 for (i
= 0; i
< 5; i
++)
1652 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1655 /* Don't allow any geometry request from the user. */
1656 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1657 XtSetValues (menu
, av
, ac
);
1659 /* Display the menu. */
1660 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1661 popup_activated_flag
= 1;
1662 x_activate_timeout_atimer ();
1665 int fact
= 4 * sizeof (LWLIB_ID
);
1666 int specpdl_count
= SPECPDL_INDEX ();
1667 record_unwind_protect (pop_down_menu
,
1668 Fcons (make_number (menu_id
>> (fact
)),
1669 make_number (menu_id
& ~(-1 << (fact
)))));
1671 /* Process events that apply to the menu. */
1672 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1674 unbind_to (specpdl_count
, Qnil
);
1678 #endif /* not USE_GTK */
1681 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1682 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1685 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1686 widget_value
**submenu_stack
1687 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1688 Lisp_Object
*subprefix_stack
1689 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1690 int submenu_depth
= 0;
1694 if (! FRAME_X_P (f
))
1699 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1701 *error
= "Empty menu";
1705 /* Create a tree of widget_value objects
1706 representing the panes and their items. */
1707 wv
= xmalloc_widget_value ();
1711 wv
->button_type
= BUTTON_TYPE_NONE
;
1716 /* Loop over all panes and items, filling in the tree. */
1718 while (i
< menu_items_used
)
1720 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1722 submenu_stack
[submenu_depth
++] = save_wv
;
1728 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1731 save_wv
= submenu_stack
[--submenu_depth
];
1735 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1736 && submenu_depth
!= 0)
1737 i
+= MENU_ITEMS_PANE_LENGTH
;
1738 /* Ignore a nil in the item list.
1739 It's meaningful only for dialog boxes. */
1740 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1742 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1744 /* Create a new pane. */
1745 Lisp_Object pane_name
, prefix
;
1748 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1749 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1751 #ifndef HAVE_MULTILINGUAL_MENU
1752 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1754 pane_name
= ENCODE_MENU_STRING (pane_name
);
1755 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1758 pane_string
= (NILP (pane_name
)
1759 ? "" : (char *) SDATA (pane_name
));
1760 /* If there is just one top-level pane, put all its items directly
1761 under the top-level menu. */
1762 if (menu_items_n_panes
== 1)
1765 /* If the pane has a meaningful name,
1766 make the pane a top-level menu item
1767 with its items as a submenu beneath it. */
1768 if (!keymaps
&& strcmp (pane_string
, ""))
1770 wv
= xmalloc_widget_value ();
1774 first_wv
->contents
= wv
;
1775 wv
->name
= pane_string
;
1776 if (keymaps
&& !NILP (prefix
))
1780 wv
->button_type
= BUTTON_TYPE_NONE
;
1785 else if (first_pane
)
1791 i
+= MENU_ITEMS_PANE_LENGTH
;
1795 /* Create a new item within current pane. */
1796 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1797 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1798 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1799 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1800 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1801 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1802 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1803 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1805 #ifndef HAVE_MULTILINGUAL_MENU
1806 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1808 item_name
= ENCODE_MENU_STRING (item_name
);
1809 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1812 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1814 descrip
= ENCODE_MENU_STRING (descrip
);
1815 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1817 #endif /* not HAVE_MULTILINGUAL_MENU */
1819 wv
= xmalloc_widget_value ();
1823 save_wv
->contents
= wv
;
1824 wv
->name
= (char *) SDATA (item_name
);
1825 if (!NILP (descrip
))
1826 wv
->key
= (char *) SDATA (descrip
);
1828 /* If this item has a null value,
1829 make the call_data null so that it won't display a box
1830 when the mouse is on it. */
1832 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1833 wv
->enabled
= !NILP (enable
);
1836 wv
->button_type
= BUTTON_TYPE_NONE
;
1837 else if (EQ (type
, QCtoggle
))
1838 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1839 else if (EQ (type
, QCradio
))
1840 wv
->button_type
= BUTTON_TYPE_RADIO
;
1844 wv
->selected
= !NILP (selected
);
1846 if (! STRINGP (help
))
1853 i
+= MENU_ITEMS_ITEM_LENGTH
;
1857 /* Deal with the title, if it is non-nil. */
1860 widget_value
*wv_title
= xmalloc_widget_value ();
1861 widget_value
*wv_sep1
= xmalloc_widget_value ();
1862 widget_value
*wv_sep2
= xmalloc_widget_value ();
1864 wv_sep2
->name
= "--";
1865 wv_sep2
->next
= first_wv
->contents
;
1866 wv_sep2
->help
= Qnil
;
1868 wv_sep1
->name
= "--";
1869 wv_sep1
->next
= wv_sep2
;
1870 wv_sep1
->help
= Qnil
;
1872 #ifndef HAVE_MULTILINGUAL_MENU
1873 if (STRING_MULTIBYTE (title
))
1874 title
= ENCODE_MENU_STRING (title
);
1877 wv_title
->name
= (char *) SDATA (title
);
1878 wv_title
->enabled
= TRUE
;
1879 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1880 wv_title
->help
= Qnil
;
1881 wv_title
->next
= wv_sep1
;
1882 first_wv
->contents
= wv_title
;
1885 /* No selection has been chosen yet. */
1886 menu_item_selection
= 0;
1888 /* Actually create and show the menu until popped down. */
1889 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1891 /* Free the widget_value objects we used to specify the contents. */
1892 free_menubar_widget_value_tree (first_wv
);
1894 /* Find the selected item, and its pane, to return
1895 the proper value. */
1896 if (menu_item_selection
!= 0)
1898 Lisp_Object prefix
, entry
;
1900 prefix
= entry
= Qnil
;
1902 while (i
< menu_items_used
)
1904 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1906 subprefix_stack
[submenu_depth
++] = prefix
;
1910 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1912 prefix
= subprefix_stack
[--submenu_depth
];
1915 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1918 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1919 i
+= MENU_ITEMS_PANE_LENGTH
;
1921 /* Ignore a nil in the item list.
1922 It's meaningful only for dialog boxes. */
1923 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1928 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1929 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1935 entry
= Fcons (entry
, Qnil
);
1937 entry
= Fcons (prefix
, entry
);
1938 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1939 if (!NILP (subprefix_stack
[j
]))
1940 entry
= Fcons (subprefix_stack
[j
], entry
);
1944 i
+= MENU_ITEMS_ITEM_LENGTH
;
1948 else if (!for_click
)
1949 /* Make "Cancel" equivalent to C-g. */
1950 Fsignal (Qquit
, Qnil
);
1957 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1959 /* The EMACS_INT cast avoids a warning. There's no problem
1960 as long as pointers have enough bits to hold small integers. */
1961 if ((int) (EMACS_INT
) client_data
!= -1)
1962 menu_item_selection
= (Lisp_Object
*) client_data
;
1964 popup_activated_flag
= 0;
1967 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1969 menu_item_selection will be set to the selection. */
1971 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1975 if (! FRAME_X_P (f
))
1978 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1979 G_CALLBACK (dialog_selection_callback
),
1980 G_CALLBACK (popup_deactivate_callback
),
1985 int specpdl_count
= SPECPDL_INDEX ();
1986 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1988 /* Display the menu. */
1989 gtk_widget_show_all (menu
);
1991 /* Process events that apply to the menu. */
1992 popup_widget_loop (1, menu
);
1994 unbind_to (specpdl_count
, Qnil
);
1998 #else /* not USE_GTK */
2000 dialog_selection_callback (widget
, id
, client_data
)
2003 XtPointer client_data
;
2005 /* The EMACS_INT cast avoids a warning. There's no problem
2006 as long as pointers have enough bits to hold small integers. */
2007 if ((int) (EMACS_INT
) client_data
!= -1)
2008 menu_item_selection
= (Lisp_Object
*) client_data
;
2011 lw_destroy_all_widgets (id
);
2013 popup_activated_flag
= 0;
2017 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2019 menu_item_selection will be set to the selection. */
2021 create_and_show_dialog (f
, first_wv
)
2023 widget_value
*first_wv
;
2030 dialog_id
= widget_id_tick
++;
2032 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
2034 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
2035 f
->output_data
.x
->widget
, 1, 0,
2036 dialog_selection_callback
, 0, 0);
2037 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
2038 /* Display the dialog box. */
2039 lw_pop_up_all_widgets (dialog_id
);
2040 popup_activated_flag
= 1;
2041 x_activate_timeout_atimer ();
2043 /* Process events that apply to the dialog box.
2044 Also handle timers. */
2046 int count
= SPECPDL_INDEX ();
2047 int fact
= 4 * sizeof (LWLIB_ID
);
2049 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2050 record_unwind_protect (pop_down_menu
,
2051 Fcons (make_number (dialog_id
>> (fact
)),
2052 make_number (dialog_id
& ~(-1 << (fact
)))));
2054 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2057 unbind_to (count
, Qnil
);
2061 #endif /* not USE_GTK */
2063 static char * button_names
[] = {
2064 "button1", "button2", "button3", "button4", "button5",
2065 "button6", "button7", "button8", "button9", "button10" };
2068 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2070 int i
, nb_buttons
=0;
2071 char dialog_name
[6];
2073 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2075 /* Number of elements seen so far, before boundary. */
2077 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2078 int boundary_seen
= 0;
2080 if (! FRAME_X_P (f
))
2085 if (menu_items_n_panes
> 1)
2087 *error_name
= "Multiple panes in dialog box";
2091 /* Create a tree of widget_value objects
2092 representing the text label and buttons. */
2094 Lisp_Object pane_name
, prefix
;
2096 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2097 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2098 pane_string
= (NILP (pane_name
)
2099 ? "" : (char *) SDATA (pane_name
));
2100 prev_wv
= xmalloc_widget_value ();
2101 prev_wv
->value
= pane_string
;
2102 if (keymaps
&& !NILP (prefix
))
2104 prev_wv
->enabled
= 1;
2105 prev_wv
->name
= "message";
2106 prev_wv
->help
= Qnil
;
2109 /* Loop over all panes and items, filling in the tree. */
2110 i
= MENU_ITEMS_PANE_LENGTH
;
2111 while (i
< menu_items_used
)
2114 /* Create a new item within current pane. */
2115 Lisp_Object item_name
, enable
, descrip
;
2116 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2117 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2119 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2121 if (NILP (item_name
))
2123 free_menubar_widget_value_tree (first_wv
);
2124 *error_name
= "Submenu in dialog items";
2127 if (EQ (item_name
, Qquote
))
2129 /* This is the boundary between left-side elts
2130 and right-side elts. Stop incrementing right_count. */
2135 if (nb_buttons
>= 9)
2137 free_menubar_widget_value_tree (first_wv
);
2138 *error_name
= "Too many dialog items";
2142 wv
= xmalloc_widget_value ();
2144 wv
->name
= (char *) button_names
[nb_buttons
];
2145 if (!NILP (descrip
))
2146 wv
->key
= (char *) SDATA (descrip
);
2147 wv
->value
= (char *) SDATA (item_name
);
2148 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2149 wv
->enabled
= !NILP (enable
);
2153 if (! boundary_seen
)
2157 i
+= MENU_ITEMS_ITEM_LENGTH
;
2160 /* If the boundary was not specified,
2161 by default put half on the left and half on the right. */
2162 if (! boundary_seen
)
2163 left_count
= nb_buttons
- nb_buttons
/ 2;
2165 wv
= xmalloc_widget_value ();
2166 wv
->name
= dialog_name
;
2169 /* Frame title: 'Q' = Question, 'I' = Information.
2170 Can also have 'E' = Error if, one day, we want
2171 a popup for errors. */
2173 dialog_name
[0] = 'Q';
2175 dialog_name
[0] = 'I';
2177 /* Dialog boxes use a really stupid name encoding
2178 which specifies how many buttons to use
2179 and how many buttons are on the right. */
2180 dialog_name
[1] = '0' + nb_buttons
;
2181 dialog_name
[2] = 'B';
2182 dialog_name
[3] = 'R';
2183 /* Number of buttons to put on the right. */
2184 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2186 wv
->contents
= first_wv
;
2190 /* No selection has been chosen yet. */
2191 menu_item_selection
= 0;
2193 /* Actually create and show the dialog. */
2194 create_and_show_dialog (f
, first_wv
);
2196 /* Free the widget_value objects we used to specify the contents. */
2197 free_menubar_widget_value_tree (first_wv
);
2199 /* Find the selected item, and its pane, to return
2200 the proper value. */
2201 if (menu_item_selection
!= 0)
2207 while (i
< menu_items_used
)
2211 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2214 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2215 i
+= MENU_ITEMS_PANE_LENGTH
;
2217 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2219 /* This is the boundary between left-side elts and
2226 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2227 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2231 entry
= Fcons (entry
, Qnil
);
2233 entry
= Fcons (prefix
, entry
);
2237 i
+= MENU_ITEMS_ITEM_LENGTH
;
2242 /* Make "Cancel" equivalent to C-g. */
2243 Fsignal (Qquit
, Qnil
);
2248 #else /* not USE_X_TOOLKIT && not USE_GTK */
2250 /* The frame of the last activated non-toolkit menu bar.
2251 Used to generate menu help events. */
2253 static struct frame
*menu_help_frame
;
2256 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2258 PANE is the pane number, and ITEM is the menu item number in
2259 the menu (currently not used).
2261 This cannot be done with generating a HELP_EVENT because
2262 XMenuActivate contains a loop that doesn't let Emacs process
2266 menu_help_callback (help_string
, pane
, item
)
2270 extern Lisp_Object Qmenu_item
;
2271 Lisp_Object
*first_item
;
2272 Lisp_Object pane_name
;
2273 Lisp_Object menu_object
;
2275 first_item
= XVECTOR (menu_items
)->contents
;
2276 if (EQ (first_item
[0], Qt
))
2277 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2278 else if (EQ (first_item
[0], Qquote
))
2279 /* This shouldn't happen, see xmenu_show. */
2280 pane_name
= empty_unibyte_string
;
2282 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2284 /* (menu-item MENU-NAME PANE-NUMBER) */
2285 menu_object
= Fcons (Qmenu_item
,
2287 Fcons (make_number (pane
), Qnil
)));
2288 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2289 Qnil
, menu_object
, make_number (item
), 1);
2296 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2297 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2299 FRAME_PTR f
= p1
->pointer
;
2300 XMenu
*menu
= p2
->pointer
;
2304 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2305 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2307 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2309 #ifdef HAVE_X_WINDOWS
2310 /* Assume the mouse has moved out of the X window.
2311 If it has actually moved in, we will get an EnterNotify. */
2312 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2314 /* State that no mouse buttons are now held.
2315 (The oldXMenu code doesn't track this info for us.)
2316 That is not necessarily true, but the fiction leads to reasonable
2317 results, and it is a pain to ask which are actually held now. */
2318 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2320 #endif /* HAVE_X_WINDOWS */
2329 xmenu_show (f
, x
, y
, for_click
, keymaps
, title
, error
, timestamp
)
2336 EMACS_UINT timestamp
;
2340 int pane
, selidx
, lpane
, status
;
2341 Lisp_Object entry
, pane_prefix
;
2343 int ulx
, uly
, width
, height
;
2344 int dispwidth
, dispheight
;
2345 int i
, j
, lines
, maxlines
;
2348 unsigned int dummy_uint
;
2349 int specpdl_count
= SPECPDL_INDEX ();
2351 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2355 if (menu_items_n_panes
== 0)
2358 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2360 *error
= "Empty menu";
2364 /* Figure out which root window F is on. */
2365 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2366 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2367 &dummy_uint
, &dummy_uint
);
2369 /* Make the menu on that window. */
2370 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2373 *error
= "Can't create menu";
2377 /* Don't GC while we prepare and show the menu,
2378 because we give the oldxmenu library pointers to the
2379 contents of strings. */
2380 inhibit_garbage_collection ();
2382 #ifdef HAVE_X_WINDOWS
2383 /* Adjust coordinates to relative to the outer (window manager) window. */
2384 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2385 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2386 #endif /* HAVE_X_WINDOWS */
2388 /* Adjust coordinates to be root-window-relative. */
2392 /* Create all the necessary panes and their items. */
2393 maxlines
= lines
= i
= 0;
2394 while (i
< menu_items_used
)
2396 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2398 /* Create a new pane. */
2399 Lisp_Object pane_name
, prefix
;
2402 maxlines
= max (maxlines
, lines
);
2404 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2405 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2406 pane_string
= (NILP (pane_name
)
2407 ? "" : (char *) SDATA (pane_name
));
2408 if (keymaps
&& !NILP (prefix
))
2411 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2412 if (lpane
== XM_FAILURE
)
2414 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2415 *error
= "Can't create pane";
2418 i
+= MENU_ITEMS_PANE_LENGTH
;
2420 /* Find the width of the widest item in this pane. */
2423 while (j
< menu_items_used
)
2426 item
= XVECTOR (menu_items
)->contents
[j
];
2434 width
= SBYTES (item
);
2435 if (width
> maxwidth
)
2438 j
+= MENU_ITEMS_ITEM_LENGTH
;
2441 /* Ignore a nil in the item list.
2442 It's meaningful only for dialog boxes. */
2443 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2447 /* Create a new item within current pane. */
2448 Lisp_Object item_name
, enable
, descrip
, help
;
2449 unsigned char *item_data
;
2452 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2453 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2455 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2456 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2457 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2459 if (!NILP (descrip
))
2461 int gap
= maxwidth
- SBYTES (item_name
);
2462 /* if alloca is fast, use that to make the space,
2463 to reduce gc needs. */
2465 = (unsigned char *) alloca (maxwidth
2466 + SBYTES (descrip
) + 1);
2467 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2468 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2470 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2471 item_data
[j
+ SBYTES (descrip
)] = 0;
2474 item_data
= SDATA (item_name
);
2476 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2477 menu
, lpane
, 0, item_data
,
2478 !NILP (enable
), help_string
)
2481 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2482 *error
= "Can't add selection to menu";
2485 i
+= MENU_ITEMS_ITEM_LENGTH
;
2490 maxlines
= max (maxlines
, lines
);
2492 /* All set and ready to fly. */
2493 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2494 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2495 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2496 x
= min (x
, dispwidth
);
2497 y
= min (y
, dispheight
);
2500 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2501 &ulx
, &uly
, &width
, &height
);
2502 if (ulx
+width
> dispwidth
)
2504 x
-= (ulx
+ width
) - dispwidth
;
2505 ulx
= dispwidth
- width
;
2507 if (uly
+height
> dispheight
)
2509 y
-= (uly
+ height
) - dispheight
;
2510 uly
= dispheight
- height
;
2512 #ifndef HAVE_X_WINDOWS
2513 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2515 /* Move the menu away of the echo area, to avoid overwriting the
2516 menu with help echo messages or vice versa. */
2517 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2519 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2520 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2529 if (ulx
< 0) x
-= ulx
;
2530 if (uly
< 0) y
-= uly
;
2534 /* If position was not given by a mouse click, adjust so upper left
2535 corner of the menu as a whole ends up at given coordinates. This
2536 is what x-popup-menu says in its documentation. */
2538 y
+= 1.5*height
/(maxlines
+2);
2541 XMenuSetAEQ (menu
, TRUE
);
2542 XMenuSetFreeze (menu
, TRUE
);
2546 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2549 record_unwind_protect (pop_down_menu
,
2550 Fcons (make_save_value (f
, 0),
2551 make_save_value (menu
, 0)));
2553 /* Help display under X won't work because XMenuActivate contains
2554 a loop that doesn't give Emacs a chance to process it. */
2555 menu_help_frame
= f
;
2556 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2557 x
, y
, ButtonReleaseMask
, &datap
,
2558 menu_help_callback
);
2564 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2567 /* Find the item number SELIDX in pane number PANE. */
2569 while (i
< menu_items_used
)
2571 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2575 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2577 i
+= MENU_ITEMS_PANE_LENGTH
;
2586 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2589 entry
= Fcons (entry
, Qnil
);
2590 if (!NILP (pane_prefix
))
2591 entry
= Fcons (pane_prefix
, entry
);
2597 i
+= MENU_ITEMS_ITEM_LENGTH
;
2603 *error
= "Can't activate menu";
2608 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2609 the menu was invoked with a mouse event as POSITION). */
2611 Fsignal (Qquit
, Qnil
);
2616 unbind_to (specpdl_count
, Qnil
);
2621 #endif /* not USE_X_TOOLKIT */
2623 #endif /* HAVE_MENUS */
2625 /* Detect if a dialog or menu has been posted. */
2628 popup_activated (void)
2630 return popup_activated_flag
;
2633 /* The following is used by delayed window autoselection. */
2635 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2636 doc
: /* Return t if a menu or popup dialog is active. */)
2640 return (popup_activated ()) ? Qt
: Qnil
;
2643 #endif /* HAVE_MENUS */
2647 syms_of_xmenu (void)
2649 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2650 staticpro (&Qdebug_on_next_call
);
2652 #ifdef USE_X_TOOLKIT
2653 widget_id_tick
= (1<<16);
2654 next_menubar_widget_id
= 1;
2657 defsubr (&Smenu_or_popup_active_p
);
2659 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2660 defsubr (&Sx_menu_bar_open_internal
);
2661 Ffset (intern_c_string ("accelerate-menu"),
2662 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2666 defsubr (&Sx_popup_dialog
);
2670 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2671 (do not change this comment) */