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 #else /* not USE_X_TOOLKIT */
94 #include "../oldXMenu/XMenu.h"
96 #endif /* not USE_X_TOOLKIT */
97 #endif /* HAVE_X_WINDOWS */
110 Lisp_Object Qdebug_on_next_call
;
112 extern Lisp_Object Qmenu_bar
;
114 extern Lisp_Object QCtoggle
, QCradio
;
116 extern Lisp_Object Voverriding_local_map
;
117 extern Lisp_Object Voverriding_local_map_menu_flag
;
119 extern Lisp_Object Qoverriding_local_map
, Qoverriding_terminal_local_map
;
121 extern Lisp_Object Qmenu_bar_update_hook
;
124 extern void set_frame_menubar (FRAME_PTR
, int, int);
125 extern XtAppContext Xt_app_con
;
127 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
129 static void popup_get_selection (XEvent
*, struct x_display_info
*,
131 #endif /* USE_X_TOOLKIT */
134 extern void set_frame_menubar (FRAME_PTR
, int, int);
135 static Lisp_Object
xdialog_show (FRAME_PTR
, int, Lisp_Object
, Lisp_Object
,
139 static int update_frame_menubar (struct frame
*);
141 /* Flag which when set indicates a dialog or menu has been posted by
142 Xt on behalf of one of the widget sets. */
143 static int popup_activated_flag
;
145 static int next_menubar_widget_id
;
147 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
148 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
149 extern widget_value
*xmalloc_widget_value (void);
150 extern widget_value
*digest_single_submenu (int, int, int);
156 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
158 static struct frame
*
159 menubar_id_to_frame (LWLIB_ID id
)
161 Lisp_Object tail
, frame
;
164 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
170 if (!FRAME_WINDOW_P (f
))
172 if (f
->output_data
.x
->id
== id
)
180 #ifdef HAVE_X_WINDOWS
181 /* Return the mouse position in *X and *Y. The coordinates are window
182 relative for the edit window in frame F.
183 This is for Fx_popup_menu. The mouse_position_hook can not
184 be used for X, as it returns window relative coordinates
185 for the window where the mouse is in. This could be the menu bar,
186 the scroll bar or the edit window. Fx_popup_menu needs to be
187 sure it is the edit window. */
189 mouse_position_for_popup (FRAME_PTR f
, int *x
, int *y
)
191 Window root
, dummy_window
;
199 XQueryPointer (FRAME_X_DISPLAY (f
),
200 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
202 /* The root window which contains the pointer. */
205 /* Window pointer is on, not used */
208 /* The position on that root window. */
211 /* x/y in dummy_window coordinates, not used. */
214 /* Modifier keys and pointer buttons, about which
216 (unsigned int *) &dummy
);
220 /* xmenu_show expects window coordinates, not root window
221 coordinates. Translate. */
222 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
223 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
226 #endif /* HAVE_X_WINDOWS */
230 DEFUN ("x-popup-dialog", Fx_popup_dialog
, Sx_popup_dialog
, 2, 3, 0,
231 doc
: /* Pop up a dialog box and return user's selection.
232 POSITION specifies which frame to use.
233 This is normally a mouse button event or a window or frame.
234 If POSITION is t, it means to use the frame the mouse is on.
235 The dialog box appears in the middle of the specified frame.
237 CONTENTS specifies the alternatives to display in the dialog box.
238 It is a list of the form (DIALOG ITEM1 ITEM2...).
239 Each ITEM is a cons cell (STRING . VALUE).
240 The return value is VALUE from the chosen item.
242 An ITEM may also be just a string--that makes a nonselectable item.
243 An ITEM may also be nil--that means to put all preceding items
244 on the left of the dialog box and all following items on the right.
245 \(By default, approximately half appear on each side.)
247 If HEADER is non-nil, the frame title for the box is "Information",
248 otherwise it is "Question".
250 If the user gets rid of the dialog box without making a valid choice,
251 for instance using the window manager, then this produces a quit and
252 `x-popup-dialog' does not return. */)
253 (Lisp_Object position
, Lisp_Object contents
, Lisp_Object header
)
260 /* Decode the first argument: find the window or frame to use. */
261 if (EQ (position
, Qt
)
262 || (CONSP (position
) && (EQ (XCAR (position
), Qmenu_bar
)
263 || EQ (XCAR (position
), Qtool_bar
))))
265 #if 0 /* Using the frame the mouse is on may not be right. */
266 /* Use the mouse's current position. */
267 FRAME_PTR new_f
= SELECTED_FRAME ();
268 Lisp_Object bar_window
;
269 enum scroll_bar_part part
;
273 (*mouse_position_hook
) (&new_f
, 1, &bar_window
, &part
, &x
, &y
, &time
);
276 XSETFRAME (window
, new_f
);
278 window
= selected_window
;
280 window
= selected_window
;
282 else if (CONSP (position
))
285 tem
= Fcar (position
);
287 window
= Fcar (Fcdr (position
));
290 tem
= Fcar (Fcdr (position
)); /* EVENT_START (position) */
291 window
= Fcar (tem
); /* POSN_WINDOW (tem) */
294 else if (WINDOWP (position
) || FRAMEP (position
))
299 /* Decode where to put the menu. */
303 else if (WINDOWP (window
))
305 CHECK_LIVE_WINDOW (window
);
306 f
= XFRAME (WINDOW_FRAME (XWINDOW (window
)));
309 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
310 but I don't want to make one now. */
311 CHECK_WINDOW (window
);
313 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
314 error ("Can not put X dialog on this terminal");
316 /* Force a redisplay before showing the dialog. If a frame is created
317 just before showing the dialog, its contents may not have been fully
318 drawn, as this depends on timing of events from the X server. Redisplay
319 is not done when a dialog is shown. If redisplay could be done in the
320 X event loop (i.e. the X event loop does not run in a signal handler)
321 this would not be needed.
323 Do this before creating the widget value that points to Lisp
324 string contents, because Fredisplay may GC and relocate them. */
327 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
328 /* Display a menu with these alternatives
329 in the middle of frame F. */
331 Lisp_Object x
, y
, frame
, newpos
;
332 XSETFRAME (frame
, f
);
333 XSETINT (x
, x_pixel_width (f
) / 2);
334 XSETINT (y
, x_pixel_height (f
) / 2);
335 newpos
= Fcons (Fcons (x
, Fcons (y
, Qnil
)), Fcons (frame
, Qnil
));
337 return Fx_popup_menu (newpos
,
338 Fcons (Fcar (contents
), Fcons (contents
, Qnil
)));
344 Lisp_Object selection
;
345 int specpdl_count
= SPECPDL_INDEX ();
347 /* Decode the dialog items from what was specified. */
348 title
= Fcar (contents
);
349 CHECK_STRING (title
);
350 record_unwind_protect (unuse_menu_items
, Qnil
);
352 if (NILP (Fcar (Fcdr (contents
))))
353 /* No buttons specified, add an "Ok" button so users can pop down
354 the dialog. Also, the lesstif/motif version crashes if there are
356 contents
= Fcons (title
, Fcons (Fcons (build_string ("Ok"), Qt
), Qnil
));
358 list_of_panes (Fcons (contents
, Qnil
));
360 /* Display them in a dialog box. */
362 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
365 unbind_to (specpdl_count
, Qnil
);
366 discard_menu_items ();
368 if (error_name
) error (error_name
);
377 /* Set menu_items_inuse so no other popup menu or dialog is created. */
380 x_menu_set_in_use (int in_use
)
382 menu_items_inuse
= in_use
? Qt
: Qnil
;
383 popup_activated_flag
= in_use
;
385 if (popup_activated_flag
)
386 x_activate_timeout_atimer ();
390 /* Wait for an X event to arrive or for a timer to expire. */
393 x_menu_wait_for_event (void *data
)
395 /* Another way to do this is to register a timer callback, that can be
396 done in GTK and Xt. But we have to do it like this when using only X
397 anyway, and with callbacks we would have three variants for timer handling
398 instead of the small ifdefs below. */
402 ! XtAppPending (Xt_app_con
)
403 #elif defined USE_GTK
404 ! gtk_events_pending ()
406 ! XPending ((Display
*) data
)
410 EMACS_TIME next_time
= timer_check (1), *ntp
;
411 long secs
= EMACS_SECS (next_time
);
412 long usecs
= EMACS_USECS (next_time
);
413 SELECT_TYPE read_fds
;
414 struct x_display_info
*dpyinfo
;
418 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
420 int fd
= ConnectionNumber (dpyinfo
->display
);
421 FD_SET (fd
, &read_fds
);
423 XFlush (dpyinfo
->display
);
426 if (secs
< 0 && usecs
< 0)
431 select (n
+ 1, &read_fds
, (SELECT_TYPE
*)0, (SELECT_TYPE
*)0, ntp
);
437 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
441 /* Loop in Xt until the menu pulldown or dialog popup has been
442 popped down (deactivated). This is used for x-popup-menu
443 and x-popup-dialog; it is not used for the menu bar.
445 NOTE: All calls to popup_get_selection should be protected
446 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
449 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
453 while (popup_activated_flag
)
457 event
= *initial_event
;
462 if (do_timers
) x_menu_wait_for_event (0);
463 XtAppNextEvent (Xt_app_con
, &event
);
466 /* Make sure we don't consider buttons grabbed after menu goes.
467 And make sure to deactivate for any ButtonRelease,
468 even if XtDispatchEvent doesn't do that. */
469 if (event
.type
== ButtonRelease
470 && dpyinfo
->display
== event
.xbutton
.display
)
472 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
473 #ifdef USE_MOTIF /* Pretending that the event came from a
474 Btn1Down seems the only way to convince Motif to
475 activate its callbacks; setting the XmNmenuPost
476 isn't working. --marcus@sysc.pdx.edu. */
477 event
.xbutton
.button
= 1;
478 /* Motif only pops down menus when no Ctrl, Alt or Mod
479 key is pressed and the button is released. So reset key state
480 so Motif thinks this is the case. */
481 event
.xbutton
.state
= 0;
484 /* Pop down on C-g and Escape. */
485 else if (event
.type
== KeyPress
486 && dpyinfo
->display
== event
.xbutton
.display
)
488 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
490 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
491 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
492 popup_activated_flag
= 0;
495 x_dispatch_event (&event
, event
.xany
.display
);
499 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
500 doc
: /* Start key navigation of the menu bar in FRAME.
501 This initially opens the first menu bar item and you can then navigate with the
502 arrow keys, select a menu entry with the return key or cancel with the
503 escape key. If FRAME has no menu bar this function does nothing.
505 If FRAME is nil or not given, use the selected frame. */)
509 FRAME_PTR f
= check_x_frame (frame
);
513 if (FRAME_EXTERNAL_MENU_BAR (f
))
514 set_frame_menubar (f
, 0, 1);
516 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
522 x_catch_errors (FRAME_X_DISPLAY (f
));
523 memset (&ev
, 0, sizeof ev
);
524 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
525 ev
.xbutton
.window
= XtWindow (menubar
);
526 ev
.xbutton
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
527 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
528 ev
.xbutton
.button
= Button1
;
529 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
530 ev
.xbutton
.same_screen
= True
;
537 XtSetArg (al
[0], XtNchildren
, &list
);
538 XtSetArg (al
[1], XtNnumChildren
, &nr
);
539 XtGetValues (menubar
, al
, 2);
540 ev
.xbutton
.window
= XtWindow (list
[0]);
544 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
545 /* From-window, to-window. */
546 ev
.xbutton
.window
, ev
.xbutton
.root
,
548 /* From-position, to-position. */
549 ev
.xbutton
.x
, ev
.xbutton
.y
,
550 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
554 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
559 ev
.type
= ButtonPress
;
560 ev
.xbutton
.state
= 0;
562 XtDispatchEvent (&ev
);
563 ev
.xbutton
.type
= ButtonRelease
;
564 ev
.xbutton
.state
= Button1Mask
;
565 XtDispatchEvent (&ev
);
573 #endif /* USE_X_TOOLKIT */
577 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
578 doc
: /* Start key navigation of the menu bar in FRAME.
579 This initially opens the first menu bar item and you can then navigate with the
580 arrow keys, select a menu entry with the return key or cancel with the
581 escape key. If FRAME has no menu bar this function does nothing.
583 If FRAME is nil or not given, use the selected frame. */)
589 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
593 f
= check_x_frame (frame
);
595 if (FRAME_EXTERNAL_MENU_BAR (f
))
596 set_frame_menubar (f
, 0, 1);
598 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
601 /* Activate the first menu. */
602 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
606 g_signal_emit_by_name (children
->data
, "activate_item");
607 popup_activated_flag
= 1;
608 g_list_free (children
);
616 /* Loop util popup_activated_flag is set to zero in a callback.
617 Used for popup menus and dialogs. */
620 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
622 ++popup_activated_flag
;
624 /* Process events in the Gtk event loop until done. */
625 while (popup_activated_flag
)
627 if (do_timers
) x_menu_wait_for_event (0);
628 gtk_main_iteration ();
633 /* Activate the menu bar of frame F.
634 This is called from keyboard.c when it gets the
635 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
637 To activate the menu bar, we use the X button-press event
638 that was saved in saved_menu_event.
639 That makes the toolkit do its thing.
641 But first we recompute the menu bar contents (the whole tree).
643 The reason for saving the button event until here, instead of
644 passing it to the toolkit right away, is that we can safely
645 execute Lisp code. */
648 x_activate_menubar (FRAME_PTR f
)
653 if (!f
->output_data
.x
->saved_menu_event
->type
)
657 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
658 f
->output_data
.x
->saved_menu_event
->xany
.window
))
662 set_frame_menubar (f
, 0, 1);
664 popup_activated_flag
= 1;
666 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
667 f
->output_data
.x
->saved_menu_event
);
669 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
673 /* Ignore this if we get it a second time. */
674 f
->output_data
.x
->saved_menu_event
->type
= 0;
677 /* This callback is invoked when the user selects a menubar cascade
678 pushbutton, but before the pulldown menu is posted. */
682 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
684 popup_activated_flag
= 1;
686 x_activate_timeout_atimer ();
691 /* This callback is invoked when a dialog or menu is finished being
692 used and has been unposted. */
696 popup_deactivate_callback (GtkWidget
*widget
, gpointer client_data
)
698 popup_activated_flag
= 0;
702 popup_deactivate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
704 popup_activated_flag
= 0;
709 /* Function that finds the frame for WIDGET and shows the HELP text
711 F is the frame if known, or NULL if not known. */
713 show_help_event (FRAME_PTR f
, xt_or_gtk_widget widget
, Lisp_Object help
)
719 XSETFRAME (frame
, f
);
720 kbd_buffer_store_help_event (frame
, help
);
724 #if 0 /* This code doesn't do anything useful. ++kfs */
725 /* WIDGET is the popup menu. It's parent is the frame's
726 widget. See which frame that is. */
727 xt_or_gtk_widget frame_widget
= XtParent (widget
);
730 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
734 && (f
= XFRAME (frame
),
735 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
739 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
743 /* Callback called when menu items are highlighted/unhighlighted
744 while moving the mouse over them. WIDGET is the menu bar or menu
745 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
746 the data structure for the menu item, or null in case of
751 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
753 xg_menu_item_cb_data
*cb_data
;
756 cb_data
= (xg_menu_item_cb_data
*) g_object_get_data (G_OBJECT (widget
),
758 if (! cb_data
) return;
760 help
= call_data
? cb_data
->help
: Qnil
;
762 /* If popup_activated_flag is greater than 1 we are in a popup menu.
763 Don't show help for them, they won't appear before the
764 popup is popped down. */
765 if (popup_activated_flag
<= 1)
766 show_help_event (cb_data
->cl_data
->f
, widget
, help
);
770 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
775 widget_value
*wv
= (widget_value
*) call_data
;
777 help
= wv
? wv
->help
: Qnil
;
779 /* Determine the frame for the help event. */
780 f
= menubar_id_to_frame (id
);
782 show_help_event (f
, widget
, help
);
787 /* Gtk calls callbacks just because we tell it what item should be
788 selected in a radio group. If this variable is set to a non-zero
789 value, we are creating menus and don't want callbacks right now.
791 static int xg_crazy_callback_abort
;
793 /* This callback is called from the menu bar pulldown menu
794 when the user makes a selection.
795 Figure out what the user chose
796 and put the appropriate events into the keyboard buffer. */
798 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
800 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
802 if (xg_crazy_callback_abort
)
805 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
808 /* For a group of radio buttons, GTK calls the selection callback first
809 for the item that was active before the selection and then for the one that
810 is active after the selection. For C-h k this means we get the help on
811 the deselected item and then the selected item is executed. Prevent that
812 by ignoring the non-active item. */
813 if (GTK_IS_RADIO_MENU_ITEM (widget
)
814 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
817 /* When a menu is popped down, X generates a focus event (i.e. focus
818 goes back to the frame below the menu). Since GTK buffers events,
819 we force it out here before the menu selection event. Otherwise
820 sit-for will exit at once if the focus event follows the menu selection
824 while (gtk_events_pending ())
825 gtk_main_iteration ();
828 find_and_call_menu_selection (cb_data
->cl_data
->f
,
829 cb_data
->cl_data
->menu_bar_items_used
,
830 cb_data
->cl_data
->menu_bar_vector
,
834 #else /* not USE_GTK */
836 /* This callback is called from the menu bar pulldown menu
837 when the user makes a selection.
838 Figure out what the user chose
839 and put the appropriate events into the keyboard buffer. */
841 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
845 f
= menubar_id_to_frame (id
);
848 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
849 f
->menu_bar_vector
, client_data
);
851 #endif /* not USE_GTK */
853 /* Recompute all the widgets of frame F, when the menu bar has been
854 changed. Value is non-zero if widgets were updated. */
857 update_frame_menubar (FRAME_PTR f
)
860 return xg_update_frame_menubar (f
);
868 x
= f
->output_data
.x
;
870 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
874 /* Save the size of the frame because the pane widget doesn't accept
875 to resize itself. So force it. */
876 columns
= FRAME_COLS (f
);
877 rows
= FRAME_LINES (f
);
879 /* Do the voodoo which means "I'm changing lots of things, don't try
880 to refigure sizes until I'm done." */
881 lw_refigure_widget (x
->column_widget
, False
);
883 /* The order in which children are managed is the top to bottom
884 order in which they are displayed in the paned window. First,
885 remove the text-area widget. */
886 XtUnmanageChild (x
->edit_widget
);
888 /* Remove the menubar that is there now, and put up the menubar that
890 XtManageChild (x
->menubar_widget
);
891 XtMapWidget (x
->menubar_widget
);
892 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
894 /* Re-manage the text-area widget, and then thrash the sizes. */
895 XtManageChild (x
->edit_widget
);
896 lw_refigure_widget (x
->column_widget
, True
);
898 /* Force the pane widget to resize itself with the right values. */
899 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
907 apply_systemfont_to_dialog (Widget w
)
909 const char *fn
= xsettings_get_system_normal_font ();
912 XrmDatabase db
= XtDatabase (XtDisplay (w
));
914 XrmPutStringResource (&db
, "*dialog.faceName", fn
);
919 apply_systemfont_to_menu (Widget w
)
921 const char *fn
= xsettings_get_system_normal_font ();
926 if (XtIsShell (w
)) /* popup menu */
928 Widget
*childs
= NULL
;
930 XtVaGetValues (w
, XtNchildren
, &childs
, NULL
);
931 if (*childs
) w
= *childs
;
934 /* Only use system font if the default is used for the menu. */
935 XtVaGetValues (w
, XtNdefaultFace
, &defflt
, NULL
);
937 XtVaSetValues (w
, XtNfaceName
, fn
, NULL
);
941 /* Set the contents of the menubar widgets of frame F.
942 The argument FIRST_TIME is currently ignored;
943 it is set the first time this is called, from initialize_frame_menubar. */
946 set_frame_menubar (FRAME_PTR f
, int first_time
, int deep_p
)
948 xt_or_gtk_widget menubar_widget
;
953 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
955 int *submenu_start
, *submenu_end
;
956 int *submenu_top_level_items
, *submenu_n_panes
;
961 menubar_widget
= f
->output_data
.x
->menubar_widget
;
963 XSETFRAME (Vmenu_updating_frame
, f
);
966 if (f
->output_data
.x
->id
== 0)
967 f
->output_data
.x
->id
= next_menubar_widget_id
++;
968 id
= f
->output_data
.x
->id
;
971 if (! menubar_widget
)
973 /* Make the first call for any given frame always go deep. */
974 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
977 f
->output_data
.x
->saved_menu_event
= (XEvent
*)xmalloc (sizeof (XEvent
));
978 f
->output_data
.x
->saved_menu_event
->type
= 0;
982 /* If we have detached menus, we must update deep so detached menus
983 also gets updated. */
984 deep_p
= deep_p
|| xg_have_tear_offs ();
989 /* Make a widget-value tree representing the entire menu trees. */
991 struct buffer
*prev
= current_buffer
;
993 int specpdl_count
= SPECPDL_INDEX ();
994 int previous_menu_items_used
= f
->menu_bar_items_used
;
995 Lisp_Object
*previous_items
996 = (Lisp_Object
*) alloca (previous_menu_items_used
997 * sizeof (Lisp_Object
));
999 /* If we are making a new widget, its contents are empty,
1000 do always reinitialize them. */
1001 if (! menubar_widget
)
1002 previous_menu_items_used
= 0;
1004 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
;
1005 specbind (Qinhibit_quit
, Qt
);
1006 /* Don't let the debugger step into this code
1007 because it is not reentrant. */
1008 specbind (Qdebug_on_next_call
, Qnil
);
1010 record_unwind_save_match_data ();
1011 if (NILP (Voverriding_local_map_menu_flag
))
1013 specbind (Qoverriding_terminal_local_map
, Qnil
);
1014 specbind (Qoverriding_local_map
, Qnil
);
1017 set_buffer_internal_1 (XBUFFER (buffer
));
1019 /* Run the Lucid hook. */
1020 safe_run_hooks (Qactivate_menubar_hook
);
1022 /* If it has changed current-menubar from previous value,
1023 really recompute the menubar from the value. */
1024 if (! NILP (Vlucid_menu_bar_dirty_flag
))
1025 call0 (Qrecompute_lucid_menubar
);
1026 safe_run_hooks (Qmenu_bar_update_hook
);
1027 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1029 items
= FRAME_MENU_BAR_ITEMS (f
);
1031 /* Save the frame's previous menu bar contents data. */
1032 if (previous_menu_items_used
)
1033 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
1034 previous_menu_items_used
* sizeof (Lisp_Object
));
1036 /* Fill in menu_items with the current menu bar contents.
1037 This can evaluate Lisp code. */
1040 menu_items
= f
->menu_bar_vector
;
1041 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
1042 submenu_start
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1043 submenu_end
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1044 submenu_n_panes
= (int *) alloca (XVECTOR (items
)->size
* sizeof (int));
1045 submenu_top_level_items
1046 = (int *) alloca (XVECTOR (items
)->size
* sizeof (int *));
1048 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1050 Lisp_Object key
, string
, maps
;
1054 key
= XVECTOR (items
)->contents
[i
];
1055 string
= XVECTOR (items
)->contents
[i
+ 1];
1056 maps
= XVECTOR (items
)->contents
[i
+ 2];
1060 submenu_start
[i
] = menu_items_used
;
1062 menu_items_n_panes
= 0;
1063 submenu_top_level_items
[i
]
1064 = parse_single_submenu (key
, string
, maps
);
1065 submenu_n_panes
[i
] = menu_items_n_panes
;
1067 submenu_end
[i
] = menu_items_used
;
1070 finish_menu_items ();
1072 /* Convert menu_items into widget_value trees
1073 to display the menu. This cannot evaluate Lisp code. */
1075 wv
= xmalloc_widget_value ();
1076 wv
->name
= "menubar";
1079 wv
->button_type
= BUTTON_TYPE_NONE
;
1083 for (i
= 0; i
< last_i
; i
+= 4)
1085 menu_items_n_panes
= submenu_n_panes
[i
];
1086 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
1087 submenu_top_level_items
[i
]);
1091 first_wv
->contents
= wv
;
1092 /* Don't set wv->name here; GC during the loop might relocate it. */
1094 wv
->button_type
= BUTTON_TYPE_NONE
;
1098 set_buffer_internal_1 (prev
);
1100 /* If there has been no change in the Lisp-level contents
1101 of the menu bar, skip redisplaying it. Just exit. */
1103 /* Compare the new menu items with the ones computed last time. */
1104 for (i
= 0; i
< previous_menu_items_used
; i
++)
1105 if (menu_items_used
== i
1106 || (!EQ (previous_items
[i
], XVECTOR (menu_items
)->contents
[i
])))
1108 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
1110 /* The menu items have not changed. Don't bother updating
1111 the menus in any form, since it would be a no-op. */
1112 free_menubar_widget_value_tree (first_wv
);
1113 discard_menu_items ();
1114 unbind_to (specpdl_count
, Qnil
);
1118 /* The menu items are different, so store them in the frame. */
1119 f
->menu_bar_vector
= menu_items
;
1120 f
->menu_bar_items_used
= menu_items_used
;
1122 /* This undoes save_menu_items. */
1123 unbind_to (specpdl_count
, Qnil
);
1125 /* Now GC cannot happen during the lifetime of the widget_value,
1126 so it's safe to store data from a Lisp_String. */
1127 wv
= first_wv
->contents
;
1128 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1131 string
= XVECTOR (items
)->contents
[i
+ 1];
1134 wv
->name
= (char *) SDATA (string
);
1135 update_submenu_strings (wv
->contents
);
1142 /* Make a widget-value tree containing
1143 just the top level menu bar strings. */
1145 wv
= xmalloc_widget_value ();
1146 wv
->name
= "menubar";
1149 wv
->button_type
= BUTTON_TYPE_NONE
;
1153 items
= FRAME_MENU_BAR_ITEMS (f
);
1154 for (i
= 0; i
< XVECTOR (items
)->size
; i
+= 4)
1158 string
= XVECTOR (items
)->contents
[i
+ 1];
1162 wv
= xmalloc_widget_value ();
1163 wv
->name
= (char *) SDATA (string
);
1166 wv
->button_type
= BUTTON_TYPE_NONE
;
1168 /* This prevents lwlib from assuming this
1169 menu item is really supposed to be empty. */
1170 /* The EMACS_INT cast avoids a warning.
1171 This value just has to be different from small integers. */
1172 wv
->call_data
= (void *) (EMACS_INT
) (-1);
1177 first_wv
->contents
= wv
;
1181 /* Forget what we thought we knew about what is in the
1182 detailed contents of the menu bar menus.
1183 Changing the top level always destroys the contents. */
1184 f
->menu_bar_items_used
= 0;
1187 /* Create or update the menu bar widget. */
1192 xg_crazy_callback_abort
= 1;
1195 /* The fourth arg is DEEP_P, which says to consider the entire
1196 menu trees we supply, rather than just the menu bar item names. */
1197 xg_modify_menubar_widgets (menubar_widget
,
1201 G_CALLBACK (menubar_selection_callback
),
1202 G_CALLBACK (popup_deactivate_callback
),
1203 G_CALLBACK (menu_highlight_callback
));
1207 GtkWidget
*wvbox
= f
->output_data
.x
->vbox_widget
;
1210 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1211 G_CALLBACK (menubar_selection_callback
),
1212 G_CALLBACK (popup_deactivate_callback
),
1213 G_CALLBACK (menu_highlight_callback
));
1215 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1219 #else /* not USE_GTK */
1222 /* Disable resizing (done for Motif!) */
1223 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1225 /* The third arg is DEEP_P, which says to consider the entire
1226 menu trees we supply, rather than just the menu bar item names. */
1227 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1229 /* Re-enable the edit widget to resize. */
1230 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1234 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1235 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1237 menubar_widget
= lw_create_widget ("menubar", "menubar", id
, first_wv
,
1238 f
->output_data
.x
->column_widget
,
1240 popup_activate_callback
,
1241 menubar_selection_callback
,
1242 popup_deactivate_callback
,
1243 menu_highlight_callback
);
1244 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1246 /* Make menu pop down on C-g. */
1247 XtOverrideTranslations (menubar_widget
, override
);
1249 apply_systemfont_to_menu (menubar_widget
);
1255 if (f
->output_data
.x
->menubar_widget
)
1256 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1259 = (f
->output_data
.x
->menubar_widget
1260 ? (f
->output_data
.x
->menubar_widget
->core
.height
1261 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1264 #if 1 /* Experimentally, we now get the right results
1265 for -geometry -0-0 without this. 24 Aug 96, rms.
1266 Maybe so, but the menu bar size is missing the pixels so the
1267 WM size hints are off by these pixels. Jan D, oct 2009. */
1269 if (FRAME_EXTERNAL_MENU_BAR (f
))
1272 XtVaGetValues (f
->output_data
.x
->column_widget
,
1273 XtNinternalBorderWidth
, &ibw
, NULL
);
1274 menubar_size
+= ibw
;
1276 #endif /* USE_LUCID */
1279 f
->output_data
.x
->menubar_height
= menubar_size
;
1281 #endif /* not USE_GTK */
1283 free_menubar_widget_value_tree (first_wv
);
1284 update_frame_menubar (f
);
1287 xg_crazy_callback_abort
= 0;
1293 /* Called from Fx_create_frame to create the initial menubar of a frame
1294 before it is mapped, so that the window is mapped with the menubar already
1295 there instead of us tacking it on later and thrashing the window after it
1299 initialize_frame_menubar (FRAME_PTR f
)
1301 /* This function is called before the first chance to redisplay
1302 the frame. It has to be, so the frame will have the right size. */
1303 FRAME_MENU_BAR_ITEMS (f
) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f
));
1304 set_frame_menubar (f
, 1, 1);
1308 /* Get rid of the menu bar of frame F, and free its storage.
1309 This is used when deleting a frame, and when turning off the menu bar.
1310 For GTK this function is in gtkutil.c. */
1314 free_frame_menubar (FRAME_PTR f
)
1316 Widget menubar_widget
;
1318 if (! FRAME_X_P (f
))
1321 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1323 f
->output_data
.x
->menubar_height
= 0;
1328 /* Removing the menu bar magically changes the shell widget's x
1329 and y position of (0, 0) which, when the menu bar is turned
1330 on again, leads to pull-down menuss appearing in strange
1331 positions near the upper-left corner of the display. This
1332 happens only with some window managers like twm and ctwm,
1333 but not with other like Motif's mwm or kwm, because the
1334 latter generate ConfigureNotify events when the menu bar
1335 is switched off, which fixes the shell position. */
1336 Position x0
, y0
, x1
, y1
;
1342 if (f
->output_data
.x
->widget
)
1343 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1346 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1347 f
->output_data
.x
->menubar_widget
= NULL
;
1349 if (f
->output_data
.x
->widget
)
1352 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1353 if (x1
== 0 && y1
== 0)
1354 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1356 x_set_window_size (f
, 0, FRAME_COLS (f
), FRAME_LINES (f
));
1361 #endif /* not USE_GTK */
1363 #endif /* USE_X_TOOLKIT || USE_GTK */
1365 /* xmenu_show actually displays a menu using the panes and items in menu_items
1366 and returns the value selected from it.
1367 There are two versions of xmenu_show, one for Xt and one for Xlib.
1368 Both assume input is blocked by the caller. */
1370 /* F is the frame the menu is for.
1371 X and Y are the frame-relative specified position,
1372 relative to the inside upper left corner of the frame F.
1373 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1374 KEYMAPS is 1 if this menu was specified with keymaps;
1375 in that case, we return a list containing the chosen item's value
1376 and perhaps also the pane's prefix.
1377 TITLE is the specified menu title.
1378 ERROR is a place to store an error message string in case of failure.
1379 (We return nil on failure, but the value doesn't actually matter.) */
1381 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1383 /* The item selected in the popup menu. */
1384 static Lisp_Object
*volatile menu_item_selection
;
1388 /* Used when position a popup menu. See menu_position_func and
1389 create_and_show_popup_menu below. */
1390 struct next_popup_x_y
1397 /* The menu position function to use if we are not putting a popup
1398 menu where the pointer is.
1399 MENU is the menu to pop up.
1400 X and Y shall on exit contain x/y where the menu shall pop up.
1401 PUSH_IN is not documented in the GTK manual.
1402 USER_DATA is any data passed in when calling gtk_menu_popup.
1403 Here it points to a struct next_popup_x_y where the coordinates
1404 to store in *X and *Y are as well as the frame for the popup.
1406 Here only X and Y are used. */
1408 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1410 struct next_popup_x_y
* data
= (struct next_popup_x_y
*)user_data
;
1412 struct x_display_info
*dpyinfo
= FRAME_X_DISPLAY_INFO (data
->f
);
1413 int disp_width
= x_display_pixel_width (dpyinfo
);
1414 int disp_height
= x_display_pixel_height (dpyinfo
);
1419 /* Check if there is room for the menu. If not, adjust x/y so that
1420 the menu is fully visible. */
1421 gtk_widget_size_request (GTK_WIDGET (menu
), &req
);
1422 if (data
->x
+ req
.width
> disp_width
)
1423 *x
-= data
->x
+ req
.width
- disp_width
;
1424 if (data
->y
+ req
.height
> disp_height
)
1425 *y
-= data
->y
+ req
.height
- disp_height
;
1429 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1431 xg_menu_item_cb_data
*cb_data
= (xg_menu_item_cb_data
*) client_data
;
1433 if (xg_crazy_callback_abort
) return;
1434 if (cb_data
) menu_item_selection
= (Lisp_Object
*) cb_data
->call_data
;
1438 pop_down_menu (Lisp_Object arg
)
1440 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
1442 popup_activated_flag
= 0;
1444 gtk_widget_destroy (GTK_WIDGET (p
->pointer
));
1449 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1451 menu_item_selection will be set to the selection. */
1453 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
, int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1457 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1458 struct next_popup_x_y popup_x_y
;
1459 int specpdl_count
= SPECPDL_INDEX ();
1461 if (! FRAME_X_P (f
))
1464 xg_crazy_callback_abort
= 1;
1465 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1466 G_CALLBACK (popup_selection_callback
),
1467 G_CALLBACK (popup_deactivate_callback
),
1468 G_CALLBACK (menu_highlight_callback
));
1469 xg_crazy_callback_abort
= 0;
1473 /* Not invoked by a click. pop up at x/y. */
1474 pos_func
= menu_position_func
;
1476 /* Adjust coordinates to be root-window-relative. */
1477 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1478 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1484 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1488 for (i
= 0; i
< 5; i
++)
1489 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1493 /* Display the menu. */
1494 gtk_widget_show_all (menu
);
1496 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1497 timestamp
> 0 ? timestamp
: gtk_get_current_event_time());
1499 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1501 if (gtk_widget_get_mapped (menu
))
1503 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1504 two. show_help_echo uses this to detect popup menus. */
1505 popup_activated_flag
= 1;
1506 /* Process events that apply to the menu. */
1507 popup_widget_loop (1, menu
);
1510 unbind_to (specpdl_count
, Qnil
);
1512 /* Must reset this manually because the button release event is not passed
1513 to Emacs event loop. */
1514 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
1517 #else /* not USE_GTK */
1519 /* We need a unique id for each widget handled by the Lucid Widget
1522 For the main windows, and popup menus, we use this counter,
1523 which we increment each time after use. This starts from 1<<16.
1525 For menu bars, we use numbers starting at 0, counted in
1526 next_menubar_widget_id. */
1527 LWLIB_ID widget_id_tick
;
1530 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1532 menu_item_selection
= (Lisp_Object
*) client_data
;
1535 /* ARG is the LWLIB ID of the dialog box, represented
1536 as a Lisp object as (HIGHPART . LOWPART). */
1539 pop_down_menu (Lisp_Object arg
)
1541 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1542 | XINT (XCDR (arg
)));
1545 lw_destroy_all_widgets (id
);
1547 popup_activated_flag
= 0;
1552 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1554 menu_item_selection will be set to the selection. */
1556 create_and_show_popup_menu (FRAME_PTR f
, widget_value
*first_wv
,
1557 int x
, int y
, int for_click
, EMACS_UINT timestamp
)
1562 XButtonPressedEvent dummy
;
1566 if (! FRAME_X_P (f
))
1569 menu_id
= widget_id_tick
++;
1570 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1571 f
->output_data
.x
->widget
, 1, 0,
1572 popup_selection_callback
,
1573 popup_deactivate_callback
,
1574 menu_highlight_callback
);
1577 apply_systemfont_to_menu (menu
);
1580 dummy
.type
= ButtonPress
;
1582 dummy
.send_event
= 0;
1583 dummy
.display
= FRAME_X_DISPLAY (f
);
1584 dummy
.time
= CurrentTime
;
1585 dummy
.root
= FRAME_X_DISPLAY_INFO (f
)->root_window
;
1586 dummy
.window
= dummy
.root
;
1587 dummy
.subwindow
= dummy
.root
;
1591 /* Adjust coordinates to be root-window-relative. */
1592 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1593 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1600 for (i
= 0; i
< 5; i
++)
1601 if (FRAME_X_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1604 /* Don't allow any geometry request from the user. */
1605 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1606 XtSetValues (menu
, av
, ac
);
1608 /* Display the menu. */
1609 lw_popup_menu (menu
, (XEvent
*) &dummy
);
1610 popup_activated_flag
= 1;
1611 x_activate_timeout_atimer ();
1614 int fact
= 4 * sizeof (LWLIB_ID
);
1615 int specpdl_count
= SPECPDL_INDEX ();
1616 record_unwind_protect (pop_down_menu
,
1617 Fcons (make_number (menu_id
>> (fact
)),
1618 make_number (menu_id
& ~(-1 << (fact
)))));
1620 /* Process events that apply to the menu. */
1621 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
), menu_id
, 1);
1623 unbind_to (specpdl_count
, Qnil
);
1627 #endif /* not USE_GTK */
1630 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
1631 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
1634 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1635 widget_value
**submenu_stack
1636 = (widget_value
**) alloca (menu_items_used
* sizeof (widget_value
*));
1637 Lisp_Object
*subprefix_stack
1638 = (Lisp_Object
*) alloca (menu_items_used
* sizeof (Lisp_Object
));
1639 int submenu_depth
= 0;
1643 if (! FRAME_X_P (f
))
1648 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1650 *error
= "Empty menu";
1654 /* Create a tree of widget_value objects
1655 representing the panes and their items. */
1656 wv
= xmalloc_widget_value ();
1660 wv
->button_type
= BUTTON_TYPE_NONE
;
1665 /* Loop over all panes and items, filling in the tree. */
1667 while (i
< menu_items_used
)
1669 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1671 submenu_stack
[submenu_depth
++] = save_wv
;
1677 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1680 save_wv
= submenu_stack
[--submenu_depth
];
1684 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
)
1685 && submenu_depth
!= 0)
1686 i
+= MENU_ITEMS_PANE_LENGTH
;
1687 /* Ignore a nil in the item list.
1688 It's meaningful only for dialog boxes. */
1689 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1691 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1693 /* Create a new pane. */
1694 Lisp_Object pane_name
, prefix
;
1697 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1698 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1700 #ifndef HAVE_MULTILINGUAL_MENU
1701 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1703 pane_name
= ENCODE_MENU_STRING (pane_name
);
1704 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1707 pane_string
= (NILP (pane_name
)
1708 ? "" : (char *) SDATA (pane_name
));
1709 /* If there is just one top-level pane, put all its items directly
1710 under the top-level menu. */
1711 if (menu_items_n_panes
== 1)
1714 /* If the pane has a meaningful name,
1715 make the pane a top-level menu item
1716 with its items as a submenu beneath it. */
1717 if (!keymaps
&& strcmp (pane_string
, ""))
1719 wv
= xmalloc_widget_value ();
1723 first_wv
->contents
= wv
;
1724 wv
->name
= pane_string
;
1725 if (keymaps
&& !NILP (prefix
))
1729 wv
->button_type
= BUTTON_TYPE_NONE
;
1734 else if (first_pane
)
1740 i
+= MENU_ITEMS_PANE_LENGTH
;
1744 /* Create a new item within current pane. */
1745 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1746 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1747 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1748 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1749 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1750 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1751 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1752 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1754 #ifndef HAVE_MULTILINGUAL_MENU
1755 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1757 item_name
= ENCODE_MENU_STRING (item_name
);
1758 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1761 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1763 descrip
= ENCODE_MENU_STRING (descrip
);
1764 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1766 #endif /* not HAVE_MULTILINGUAL_MENU */
1768 wv
= xmalloc_widget_value ();
1772 save_wv
->contents
= wv
;
1773 wv
->name
= (char *) SDATA (item_name
);
1774 if (!NILP (descrip
))
1775 wv
->key
= (char *) SDATA (descrip
);
1777 /* If this item has a null value,
1778 make the call_data null so that it won't display a box
1779 when the mouse is on it. */
1781 = (!NILP (def
) ? (void *) &XVECTOR (menu_items
)->contents
[i
] : 0);
1782 wv
->enabled
= !NILP (enable
);
1785 wv
->button_type
= BUTTON_TYPE_NONE
;
1786 else if (EQ (type
, QCtoggle
))
1787 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1788 else if (EQ (type
, QCradio
))
1789 wv
->button_type
= BUTTON_TYPE_RADIO
;
1793 wv
->selected
= !NILP (selected
);
1795 if (! STRINGP (help
))
1802 i
+= MENU_ITEMS_ITEM_LENGTH
;
1806 /* Deal with the title, if it is non-nil. */
1809 widget_value
*wv_title
= xmalloc_widget_value ();
1810 widget_value
*wv_sep1
= xmalloc_widget_value ();
1811 widget_value
*wv_sep2
= xmalloc_widget_value ();
1813 wv_sep2
->name
= "--";
1814 wv_sep2
->next
= first_wv
->contents
;
1815 wv_sep2
->help
= Qnil
;
1817 wv_sep1
->name
= "--";
1818 wv_sep1
->next
= wv_sep2
;
1819 wv_sep1
->help
= Qnil
;
1821 #ifndef HAVE_MULTILINGUAL_MENU
1822 if (STRING_MULTIBYTE (title
))
1823 title
= ENCODE_MENU_STRING (title
);
1826 wv_title
->name
= (char *) SDATA (title
);
1827 wv_title
->enabled
= TRUE
;
1828 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1829 wv_title
->help
= Qnil
;
1830 wv_title
->next
= wv_sep1
;
1831 first_wv
->contents
= wv_title
;
1834 /* No selection has been chosen yet. */
1835 menu_item_selection
= 0;
1837 /* Actually create and show the menu until popped down. */
1838 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
, timestamp
);
1840 /* Free the widget_value objects we used to specify the contents. */
1841 free_menubar_widget_value_tree (first_wv
);
1843 /* Find the selected item, and its pane, to return
1844 the proper value. */
1845 if (menu_item_selection
!= 0)
1847 Lisp_Object prefix
, entry
;
1849 prefix
= entry
= Qnil
;
1851 while (i
< menu_items_used
)
1853 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qnil
))
1855 subprefix_stack
[submenu_depth
++] = prefix
;
1859 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qlambda
))
1861 prefix
= subprefix_stack
[--submenu_depth
];
1864 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
1867 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
1868 i
+= MENU_ITEMS_PANE_LENGTH
;
1870 /* Ignore a nil in the item list.
1871 It's meaningful only for dialog boxes. */
1872 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
1877 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
1878 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
1884 entry
= Fcons (entry
, Qnil
);
1886 entry
= Fcons (prefix
, entry
);
1887 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1888 if (!NILP (subprefix_stack
[j
]))
1889 entry
= Fcons (subprefix_stack
[j
], entry
);
1893 i
+= MENU_ITEMS_ITEM_LENGTH
;
1897 else if (!for_click
)
1898 /* Make "Cancel" equivalent to C-g. */
1899 Fsignal (Qquit
, Qnil
);
1906 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1908 /* The EMACS_INT cast avoids a warning. There's no problem
1909 as long as pointers have enough bits to hold small integers. */
1910 if ((int) (EMACS_INT
) client_data
!= -1)
1911 menu_item_selection
= (Lisp_Object
*) client_data
;
1913 popup_activated_flag
= 0;
1916 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1918 menu_item_selection will be set to the selection. */
1920 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1924 if (! FRAME_X_P (f
))
1927 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1928 G_CALLBACK (dialog_selection_callback
),
1929 G_CALLBACK (popup_deactivate_callback
),
1934 int specpdl_count
= SPECPDL_INDEX ();
1935 record_unwind_protect (pop_down_menu
, make_save_value (menu
, 0));
1937 /* Display the menu. */
1938 gtk_widget_show_all (menu
);
1940 /* Process events that apply to the menu. */
1941 popup_widget_loop (1, menu
);
1943 unbind_to (specpdl_count
, Qnil
);
1947 #else /* not USE_GTK */
1949 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1951 /* The EMACS_INT cast avoids a warning. There's no problem
1952 as long as pointers have enough bits to hold small integers. */
1953 if ((int) (EMACS_INT
) client_data
!= -1)
1954 menu_item_selection
= (Lisp_Object
*) client_data
;
1957 lw_destroy_all_widgets (id
);
1959 popup_activated_flag
= 0;
1963 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1965 menu_item_selection will be set to the selection. */
1967 create_and_show_dialog (FRAME_PTR f
, widget_value
*first_wv
)
1974 dialog_id
= widget_id_tick
++;
1976 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1978 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1979 f
->output_data
.x
->widget
, 1, 0,
1980 dialog_selection_callback
, 0, 0);
1981 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1982 /* Display the dialog box. */
1983 lw_pop_up_all_widgets (dialog_id
);
1984 popup_activated_flag
= 1;
1985 x_activate_timeout_atimer ();
1987 /* Process events that apply to the dialog box.
1988 Also handle timers. */
1990 int count
= SPECPDL_INDEX ();
1991 int fact
= 4 * sizeof (LWLIB_ID
);
1993 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1994 record_unwind_protect (pop_down_menu
,
1995 Fcons (make_number (dialog_id
>> (fact
)),
1996 make_number (dialog_id
& ~(-1 << (fact
)))));
1998 popup_get_selection ((XEvent
*) 0, FRAME_X_DISPLAY_INFO (f
),
2001 unbind_to (count
, Qnil
);
2005 #endif /* not USE_GTK */
2007 static char * button_names
[] = {
2008 "button1", "button2", "button3", "button4", "button5",
2009 "button6", "button7", "button8", "button9", "button10" };
2012 xdialog_show (FRAME_PTR f
, int keymaps
, Lisp_Object title
, Lisp_Object header
, char **error_name
)
2014 int i
, nb_buttons
=0;
2015 char dialog_name
[6];
2017 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
2019 /* Number of elements seen so far, before boundary. */
2021 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2022 int boundary_seen
= 0;
2024 if (! FRAME_X_P (f
))
2029 if (menu_items_n_panes
> 1)
2031 *error_name
= "Multiple panes in dialog box";
2035 /* Create a tree of widget_value objects
2036 representing the text label and buttons. */
2038 Lisp_Object pane_name
, prefix
;
2040 pane_name
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_NAME
];
2041 prefix
= XVECTOR (menu_items
)->contents
[MENU_ITEMS_PANE_PREFIX
];
2042 pane_string
= (NILP (pane_name
)
2043 ? "" : (char *) SDATA (pane_name
));
2044 prev_wv
= xmalloc_widget_value ();
2045 prev_wv
->value
= pane_string
;
2046 if (keymaps
&& !NILP (prefix
))
2048 prev_wv
->enabled
= 1;
2049 prev_wv
->name
= "message";
2050 prev_wv
->help
= Qnil
;
2053 /* Loop over all panes and items, filling in the tree. */
2054 i
= MENU_ITEMS_PANE_LENGTH
;
2055 while (i
< menu_items_used
)
2058 /* Create a new item within current pane. */
2059 Lisp_Object item_name
, enable
, descrip
;
2060 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2061 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2063 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2065 if (NILP (item_name
))
2067 free_menubar_widget_value_tree (first_wv
);
2068 *error_name
= "Submenu in dialog items";
2071 if (EQ (item_name
, Qquote
))
2073 /* This is the boundary between left-side elts
2074 and right-side elts. Stop incrementing right_count. */
2079 if (nb_buttons
>= 9)
2081 free_menubar_widget_value_tree (first_wv
);
2082 *error_name
= "Too many dialog items";
2086 wv
= xmalloc_widget_value ();
2088 wv
->name
= (char *) button_names
[nb_buttons
];
2089 if (!NILP (descrip
))
2090 wv
->key
= (char *) SDATA (descrip
);
2091 wv
->value
= (char *) SDATA (item_name
);
2092 wv
->call_data
= (void *) &XVECTOR (menu_items
)->contents
[i
];
2093 wv
->enabled
= !NILP (enable
);
2097 if (! boundary_seen
)
2101 i
+= MENU_ITEMS_ITEM_LENGTH
;
2104 /* If the boundary was not specified,
2105 by default put half on the left and half on the right. */
2106 if (! boundary_seen
)
2107 left_count
= nb_buttons
- nb_buttons
/ 2;
2109 wv
= xmalloc_widget_value ();
2110 wv
->name
= dialog_name
;
2113 /* Frame title: 'Q' = Question, 'I' = Information.
2114 Can also have 'E' = Error if, one day, we want
2115 a popup for errors. */
2117 dialog_name
[0] = 'Q';
2119 dialog_name
[0] = 'I';
2121 /* Dialog boxes use a really stupid name encoding
2122 which specifies how many buttons to use
2123 and how many buttons are on the right. */
2124 dialog_name
[1] = '0' + nb_buttons
;
2125 dialog_name
[2] = 'B';
2126 dialog_name
[3] = 'R';
2127 /* Number of buttons to put on the right. */
2128 dialog_name
[4] = '0' + nb_buttons
- left_count
;
2130 wv
->contents
= first_wv
;
2134 /* No selection has been chosen yet. */
2135 menu_item_selection
= 0;
2137 /* Actually create and show the dialog. */
2138 create_and_show_dialog (f
, first_wv
);
2140 /* Free the widget_value objects we used to specify the contents. */
2141 free_menubar_widget_value_tree (first_wv
);
2143 /* Find the selected item, and its pane, to return
2144 the proper value. */
2145 if (menu_item_selection
!= 0)
2151 while (i
< menu_items_used
)
2155 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2158 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2159 i
+= MENU_ITEMS_PANE_LENGTH
;
2161 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2163 /* This is the boundary between left-side elts and
2170 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2171 if (menu_item_selection
== &XVECTOR (menu_items
)->contents
[i
])
2175 entry
= Fcons (entry
, Qnil
);
2177 entry
= Fcons (prefix
, entry
);
2181 i
+= MENU_ITEMS_ITEM_LENGTH
;
2186 /* Make "Cancel" equivalent to C-g. */
2187 Fsignal (Qquit
, Qnil
);
2192 #else /* not USE_X_TOOLKIT && not USE_GTK */
2194 /* The frame of the last activated non-toolkit menu bar.
2195 Used to generate menu help events. */
2197 static struct frame
*menu_help_frame
;
2200 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2202 PANE is the pane number, and ITEM is the menu item number in
2203 the menu (currently not used).
2205 This cannot be done with generating a HELP_EVENT because
2206 XMenuActivate contains a loop that doesn't let Emacs process
2210 menu_help_callback (char *help_string
, int pane
, int item
)
2212 extern Lisp_Object Qmenu_item
;
2213 Lisp_Object
*first_item
;
2214 Lisp_Object pane_name
;
2215 Lisp_Object menu_object
;
2217 first_item
= XVECTOR (menu_items
)->contents
;
2218 if (EQ (first_item
[0], Qt
))
2219 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2220 else if (EQ (first_item
[0], Qquote
))
2221 /* This shouldn't happen, see xmenu_show. */
2222 pane_name
= empty_unibyte_string
;
2224 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2226 /* (menu-item MENU-NAME PANE-NUMBER) */
2227 menu_object
= Fcons (Qmenu_item
,
2229 Fcons (make_number (pane
), Qnil
)));
2230 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2231 Qnil
, menu_object
, make_number (item
), 1);
2235 pop_down_menu (Lisp_Object arg
)
2237 struct Lisp_Save_Value
*p1
= XSAVE_VALUE (Fcar (arg
));
2238 struct Lisp_Save_Value
*p2
= XSAVE_VALUE (Fcdr (arg
));
2240 FRAME_PTR f
= p1
->pointer
;
2241 XMenu
*menu
= p2
->pointer
;
2245 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2246 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2248 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2250 #ifdef HAVE_X_WINDOWS
2251 /* Assume the mouse has moved out of the X window.
2252 If it has actually moved in, we will get an EnterNotify. */
2253 x_mouse_leave (FRAME_X_DISPLAY_INFO (f
));
2255 /* State that no mouse buttons are now held.
2256 (The oldXMenu code doesn't track this info for us.)
2257 That is not necessarily true, but the fiction leads to reasonable
2258 results, and it is a pain to ask which are actually held now. */
2259 FRAME_X_DISPLAY_INFO (f
)->grabbed
= 0;
2261 #endif /* HAVE_X_WINDOWS */
2270 xmenu_show (FRAME_PTR f
, int x
, int y
, int for_click
, int keymaps
,
2271 Lisp_Object title
, char **error
, EMACS_UINT timestamp
)
2275 int pane
, selidx
, lpane
, status
;
2276 Lisp_Object entry
, pane_prefix
;
2278 int ulx
, uly
, width
, height
;
2279 int dispwidth
, dispheight
;
2280 int i
, j
, lines
, maxlines
;
2283 unsigned int dummy_uint
;
2284 int specpdl_count
= SPECPDL_INDEX ();
2286 if (! FRAME_X_P (f
) && ! FRAME_MSDOS_P (f
))
2290 if (menu_items_n_panes
== 0)
2293 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2295 *error
= "Empty menu";
2299 /* Figure out which root window F is on. */
2300 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2301 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2302 &dummy_uint
, &dummy_uint
);
2304 /* Make the menu on that window. */
2305 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2308 *error
= "Can't create menu";
2312 /* Don't GC while we prepare and show the menu,
2313 because we give the oldxmenu library pointers to the
2314 contents of strings. */
2315 inhibit_garbage_collection ();
2317 #ifdef HAVE_X_WINDOWS
2318 /* Adjust coordinates to relative to the outer (window manager) window. */
2319 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2320 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2321 #endif /* HAVE_X_WINDOWS */
2323 /* Adjust coordinates to be root-window-relative. */
2327 /* Create all the necessary panes and their items. */
2328 maxlines
= lines
= i
= 0;
2329 while (i
< menu_items_used
)
2331 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2333 /* Create a new pane. */
2334 Lisp_Object pane_name
, prefix
;
2337 maxlines
= max (maxlines
, lines
);
2339 pane_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_NAME
];
2340 prefix
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2341 pane_string
= (NILP (pane_name
)
2342 ? "" : (char *) SDATA (pane_name
));
2343 if (keymaps
&& !NILP (prefix
))
2346 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2347 if (lpane
== XM_FAILURE
)
2349 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2350 *error
= "Can't create pane";
2353 i
+= MENU_ITEMS_PANE_LENGTH
;
2355 /* Find the width of the widest item in this pane. */
2358 while (j
< menu_items_used
)
2361 item
= XVECTOR (menu_items
)->contents
[j
];
2369 width
= SBYTES (item
);
2370 if (width
> maxwidth
)
2373 j
+= MENU_ITEMS_ITEM_LENGTH
;
2376 /* Ignore a nil in the item list.
2377 It's meaningful only for dialog boxes. */
2378 else if (EQ (XVECTOR (menu_items
)->contents
[i
], Qquote
))
2382 /* Create a new item within current pane. */
2383 Lisp_Object item_name
, enable
, descrip
, help
;
2384 unsigned char *item_data
;
2387 item_name
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_NAME
];
2388 enable
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_ENABLE
];
2390 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_EQUIV_KEY
];
2391 help
= XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_HELP
];
2392 help_string
= STRINGP (help
) ? SDATA (help
) : NULL
;
2394 if (!NILP (descrip
))
2396 int gap
= maxwidth
- SBYTES (item_name
);
2397 /* if alloca is fast, use that to make the space,
2398 to reduce gc needs. */
2400 = (unsigned char *) alloca (maxwidth
2401 + SBYTES (descrip
) + 1);
2402 memcpy (item_data
, SDATA (item_name
), SBYTES (item_name
));
2403 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2405 memcpy (item_data
+ j
, SDATA (descrip
), SBYTES (descrip
));
2406 item_data
[j
+ SBYTES (descrip
)] = 0;
2409 item_data
= SDATA (item_name
);
2411 if (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2412 menu
, lpane
, 0, item_data
,
2413 !NILP (enable
), help_string
)
2416 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2417 *error
= "Can't add selection to menu";
2420 i
+= MENU_ITEMS_ITEM_LENGTH
;
2425 maxlines
= max (maxlines
, lines
);
2427 /* All set and ready to fly. */
2428 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2429 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2430 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2431 x
= min (x
, dispwidth
);
2432 y
= min (y
, dispheight
);
2435 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2436 &ulx
, &uly
, &width
, &height
);
2437 if (ulx
+width
> dispwidth
)
2439 x
-= (ulx
+ width
) - dispwidth
;
2440 ulx
= dispwidth
- width
;
2442 if (uly
+height
> dispheight
)
2444 y
-= (uly
+ height
) - dispheight
;
2445 uly
= dispheight
- height
;
2447 #ifndef HAVE_X_WINDOWS
2448 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2450 /* Move the menu away of the echo area, to avoid overwriting the
2451 menu with help echo messages or vice versa. */
2452 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2454 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2455 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2464 if (ulx
< 0) x
-= ulx
;
2465 if (uly
< 0) y
-= uly
;
2469 /* If position was not given by a mouse click, adjust so upper left
2470 corner of the menu as a whole ends up at given coordinates. This
2471 is what x-popup-menu says in its documentation. */
2473 y
+= 1.5*height
/(maxlines
+2);
2476 XMenuSetAEQ (menu
, TRUE
);
2477 XMenuSetFreeze (menu
, TRUE
);
2481 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2484 record_unwind_protect (pop_down_menu
,
2485 Fcons (make_save_value (f
, 0),
2486 make_save_value (menu
, 0)));
2488 /* Help display under X won't work because XMenuActivate contains
2489 a loop that doesn't give Emacs a chance to process it. */
2490 menu_help_frame
= f
;
2491 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2492 x
, y
, ButtonReleaseMask
, &datap
,
2493 menu_help_callback
);
2499 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2502 /* Find the item number SELIDX in pane number PANE. */
2504 while (i
< menu_items_used
)
2506 if (EQ (XVECTOR (menu_items
)->contents
[i
], Qt
))
2510 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_PANE_PREFIX
];
2512 i
+= MENU_ITEMS_PANE_LENGTH
;
2521 = XVECTOR (menu_items
)->contents
[i
+ MENU_ITEMS_ITEM_VALUE
];
2524 entry
= Fcons (entry
, Qnil
);
2525 if (!NILP (pane_prefix
))
2526 entry
= Fcons (pane_prefix
, entry
);
2532 i
+= MENU_ITEMS_ITEM_LENGTH
;
2538 *error
= "Can't activate menu";
2543 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2544 the menu was invoked with a mouse event as POSITION). */
2546 Fsignal (Qquit
, Qnil
);
2551 unbind_to (specpdl_count
, Qnil
);
2556 #endif /* not USE_X_TOOLKIT */
2558 #endif /* HAVE_MENUS */
2560 /* Detect if a dialog or menu has been posted. */
2563 popup_activated (void)
2565 return popup_activated_flag
;
2568 /* The following is used by delayed window autoselection. */
2570 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2571 doc
: /* Return t if a menu or popup dialog is active. */)
2575 return (popup_activated ()) ? Qt
: Qnil
;
2578 #endif /* HAVE_MENUS */
2582 syms_of_xmenu (void)
2584 Qdebug_on_next_call
= intern_c_string ("debug-on-next-call");
2585 staticpro (&Qdebug_on_next_call
);
2587 #ifdef USE_X_TOOLKIT
2588 widget_id_tick
= (1<<16);
2589 next_menubar_widget_id
= 1;
2592 defsubr (&Smenu_or_popup_active_p
);
2594 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2595 defsubr (&Sx_menu_bar_open_internal
);
2596 Ffset (intern_c_string ("accelerate-menu"),
2597 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));
2601 defsubr (&Sx_popup_dialog
);
2605 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2606 (do not change this comment) */