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 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
114 static Lisp_Object
xdialog_show (struct frame
*, bool, Lisp_Object
, Lisp_Object
,
118 /* Flag which when set indicates a dialog or menu has been posted by
119 Xt on behalf of one of the widget sets. */
120 static int popup_activated_flag
;
125 static int next_menubar_widget_id
;
127 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
129 static struct frame
*
130 menubar_id_to_frame (LWLIB_ID id
)
132 Lisp_Object tail
, frame
;
135 FOR_EACH_FRAME (tail
, frame
)
138 if (!FRAME_WINDOW_P (f
))
140 if (f
->output_data
.x
->id
== id
)
148 #ifdef HAVE_X_WINDOWS
149 /* Return the mouse position in *X and *Y. The coordinates are window
150 relative for the edit window in frame F.
151 This is for Fx_popup_menu. The mouse_position_hook can not
152 be used for X, as it returns window relative coordinates
153 for the window where the mouse is in. This could be the menu bar,
154 the scroll bar or the edit window. Fx_popup_menu needs to be
155 sure it is the edit window. */
157 mouse_position_for_popup (struct frame
*f
, int *x
, int *y
)
159 Window root
, dummy_window
;
162 eassert (FRAME_X_P (f
));
166 XQueryPointer (FRAME_X_DISPLAY (f
),
167 DefaultRootWindow (FRAME_X_DISPLAY (f
)),
169 /* The root window which contains the pointer. */
172 /* Window pointer is on, not used */
175 /* The position on that root window. */
178 /* x/y in dummy_window coordinates, not used. */
181 /* Modifier keys and pointer buttons, about which
183 (unsigned int *) &dummy
);
187 /* xmenu_show expects window coordinates, not root window
188 coordinates. Translate. */
189 *x
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
190 *y
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
193 #endif /* HAVE_X_WINDOWS */
197 #if defined USE_GTK || defined USE_MOTIF
199 /* Set menu_items_inuse so no other popup menu or dialog is created. */
202 x_menu_set_in_use (int in_use
)
204 menu_items_inuse
= in_use
? Qt
: Qnil
;
205 popup_activated_flag
= in_use
;
207 if (popup_activated_flag
)
208 x_activate_timeout_atimer ();
214 /* Wait for an X event to arrive or for a timer to expire. */
220 x_menu_wait_for_event (void *data
)
222 /* Another way to do this is to register a timer callback, that can be
223 done in GTK and Xt. But we have to do it like this when using only X
224 anyway, and with callbacks we would have three variants for timer handling
225 instead of the small ifdefs below. */
229 ! XtAppPending (Xt_app_con
)
230 #elif defined USE_GTK
231 ! gtk_events_pending ()
237 struct timespec next_time
= timer_check (), *ntp
;
239 struct x_display_info
*dpyinfo
;
243 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
245 int fd
= ConnectionNumber (dpyinfo
->display
);
246 FD_SET (fd
, &read_fds
);
248 XFlush (dpyinfo
->display
);
251 if (! timespec_valid_p (next_time
))
256 #if defined USE_GTK && defined HAVE_GTK3
257 /* Gtk3 have arrows on menus when they don't fit. When the
258 pointer is over an arrow, a timeout scrolls it a bit. Use
259 xg_select so that timeout gets triggered. */
260 xg_select (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
262 pselect (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
269 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
273 /* Loop in Xt until the menu pulldown or dialog popup has been
274 popped down (deactivated). This is used for x-popup-menu
275 and x-popup-dialog; it is not used for the menu bar.
277 NOTE: All calls to popup_get_selection should be protected
278 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
281 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
, LWLIB_ID id
, int do_timers
)
285 while (popup_activated_flag
)
289 event
= *initial_event
;
294 if (do_timers
) x_menu_wait_for_event (0);
295 XtAppNextEvent (Xt_app_con
, &event
);
298 /* Make sure we don't consider buttons grabbed after menu goes.
299 And make sure to deactivate for any ButtonRelease,
300 even if XtDispatchEvent doesn't do that. */
301 if (event
.type
== ButtonRelease
302 && dpyinfo
->display
== event
.xbutton
.display
)
304 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
305 #ifdef USE_MOTIF /* Pretending that the event came from a
306 Btn1Down seems the only way to convince Motif to
307 activate its callbacks; setting the XmNmenuPost
308 isn't working. --marcus@sysc.pdx.edu. */
309 event
.xbutton
.button
= 1;
310 /* Motif only pops down menus when no Ctrl, Alt or Mod
311 key is pressed and the button is released. So reset key state
312 so Motif thinks this is the case. */
313 event
.xbutton
.state
= 0;
316 /* Pop down on C-g and Escape. */
317 else if (event
.type
== KeyPress
318 && dpyinfo
->display
== event
.xbutton
.display
)
320 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
322 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
323 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
324 popup_activated_flag
= 0;
327 x_dispatch_event (&event
, event
.xany
.display
);
331 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
332 doc
: /* Start key navigation of the menu bar in FRAME.
333 This initially opens the first menu bar item and you can then navigate with the
334 arrow keys, select a menu entry with the return key or cancel with the
335 escape key. If FRAME has no menu bar this function does nothing.
337 If FRAME is nil or not given, use the selected frame. */)
341 struct frame
*f
= decode_window_system_frame (frame
);
345 if (FRAME_EXTERNAL_MENU_BAR (f
))
346 set_frame_menubar (f
, 0, 1);
348 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
354 x_catch_errors (FRAME_X_DISPLAY (f
));
355 memset (&ev
, 0, sizeof ev
);
356 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
357 ev
.xbutton
.window
= XtWindow (menubar
);
358 ev
.xbutton
.root
= FRAME_DISPLAY_INFO (f
)->root_window
;
359 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
360 ev
.xbutton
.button
= Button1
;
361 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
362 ev
.xbutton
.same_screen
= True
;
369 XtSetArg (al
[0], XtNchildren
, &list
);
370 XtSetArg (al
[1], XtNnumChildren
, &nr
);
371 XtGetValues (menubar
, al
, 2);
372 ev
.xbutton
.window
= XtWindow (list
[0]);
376 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
377 /* From-window, to-window. */
378 ev
.xbutton
.window
, ev
.xbutton
.root
,
380 /* From-position, to-position. */
381 ev
.xbutton
.x
, ev
.xbutton
.y
,
382 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
386 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
391 ev
.type
= ButtonPress
;
392 ev
.xbutton
.state
= 0;
394 XtDispatchEvent (&ev
);
395 ev
.xbutton
.type
= ButtonRelease
;
396 ev
.xbutton
.state
= Button1Mask
;
397 XtDispatchEvent (&ev
);
405 #endif /* USE_X_TOOLKIT */
409 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
410 doc
: /* Start key navigation of the menu bar in FRAME.
411 This initially opens the first menu bar item and you can then navigate with the
412 arrow keys, select a menu entry with the return key or cancel with the
413 escape key. If FRAME has no menu bar this function does nothing.
415 If FRAME is nil or not given, use the selected frame. */)
422 f
= decode_window_system_frame (frame
);
424 if (FRAME_EXTERNAL_MENU_BAR (f
))
425 set_frame_menubar (f
, 0, 1);
427 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
430 /* Activate the first menu. */
431 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
435 g_signal_emit_by_name (children
->data
, "activate_item");
436 popup_activated_flag
= 1;
437 g_list_free (children
);
445 /* Loop util popup_activated_flag is set to zero in a callback.
446 Used for popup menus and dialogs. */
449 popup_widget_loop (int do_timers
, GtkWidget
*widget
)
451 ++popup_activated_flag
;
453 /* Process events in the Gtk event loop until done. */
454 while (popup_activated_flag
)
456 if (do_timers
) x_menu_wait_for_event (0);
457 gtk_main_iteration ();
462 /* Activate the menu bar of frame F.
463 This is called from keyboard.c when it gets the
464 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
466 To activate the menu bar, we use the X button-press event
467 that was saved in saved_menu_event.
468 That makes the toolkit do its thing.
470 But first we recompute the menu bar contents (the whole tree).
472 The reason for saving the button event until here, instead of
473 passing it to the toolkit right away, is that we can safely
474 execute Lisp code. */
477 x_activate_menubar (struct frame
*f
)
479 eassert (FRAME_X_P (f
));
481 if (!f
->output_data
.x
->saved_menu_event
->type
)
485 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
486 f
->output_data
.x
->saved_menu_event
->xany
.window
))
490 set_frame_menubar (f
, 0, 1);
492 popup_activated_flag
= 1;
494 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
495 f
->output_data
.x
->saved_menu_event
);
497 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
501 /* Ignore this if we get it a second time. */
502 f
->output_data
.x
->saved_menu_event
->type
= 0;
505 /* This callback is invoked when the user selects a menubar cascade
506 pushbutton, but before the pulldown menu is posted. */
510 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
512 popup_activated_flag
= 1;
513 x_activate_timeout_atimer ();
517 /* This callback is invoked when a dialog or menu is finished being
518 used and has been unposted. */
521 popup_deactivate_callback (
523 GtkWidget
*widget
, gpointer client_data
525 Widget widget
, LWLIB_ID id
, XtPointer client_data
529 popup_activated_flag
= 0;
533 /* Function that finds the frame for WIDGET and shows the HELP text
535 F is the frame if known, or NULL if not known. */
537 show_help_event (struct frame
*f
, xt_or_gtk_widget widget
, Lisp_Object help
)
543 XSETFRAME (frame
, f
);
544 kbd_buffer_store_help_event (frame
, help
);
548 #if 0 /* This code doesn't do anything useful. ++kfs */
549 /* WIDGET is the popup menu. It's parent is the frame's
550 widget. See which frame that is. */
551 xt_or_gtk_widget frame_widget
= XtParent (widget
);
554 for (tail
= Vframe_list
; CONSP (tail
); tail
= XCDR (tail
))
558 && (f
= XFRAME (frame
),
559 FRAME_X_P (f
) && f
->output_data
.x
->widget
== frame_widget
))
563 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
567 /* Callback called when menu items are highlighted/unhighlighted
568 while moving the mouse over them. WIDGET is the menu bar or menu
569 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
570 the data structure for the menu item, or null in case of
575 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
577 xg_menu_item_cb_data
*cb_data
;
580 cb_data
= g_object_get_data (G_OBJECT (widget
), XG_ITEM_DATA
);
581 if (! cb_data
) return;
583 help
= call_data
? cb_data
->help
: Qnil
;
585 /* If popup_activated_flag is greater than 1 we are in a popup menu.
586 Don't pass the frame to show_help_event for those.
587 Passing frame creates an Emacs event. As we are looping in
588 popup_widget_loop, it won't be handled. Passing NULL shows the tip
589 directly without using an Emacs event. This is what the Lucid code
591 show_help_event (popup_activated_flag
<= 1 ? cb_data
->cl_data
->f
: NULL
,
596 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
598 widget_value
*wv
= call_data
;
599 Lisp_Object help
= wv
? wv
->help
: Qnil
;
601 /* Determine the frame for the help event. */
602 struct frame
*f
= menubar_id_to_frame (id
);
604 show_help_event (f
, widget
, help
);
609 /* Gtk calls callbacks just because we tell it what item should be
610 selected in a radio group. If this variable is set to a non-zero
611 value, we are creating menus and don't want callbacks right now.
613 static int xg_crazy_callback_abort
;
615 /* This callback is called from the menu bar pulldown menu
616 when the user makes a selection.
617 Figure out what the user chose
618 and put the appropriate events into the keyboard buffer. */
620 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
622 xg_menu_item_cb_data
*cb_data
= client_data
;
624 if (xg_crazy_callback_abort
)
627 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
630 /* For a group of radio buttons, GTK calls the selection callback first
631 for the item that was active before the selection and then for the one that
632 is active after the selection. For C-h k this means we get the help on
633 the deselected item and then the selected item is executed. Prevent that
634 by ignoring the non-active item. */
635 if (GTK_IS_RADIO_MENU_ITEM (widget
)
636 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
639 /* When a menu is popped down, X generates a focus event (i.e. focus
640 goes back to the frame below the menu). Since GTK buffers events,
641 we force it out here before the menu selection event. Otherwise
642 sit-for will exit at once if the focus event follows the menu selection
646 while (gtk_events_pending ())
647 gtk_main_iteration ();
650 find_and_call_menu_selection (cb_data
->cl_data
->f
,
651 cb_data
->cl_data
->menu_bar_items_used
,
652 cb_data
->cl_data
->menu_bar_vector
,
656 #else /* not USE_GTK */
658 /* This callback is called from the menu bar pulldown menu
659 when the user makes a selection.
660 Figure out what the user chose
661 and put the appropriate events into the keyboard buffer. */
663 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
667 f
= menubar_id_to_frame (id
);
670 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
671 f
->menu_bar_vector
, client_data
);
673 #endif /* not USE_GTK */
675 /* Recompute all the widgets of frame F, when the menu bar has been
679 update_frame_menubar (struct frame
*f
)
682 xg_update_frame_menubar (f
);
687 eassert (FRAME_X_P (f
));
689 x
= f
->output_data
.x
;
691 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
695 /* Save the size of the frame because the pane widget doesn't accept
696 to resize itself. So force it. */
697 columns
= FRAME_COLS (f
);
698 rows
= FRAME_LINES (f
);
700 /* Do the voodoo which means "I'm changing lots of things, don't try
701 to refigure sizes until I'm done." */
702 lw_refigure_widget (x
->column_widget
, False
);
704 /* The order in which children are managed is the top to bottom
705 order in which they are displayed in the paned window. First,
706 remove the text-area widget. */
707 XtUnmanageChild (x
->edit_widget
);
709 /* Remove the menubar that is there now, and put up the menubar that
711 XtManageChild (x
->menubar_widget
);
712 XtMapWidget (x
->menubar_widget
);
713 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
715 /* Re-manage the text-area widget, and then thrash the sizes. */
716 XtManageChild (x
->edit_widget
);
717 lw_refigure_widget (x
->column_widget
, True
);
719 /* Force the pane widget to resize itself with the right values. */
720 EmacsFrameSetCharSize (x
->edit_widget
, columns
, rows
);
727 apply_systemfont_to_dialog (Widget w
)
729 const char *fn
= xsettings_get_system_normal_font ();
732 XrmDatabase db
= XtDatabase (XtDisplay (w
));
734 XrmPutStringResource (&db
, "*dialog.font", fn
);
739 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
741 const char *fn
= xsettings_get_system_normal_font ();
745 XrmDatabase db
= XtDatabase (XtDisplay (w
));
748 XrmPutStringResource (&db
, "*menubar*font", fn
);
749 XrmPutStringResource (&db
, "*popup*font", fn
);
756 /* Set the contents of the menubar widgets of frame F.
757 The argument FIRST_TIME is currently ignored;
758 it is set the first time this is called, from initialize_frame_menubar. */
761 set_frame_menubar (struct frame
*f
, bool first_time
, bool deep_p
)
763 xt_or_gtk_widget menubar_widget
;
768 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
770 int *submenu_start
, *submenu_end
;
771 bool *submenu_top_level_items
;
772 int *submenu_n_panes
;
774 eassert (FRAME_X_P (f
));
776 menubar_widget
= f
->output_data
.x
->menubar_widget
;
778 XSETFRAME (Vmenu_updating_frame
, f
);
781 if (f
->output_data
.x
->id
== 0)
782 f
->output_data
.x
->id
= next_menubar_widget_id
++;
783 id
= f
->output_data
.x
->id
;
786 if (! menubar_widget
)
788 /* Make the first call for any given frame always go deep. */
789 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
792 f
->output_data
.x
->saved_menu_event
= xmalloc (sizeof (XEvent
));
793 f
->output_data
.x
->saved_menu_event
->type
= 0;
797 /* If we have detached menus, we must update deep so detached menus
798 also gets updated. */
799 deep_p
= deep_p
|| xg_have_tear_offs (f
);
804 /* Make a widget-value tree representing the entire menu trees. */
806 struct buffer
*prev
= current_buffer
;
808 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
809 int previous_menu_items_used
= f
->menu_bar_items_used
;
810 Lisp_Object
*previous_items
811 = alloca (previous_menu_items_used
* sizeof *previous_items
);
814 /* If we are making a new widget, its contents are empty,
815 do always reinitialize them. */
816 if (! menubar_widget
)
817 previous_menu_items_used
= 0;
819 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->contents
;
820 specbind (Qinhibit_quit
, Qt
);
821 /* Don't let the debugger step into this code
822 because it is not reentrant. */
823 specbind (Qdebug_on_next_call
, Qnil
);
825 record_unwind_save_match_data ();
826 if (NILP (Voverriding_local_map_menu_flag
))
828 specbind (Qoverriding_terminal_local_map
, Qnil
);
829 specbind (Qoverriding_local_map
, Qnil
);
832 set_buffer_internal_1 (XBUFFER (buffer
));
834 /* Run the Lucid hook. */
835 safe_run_hooks (Qactivate_menubar_hook
);
837 /* If it has changed current-menubar from previous value,
838 really recompute the menubar from the value. */
839 if (! NILP (Vlucid_menu_bar_dirty_flag
))
840 call0 (Qrecompute_lucid_menubar
);
841 safe_run_hooks (Qmenu_bar_update_hook
);
842 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
844 items
= FRAME_MENU_BAR_ITEMS (f
);
846 /* Save the frame's previous menu bar contents data. */
847 if (previous_menu_items_used
)
848 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
849 previous_menu_items_used
* word_size
);
851 /* Fill in menu_items with the current menu bar contents.
852 This can evaluate Lisp code. */
855 menu_items
= f
->menu_bar_vector
;
856 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
857 subitems
= ASIZE (items
) / 4;
858 submenu_start
= alloca ((subitems
+ 1) * sizeof *submenu_start
);
859 submenu_end
= alloca (subitems
* sizeof *submenu_end
);
860 submenu_n_panes
= alloca (subitems
* sizeof *submenu_n_panes
);
861 submenu_top_level_items
= alloca (subitems
862 * sizeof *submenu_top_level_items
);
864 for (i
= 0; i
< subitems
; i
++)
866 Lisp_Object key
, string
, maps
;
868 key
= AREF (items
, 4 * i
);
869 string
= AREF (items
, 4 * i
+ 1);
870 maps
= AREF (items
, 4 * i
+ 2);
874 submenu_start
[i
] = menu_items_used
;
876 menu_items_n_panes
= 0;
877 submenu_top_level_items
[i
]
878 = parse_single_submenu (key
, string
, maps
);
879 submenu_n_panes
[i
] = menu_items_n_panes
;
881 submenu_end
[i
] = menu_items_used
;
884 submenu_start
[i
] = -1;
885 finish_menu_items ();
887 /* Convert menu_items into widget_value trees
888 to display the menu. This cannot evaluate Lisp code. */
890 wv
= xmalloc_widget_value ();
891 wv
->name
= "menubar";
894 wv
->button_type
= BUTTON_TYPE_NONE
;
898 for (i
= 0; submenu_start
[i
] >= 0; i
++)
900 menu_items_n_panes
= submenu_n_panes
[i
];
901 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
902 submenu_top_level_items
[i
]);
906 first_wv
->contents
= wv
;
907 /* Don't set wv->name here; GC during the loop might relocate it. */
909 wv
->button_type
= BUTTON_TYPE_NONE
;
913 set_buffer_internal_1 (prev
);
915 /* If there has been no change in the Lisp-level contents
916 of the menu bar, skip redisplaying it. Just exit. */
918 /* Compare the new menu items with the ones computed last time. */
919 for (i
= 0; i
< previous_menu_items_used
; i
++)
920 if (menu_items_used
== i
921 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
923 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
925 /* The menu items have not changed. Don't bother updating
926 the menus in any form, since it would be a no-op. */
927 free_menubar_widget_value_tree (first_wv
);
928 discard_menu_items ();
929 unbind_to (specpdl_count
, Qnil
);
933 /* The menu items are different, so store them in the frame. */
934 fset_menu_bar_vector (f
, menu_items
);
935 f
->menu_bar_items_used
= menu_items_used
;
937 /* This undoes save_menu_items. */
938 unbind_to (specpdl_count
, Qnil
);
940 /* Now GC cannot happen during the lifetime of the widget_value,
941 so it's safe to store data from a Lisp_String. */
942 wv
= first_wv
->contents
;
943 for (i
= 0; i
< ASIZE (items
); i
+= 4)
946 string
= AREF (items
, i
+ 1);
949 wv
->name
= SSDATA (string
);
950 update_submenu_strings (wv
->contents
);
957 /* Make a widget-value tree containing
958 just the top level menu bar strings. */
960 wv
= xmalloc_widget_value ();
961 wv
->name
= "menubar";
964 wv
->button_type
= BUTTON_TYPE_NONE
;
968 items
= FRAME_MENU_BAR_ITEMS (f
);
969 for (i
= 0; i
< ASIZE (items
); i
+= 4)
973 string
= AREF (items
, i
+ 1);
977 wv
= xmalloc_widget_value ();
978 wv
->name
= SSDATA (string
);
981 wv
->button_type
= BUTTON_TYPE_NONE
;
983 /* This prevents lwlib from assuming this
984 menu item is really supposed to be empty. */
985 /* The intptr_t cast avoids a warning.
986 This value just has to be different from small integers. */
987 wv
->call_data
= (void *) (intptr_t) (-1);
992 first_wv
->contents
= wv
;
996 /* Forget what we thought we knew about what is in the
997 detailed contents of the menu bar menus.
998 Changing the top level always destroys the contents. */
999 f
->menu_bar_items_used
= 0;
1002 /* Create or update the menu bar widget. */
1007 xg_crazy_callback_abort
= 1;
1010 /* The fourth arg is DEEP_P, which says to consider the entire
1011 menu trees we supply, rather than just the menu bar item names. */
1012 xg_modify_menubar_widgets (menubar_widget
,
1016 G_CALLBACK (menubar_selection_callback
),
1017 G_CALLBACK (popup_deactivate_callback
),
1018 G_CALLBACK (menu_highlight_callback
));
1023 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
1024 G_CALLBACK (menubar_selection_callback
),
1025 G_CALLBACK (popup_deactivate_callback
),
1026 G_CALLBACK (menu_highlight_callback
));
1028 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1032 #else /* not USE_GTK */
1035 /* Disable resizing (done for Motif!) */
1036 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
1038 /* The third arg is DEEP_P, which says to consider the entire
1039 menu trees we supply, rather than just the menu bar item names. */
1040 lw_modify_all_widgets (id
, first_wv
, deep_p
);
1042 /* Re-enable the edit widget to resize. */
1043 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
1047 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1048 XtTranslations override
= XtParseTranslationTable (menuOverride
);
1051 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
1053 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
1055 f
->output_data
.x
->column_widget
,
1057 popup_activate_callback
,
1058 menubar_selection_callback
,
1059 popup_deactivate_callback
,
1060 menu_highlight_callback
);
1061 f
->output_data
.x
->menubar_widget
= menubar_widget
;
1063 /* Make menu pop down on C-g. */
1064 XtOverrideTranslations (menubar_widget
, override
);
1069 if (f
->output_data
.x
->menubar_widget
)
1070 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
1073 = (f
->output_data
.x
->menubar_widget
1074 ? (f
->output_data
.x
->menubar_widget
->core
.height
1075 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
1078 #if 1 /* Experimentally, we now get the right results
1079 for -geometry -0-0 without this. 24 Aug 96, rms.
1080 Maybe so, but the menu bar size is missing the pixels so the
1081 WM size hints are off by these pixels. Jan D, oct 2009. */
1083 if (FRAME_EXTERNAL_MENU_BAR (f
))
1086 XtVaGetValues (f
->output_data
.x
->column_widget
,
1087 XtNinternalBorderWidth
, &ibw
, NULL
);
1088 menubar_size
+= ibw
;
1090 #endif /* USE_LUCID */
1093 f
->output_data
.x
->menubar_height
= menubar_size
;
1095 #endif /* not USE_GTK */
1097 free_menubar_widget_value_tree (first_wv
);
1098 update_frame_menubar (f
);
1101 xg_crazy_callback_abort
= 0;
1107 /* Called from Fx_create_frame to create the initial menubar of a frame
1108 before it is mapped, so that the window is mapped with the menubar already
1109 there instead of us tacking it on later and thrashing the window after it
1113 initialize_frame_menubar (struct frame
*f
)
1115 /* This function is called before the first chance to redisplay
1116 the frame. It has to be, so the frame will have the right size. */
1117 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
1118 set_frame_menubar (f
, 1, 1);
1122 /* Get rid of the menu bar of frame F, and free its storage.
1123 This is used when deleting a frame, and when turning off the menu bar.
1124 For GTK this function is in gtkutil.c. */
1128 free_frame_menubar (struct frame
*f
)
1130 Widget menubar_widget
;
1132 eassert (FRAME_X_P (f
));
1134 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1136 f
->output_data
.x
->menubar_height
= 0;
1141 /* Removing the menu bar magically changes the shell widget's x
1142 and y position of (0, 0) which, when the menu bar is turned
1143 on again, leads to pull-down menus appearing in strange
1144 positions near the upper-left corner of the display. This
1145 happens only with some window managers like twm and ctwm,
1146 but not with other like Motif's mwm or kwm, because the
1147 latter generate ConfigureNotify events when the menu bar
1148 is switched off, which fixes the shell position. */
1149 Position x0
, y0
, x1
, y1
;
1155 if (f
->output_data
.x
->widget
)
1156 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1159 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1160 f
->output_data
.x
->menubar_widget
= NULL
;
1162 if (f
->output_data
.x
->widget
)
1165 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1166 if (x1
== 0 && y1
== 0)
1167 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1169 x_set_window_size (f
, 0, FRAME_TEXT_WIDTH (f
), FRAME_TEXT_HEIGHT (f
), 1);
1174 #endif /* not USE_GTK */
1176 #endif /* USE_X_TOOLKIT || USE_GTK */
1178 /* xmenu_show actually displays a menu using the panes and items in menu_items
1179 and returns the value selected from it.
1180 There are two versions of xmenu_show, one for Xt and one for Xlib.
1181 Both assume input is blocked by the caller. */
1183 /* F is the frame the menu is for.
1184 X and Y are the frame-relative specified position,
1185 relative to the inside upper left corner of the frame F.
1186 FOR_CLICK is true if this menu was invoked for a mouse click.
1187 KEYMAPS is true if this menu was specified with keymaps;
1188 in that case, we return a list containing the chosen item's value
1189 and perhaps also the pane's prefix.
1190 TITLE is the specified menu title.
1191 ERROR is a place to store an error message string in case of failure.
1192 (We return nil on failure, but the value doesn't actually matter.) */
1194 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1196 /* The item selected in the popup menu. */
1197 static Lisp_Object
*volatile menu_item_selection
;
1201 /* Used when position a popup menu. See menu_position_func and
1202 create_and_show_popup_menu below. */
1203 struct next_popup_x_y
1210 /* The menu position function to use if we are not putting a popup
1211 menu where the pointer is.
1212 MENU is the menu to pop up.
1213 X and Y shall on exit contain x/y where the menu shall pop up.
1214 PUSH_IN is not documented in the GTK manual.
1215 USER_DATA is any data passed in when calling gtk_menu_popup.
1216 Here it points to a struct next_popup_x_y where the coordinates
1217 to store in *X and *Y are as well as the frame for the popup.
1219 Here only X and Y are used. */
1221 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1223 struct next_popup_x_y
*data
= user_data
;
1225 struct x_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (data
->f
);
1226 int disp_width
= x_display_pixel_width (dpyinfo
);
1227 int disp_height
= x_display_pixel_height (dpyinfo
);
1232 /* Check if there is room for the menu. If not, adjust x/y so that
1233 the menu is fully visible. */
1234 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1235 if (data
->x
+ req
.width
> disp_width
)
1236 *x
-= data
->x
+ req
.width
- disp_width
;
1237 if (data
->y
+ req
.height
> disp_height
)
1238 *y
-= data
->y
+ req
.height
- disp_height
;
1242 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1244 xg_menu_item_cb_data
*cb_data
= client_data
;
1246 if (xg_crazy_callback_abort
) return;
1247 if (cb_data
) menu_item_selection
= cb_data
->call_data
;
1251 pop_down_menu (void *arg
)
1253 popup_activated_flag
= 0;
1255 gtk_widget_destroy (GTK_WIDGET (arg
));
1259 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1261 menu_item_selection will be set to the selection. */
1263 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1264 int x
, int y
, bool for_click
)
1268 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1269 struct next_popup_x_y popup_x_y
;
1270 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1271 bool use_pos_func
= ! for_click
;
1274 /* Always use position function for Gtk3. Otherwise menus may become
1275 too small to show anything. */
1279 eassert (FRAME_X_P (f
));
1281 xg_crazy_callback_abort
= 1;
1282 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1283 G_CALLBACK (popup_selection_callback
),
1284 G_CALLBACK (popup_deactivate_callback
),
1285 G_CALLBACK (menu_highlight_callback
));
1286 xg_crazy_callback_abort
= 0;
1290 /* Not invoked by a click. pop up at x/y. */
1291 pos_func
= menu_position_func
;
1293 /* Adjust coordinates to be root-window-relative. */
1294 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1295 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1301 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1306 for (i
= 0; i
< 5; i
++)
1307 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1309 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1313 /* Display the menu. */
1314 gtk_widget_show_all (menu
);
1316 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1317 FRAME_DISPLAY_INFO (f
)->last_user_time
);
1319 record_unwind_protect_ptr (pop_down_menu
, menu
);
1321 if (gtk_widget_get_mapped (menu
))
1323 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1324 two. show_help_echo uses this to detect popup menus. */
1325 popup_activated_flag
= 1;
1326 /* Process events that apply to the menu. */
1327 popup_widget_loop (1, menu
);
1330 unbind_to (specpdl_count
, Qnil
);
1332 /* Must reset this manually because the button release event is not passed
1333 to Emacs event loop. */
1334 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1337 #else /* not USE_GTK */
1339 /* We need a unique id for each widget handled by the Lucid Widget
1342 For the main windows, and popup menus, we use this counter,
1343 which we increment each time after use. This starts from 1<<16.
1345 For menu bars, we use numbers starting at 0, counted in
1346 next_menubar_widget_id. */
1347 LWLIB_ID widget_id_tick
;
1350 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1352 menu_item_selection
= client_data
;
1355 /* ARG is the LWLIB ID of the dialog box, represented
1356 as a Lisp object as (HIGHPART . LOWPART). */
1359 pop_down_menu (Lisp_Object arg
)
1361 LWLIB_ID id
= (XINT (XCAR (arg
)) << 4 * sizeof (LWLIB_ID
)
1362 | XINT (XCDR (arg
)));
1365 lw_destroy_all_widgets (id
);
1367 popup_activated_flag
= 0;
1370 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1372 menu_item_selection will be set to the selection. */
1374 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1375 int x
, int y
, bool for_click
)
1381 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1385 eassert (FRAME_X_P (f
));
1388 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1391 menu_id
= widget_id_tick
++;
1392 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1393 f
->output_data
.x
->widget
, 1, 0,
1394 popup_selection_callback
,
1395 popup_deactivate_callback
,
1396 menu_highlight_callback
);
1398 event
->type
= ButtonPress
;
1400 event
->send_event
= 0;
1401 event
->display
= FRAME_X_DISPLAY (f
);
1402 event
->time
= CurrentTime
;
1403 event
->root
= FRAME_DISPLAY_INFO (f
)->root_window
;
1404 event
->window
= event
->subwindow
= event
->root
;
1408 /* Adjust coordinates to be root-window-relative. */
1409 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1410 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1417 for (i
= 0; i
< 5; i
++)
1418 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1421 /* Don't allow any geometry request from the user. */
1422 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1423 XtSetValues (menu
, av
, ac
);
1425 /* Display the menu. */
1426 lw_popup_menu (menu
, &dummy
);
1427 popup_activated_flag
= 1;
1428 x_activate_timeout_atimer ();
1431 int fact
= 4 * sizeof (LWLIB_ID
);
1432 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1433 record_unwind_protect (pop_down_menu
,
1434 Fcons (make_number (menu_id
>> (fact
)),
1435 make_number (menu_id
& ~(-1 << (fact
)))));
1437 /* Process events that apply to the menu. */
1438 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), menu_id
, 1);
1440 unbind_to (specpdl_count
, Qnil
);
1444 #endif /* not USE_GTK */
1447 cleanup_widget_value_tree (void *arg
)
1449 free_menubar_widget_value_tree (arg
);
1453 xmenu_show (struct frame
*f
, int x
, int y
, bool for_click
, bool keymaps
,
1454 Lisp_Object title
, const char **error_name
)
1457 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1458 widget_value
**submenu_stack
1459 = alloca (menu_items_used
* sizeof *submenu_stack
);
1460 Lisp_Object
*subprefix_stack
1461 = alloca (menu_items_used
* sizeof *subprefix_stack
);
1462 int submenu_depth
= 0;
1466 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1468 eassert (FRAME_X_P (f
));
1472 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1474 *error_name
= "Empty menu";
1480 /* Create a tree of widget_value objects
1481 representing the panes and their items. */
1482 wv
= xmalloc_widget_value ();
1486 wv
->button_type
= BUTTON_TYPE_NONE
;
1491 /* Loop over all panes and items, filling in the tree. */
1493 while (i
< menu_items_used
)
1495 if (EQ (AREF (menu_items
, i
), Qnil
))
1497 submenu_stack
[submenu_depth
++] = save_wv
;
1503 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1506 save_wv
= submenu_stack
[--submenu_depth
];
1510 else if (EQ (AREF (menu_items
, i
), Qt
)
1511 && submenu_depth
!= 0)
1512 i
+= MENU_ITEMS_PANE_LENGTH
;
1513 /* Ignore a nil in the item list.
1514 It's meaningful only for dialog boxes. */
1515 else if (EQ (AREF (menu_items
, i
), Qquote
))
1517 else if (EQ (AREF (menu_items
, i
), Qt
))
1519 /* Create a new pane. */
1520 Lisp_Object pane_name
, prefix
;
1521 const char *pane_string
;
1523 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1524 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1526 #ifndef HAVE_MULTILINGUAL_MENU
1527 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1529 pane_name
= ENCODE_MENU_STRING (pane_name
);
1530 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1533 pane_string
= (NILP (pane_name
)
1534 ? "" : SSDATA (pane_name
));
1535 /* If there is just one top-level pane, put all its items directly
1536 under the top-level menu. */
1537 if (menu_items_n_panes
== 1)
1540 /* If the pane has a meaningful name,
1541 make the pane a top-level menu item
1542 with its items as a submenu beneath it. */
1543 if (!keymaps
&& strcmp (pane_string
, ""))
1545 wv
= xmalloc_widget_value ();
1549 first_wv
->contents
= wv
;
1550 wv
->name
= (char *) pane_string
;
1551 if (keymaps
&& !NILP (prefix
))
1555 wv
->button_type
= BUTTON_TYPE_NONE
;
1560 else if (first_pane
)
1566 i
+= MENU_ITEMS_PANE_LENGTH
;
1570 /* Create a new item within current pane. */
1571 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1572 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1573 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1574 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1575 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1576 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1577 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1578 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1580 #ifndef HAVE_MULTILINGUAL_MENU
1581 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1583 item_name
= ENCODE_MENU_STRING (item_name
);
1584 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1587 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1589 descrip
= ENCODE_MENU_STRING (descrip
);
1590 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1592 #endif /* not HAVE_MULTILINGUAL_MENU */
1594 wv
= xmalloc_widget_value ();
1598 save_wv
->contents
= wv
;
1599 wv
->name
= SSDATA (item_name
);
1600 if (!NILP (descrip
))
1601 wv
->key
= SSDATA (descrip
);
1603 /* If this item has a null value,
1604 make the call_data null so that it won't display a box
1605 when the mouse is on it. */
1606 wv
->call_data
= !NILP (def
) ? aref_addr (menu_items
, i
) : 0;
1607 wv
->enabled
= !NILP (enable
);
1610 wv
->button_type
= BUTTON_TYPE_NONE
;
1611 else if (EQ (type
, QCtoggle
))
1612 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1613 else if (EQ (type
, QCradio
))
1614 wv
->button_type
= BUTTON_TYPE_RADIO
;
1618 wv
->selected
= !NILP (selected
);
1620 if (! STRINGP (help
))
1627 i
+= MENU_ITEMS_ITEM_LENGTH
;
1631 /* Deal with the title, if it is non-nil. */
1634 widget_value
*wv_title
= xmalloc_widget_value ();
1635 widget_value
*wv_sep1
= xmalloc_widget_value ();
1636 widget_value
*wv_sep2
= xmalloc_widget_value ();
1638 wv_sep2
->name
= "--";
1639 wv_sep2
->next
= first_wv
->contents
;
1640 wv_sep2
->help
= Qnil
;
1642 wv_sep1
->name
= "--";
1643 wv_sep1
->next
= wv_sep2
;
1644 wv_sep1
->help
= Qnil
;
1646 #ifndef HAVE_MULTILINGUAL_MENU
1647 if (STRING_MULTIBYTE (title
))
1648 title
= ENCODE_MENU_STRING (title
);
1651 wv_title
->name
= SSDATA (title
);
1652 wv_title
->enabled
= true;
1653 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1654 wv_title
->help
= Qnil
;
1655 wv_title
->next
= wv_sep1
;
1656 first_wv
->contents
= wv_title
;
1659 /* No selection has been chosen yet. */
1660 menu_item_selection
= 0;
1662 /* Make sure to free the widget_value objects we used to specify the
1663 contents even with longjmp. */
1664 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1666 /* Actually create and show the menu until popped down. */
1667 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
);
1669 unbind_to (specpdl_count
, Qnil
);
1671 /* Find the selected item, and its pane, to return
1672 the proper value. */
1673 if (menu_item_selection
!= 0)
1675 Lisp_Object prefix
, entry
;
1677 prefix
= entry
= Qnil
;
1679 while (i
< menu_items_used
)
1681 if (EQ (AREF (menu_items
, i
), Qnil
))
1683 subprefix_stack
[submenu_depth
++] = prefix
;
1687 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1689 prefix
= subprefix_stack
[--submenu_depth
];
1692 else if (EQ (AREF (menu_items
, i
), Qt
))
1695 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1696 i
+= MENU_ITEMS_PANE_LENGTH
;
1698 /* Ignore a nil in the item list.
1699 It's meaningful only for dialog boxes. */
1700 else if (EQ (AREF (menu_items
, i
), Qquote
))
1705 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1706 if (menu_item_selection
== aref_addr (menu_items
, i
))
1712 entry
= list1 (entry
);
1714 entry
= Fcons (prefix
, entry
);
1715 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1716 if (!NILP (subprefix_stack
[j
]))
1717 entry
= Fcons (subprefix_stack
[j
], entry
);
1722 i
+= MENU_ITEMS_ITEM_LENGTH
;
1726 else if (!for_click
)
1729 /* Make "Cancel" equivalent to C-g. */
1730 Fsignal (Qquit
, Qnil
);
1739 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1741 /* Treat the pointer as an integer. There's no problem
1742 as long as pointers have enough bits to hold small integers. */
1743 if ((intptr_t) client_data
!= -1)
1744 menu_item_selection
= client_data
;
1746 popup_activated_flag
= 0;
1749 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1751 menu_item_selection will be set to the selection. */
1753 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1757 eassert (FRAME_X_P (f
));
1759 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1760 G_CALLBACK (dialog_selection_callback
),
1761 G_CALLBACK (popup_deactivate_callback
),
1766 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1767 record_unwind_protect_ptr (pop_down_menu
, menu
);
1769 /* Display the menu. */
1770 gtk_widget_show_all (menu
);
1772 /* Process events that apply to the menu. */
1773 popup_widget_loop (1, menu
);
1775 unbind_to (specpdl_count
, Qnil
);
1779 #else /* not USE_GTK */
1781 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1783 /* Treat the pointer as an integer. There's no problem
1784 as long as pointers have enough bits to hold small integers. */
1785 if ((intptr_t) client_data
!= -1)
1786 menu_item_selection
= client_data
;
1789 lw_destroy_all_widgets (id
);
1791 popup_activated_flag
= 0;
1795 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1797 menu_item_selection will be set to the selection. */
1799 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1803 eassert (FRAME_X_P (f
));
1805 dialog_id
= widget_id_tick
++;
1807 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1809 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1810 f
->output_data
.x
->widget
, 1, 0,
1811 dialog_selection_callback
, 0, 0);
1812 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1813 /* Display the dialog box. */
1814 lw_pop_up_all_widgets (dialog_id
);
1815 popup_activated_flag
= 1;
1816 x_activate_timeout_atimer ();
1818 /* Process events that apply to the dialog box.
1819 Also handle timers. */
1821 ptrdiff_t count
= SPECPDL_INDEX ();
1822 int fact
= 4 * sizeof (LWLIB_ID
);
1824 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1825 record_unwind_protect (pop_down_menu
,
1826 Fcons (make_number (dialog_id
>> (fact
)),
1827 make_number (dialog_id
& ~(-1 << (fact
)))));
1829 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), dialog_id
, 1);
1831 unbind_to (count
, Qnil
);
1835 #endif /* not USE_GTK */
1837 static const char * button_names
[] = {
1838 "button1", "button2", "button3", "button4", "button5",
1839 "button6", "button7", "button8", "button9", "button10" };
1842 xdialog_show (struct frame
*f
,
1846 const char **error_name
)
1848 int i
, nb_buttons
=0;
1849 char dialog_name
[6];
1851 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1853 /* Number of elements seen so far, before boundary. */
1855 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1856 int boundary_seen
= 0;
1858 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1860 eassert (FRAME_X_P (f
));
1864 if (menu_items_n_panes
> 1)
1866 *error_name
= "Multiple panes in dialog box";
1870 /* Create a tree of widget_value objects
1871 representing the text label and buttons. */
1873 Lisp_Object pane_name
, prefix
;
1874 const char *pane_string
;
1875 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1876 prefix
= AREF (menu_items
, MENU_ITEMS_PANE_PREFIX
);
1877 pane_string
= (NILP (pane_name
)
1878 ? "" : SSDATA (pane_name
));
1879 prev_wv
= xmalloc_widget_value ();
1880 prev_wv
->value
= (char *) pane_string
;
1881 if (keymaps
&& !NILP (prefix
))
1883 prev_wv
->enabled
= 1;
1884 prev_wv
->name
= "message";
1885 prev_wv
->help
= Qnil
;
1888 /* Loop over all panes and items, filling in the tree. */
1889 i
= MENU_ITEMS_PANE_LENGTH
;
1890 while (i
< menu_items_used
)
1893 /* Create a new item within current pane. */
1894 Lisp_Object item_name
, enable
, descrip
;
1895 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1896 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1898 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1900 if (NILP (item_name
))
1902 free_menubar_widget_value_tree (first_wv
);
1903 *error_name
= "Submenu in dialog items";
1906 if (EQ (item_name
, Qquote
))
1908 /* This is the boundary between left-side elts
1909 and right-side elts. Stop incrementing right_count. */
1914 if (nb_buttons
>= 9)
1916 free_menubar_widget_value_tree (first_wv
);
1917 *error_name
= "Too many dialog items";
1921 wv
= xmalloc_widget_value ();
1923 wv
->name
= (char *) button_names
[nb_buttons
];
1924 if (!NILP (descrip
))
1925 wv
->key
= SSDATA (descrip
);
1926 wv
->value
= SSDATA (item_name
);
1927 wv
->call_data
= aref_addr (menu_items
, i
);
1928 wv
->enabled
= !NILP (enable
);
1932 if (! boundary_seen
)
1936 i
+= MENU_ITEMS_ITEM_LENGTH
;
1939 /* If the boundary was not specified,
1940 by default put half on the left and half on the right. */
1941 if (! boundary_seen
)
1942 left_count
= nb_buttons
- nb_buttons
/ 2;
1944 wv
= xmalloc_widget_value ();
1945 wv
->name
= dialog_name
;
1948 /* Frame title: 'Q' = Question, 'I' = Information.
1949 Can also have 'E' = Error if, one day, we want
1950 a popup for errors. */
1952 dialog_name
[0] = 'Q';
1954 dialog_name
[0] = 'I';
1956 /* Dialog boxes use a really stupid name encoding
1957 which specifies how many buttons to use
1958 and how many buttons are on the right. */
1959 dialog_name
[1] = '0' + nb_buttons
;
1960 dialog_name
[2] = 'B';
1961 dialog_name
[3] = 'R';
1962 /* Number of buttons to put on the right. */
1963 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1965 wv
->contents
= first_wv
;
1969 /* No selection has been chosen yet. */
1970 menu_item_selection
= 0;
1972 /* Make sure to free the widget_value objects we used to specify the
1973 contents even with longjmp. */
1974 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1976 /* Actually create and show the dialog. */
1977 create_and_show_dialog (f
, first_wv
);
1979 unbind_to (specpdl_count
, Qnil
);
1981 /* Find the selected item, and its pane, to return
1982 the proper value. */
1983 if (menu_item_selection
!= 0)
1989 while (i
< menu_items_used
)
1993 if (EQ (AREF (menu_items
, i
), Qt
))
1996 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1997 i
+= MENU_ITEMS_PANE_LENGTH
;
1999 else if (EQ (AREF (menu_items
, i
), Qquote
))
2001 /* This is the boundary between left-side elts and
2008 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2009 if (menu_item_selection
== aref_addr (menu_items
, i
))
2013 entry
= list1 (entry
);
2015 entry
= Fcons (prefix
, entry
);
2019 i
+= MENU_ITEMS_ITEM_LENGTH
;
2024 /* Make "Cancel" equivalent to C-g. */
2025 Fsignal (Qquit
, Qnil
);
2031 xw_popup_dialog (struct frame
*f
, Lisp_Object header
, Lisp_Object contents
)
2034 const char *error_name
;
2035 Lisp_Object selection
;
2036 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2038 check_window_system (f
);
2040 /* Decode the dialog items from what was specified. */
2041 title
= Fcar (contents
);
2042 CHECK_STRING (title
);
2043 record_unwind_protect_void (unuse_menu_items
);
2045 if (NILP (Fcar (Fcdr (contents
))))
2046 /* No buttons specified, add an "Ok" button so users can pop down
2047 the dialog. Also, the lesstif/motif version crashes if there are
2049 contents
= list2 (title
, Fcons (build_string ("Ok"), Qt
));
2051 list_of_panes (list1 (contents
));
2053 /* Display them in a dialog box. */
2055 selection
= xdialog_show (f
, 0, title
, header
, &error_name
);
2058 unbind_to (specpdl_count
, Qnil
);
2059 discard_menu_items ();
2061 if (error_name
) error ("%s", error_name
);
2065 #else /* not USE_X_TOOLKIT && not USE_GTK */
2067 /* The frame of the last activated non-toolkit menu bar.
2068 Used to generate menu help events. */
2070 static struct frame
*menu_help_frame
;
2073 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2075 PANE is the pane number, and ITEM is the menu item number in
2076 the menu (currently not used).
2078 This cannot be done with generating a HELP_EVENT because
2079 XMenuActivate contains a loop that doesn't let Emacs process
2083 menu_help_callback (char const *help_string
, int pane
, int item
)
2085 Lisp_Object
*first_item
;
2086 Lisp_Object pane_name
;
2087 Lisp_Object menu_object
;
2089 first_item
= XVECTOR (menu_items
)->contents
;
2090 if (EQ (first_item
[0], Qt
))
2091 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2092 else if (EQ (first_item
[0], Qquote
))
2093 /* This shouldn't happen, see xmenu_show. */
2094 pane_name
= empty_unibyte_string
;
2096 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2098 /* (menu-item MENU-NAME PANE-NUMBER) */
2099 menu_object
= list3 (Qmenu_item
, pane_name
, make_number (pane
));
2100 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2101 Qnil
, menu_object
, make_number (item
));
2105 pop_down_menu (Lisp_Object arg
)
2107 struct frame
*f
= XSAVE_POINTER (arg
, 0);
2108 XMenu
*menu
= XSAVE_POINTER (arg
, 1);
2112 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2113 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2115 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2117 #ifdef HAVE_X_WINDOWS
2118 /* Assume the mouse has moved out of the X window.
2119 If it has actually moved in, we will get an EnterNotify. */
2120 x_mouse_leave (FRAME_DISPLAY_INFO (f
));
2122 /* State that no mouse buttons are now held.
2123 (The oldXMenu code doesn't track this info for us.)
2124 That is not necessarily true, but the fiction leads to reasonable
2125 results, and it is a pain to ask which are actually held now. */
2126 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
2128 #endif /* HAVE_X_WINDOWS */
2135 xmenu_show (struct frame
*f
, int x
, int y
, bool for_click
, bool keymaps
,
2136 Lisp_Object title
, const char **error_name
)
2140 int pane
, selidx
, lpane
, status
;
2141 Lisp_Object entry
, pane_prefix
;
2143 int ulx
, uly
, width
, height
;
2144 int dispwidth
, dispheight
;
2145 int i
, j
, lines
, maxlines
;
2148 unsigned int dummy_uint
;
2149 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2151 eassert (FRAME_X_P (f
) || FRAME_MSDOS_P (f
));
2154 if (menu_items_n_panes
== 0)
2157 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2159 *error_name
= "Empty menu";
2165 /* Figure out which root window F is on. */
2166 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2167 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2168 &dummy_uint
, &dummy_uint
);
2170 /* Make the menu on that window. */
2171 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2174 *error_name
= "Can't create menu";
2179 /* Don't GC while we prepare and show the menu,
2180 because we give the oldxmenu library pointers to the
2181 contents of strings. */
2182 inhibit_garbage_collection ();
2184 #ifdef HAVE_X_WINDOWS
2185 /* Adjust coordinates to relative to the outer (window manager) window. */
2186 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2187 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2188 #endif /* HAVE_X_WINDOWS */
2190 /* Adjust coordinates to be root-window-relative. */
2194 /* Create all the necessary panes and their items. */
2195 maxwidth
= maxlines
= lines
= i
= 0;
2197 while (i
< menu_items_used
)
2199 if (EQ (AREF (menu_items
, i
), Qt
))
2201 /* Create a new pane. */
2202 Lisp_Object pane_name
, prefix
;
2203 const char *pane_string
;
2205 maxlines
= max (maxlines
, lines
);
2207 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2208 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2209 pane_string
= (NILP (pane_name
)
2210 ? "" : SSDATA (pane_name
));
2211 if (keymaps
&& !NILP (prefix
))
2214 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, TRUE
);
2215 if (lpane
== XM_FAILURE
)
2217 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2218 *error_name
= "Can't create pane";
2222 i
+= MENU_ITEMS_PANE_LENGTH
;
2224 /* Find the width of the widest item in this pane. */
2226 while (j
< menu_items_used
)
2229 item
= AREF (menu_items
, j
);
2237 width
= SBYTES (item
);
2238 if (width
> maxwidth
)
2241 j
+= MENU_ITEMS_ITEM_LENGTH
;
2244 /* Ignore a nil in the item list.
2245 It's meaningful only for dialog boxes. */
2246 else if (EQ (AREF (menu_items
, i
), Qquote
))
2250 /* Create a new item within current pane. */
2251 Lisp_Object item_name
, enable
, descrip
, help
;
2253 char const *help_string
;
2255 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2256 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2258 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2259 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2260 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2262 if (!NILP (descrip
))
2264 /* if alloca is fast, use that to make the space,
2265 to reduce gc needs. */
2266 item_data
= alloca (maxwidth
+ SBYTES (descrip
) + 1);
2267 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2268 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2270 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2271 item_data
[j
+ SBYTES (descrip
)] = 0;
2274 item_data
= SSDATA (item_name
);
2276 if (lpane
== XM_FAILURE
2277 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2278 menu
, lpane
, 0, item_data
,
2279 !NILP (enable
), help_string
)
2282 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2283 *error_name
= "Can't add selection to menu";
2287 i
+= MENU_ITEMS_ITEM_LENGTH
;
2292 maxlines
= max (maxlines
, lines
);
2294 /* All set and ready to fly. */
2295 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2296 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2297 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2298 x
= min (x
, dispwidth
);
2299 y
= min (y
, dispheight
);
2302 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2303 &ulx
, &uly
, &width
, &height
);
2304 if (ulx
+width
> dispwidth
)
2306 x
-= (ulx
+ width
) - dispwidth
;
2307 ulx
= dispwidth
- width
;
2309 if (uly
+height
> dispheight
)
2311 y
-= (uly
+ height
) - dispheight
;
2312 uly
= dispheight
- height
;
2314 #ifndef HAVE_X_WINDOWS
2315 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2317 /* Move the menu away of the echo area, to avoid overwriting the
2318 menu with help echo messages or vice versa. */
2319 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2321 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2322 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2331 if (ulx
< 0) x
-= ulx
;
2332 if (uly
< 0) y
-= uly
;
2336 /* If position was not given by a mouse click, adjust so upper left
2337 corner of the menu as a whole ends up at given coordinates. This
2338 is what x-popup-menu says in its documentation. */
2340 y
+= 1.5*height
/(maxlines
+2);
2343 XMenuSetAEQ (menu
, TRUE
);
2344 XMenuSetFreeze (menu
, TRUE
);
2348 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2351 record_unwind_protect (pop_down_menu
, make_save_ptr_ptr (f
, menu
));
2353 /* Help display under X won't work because XMenuActivate contains
2354 a loop that doesn't give Emacs a chance to process it. */
2355 menu_help_frame
= f
;
2356 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2357 x
, y
, ButtonReleaseMask
, &datap
,
2358 menu_help_callback
);
2359 entry
= pane_prefix
= Qnil
;
2365 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2368 /* Find the item number SELIDX in pane number PANE. */
2370 while (i
< menu_items_used
)
2372 if (EQ (AREF (menu_items
, i
), Qt
))
2376 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2378 i
+= MENU_ITEMS_PANE_LENGTH
;
2387 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2390 entry
= list1 (entry
);
2391 if (!NILP (pane_prefix
))
2392 entry
= Fcons (pane_prefix
, entry
);
2398 i
+= MENU_ITEMS_ITEM_LENGTH
;
2404 *error_name
= "Can't activate menu";
2408 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2409 the menu was invoked with a mouse event as POSITION). */
2413 Fsignal (Qquit
, Qnil
);
2419 unbind_to (specpdl_count
, Qnil
);
2424 #endif /* not USE_X_TOOLKIT */
2427 /* Detect if a dialog or menu has been posted. MSDOS has its own
2428 implementation on msdos.c. */
2431 popup_activated (void)
2433 return popup_activated_flag
;
2435 #endif /* not MSDOS */
2437 /* The following is used by delayed window autoselection. */
2439 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2440 doc
: /* Return t if a menu or popup dialog is active. */)
2443 return (popup_activated ()) ? Qt
: Qnil
;
2447 syms_of_xmenu (void)
2449 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2451 #ifdef USE_X_TOOLKIT
2452 widget_id_tick
= (1<<16);
2453 next_menubar_widget_id
= 1;
2456 defsubr (&Smenu_or_popup_active_p
);
2458 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2459 defsubr (&Sx_menu_bar_open_internal
);
2460 Ffset (intern_c_string ("accelerate-menu"),
2461 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));