1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2014 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
41 #include "termhooks.h"
43 #include "blockinput.h"
44 #include "character.h"
48 #include "sysselect.h"
55 /* This may include sys/types.h, and that somehow loses
56 if this is not done before the other system files. */
60 /* Load sys/types.h if not already loaded.
61 In some systems loading it twice is suicidal. */
63 #include <sys/types.h>
66 #include "dispextern.h"
69 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
70 code accepts the Emacs internal encoding. */
71 #undef HAVE_MULTILINGUAL_MENU
75 #include <X11/IntrinsicP.h>
76 #include <X11/CoreP.h>
77 #include <X11/StringDefs.h>
78 #include <X11/Shell.h>
80 #include "xsettings.h"
81 #include "../lwlib/xlwmenu.h"
83 #include <X11/Xaw3d/Paned.h>
84 #else /* !HAVE_XAW3D */
85 #include <X11/Xaw/Paned.h>
86 #endif /* HAVE_XAW3D */
87 #endif /* USE_LUCID */
89 #include "../lwlib/lwlib.h"
91 #else /* not USE_X_TOOLKIT */
93 #include "../oldXMenu/XMenu.h"
95 #endif /* not USE_X_TOOLKIT */
96 #endif /* HAVE_X_WINDOWS */
101 #include "xgselect.h"
111 static Lisp_Object Qdebug_on_next_call
;
113 /* Flag which when set indicates a dialog or menu has been posted by
114 Xt on behalf of one of the widget sets. */
115 static int popup_activated_flag
;
120 static int next_menubar_widget_id
;
122 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
124 static struct frame
*
125 menubar_id_to_frame (LWLIB_ID id
)
127 Lisp_Object tail
, frame
;
130 FOR_EACH_FRAME (tail
, frame
)
133 if (!FRAME_WINDOW_P (f
))
135 if (f
->output_data
.x
->id
== id
)
143 #ifdef HAVE_X_WINDOWS
144 /* Return the mouse position in *X and *Y. The coordinates are window
145 relative for the edit window in frame F.
146 This is for Fx_popup_menu. The mouse_position_hook can not
147 be used for X, as it returns window relative coordinates
148 for the window where the mouse is in. This could be the menu bar,
149 the scroll bar or the edit window. Fx_popup_menu needs to be
150 sure it is the edit window. */
152 mouse_position_for_popup (struct frame
*f
, int *x
, int *y
)
154 Window root
, dummy_window
;
157 eassert (FRAME_X_P (f
));
161 XQueryPointer (FRAME_X_DISPLAY (f
),
162 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
164 /* The root window which contains the pointer. */
167 /* Window pointer is on, not used */
170 /* The position on that root window. */
173 /* x/y in dummy_window coordinates, not used. */
176 /* Modifier keys and pointer buttons, about which
178 (unsigned int *) &dummy
);
182 /* x_menu_show expects window coordinates, not root window
183 coordinates. Translate. */
184 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
185 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
188 #endif /* HAVE_X_WINDOWS */
192 #if defined USE_GTK || defined USE_MOTIF
194 /* Set menu_items_inuse so no other popup menu or dialog is created. */
197 x_menu_set_in_use (int in_use
)
199 menu_items_inuse
= in_use
? Qt
: Qnil
;
200 popup_activated_flag
= in_use
;
202 if (popup_activated_flag
)
203 x_activate_timeout_atimer ();
209 /* Wait for an X event to arrive or for a timer to expire. */
215 x_menu_wait_for_event (void *data
)
217 /* Another way to do this is to register a timer callback, that can be
218 done in GTK and Xt. But we have to do it like this when using only X
219 anyway, and with callbacks we would have three variants for timer handling
220 instead of the small ifdefs below. */
224 ! XtAppPending (Xt_app_con
)
225 #elif defined USE_GTK
226 ! gtk_events_pending ()
232 struct timespec next_time
= timer_check (), *ntp
;
234 struct x_display_info
*dpyinfo
;
238 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
240 int fd
= ConnectionNumber (dpyinfo
->display
);
241 FD_SET (fd
, &read_fds
);
243 XFlush (dpyinfo
->display
);
246 if (! timespec_valid_p (next_time
))
251 #if defined USE_GTK && defined HAVE_GTK3
252 /* Gtk3 have arrows on menus when they don't fit. When the
253 pointer is over an arrow, a timeout scrolls it a bit. Use
254 xg_select so that timeout gets triggered. */
255 xg_select (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
257 pselect (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
264 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
268 /* Loop in Xt until the menu pulldown or dialog popup has been
269 popped down (deactivated). This is used for x-popup-menu
270 and x-popup-dialog; it is not used for the menu bar.
272 NOTE: All calls to popup_get_selection should be protected
273 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
276 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
280 while (popup_activated_flag
)
284 event
= *initial_event
;
289 if (do_timers
) x_menu_wait_for_event (0);
290 XtAppNextEvent (Xt_app_con
, &event
);
293 /* Make sure we don't consider buttons grabbed after menu goes.
294 And make sure to deactivate for any ButtonRelease,
295 even if XtDispatchEvent doesn't do that. */
296 if (event
.type
== ButtonRelease
297 && dpyinfo
->display
== event
.xbutton
.display
)
299 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
300 #ifdef USE_MOTIF /* Pretending that the event came from a
301 Btn1Down seems the only way to convince Motif to
302 activate its callbacks; setting the XmNmenuPost
303 isn't working. --marcus@sysc.pdx.edu. */
304 event
.xbutton
.button
= 1;
305 /* Motif only pops down menus when no Ctrl, Alt or Mod
306 key is pressed and the button is released. So reset key state
307 so Motif thinks this is the case. */
308 event
.xbutton
.state
= 0;
311 /* Pop down on C-g and Escape. */
312 else if (event
.type
== KeyPress
313 && dpyinfo
->display
== event
.xbutton
.display
)
315 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
317 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
318 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
319 popup_activated_flag
= 0;
322 x_dispatch_event (&event
, event
.xany
.display
);
326 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
327 doc
: /* Start key navigation of the menu bar in FRAME.
328 This initially opens the first menu bar item and you can then navigate with the
329 arrow keys, select a menu entry with the return key or cancel with the
330 escape key. If FRAME has no menu bar this function does nothing.
332 If FRAME is nil or not given, use the selected frame. */)
336 struct frame
*f
= decode_window_system_frame (frame
);
340 if (FRAME_EXTERNAL_MENU_BAR (f
))
341 set_frame_menubar (f
, 0, 1);
343 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
349 x_catch_errors (FRAME_X_DISPLAY (f
));
350 memset (&ev
, 0, sizeof ev
);
351 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
352 ev
.xbutton
.window
= XtWindow (menubar
);
353 ev
.xbutton
.root
= FRAME_DISPLAY_INFO (f
)->root_window
;
354 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
355 ev
.xbutton
.button
= Button1
;
356 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
357 ev
.xbutton
.same_screen
= True
;
364 XtSetArg (al
[0], XtNchildren
, &list
);
365 XtSetArg (al
[1], XtNnumChildren
, &nr
);
366 XtGetValues (menubar
, al
, 2);
367 ev
.xbutton
.window
= XtWindow (list
[0]);
371 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
372 /* From-window, to-window. */
373 ev
.xbutton
.window
, ev
.xbutton
.root
,
375 /* From-position, to-position. */
376 ev
.xbutton
.x
, ev
.xbutton
.y
,
377 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
381 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
386 ev
.type
= ButtonPress
;
387 ev
.xbutton
.state
= 0;
389 XtDispatchEvent (&ev
);
390 ev
.xbutton
.type
= ButtonRelease
;
391 ev
.xbutton
.state
= Button1Mask
;
392 XtDispatchEvent (&ev
);
400 #endif /* USE_X_TOOLKIT */
404 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
405 doc
: /* Start key navigation of the menu bar in FRAME.
406 This initially opens the first menu bar item and you can then navigate with the
407 arrow keys, select a menu entry with the return key or cancel with the
408 escape key. If FRAME has no menu bar this function does nothing.
410 If FRAME is nil or not given, use the selected frame. */)
417 f
= decode_window_system_frame (frame
);
419 if (FRAME_EXTERNAL_MENU_BAR (f
))
420 set_frame_menubar (f
, 0, 1);
422 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
425 /* Activate the first menu. */
426 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
430 g_signal_emit_by_name (children
->data
, "activate_item");
431 popup_activated_flag
= 1;
432 g_list_free (children
);
440 /* Loop util popup_activated_flag is set to zero in a callback.
441 Used for popup menus and dialogs. */
444 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
446 ++popup_activated_flag
;
448 /* Process events in the Gtk event loop until done. */
449 while (popup_activated_flag
)
451 if (do_timers
) x_menu_wait_for_event (0);
452 gtk_main_iteration ();
457 /* Activate the menu bar of frame F.
458 This is called from keyboard.c when it gets the
459 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
461 To activate the menu bar, we use the X button-press event
462 that was saved in saved_menu_event.
463 That makes the toolkit do its thing.
465 But first we recompute the menu bar contents (the whole tree).
467 The reason for saving the button event until here, instead of
468 passing it to the toolkit right away, is that we can safely
469 execute Lisp code. */
472 x_activate_menubar (struct frame
*f
)
474 eassert (FRAME_X_P (f
));
476 if (!f
->output_data
.x
->saved_menu_event
->type
)
480 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
481 f
->output_data
.x
->saved_menu_event
->xany
.window
))
485 set_frame_menubar (f
, 0, 1);
487 popup_activated_flag
= 1;
489 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
490 f
->output_data
.x
->saved_menu_event
);
492 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
496 /* Ignore this if we get it a second time. */
497 f
->output_data
.x
->saved_menu_event
->type
= 0;
500 /* This callback is invoked when the user selects a menubar cascade
501 pushbutton, but before the pulldown menu is posted. */
505 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
507 popup_activated_flag
= 1;
508 x_activate_timeout_atimer ();
512 /* This callback is invoked when a dialog or menu is finished being
513 used and has been unposted. */
516 popup_deactivate_callback (
518 GtkWidget
*widget
, gpointer client_data
520 Widget widget
, LWLIB_ID id
, XtPointer client_data
524 popup_activated_flag
= 0;
528 /* Function that finds the frame for WIDGET and shows the HELP text
530 F is the frame if known, or NULL if not known. */
532 show_help_event (struct frame
*f
, xt_or_gtk_widget widget
, Lisp_Object help
)
538 XSETFRAME (frame
, f
);
539 kbd_buffer_store_help_event (frame
, help
);
543 #if 0 /* This code doesn't do anything useful. ++kfs */
544 /* WIDGET is the popup menu. It's parent is the frame's
545 widget. See which frame that is. */
546 xt_or_gtk_widget frame_widget
= XtParent (widget
);
549 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
553 && (f
= XFRAME (frame
),
554 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
558 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
562 /* Callback called when menu items are highlighted/unhighlighted
563 while moving the mouse over them. WIDGET is the menu bar or menu
564 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
565 the data structure for the menu item, or null in case of
570 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
572 xg_menu_item_cb_data
*cb_data
;
575 cb_data
= g_object_get_data (G_OBJECT (widget
), XG_ITEM_DATA
);
576 if (! cb_data
) return;
578 help
= call_data
? cb_data
->help
: Qnil
;
580 /* If popup_activated_flag is greater than 1 we are in a popup menu.
581 Don't pass the frame to show_help_event for those.
582 Passing frame creates an Emacs event. As we are looping in
583 popup_widget_loop, it won't be handled. Passing NULL shows the tip
584 directly without using an Emacs event. This is what the Lucid code
586 show_help_event (popup_activated_flag
<= 1 ? cb_data
->cl_data
->f
: NULL
,
591 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
593 widget_value
*wv
= call_data
;
594 Lisp_Object help
= wv
? wv
->help
: Qnil
;
596 /* Determine the frame for the help event. */
597 struct frame
*f
= menubar_id_to_frame (id
);
599 show_help_event (f
, widget
, help
);
604 /* Gtk calls callbacks just because we tell it what item should be
605 selected in a radio group. If this variable is set to a non-zero
606 value, we are creating menus and don't want callbacks right now.
608 static int xg_crazy_callback_abort
;
610 /* This callback is called from the menu bar pulldown menu
611 when the user makes a selection.
612 Figure out what the user chose
613 and put the appropriate events into the keyboard buffer. */
615 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
617 xg_menu_item_cb_data
*cb_data
= client_data
;
619 if (xg_crazy_callback_abort
)
622 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
625 /* For a group of radio buttons, GTK calls the selection callback first
626 for the item that was active before the selection and then for the one that
627 is active after the selection. For C-h k this means we get the help on
628 the deselected item and then the selected item is executed. Prevent that
629 by ignoring the non-active item. */
630 if (GTK_IS_RADIO_MENU_ITEM (widget
)
631 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
634 /* When a menu is popped down, X generates a focus event (i.e. focus
635 goes back to the frame below the menu). Since GTK buffers events,
636 we force it out here before the menu selection event. Otherwise
637 sit-for will exit at once if the focus event follows the menu selection
641 while (gtk_events_pending ())
642 gtk_main_iteration ();
645 find_and_call_menu_selection (cb_data
->cl_data
->f
,
646 cb_data
->cl_data
->menu_bar_items_used
,
647 cb_data
->cl_data
->menu_bar_vector
,
651 #else /* not USE_GTK */
653 /* This callback is called from the menu bar pulldown menu
654 when the user makes a selection.
655 Figure out what the user chose
656 and put the appropriate events into the keyboard buffer. */
658 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
662 f
= menubar_id_to_frame (id
);
665 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
666 f
->menu_bar_vector
, client_data
);
668 #endif /* not USE_GTK */
670 /* Recompute all the widgets of frame F, when the menu bar has been
674 update_frame_menubar (struct frame
*f
)
677 xg_update_frame_menubar (f
);
682 eassert (FRAME_X_P (f
));
684 x
= f
->output_data
.x
;
686 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
690 /* Save the size of the frame because the pane widget doesn't accept
691 to resize itself. So force it. */
692 columns
= FRAME_COLS (f
);
693 rows
= FRAME_LINES (f
);
695 /* Do the voodoo which means "I'm changing lots of things, don't try
696 to refigure sizes until I'm done." */
697 lw_refigure_widget (x
->column_widget
, False
);
699 /* The order in which children are managed is the top to bottom
700 order in which they are displayed in the paned window. First,
701 remove the text-area widget. */
702 XtUnmanageChild (x
->edit_widget
);
704 /* Remove the menubar that is there now, and put up the menubar that
706 XtManageChild (x
->menubar_widget
);
707 XtMapWidget (x
->menubar_widget
);
708 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
710 /* Re-manage the text-area widget, and then thrash the sizes. */
711 XtManageChild (x
->edit_widget
);
712 lw_refigure_widget (x
->column_widget
, True
);
714 /* Force the pane widget to resize itself with the right values. */
715 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
722 apply_systemfont_to_dialog (Widget w
)
724 const char *fn
= xsettings_get_system_normal_font ();
727 XrmDatabase db
= XtDatabase (XtDisplay (w
));
729 XrmPutStringResource (&db
, "*dialog.font", fn
);
734 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
736 const char *fn
= xsettings_get_system_normal_font ();
740 XrmDatabase db
= XtDatabase (XtDisplay (w
));
743 XrmPutStringResource (&db
, "*menubar*font", fn
);
744 XrmPutStringResource (&db
, "*popup*font", fn
);
751 /* Set the contents of the menubar widgets of frame F.
752 The argument FIRST_TIME is currently ignored;
753 it is set the first time this is called, from initialize_frame_menubar. */
756 set_frame_menubar (struct frame
*f
, bool first_time
, bool deep_p
)
758 xt_or_gtk_widget menubar_widget
;
763 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
765 int *submenu_start
, *submenu_end
;
766 bool *submenu_top_level_items
;
767 int *submenu_n_panes
;
769 eassert (FRAME_X_P (f
));
771 menubar_widget
= f
->output_data
.x
->menubar_widget
;
773 XSETFRAME (Vmenu_updating_frame
, f
);
776 if (f
->output_data
.x
->id
== 0)
777 f
->output_data
.x
->id
= next_menubar_widget_id
++;
778 id
= f
->output_data
.x
->id
;
781 if (! menubar_widget
)
783 /* Make the first call for any given frame always go deep. */
784 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
787 f
->output_data
.x
->saved_menu_event
= xmalloc (sizeof (XEvent
));
788 f
->output_data
.x
->saved_menu_event
->type
= 0;
792 /* If we have detached menus, we must update deep so detached menus
793 also gets updated. */
794 deep_p
= deep_p
|| xg_have_tear_offs (f
);
799 /* Make a widget-value tree representing the entire menu trees. */
801 struct buffer
*prev
= current_buffer
;
803 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
804 int previous_menu_items_used
= f
->menu_bar_items_used
;
805 Lisp_Object
*previous_items
806 = alloca (previous_menu_items_used
* sizeof *previous_items
);
809 /* If we are making a new widget, its contents are empty,
810 do always reinitialize them. */
811 if (! menubar_widget
)
812 previous_menu_items_used
= 0;
814 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->contents
;
815 specbind (Qinhibit_quit
, Qt
);
816 /* Don't let the debugger step into this code
817 because it is not reentrant. */
818 specbind (Qdebug_on_next_call
, Qnil
);
820 record_unwind_save_match_data ();
821 if (NILP (Voverriding_local_map_menu_flag
))
823 specbind (Qoverriding_terminal_local_map
, Qnil
);
824 specbind (Qoverriding_local_map
, Qnil
);
827 set_buffer_internal_1 (XBUFFER (buffer
));
829 /* Run the Lucid hook. */
830 safe_run_hooks (Qactivate_menubar_hook
);
832 /* If it has changed current-menubar from previous value,
833 really recompute the menubar from the value. */
834 if (! NILP (Vlucid_menu_bar_dirty_flag
))
835 call0 (Qrecompute_lucid_menubar
);
836 safe_run_hooks (Qmenu_bar_update_hook
);
837 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
839 items
= FRAME_MENU_BAR_ITEMS (f
);
841 /* Save the frame's previous menu bar contents data. */
842 if (previous_menu_items_used
)
843 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
844 previous_menu_items_used
* word_size
);
846 /* Fill in menu_items with the current menu bar contents.
847 This can evaluate Lisp code. */
850 menu_items
= f
->menu_bar_vector
;
851 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
852 subitems
= ASIZE (items
) / 4;
853 submenu_start
= alloca ((subitems
+ 1) * sizeof *submenu_start
);
854 submenu_end
= alloca (subitems
* sizeof *submenu_end
);
855 submenu_n_panes
= alloca (subitems
* sizeof *submenu_n_panes
);
856 submenu_top_level_items
= alloca (subitems
857 * sizeof *submenu_top_level_items
);
859 for (i
= 0; i
< subitems
; i
++)
861 Lisp_Object key
, string
, maps
;
863 key
= AREF (items
, 4 * i
);
864 string
= AREF (items
, 4 * i
+ 1);
865 maps
= AREF (items
, 4 * i
+ 2);
869 submenu_start
[i
] = menu_items_used
;
871 menu_items_n_panes
= 0;
872 submenu_top_level_items
[i
]
873 = parse_single_submenu (key
, string
, maps
);
874 submenu_n_panes
[i
] = menu_items_n_panes
;
876 submenu_end
[i
] = menu_items_used
;
879 submenu_start
[i
] = -1;
880 finish_menu_items ();
882 /* Convert menu_items into widget_value trees
883 to display the menu. This cannot evaluate Lisp code. */
885 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
886 wv
->button_type
= BUTTON_TYPE_NONE
;
889 for (i
= 0; submenu_start
[i
] >= 0; i
++)
891 menu_items_n_panes
= submenu_n_panes
[i
];
892 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
893 submenu_top_level_items
[i
]);
897 first_wv
->contents
= wv
;
898 /* Don't set wv->name here; GC during the loop might relocate it. */
900 wv
->button_type
= BUTTON_TYPE_NONE
;
904 set_buffer_internal_1 (prev
);
906 /* If there has been no change in the Lisp-level contents
907 of the menu bar, skip redisplaying it. Just exit. */
909 /* Compare the new menu items with the ones computed last time. */
910 for (i
= 0; i
< previous_menu_items_used
; i
++)
911 if (menu_items_used
== i
912 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
914 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
916 /* The menu items have not changed. Don't bother updating
917 the menus in any form, since it would be a no-op. */
918 free_menubar_widget_value_tree (first_wv
);
919 discard_menu_items ();
920 unbind_to (specpdl_count
, Qnil
);
924 /* The menu items are different, so store them in the frame. */
925 fset_menu_bar_vector (f
, menu_items
);
926 f
->menu_bar_items_used
= menu_items_used
;
928 /* This undoes save_menu_items. */
929 unbind_to (specpdl_count
, Qnil
);
931 /* Now GC cannot happen during the lifetime of the widget_value,
932 so it's safe to store data from a Lisp_String. */
933 wv
= first_wv
->contents
;
934 for (i
= 0; i
< ASIZE (items
); i
+= 4)
937 string
= AREF (items
, i
+ 1);
940 wv
->name
= SSDATA (string
);
941 update_submenu_strings (wv
->contents
);
948 /* Make a widget-value tree containing
949 just the top level menu bar strings. */
951 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
952 wv
->button_type
= BUTTON_TYPE_NONE
;
955 items
= FRAME_MENU_BAR_ITEMS (f
);
956 for (i
= 0; i
< ASIZE (items
); i
+= 4)
960 string
= AREF (items
, i
+ 1);
964 wv
= make_widget_value (SSDATA (string
), NULL
, true, Qnil
);
965 wv
->button_type
= BUTTON_TYPE_NONE
;
966 /* This prevents lwlib from assuming this
967 menu item is really supposed to be empty. */
968 /* The intptr_t cast avoids a warning.
969 This value just has to be different from small integers. */
970 wv
->call_data
= (void *) (intptr_t) (-1);
975 first_wv
->contents
= wv
;
979 /* Forget what we thought we knew about what is in the
980 detailed contents of the menu bar menus.
981 Changing the top level always destroys the contents. */
982 f
->menu_bar_items_used
= 0;
985 /* Create or update the menu bar widget. */
990 xg_crazy_callback_abort
= 1;
993 /* The fourth arg is DEEP_P, which says to consider the entire
994 menu trees we supply, rather than just the menu bar item names. */
995 xg_modify_menubar_widgets (menubar_widget
,
999 G_CALLBACK (menubar_selection_callback
),
1000 G_CALLBACK (popup_deactivate_callback
),
1001 G_CALLBACK (menu_highlight_callback
));
1006 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1007 G_CALLBACK (menubar_selection_callback
),
1008 G_CALLBACK (popup_deactivate_callback
),
1009 G_CALLBACK (menu_highlight_callback
));
1011 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1015 #else /* not USE_GTK */
1018 /* Disable resizing (done for Motif!) */
1019 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1021 /* The third arg is DEEP_P, which says to consider the entire
1022 menu trees we supply, rather than just the menu bar item names. */
1023 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1025 /* Re-enable the edit widget to resize. */
1026 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1030 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1031 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1034 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
1036 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
1038 f
->output_data
.x
->column_widget
,
1040 popup_activate_callback
,
1041 menubar_selection_callback
,
1042 popup_deactivate_callback
,
1043 menu_highlight_callback
);
1044 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1046 /* Make menu pop down on C-g. */
1047 XtOverrideTranslations (menubar_widget
, override
);
1052 if (f
->output_data
.x
->menubar_widget
)
1053 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1056 = (f
->output_data
.x
->menubar_widget
1057 ? (f
->output_data
.x
->menubar_widget
->core
.height
1058 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1061 #if 1 /* Experimentally, we now get the right results
1062 for -geometry -0-0 without this. 24 Aug 96, rms.
1063 Maybe so, but the menu bar size is missing the pixels so the
1064 WM size hints are off by these pixels. Jan D, oct 2009. */
1066 if (FRAME_EXTERNAL_MENU_BAR (f
))
1069 XtVaGetValues (f
->output_data
.x
->column_widget
,
1070 XtNinternalBorderWidth
, &ibw
, NULL
);
1071 menubar_size
+= ibw
;
1073 #endif /* USE_LUCID */
1076 f
->output_data
.x
->menubar_height
= menubar_size
;
1078 #endif /* not USE_GTK */
1080 free_menubar_widget_value_tree (first_wv
);
1081 update_frame_menubar (f
);
1084 xg_crazy_callback_abort
= 0;
1090 /* Called from Fx_create_frame to create the initial menubar of a frame
1091 before it is mapped, so that the window is mapped with the menubar already
1092 there instead of us tacking it on later and thrashing the window after it
1096 initialize_frame_menubar (struct frame
*f
)
1098 /* This function is called before the first chance to redisplay
1099 the frame. It has to be, so the frame will have the right size. */
1100 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
1101 set_frame_menubar (f
, 1, 1);
1105 /* Get rid of the menu bar of frame F, and free its storage.
1106 This is used when deleting a frame, and when turning off the menu bar.
1107 For GTK this function is in gtkutil.c. */
1111 free_frame_menubar (struct frame
*f
)
1113 Widget menubar_widget
;
1115 eassert (FRAME_X_P (f
));
1117 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1119 f
->output_data
.x
->menubar_height
= 0;
1124 /* Removing the menu bar magically changes the shell widget's x
1125 and y position of (0, 0) which, when the menu bar is turned
1126 on again, leads to pull-down menus appearing in strange
1127 positions near the upper-left corner of the display. This
1128 happens only with some window managers like twm and ctwm,
1129 but not with other like Motif's mwm or kwm, because the
1130 latter generate ConfigureNotify events when the menu bar
1131 is switched off, which fixes the shell position. */
1132 Position x0
, y0
, x1
, y1
;
1138 if (f
->output_data
.x
->widget
)
1139 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1142 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1143 f
->output_data
.x
->menubar_widget
= NULL
;
1145 if (f
->output_data
.x
->widget
)
1148 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1149 if (x1
== 0 && y1
== 0)
1150 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1152 x_set_window_size (f
, 0, FRAME_TEXT_WIDTH (f
), FRAME_TEXT_HEIGHT (f
), 1);
1157 #endif /* not USE_GTK */
1159 #endif /* USE_X_TOOLKIT || USE_GTK */
1161 /* x_menu_show actually displays a menu using the panes and items in menu_items
1162 and returns the value selected from it.
1163 There are two versions of x_menu_show, one for Xt and one for Xlib.
1164 Both assume input is blocked by the caller. */
1166 /* F is the frame the menu is for.
1167 X and Y are the frame-relative specified position,
1168 relative to the inside upper left corner of the frame F.
1169 Bitfield MENUFLAGS bits are:
1170 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1171 MENU_KEYMAPS is set if this menu was specified with keymaps;
1172 in that case, we return a list containing the chosen item's value
1173 and perhaps also the pane's prefix.
1174 TITLE is the specified menu title.
1175 ERROR is a place to store an error message string in case of failure.
1176 (We return nil on failure, but the value doesn't actually matter.) */
1178 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1180 /* The item selected in the popup menu. */
1181 static Lisp_Object
*volatile menu_item_selection
;
1185 /* Used when position a popup menu. See menu_position_func and
1186 create_and_show_popup_menu below. */
1187 struct next_popup_x_y
1194 /* The menu position function to use if we are not putting a popup
1195 menu where the pointer is.
1196 MENU is the menu to pop up.
1197 X and Y shall on exit contain x/y where the menu shall pop up.
1198 PUSH_IN is not documented in the GTK manual.
1199 USER_DATA is any data passed in when calling gtk_menu_popup.
1200 Here it points to a struct next_popup_x_y where the coordinates
1201 to store in *X and *Y are as well as the frame for the popup.
1203 Here only X and Y are used. */
1205 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1207 struct next_popup_x_y
*data
= user_data
;
1209 struct x_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (data
->f
);
1210 int disp_width
= x_display_pixel_width (dpyinfo
);
1211 int disp_height
= x_display_pixel_height (dpyinfo
);
1216 /* Check if there is room for the menu. If not, adjust x/y so that
1217 the menu is fully visible. */
1218 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1219 if (data
->x
+ req
.width
> disp_width
)
1220 *x
-= data
->x
+ req
.width
- disp_width
;
1221 if (data
->y
+ req
.height
> disp_height
)
1222 *y
-= data
->y
+ req
.height
- disp_height
;
1226 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1228 xg_menu_item_cb_data
*cb_data
= client_data
;
1230 if (xg_crazy_callback_abort
) return;
1231 if (cb_data
) menu_item_selection
= cb_data
->call_data
;
1235 pop_down_menu (void *arg
)
1237 popup_activated_flag
= 0;
1239 gtk_widget_destroy (GTK_WIDGET (arg
));
1243 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1245 menu_item_selection will be set to the selection. */
1247 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1248 int x
, int y
, bool for_click
)
1252 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1253 struct next_popup_x_y popup_x_y
;
1254 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1255 bool use_pos_func
= ! for_click
;
1258 /* Always use position function for Gtk3. Otherwise menus may become
1259 too small to show anything. */
1263 eassert (FRAME_X_P (f
));
1265 xg_crazy_callback_abort
= 1;
1266 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1267 G_CALLBACK (popup_selection_callback
),
1268 G_CALLBACK (popup_deactivate_callback
),
1269 G_CALLBACK (menu_highlight_callback
));
1270 xg_crazy_callback_abort
= 0;
1274 /* Not invoked by a click. pop up at x/y. */
1275 pos_func
= menu_position_func
;
1277 /* Adjust coordinates to be root-window-relative. */
1278 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1279 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1285 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1290 for (i
= 0; i
< 5; i
++)
1291 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1293 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1297 /* Display the menu. */
1298 gtk_widget_show_all (menu
);
1300 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1301 FRAME_DISPLAY_INFO (f
)->last_user_time
);
1303 record_unwind_protect_ptr (pop_down_menu
, menu
);
1305 if (gtk_widget_get_mapped (menu
))
1307 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1308 two. show_help_echo uses this to detect popup menus. */
1309 popup_activated_flag
= 1;
1310 /* Process events that apply to the menu. */
1311 popup_widget_loop (1, menu
);
1314 unbind_to (specpdl_count
, Qnil
);
1316 /* Must reset this manually because the button release event is not passed
1317 to Emacs event loop. */
1318 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1321 #else /* not USE_GTK */
1323 /* We need a unique id for each widget handled by the Lucid Widget
1326 For the main windows, and popup menus, we use this counter,
1327 which we increment each time after use. This starts from 1<<16.
1329 For menu bars, we use numbers starting at 0, counted in
1330 next_menubar_widget_id. */
1331 LWLIB_ID widget_id_tick
;
1334 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1336 menu_item_selection
= client_data
;
1339 /* ARG is the LWLIB ID of the dialog box, represented
1340 as a Lisp object as (HIGHPART . LOWPART). */
1343 pop_down_menu (Lisp_Object arg
)
1345 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1346 | XINT (XCDR (arg
)));
1349 lw_destroy_all_widgets (id
);
1351 popup_activated_flag
= 0;
1354 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1356 menu_item_selection will be set to the selection. */
1358 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1359 int x
, int y
, bool for_click
)
1365 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1369 eassert (FRAME_X_P (f
));
1372 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1375 menu_id
= widget_id_tick
++;
1376 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1377 f
->output_data
.x
->widget
, 1, 0,
1378 popup_selection_callback
,
1379 popup_deactivate_callback
,
1380 menu_highlight_callback
);
1382 event
->type
= ButtonPress
;
1384 event
->send_event
= 0;
1385 event
->display
= FRAME_X_DISPLAY (f
);
1386 event
->time
= CurrentTime
;
1387 event
->root
= FRAME_DISPLAY_INFO (f
)->root_window
;
1388 event
->window
= event
->subwindow
= event
->root
;
1392 /* Adjust coordinates to be root-window-relative. */
1393 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1394 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1401 for (i
= 0; i
< 5; i
++)
1402 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1405 /* Don't allow any geometry request from the user. */
1406 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1407 XtSetValues (menu
, av
, ac
);
1409 /* Display the menu. */
1410 lw_popup_menu (menu
, &dummy
);
1411 popup_activated_flag
= 1;
1412 x_activate_timeout_atimer ();
1415 int fact
= 4 * sizeof (LWLIB_ID
);
1416 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1417 record_unwind_protect (pop_down_menu
,
1418 Fcons (make_number (menu_id
>> (fact
)),
1419 make_number (menu_id
& ~(-1 << (fact
)))));
1421 /* Process events that apply to the menu. */
1422 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), menu_id
, 1);
1424 unbind_to (specpdl_count
, Qnil
);
1428 #endif /* not USE_GTK */
1431 cleanup_widget_value_tree (void *arg
)
1433 free_menubar_widget_value_tree (arg
);
1437 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
1438 Lisp_Object title
, const char **error_name
)
1441 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1442 widget_value
**submenu_stack
1443 = alloca (menu_items_used
* sizeof *submenu_stack
);
1444 Lisp_Object
*subprefix_stack
1445 = alloca (menu_items_used
* sizeof *subprefix_stack
);
1446 int submenu_depth
= 0;
1450 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1452 eassert (FRAME_X_P (f
));
1456 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1458 *error_name
= "Empty menu";
1464 /* Create a tree of widget_value objects
1465 representing the panes and their items. */
1466 wv
= make_widget_value ("menu", NULL
, true, Qnil
);
1467 wv
->button_type
= BUTTON_TYPE_NONE
;
1471 /* Loop over all panes and items, filling in the tree. */
1473 while (i
< menu_items_used
)
1475 if (EQ (AREF (menu_items
, i
), Qnil
))
1477 submenu_stack
[submenu_depth
++] = save_wv
;
1483 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1486 save_wv
= submenu_stack
[--submenu_depth
];
1490 else if (EQ (AREF (menu_items
, i
), Qt
)
1491 && submenu_depth
!= 0)
1492 i
+= MENU_ITEMS_PANE_LENGTH
;
1493 /* Ignore a nil in the item list.
1494 It's meaningful only for dialog boxes. */
1495 else if (EQ (AREF (menu_items
, i
), Qquote
))
1497 else if (EQ (AREF (menu_items
, i
), Qt
))
1499 /* Create a new pane. */
1500 Lisp_Object pane_name
, prefix
;
1501 const char *pane_string
;
1503 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1504 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1506 #ifndef HAVE_MULTILINGUAL_MENU
1507 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1509 pane_name
= ENCODE_MENU_STRING (pane_name
);
1510 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1513 pane_string
= (NILP (pane_name
)
1514 ? "" : SSDATA (pane_name
));
1515 /* If there is just one top-level pane, put all its items directly
1516 under the top-level menu. */
1517 if (menu_items_n_panes
== 1)
1520 /* If the pane has a meaningful name,
1521 make the pane a top-level menu item
1522 with its items as a submenu beneath it. */
1523 if (!(menuflags
& MENU_KEYMAPS
) && strcmp (pane_string
, ""))
1525 wv
= make_widget_value (pane_string
, NULL
, true, Qnil
);
1529 first_wv
->contents
= wv
;
1530 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
1532 wv
->button_type
= BUTTON_TYPE_NONE
;
1536 else if (first_pane
)
1542 i
+= MENU_ITEMS_PANE_LENGTH
;
1546 /* Create a new item within current pane. */
1547 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1548 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1549 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1550 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1551 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1552 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1553 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1554 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1556 #ifndef HAVE_MULTILINGUAL_MENU
1557 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1559 item_name
= ENCODE_MENU_STRING (item_name
);
1560 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1563 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1565 descrip
= ENCODE_MENU_STRING (descrip
);
1566 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1568 #endif /* not HAVE_MULTILINGUAL_MENU */
1570 wv
= make_widget_value (SSDATA (item_name
), NULL
, !NILP (enable
),
1571 STRINGP (help
) ? help
: Qnil
);
1575 save_wv
->contents
= wv
;
1576 if (!NILP (descrip
))
1577 wv
->key
= SSDATA (descrip
);
1578 /* If this item has a null value,
1579 make the call_data null so that it won't display a box
1580 when the mouse is on it. */
1581 wv
->call_data
= !NILP (def
) ? aref_addr (menu_items
, i
) : 0;
1584 wv
->button_type
= BUTTON_TYPE_NONE
;
1585 else if (EQ (type
, QCtoggle
))
1586 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1587 else if (EQ (type
, QCradio
))
1588 wv
->button_type
= BUTTON_TYPE_RADIO
;
1592 wv
->selected
= !NILP (selected
);
1596 i
+= MENU_ITEMS_ITEM_LENGTH
;
1600 /* Deal with the title, if it is non-nil. */
1603 widget_value
*wv_title
;
1604 widget_value
*wv_sep1
= make_widget_value ("--", NULL
, false, Qnil
);
1605 widget_value
*wv_sep2
= make_widget_value ("--", NULL
, false, Qnil
);
1607 wv_sep2
->next
= first_wv
->contents
;
1608 wv_sep1
->next
= wv_sep2
;
1610 #ifndef HAVE_MULTILINGUAL_MENU
1611 if (STRING_MULTIBYTE (title
))
1612 title
= ENCODE_MENU_STRING (title
);
1615 wv_title
= make_widget_value (SSDATA (title
), NULL
, true, Qnil
);
1616 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1617 wv_title
->next
= wv_sep1
;
1618 first_wv
->contents
= wv_title
;
1621 /* No selection has been chosen yet. */
1622 menu_item_selection
= 0;
1624 /* Make sure to free the widget_value objects we used to specify the
1625 contents even with longjmp. */
1626 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1628 /* Actually create and show the menu until popped down. */
1629 create_and_show_popup_menu (f
, first_wv
, x
, y
,
1630 menuflags
& MENU_FOR_CLICK
);
1632 unbind_to (specpdl_count
, Qnil
);
1634 /* Find the selected item, and its pane, to return
1635 the proper value. */
1636 if (menu_item_selection
!= 0)
1638 Lisp_Object prefix
, entry
;
1640 prefix
= entry
= Qnil
;
1642 while (i
< menu_items_used
)
1644 if (EQ (AREF (menu_items
, i
), Qnil
))
1646 subprefix_stack
[submenu_depth
++] = prefix
;
1650 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1652 prefix
= subprefix_stack
[--submenu_depth
];
1655 else if (EQ (AREF (menu_items
, i
), Qt
))
1658 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1659 i
+= MENU_ITEMS_PANE_LENGTH
;
1661 /* Ignore a nil in the item list.
1662 It's meaningful only for dialog boxes. */
1663 else if (EQ (AREF (menu_items
, i
), Qquote
))
1668 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1669 if (menu_item_selection
== aref_addr (menu_items
, i
))
1671 if (menuflags
& MENU_KEYMAPS
)
1675 entry
= list1 (entry
);
1677 entry
= Fcons (prefix
, entry
);
1678 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1679 if (!NILP (subprefix_stack
[j
]))
1680 entry
= Fcons (subprefix_stack
[j
], entry
);
1685 i
+= MENU_ITEMS_ITEM_LENGTH
;
1689 else if (!(menuflags
& MENU_FOR_CLICK
))
1692 /* Make "Cancel" equivalent to C-g. */
1693 Fsignal (Qquit
, Qnil
);
1702 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1704 /* Treat the pointer as an integer. There's no problem
1705 as long as pointers have enough bits to hold small integers. */
1706 if ((intptr_t) client_data
!= -1)
1707 menu_item_selection
= client_data
;
1709 popup_activated_flag
= 0;
1712 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1714 menu_item_selection will be set to the selection. */
1716 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1720 eassert (FRAME_X_P (f
));
1722 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1723 G_CALLBACK (dialog_selection_callback
),
1724 G_CALLBACK (popup_deactivate_callback
),
1729 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1730 record_unwind_protect_ptr (pop_down_menu
, menu
);
1732 /* Display the menu. */
1733 gtk_widget_show_all (menu
);
1735 /* Process events that apply to the menu. */
1736 popup_widget_loop (1, menu
);
1738 unbind_to (specpdl_count
, Qnil
);
1742 #else /* not USE_GTK */
1744 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1746 /* Treat the pointer as an integer. There's no problem
1747 as long as pointers have enough bits to hold small integers. */
1748 if ((intptr_t) client_data
!= -1)
1749 menu_item_selection
= client_data
;
1752 lw_destroy_all_widgets (id
);
1754 popup_activated_flag
= 0;
1758 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1760 menu_item_selection will be set to the selection. */
1762 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1766 eassert (FRAME_X_P (f
));
1768 dialog_id
= widget_id_tick
++;
1770 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1772 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1773 f
->output_data
.x
->widget
, 1, 0,
1774 dialog_selection_callback
, 0, 0);
1775 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1776 /* Display the dialog box. */
1777 lw_pop_up_all_widgets (dialog_id
);
1778 popup_activated_flag
= 1;
1779 x_activate_timeout_atimer ();
1781 /* Process events that apply to the dialog box.
1782 Also handle timers. */
1784 ptrdiff_t count
= SPECPDL_INDEX ();
1785 int fact
= 4 * sizeof (LWLIB_ID
);
1787 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1788 record_unwind_protect (pop_down_menu
,
1789 Fcons (make_number (dialog_id
>> (fact
)),
1790 make_number (dialog_id
& ~(-1 << (fact
)))));
1792 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), dialog_id
, 1);
1794 unbind_to (count
, Qnil
);
1798 #endif /* not USE_GTK */
1800 static const char * button_names
[] = {
1801 "button1", "button2", "button3", "button4", "button5",
1802 "button6", "button7", "button8", "button9", "button10" };
1805 x_dialog_show (struct frame
*f
, Lisp_Object title
,
1806 Lisp_Object header
, const char **error_name
)
1808 int i
, nb_buttons
=0;
1809 char dialog_name
[6];
1811 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1813 /* Number of elements seen so far, before boundary. */
1815 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1816 int boundary_seen
= 0;
1818 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1820 eassert (FRAME_X_P (f
));
1824 if (menu_items_n_panes
> 1)
1826 *error_name
= "Multiple panes in dialog box";
1830 /* Create a tree of widget_value objects
1831 representing the text label and buttons. */
1833 Lisp_Object pane_name
;
1834 const char *pane_string
;
1835 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1836 pane_string
= (NILP (pane_name
)
1837 ? "" : SSDATA (pane_name
));
1838 prev_wv
= make_widget_value ("message", (char *) pane_string
, true, Qnil
);
1841 /* Loop over all panes and items, filling in the tree. */
1842 i
= MENU_ITEMS_PANE_LENGTH
;
1843 while (i
< menu_items_used
)
1846 /* Create a new item within current pane. */
1847 Lisp_Object item_name
, enable
, descrip
;
1848 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1849 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1851 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1853 if (NILP (item_name
))
1855 free_menubar_widget_value_tree (first_wv
);
1856 *error_name
= "Submenu in dialog items";
1859 if (EQ (item_name
, Qquote
))
1861 /* This is the boundary between left-side elts
1862 and right-side elts. Stop incrementing right_count. */
1867 if (nb_buttons
>= 9)
1869 free_menubar_widget_value_tree (first_wv
);
1870 *error_name
= "Too many dialog items";
1874 wv
= make_widget_value (button_names
[nb_buttons
],
1876 !NILP (enable
), Qnil
);
1878 if (!NILP (descrip
))
1879 wv
->key
= SSDATA (descrip
);
1880 wv
->call_data
= aref_addr (menu_items
, i
);
1883 if (! boundary_seen
)
1887 i
+= MENU_ITEMS_ITEM_LENGTH
;
1890 /* If the boundary was not specified,
1891 by default put half on the left and half on the right. */
1892 if (! boundary_seen
)
1893 left_count
= nb_buttons
- nb_buttons
/ 2;
1895 wv
= make_widget_value (dialog_name
, NULL
, false, Qnil
);
1897 /* Frame title: 'Q' = Question, 'I' = Information.
1898 Can also have 'E' = Error if, one day, we want
1899 a popup for errors. */
1901 dialog_name
[0] = 'Q';
1903 dialog_name
[0] = 'I';
1905 /* Dialog boxes use a really stupid name encoding
1906 which specifies how many buttons to use
1907 and how many buttons are on the right. */
1908 dialog_name
[1] = '0' + nb_buttons
;
1909 dialog_name
[2] = 'B';
1910 dialog_name
[3] = 'R';
1911 /* Number of buttons to put on the right. */
1912 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1914 wv
->contents
= first_wv
;
1918 /* No selection has been chosen yet. */
1919 menu_item_selection
= 0;
1921 /* Make sure to free the widget_value objects we used to specify the
1922 contents even with longjmp. */
1923 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1925 /* Actually create and show the dialog. */
1926 create_and_show_dialog (f
, first_wv
);
1928 unbind_to (specpdl_count
, Qnil
);
1930 /* Find the selected item, and its pane, to return
1931 the proper value. */
1932 if (menu_item_selection
!= 0)
1935 while (i
< menu_items_used
)
1939 if (EQ (AREF (menu_items
, i
), Qt
))
1940 i
+= MENU_ITEMS_PANE_LENGTH
;
1941 else if (EQ (AREF (menu_items
, i
), Qquote
))
1943 /* This is the boundary between left-side elts and
1950 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1951 if (menu_item_selection
== aref_addr (menu_items
, i
))
1953 i
+= MENU_ITEMS_ITEM_LENGTH
;
1958 /* Make "Cancel" equivalent to C-g. */
1959 Fsignal (Qquit
, Qnil
);
1965 xw_popup_dialog (struct frame
*f
, Lisp_Object header
, Lisp_Object contents
)
1968 const char *error_name
;
1969 Lisp_Object selection
;
1970 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1972 check_window_system (f
);
1974 /* Decode the dialog items from what was specified. */
1975 title
= Fcar (contents
);
1976 CHECK_STRING (title
);
1977 record_unwind_protect_void (unuse_menu_items
);
1979 if (NILP (Fcar (Fcdr (contents
))))
1980 /* No buttons specified, add an "Ok" button so users can pop down
1981 the dialog. Also, the lesstif/motif version crashes if there are
1983 contents
= list2 (title
, Fcons (build_string ("Ok"), Qt
));
1985 list_of_panes (list1 (contents
));
1987 /* Display them in a dialog box. */
1989 selection
= x_dialog_show (f
, title
, header
, &error_name
);
1992 unbind_to (specpdl_count
, Qnil
);
1993 discard_menu_items ();
1995 if (error_name
) error ("%s", error_name
);
1999 #else /* not USE_X_TOOLKIT && not USE_GTK */
2001 /* The frame of the last activated non-toolkit menu bar.
2002 Used to generate menu help events. */
2004 static struct frame
*menu_help_frame
;
2007 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2009 PANE is the pane number, and ITEM is the menu item number in
2010 the menu (currently not used).
2012 This cannot be done with generating a HELP_EVENT because
2013 XMenuActivate contains a loop that doesn't let Emacs process
2017 menu_help_callback (char const *help_string
, int pane
, int item
)
2019 Lisp_Object
*first_item
;
2020 Lisp_Object pane_name
;
2021 Lisp_Object menu_object
;
2023 first_item
= XVECTOR (menu_items
)->contents
;
2024 if (EQ (first_item
[0], Qt
))
2025 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2026 else if (EQ (first_item
[0], Qquote
))
2027 /* This shouldn't happen, see x_menu_show. */
2028 pane_name
= empty_unibyte_string
;
2030 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2032 /* (menu-item MENU-NAME PANE-NUMBER) */
2033 menu_object
= list3 (Qmenu_item
, pane_name
, make_number (pane
));
2034 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2035 Qnil
, menu_object
, make_number (item
));
2039 pop_down_menu (Lisp_Object arg
)
2041 struct frame
*f
= XSAVE_POINTER (arg
, 0);
2042 XMenu
*menu
= XSAVE_POINTER (arg
, 1);
2046 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2047 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2049 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2051 #ifdef HAVE_X_WINDOWS
2052 /* Assume the mouse has moved out of the X window.
2053 If it has actually moved in, we will get an EnterNotify. */
2054 x_mouse_leave (FRAME_DISPLAY_INFO (f
));
2056 /* State that no mouse buttons are now held.
2057 (The oldXMenu code doesn't track this info for us.)
2058 That is not necessarily true, but the fiction leads to reasonable
2059 results, and it is a pain to ask which are actually held now. */
2060 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
2062 #endif /* HAVE_X_WINDOWS */
2069 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
2070 Lisp_Object title
, const char **error_name
)
2074 int pane
, selidx
, lpane
, status
;
2075 Lisp_Object entry
, pane_prefix
;
2077 int ulx
, uly
, width
, height
;
2078 int dispwidth
, dispheight
;
2079 int i
, j
, lines
, maxlines
;
2082 unsigned int dummy_uint
;
2083 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2085 eassert (FRAME_X_P (f
) || FRAME_MSDOS_P (f
));
2088 if (menu_items_n_panes
== 0)
2091 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2093 *error_name
= "Empty menu";
2099 /* Figure out which root window F is on. */
2100 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2101 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2102 &dummy_uint
, &dummy_uint
);
2104 /* Make the menu on that window. */
2105 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2108 *error_name
= "Can't create menu";
2113 /* Don't GC while we prepare and show the menu,
2114 because we give the oldxmenu library pointers to the
2115 contents of strings. */
2116 inhibit_garbage_collection ();
2118 #ifdef HAVE_X_WINDOWS
2119 /* Adjust coordinates to relative to the outer (window manager) window. */
2120 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2121 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2122 #endif /* HAVE_X_WINDOWS */
2124 /* Adjust coordinates to be root-window-relative. */
2128 /* Create all the necessary panes and their items. */
2129 maxwidth
= maxlines
= lines
= i
= 0;
2131 while (i
< menu_items_used
)
2133 if (EQ (AREF (menu_items
, i
), Qt
))
2135 /* Create a new pane. */
2136 Lisp_Object pane_name
, prefix
;
2137 const char *pane_string
;
2139 maxlines
= max (maxlines
, lines
);
2141 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2142 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2143 pane_string
= (NILP (pane_name
)
2144 ? "" : SSDATA (pane_name
));
2145 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
2148 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2149 if (lpane
== XM_FAILURE
)
2151 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2152 *error_name
= "Can't create pane";
2156 i
+= MENU_ITEMS_PANE_LENGTH
;
2158 /* Find the width of the widest item in this pane. */
2160 while (j
< menu_items_used
)
2163 item
= AREF (menu_items
, j
);
2171 width
= SBYTES (item
);
2172 if (width
> maxwidth
)
2175 j
+= MENU_ITEMS_ITEM_LENGTH
;
2178 /* Ignore a nil in the item list.
2179 It's meaningful only for dialog boxes. */
2180 else if (EQ (AREF (menu_items
, i
), Qquote
))
2184 /* Create a new item within current pane. */
2185 Lisp_Object item_name
, enable
, descrip
, help
;
2187 char const *help_string
;
2189 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2190 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2192 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2193 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2194 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2196 if (!NILP (descrip
))
2198 /* if alloca is fast, use that to make the space,
2199 to reduce gc needs. */
2200 item_data
= alloca (maxwidth
+ SBYTES (descrip
) + 1);
2201 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2202 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2204 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2205 item_data
[j
+ SBYTES (descrip
)] = 0;
2208 item_data
= SSDATA (item_name
);
2210 if (lpane
== XM_FAILURE
2211 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2212 menu
, lpane
, 0, item_data
,
2213 !NILP (enable
), help_string
)
2216 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2217 *error_name
= "Can't add selection to menu";
2221 i
+= MENU_ITEMS_ITEM_LENGTH
;
2226 maxlines
= max (maxlines
, lines
);
2228 /* All set and ready to fly. */
2229 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2230 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2231 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2232 x
= min (x
, dispwidth
);
2233 y
= min (y
, dispheight
);
2236 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2237 &ulx
, &uly
, &width
, &height
);
2238 if (ulx
+width
> dispwidth
)
2240 x
-= (ulx
+ width
) - dispwidth
;
2241 ulx
= dispwidth
- width
;
2243 if (uly
+height
> dispheight
)
2245 y
-= (uly
+ height
) - dispheight
;
2246 uly
= dispheight
- height
;
2248 #ifndef HAVE_X_WINDOWS
2249 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2251 /* Move the menu away of the echo area, to avoid overwriting the
2252 menu with help echo messages or vice versa. */
2253 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2255 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2256 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2265 if (ulx
< 0) x
-= ulx
;
2266 if (uly
< 0) y
-= uly
;
2268 if (!(menuflags
& MENU_FOR_CLICK
))
2270 /* If position was not given by a mouse click, adjust so upper left
2271 corner of the menu as a whole ends up at given coordinates. This
2272 is what x-popup-menu says in its documentation. */
2274 y
+= 1.5*height
/(maxlines
+2);
2277 XMenuSetAEQ (menu
, TRUE
);
2278 XMenuSetFreeze (menu
, TRUE
);
2282 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2285 record_unwind_protect (pop_down_menu
, make_save_ptr_ptr (f
, menu
));
2287 /* Help display under X won't work because XMenuActivate contains
2288 a loop that doesn't give Emacs a chance to process it. */
2289 menu_help_frame
= f
;
2290 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2291 x
, y
, ButtonReleaseMask
, &datap
,
2292 menu_help_callback
);
2293 entry
= pane_prefix
= Qnil
;
2299 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2302 /* Find the item number SELIDX in pane number PANE. */
2304 while (i
< menu_items_used
)
2306 if (EQ (AREF (menu_items
, i
), Qt
))
2310 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2312 i
+= MENU_ITEMS_PANE_LENGTH
;
2321 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2322 if (menuflags
& MENU_KEYMAPS
)
2324 entry
= list1 (entry
);
2325 if (!NILP (pane_prefix
))
2326 entry
= Fcons (pane_prefix
, entry
);
2332 i
+= MENU_ITEMS_ITEM_LENGTH
;
2338 *error_name
= "Can't activate menu";
2342 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2343 the menu was invoked with a mouse event as POSITION). */
2344 if (!(menuflags
& MENU_FOR_CLICK
))
2347 Fsignal (Qquit
, Qnil
);
2353 unbind_to (specpdl_count
, Qnil
);
2358 #endif /* not USE_X_TOOLKIT */
2361 /* Detect if a dialog or menu has been posted. MSDOS has its own
2362 implementation on msdos.c. */
2365 popup_activated (void)
2367 return popup_activated_flag
;
2369 #endif /* not MSDOS */
2371 /* The following is used by delayed window autoselection. */
2373 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2374 doc
: /* Return t if a menu or popup dialog is active. */)
2377 return (popup_activated ()) ? Qt
: Qnil
;
2381 syms_of_xmenu (void)
2383 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2385 #ifdef USE_X_TOOLKIT
2386 widget_id_tick
= (1<<16);
2387 next_menubar_widget_id
= 1;
2390 defsubr (&Smenu_or_popup_active_p
);
2392 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2393 defsubr (&Sx_menu_bar_open_internal
);
2394 Ffset (intern_c_string ("accelerate-menu"),
2395 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));