1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2019 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 (at
11 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 <https://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"
46 #include "sysselect.h"
53 /* This may include sys/types.h, and that somehow loses
54 if this is not done before the other system files. */
58 /* Load sys/types.h if not already loaded.
59 In some systems loading it twice is suicidal. */
61 #include <sys/types.h>
65 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
66 code accepts the Emacs internal encoding. */
67 #undef HAVE_MULTILINGUAL_MENU
71 #include <X11/IntrinsicP.h>
72 #include <X11/CoreP.h>
73 #include <X11/StringDefs.h>
74 #include <X11/Shell.h>
76 #include "xsettings.h"
77 #include "../lwlib/xlwmenu.h"
79 #include <X11/Xaw3d/Paned.h>
80 #else /* !HAVE_XAW3D */
81 #include <X11/Xaw/Paned.h>
82 #endif /* HAVE_XAW3D */
83 #endif /* USE_LUCID */
85 #include "../lwlib/lwlib.h"
87 #else /* not USE_X_TOOLKIT */
89 #include "../oldXMenu/XMenu.h"
91 #endif /* not USE_X_TOOLKIT */
92 #endif /* HAVE_X_WINDOWS */
104 /* Flag which when set indicates a dialog or menu has been posted by
105 Xt on behalf of one of the widget sets. */
106 static int popup_activated_flag
;
111 static LWLIB_ID next_menubar_widget_id
;
113 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
115 static struct frame
*
116 menubar_id_to_frame (LWLIB_ID id
)
118 Lisp_Object tail
, frame
;
121 FOR_EACH_FRAME (tail
, frame
)
124 if (!FRAME_WINDOW_P (f
))
126 if (f
->output_data
.x
->id
== id
)
136 #if defined USE_GTK || defined USE_MOTIF
138 /* Set menu_items_inuse so no other popup menu or dialog is created. */
141 x_menu_set_in_use (bool in_use
)
143 Lisp_Object frames
, frame
;
145 menu_items_inuse
= in_use
? Qt
: Qnil
;
146 popup_activated_flag
= in_use
;
148 if (popup_activated_flag
)
149 x_activate_timeout_atimer ();
152 /* Don't let frames in `above' z-group obscure popups. */
153 FOR_EACH_FRAME (frames
, frame
)
155 struct frame
*f
= XFRAME (frame
);
157 if (in_use
&& FRAME_Z_GROUP_ABOVE (f
))
158 x_set_z_group (f
, Qabove_suspended
, Qabove
);
159 else if (!in_use
&& FRAME_Z_GROUP_ABOVE_SUSPENDED (f
))
160 x_set_z_group (f
, Qabove
, Qabove_suspended
);
165 /* Wait for an X event to arrive or for a timer to expire. */
168 x_menu_wait_for_event (void *data
)
170 /* Another way to do this is to register a timer callback, that can be
171 done in GTK and Xt. But we have to do it like this when using only X
172 anyway, and with callbacks we would have three variants for timer handling
173 instead of the small ifdefs below. */
177 ! XtAppPending (Xt_app_con
)
178 #elif defined USE_GTK
179 ! gtk_events_pending ()
185 struct timespec next_time
= timer_check (), *ntp
;
187 struct x_display_info
*dpyinfo
;
191 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
193 int fd
= ConnectionNumber (dpyinfo
->display
);
194 FD_SET (fd
, &read_fds
);
196 XFlush (dpyinfo
->display
);
199 if (! timespec_valid_p (next_time
))
204 #if defined USE_GTK && defined HAVE_GTK3
205 /* Gtk3 have arrows on menus when they don't fit. When the
206 pointer is over an arrow, a timeout scrolls it a bit. Use
207 xg_select so that timeout gets triggered. */
208 xg_select (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
210 pselect (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
217 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
221 /* Loop in Xt until the menu pulldown or dialog popup has been
222 popped down (deactivated). This is used for x-popup-menu
223 and x-popup-dialog; it is not used for the menu bar.
225 NOTE: All calls to popup_get_selection should be protected
226 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
229 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
,
230 LWLIB_ID id
, bool do_timers
)
234 while (popup_activated_flag
)
238 event
= *initial_event
;
243 if (do_timers
) x_menu_wait_for_event (0);
244 XtAppNextEvent (Xt_app_con
, &event
);
247 /* Make sure we don't consider buttons grabbed after menu goes.
248 And make sure to deactivate for any ButtonRelease,
249 even if XtDispatchEvent doesn't do that. */
250 if (event
.type
== ButtonRelease
251 && dpyinfo
->display
== event
.xbutton
.display
)
253 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
254 #ifdef USE_MOTIF /* Pretending that the event came from a
255 Btn1Down seems the only way to convince Motif to
256 activate its callbacks; setting the XmNmenuPost
257 isn't working. --marcus@sysc.pdx.edu. */
258 event
.xbutton
.button
= 1;
259 /* Motif only pops down menus when no Ctrl, Alt or Mod
260 key is pressed and the button is released. So reset key state
261 so Motif thinks this is the case. */
262 event
.xbutton
.state
= 0;
265 /* Pop down on C-g and Escape. */
266 else if (event
.type
== KeyPress
267 && dpyinfo
->display
== event
.xbutton
.display
)
269 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
271 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
272 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
273 popup_activated_flag
= 0;
276 x_dispatch_event (&event
, event
.xany
.display
);
280 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
281 doc
: /* Start key navigation of the menu bar in FRAME.
282 This initially opens the first menu bar item and you can then navigate with the
283 arrow keys, select a menu entry with the return key or cancel with the
284 escape key. If FRAME has no menu bar this function does nothing.
286 If FRAME is nil or not given, use the selected frame. */)
290 struct frame
*f
= decode_window_system_frame (frame
);
294 if (FRAME_EXTERNAL_MENU_BAR (f
))
295 set_frame_menubar (f
, false, true);
297 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
301 bool error_p
= false;
303 x_catch_errors (FRAME_X_DISPLAY (f
));
304 memset (&ev
, 0, sizeof ev
);
305 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
306 ev
.xbutton
.window
= XtWindow (menubar
);
307 ev
.xbutton
.root
= FRAME_DISPLAY_INFO (f
)->root_window
;
308 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
309 ev
.xbutton
.button
= Button1
;
310 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
311 ev
.xbutton
.same_screen
= True
;
318 XtSetArg (al
[0], XtNchildren
, &list
);
319 XtSetArg (al
[1], XtNnumChildren
, &nr
);
320 XtGetValues (menubar
, al
, 2);
321 ev
.xbutton
.window
= XtWindow (list
[0]);
325 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
326 /* From-window, to-window. */
327 ev
.xbutton
.window
, ev
.xbutton
.root
,
329 /* From-position, to-position. */
330 ev
.xbutton
.x
, ev
.xbutton
.y
,
331 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
335 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
336 x_uncatch_errors_after_check ();
340 ev
.type
= ButtonPress
;
341 ev
.xbutton
.state
= 0;
343 XtDispatchEvent (&ev
);
344 ev
.xbutton
.type
= ButtonRelease
;
345 ev
.xbutton
.state
= Button1Mask
;
346 XtDispatchEvent (&ev
);
354 #endif /* USE_X_TOOLKIT */
358 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
359 doc
: /* Start key navigation of the menu bar in FRAME.
360 This initially opens the first menu bar item and you can then navigate with the
361 arrow keys, select a menu entry with the return key or cancel with the
362 escape key. If FRAME has no menu bar this function does nothing.
364 If FRAME is nil or not given, use the selected frame. */)
371 f
= decode_window_system_frame (frame
);
373 if (FRAME_EXTERNAL_MENU_BAR (f
))
374 set_frame_menubar (f
, false, true);
376 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
379 /* Activate the first menu. */
380 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
384 g_signal_emit_by_name (children
->data
, "activate_item");
385 popup_activated_flag
= 1;
386 g_list_free (children
);
394 /* Loop util popup_activated_flag is set to zero in a callback.
395 Used for popup menus and dialogs. */
398 popup_widget_loop (bool do_timers
, GtkWidget
*widget
)
400 ++popup_activated_flag
;
402 /* Process events in the Gtk event loop until done. */
403 while (popup_activated_flag
)
405 if (do_timers
) x_menu_wait_for_event (0);
406 gtk_main_iteration ();
411 /* Activate the menu bar of frame F.
412 This is called from keyboard.c when it gets the
413 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
415 To activate the menu bar, we use the X button-press event
416 that was saved in saved_menu_event.
417 That makes the toolkit do its thing.
419 But first we recompute the menu bar contents (the whole tree).
421 The reason for saving the button event until here, instead of
422 passing it to the toolkit right away, is that we can safely
423 execute Lisp code. */
426 x_activate_menubar (struct frame
*f
)
428 eassert (FRAME_X_P (f
));
430 if (!f
->output_data
.x
->saved_menu_event
->type
)
434 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
435 f
->output_data
.x
->saved_menu_event
->xany
.window
))
439 set_frame_menubar (f
, false, true);
441 popup_activated_flag
= 1;
443 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
444 f
->output_data
.x
->saved_menu_event
);
446 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
450 /* Ignore this if we get it a second time. */
451 f
->output_data
.x
->saved_menu_event
->type
= 0;
454 /* This callback is invoked when the user selects a menubar cascade
455 pushbutton, but before the pulldown menu is posted. */
459 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
461 popup_activated_flag
= 1;
462 x_activate_timeout_atimer ();
466 /* This callback is invoked when a dialog or menu is finished being
467 used and has been unposted. */
470 popup_deactivate_callback (
472 GtkWidget
*widget
, gpointer client_data
474 Widget widget
, LWLIB_ID id
, XtPointer client_data
478 popup_activated_flag
= 0;
482 /* Function that finds the frame for WIDGET and shows the HELP text
484 F is the frame if known, or NULL if not known. */
486 show_help_event (struct frame
*f
, xt_or_gtk_widget widget
, Lisp_Object help
)
492 XSETFRAME (frame
, f
);
493 kbd_buffer_store_help_event (frame
, help
);
496 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
499 /* Callback called when menu items are highlighted/unhighlighted
500 while moving the mouse over them. WIDGET is the menu bar or menu
501 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
502 the data structure for the menu item, or null in case of
507 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
509 xg_menu_item_cb_data
*cb_data
;
512 cb_data
= g_object_get_data (G_OBJECT (widget
), XG_ITEM_DATA
);
513 if (! cb_data
) return;
515 help
= call_data
? cb_data
->help
: Qnil
;
517 /* If popup_activated_flag is greater than 1 we are in a popup menu.
518 Don't pass the frame to show_help_event for those.
519 Passing frame creates an Emacs event. As we are looping in
520 popup_widget_loop, it won't be handled. Passing NULL shows the tip
521 directly without using an Emacs event. This is what the Lucid code
523 show_help_event (popup_activated_flag
<= 1 ? cb_data
->cl_data
->f
: NULL
,
528 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
530 widget_value
*wv
= call_data
;
531 Lisp_Object help
= wv
? wv
->help
: Qnil
;
533 /* Determine the frame for the help event. */
534 struct frame
*f
= menubar_id_to_frame (id
);
536 show_help_event (f
, widget
, help
);
541 /* Gtk calls callbacks just because we tell it what item should be
542 selected in a radio group. If this variable is set to a non-zero
543 value, we are creating menus and don't want callbacks right now.
545 static bool xg_crazy_callback_abort
;
547 /* This callback is called from the menu bar pulldown menu
548 when the user makes a selection.
549 Figure out what the user chose
550 and put the appropriate events into the keyboard buffer. */
552 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
554 xg_menu_item_cb_data
*cb_data
= client_data
;
556 if (xg_crazy_callback_abort
)
559 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
562 /* For a group of radio buttons, GTK calls the selection callback first
563 for the item that was active before the selection and then for the one that
564 is active after the selection. For C-h k this means we get the help on
565 the deselected item and then the selected item is executed. Prevent that
566 by ignoring the non-active item. */
567 if (GTK_IS_RADIO_MENU_ITEM (widget
)
568 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
571 /* When a menu is popped down, X generates a focus event (i.e. focus
572 goes back to the frame below the menu). Since GTK buffers events,
573 we force it out here before the menu selection event. Otherwise
574 sit-for will exit at once if the focus event follows the menu selection
578 while (gtk_events_pending ())
579 gtk_main_iteration ();
582 find_and_call_menu_selection (cb_data
->cl_data
->f
,
583 cb_data
->cl_data
->menu_bar_items_used
,
584 cb_data
->cl_data
->menu_bar_vector
,
588 #else /* not USE_GTK */
590 /* This callback is called from the menu bar pulldown menu
591 when the user makes a selection.
592 Figure out what the user chose
593 and put the appropriate events into the keyboard buffer. */
595 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
599 f
= menubar_id_to_frame (id
);
602 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
603 f
->menu_bar_vector
, client_data
);
605 #endif /* not USE_GTK */
607 /* Recompute all the widgets of frame F, when the menu bar has been
611 update_frame_menubar (struct frame
*f
)
614 xg_update_frame_menubar (f
);
618 eassert (FRAME_X_P (f
));
620 x
= f
->output_data
.x
;
622 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
627 /* Do the voodoo which means "I'm changing lots of things, don't try
628 to refigure sizes until I'm done." */
629 lw_refigure_widget (x
->column_widget
, False
);
631 /* The order in which children are managed is the top to bottom
632 order in which they are displayed in the paned window. First,
633 remove the text-area widget. */
634 XtUnmanageChild (x
->edit_widget
);
636 /* Remove the menubar that is there now, and put up the menubar that
638 XtManageChild (x
->menubar_widget
);
639 XtMapWidget (x
->menubar_widget
);
640 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
642 /* Re-manage the text-area widget, and then thrash the sizes. */
643 XtManageChild (x
->edit_widget
);
644 lw_refigure_widget (x
->column_widget
, True
);
646 /* Force the pane widget to resize itself. */
647 adjust_frame_size (f
, -1, -1, 2, false, Qupdate_frame_menubar
);
654 apply_systemfont_to_dialog (Widget w
)
656 const char *fn
= xsettings_get_system_normal_font ();
659 XrmDatabase db
= XtDatabase (XtDisplay (w
));
661 XrmPutStringResource (&db
, "*dialog.font", fn
);
666 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
668 const char *fn
= xsettings_get_system_normal_font ();
672 XrmDatabase db
= XtDatabase (XtDisplay (w
));
675 XrmPutStringResource (&db
, "*menubar*font", fn
);
676 XrmPutStringResource (&db
, "*popup*font", fn
);
683 /* Set the contents of the menubar widgets of frame F.
684 The argument FIRST_TIME is currently ignored;
685 it is set the first time this is called, from initialize_frame_menubar. */
688 set_frame_menubar (struct frame
*f
, bool first_time
, bool deep_p
)
690 xt_or_gtk_widget menubar_widget
, old_widget
;
695 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
697 int *submenu_start
, *submenu_end
;
698 bool *submenu_top_level_items
;
699 int *submenu_n_panes
;
701 eassert (FRAME_X_P (f
));
703 menubar_widget
= old_widget
= f
->output_data
.x
->menubar_widget
;
705 XSETFRAME (Vmenu_updating_frame
, f
);
708 if (f
->output_data
.x
->id
== 0)
709 f
->output_data
.x
->id
= next_menubar_widget_id
++;
710 id
= f
->output_data
.x
->id
;
713 if (! menubar_widget
)
715 /* Make the first call for any given frame always go deep. */
716 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
719 f
->output_data
.x
->saved_menu_event
= xmalloc (sizeof (XEvent
));
720 f
->output_data
.x
->saved_menu_event
->type
= 0;
725 /* Make a widget-value tree representing the entire menu trees. */
727 struct buffer
*prev
= current_buffer
;
729 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
730 int previous_menu_items_used
= f
->menu_bar_items_used
;
731 Lisp_Object
*previous_items
732 = alloca (previous_menu_items_used
* sizeof *previous_items
);
735 /* If we are making a new widget, its contents are empty,
736 do always reinitialize them. */
737 if (! menubar_widget
)
738 previous_menu_items_used
= 0;
740 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->contents
;
741 specbind (Qinhibit_quit
, Qt
);
742 /* Don't let the debugger step into this code
743 because it is not reentrant. */
744 specbind (Qdebug_on_next_call
, Qnil
);
746 record_unwind_save_match_data ();
747 if (NILP (Voverriding_local_map_menu_flag
))
749 specbind (Qoverriding_terminal_local_map
, Qnil
);
750 specbind (Qoverriding_local_map
, Qnil
);
753 set_buffer_internal_1 (XBUFFER (buffer
));
755 /* Run the Lucid hook. */
756 safe_run_hooks (Qactivate_menubar_hook
);
758 /* If it has changed current-menubar from previous value,
759 really recompute the menubar from the value. */
760 if (! NILP (Vlucid_menu_bar_dirty_flag
))
761 call0 (Qrecompute_lucid_menubar
);
762 safe_run_hooks (Qmenu_bar_update_hook
);
763 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
765 items
= FRAME_MENU_BAR_ITEMS (f
);
767 /* Save the frame's previous menu bar contents data. */
768 if (previous_menu_items_used
)
769 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
770 previous_menu_items_used
* word_size
);
772 /* Fill in menu_items with the current menu bar contents.
773 This can evaluate Lisp code. */
776 menu_items
= f
->menu_bar_vector
;
777 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
778 subitems
= ASIZE (items
) / 4;
779 submenu_start
= alloca ((subitems
+ 1) * sizeof *submenu_start
);
780 submenu_end
= alloca (subitems
* sizeof *submenu_end
);
781 submenu_n_panes
= alloca (subitems
* sizeof *submenu_n_panes
);
782 submenu_top_level_items
= alloca (subitems
783 * sizeof *submenu_top_level_items
);
785 for (i
= 0; i
< subitems
; i
++)
787 Lisp_Object key
, string
, maps
;
789 key
= AREF (items
, 4 * i
);
790 string
= AREF (items
, 4 * i
+ 1);
791 maps
= AREF (items
, 4 * i
+ 2);
795 submenu_start
[i
] = menu_items_used
;
797 menu_items_n_panes
= 0;
798 submenu_top_level_items
[i
]
799 = parse_single_submenu (key
, string
, maps
);
800 submenu_n_panes
[i
] = menu_items_n_panes
;
802 submenu_end
[i
] = menu_items_used
;
805 submenu_start
[i
] = -1;
806 finish_menu_items ();
808 /* Convert menu_items into widget_value trees
809 to display the menu. This cannot evaluate Lisp code. */
811 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
812 wv
->button_type
= BUTTON_TYPE_NONE
;
815 for (i
= 0; submenu_start
[i
] >= 0; i
++)
817 menu_items_n_panes
= submenu_n_panes
[i
];
818 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
819 submenu_top_level_items
[i
]);
823 first_wv
->contents
= wv
;
824 /* Don't set wv->name here; GC during the loop might relocate it. */
826 wv
->button_type
= BUTTON_TYPE_NONE
;
830 set_buffer_internal_1 (prev
);
832 /* If there has been no change in the Lisp-level contents
833 of the menu bar, skip redisplaying it. Just exit. */
835 /* Compare the new menu items with the ones computed last time. */
836 for (i
= 0; i
< previous_menu_items_used
; i
++)
837 if (menu_items_used
== i
838 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
840 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
842 /* The menu items have not changed. Don't bother updating
843 the menus in any form, since it would be a no-op. */
844 free_menubar_widget_value_tree (first_wv
);
845 discard_menu_items ();
846 unbind_to (specpdl_count
, Qnil
);
850 /* The menu items are different, so store them in the frame. */
851 fset_menu_bar_vector (f
, menu_items
);
852 f
->menu_bar_items_used
= menu_items_used
;
854 /* This undoes save_menu_items. */
855 unbind_to (specpdl_count
, Qnil
);
857 /* Now GC cannot happen during the lifetime of the widget_value,
858 so it's safe to store data from a Lisp_String. */
859 wv
= first_wv
->contents
;
860 for (i
= 0; i
< ASIZE (items
); i
+= 4)
863 string
= AREF (items
, i
+ 1);
866 wv
->name
= SSDATA (string
);
867 update_submenu_strings (wv
->contents
);
874 /* Make a widget-value tree containing
875 just the top level menu bar strings. */
877 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
878 wv
->button_type
= BUTTON_TYPE_NONE
;
881 items
= FRAME_MENU_BAR_ITEMS (f
);
882 for (i
= 0; i
< ASIZE (items
); i
+= 4)
886 string
= AREF (items
, i
+ 1);
890 wv
= make_widget_value (SSDATA (string
), NULL
, true, Qnil
);
891 wv
->button_type
= BUTTON_TYPE_NONE
;
892 /* This prevents lwlib from assuming this
893 menu item is really supposed to be empty. */
894 /* The intptr_t cast avoids a warning.
895 This value just has to be different from small integers. */
896 wv
->call_data
= (void *) (intptr_t) (-1);
901 first_wv
->contents
= wv
;
905 /* Forget what we thought we knew about what is in the
906 detailed contents of the menu bar menus.
907 Changing the top level always destroys the contents. */
908 f
->menu_bar_items_used
= 0;
911 /* Create or update the menu bar widget. */
916 xg_crazy_callback_abort
= true;
919 /* The fourth arg is DEEP_P, which says to consider the entire
920 menu trees we supply, rather than just the menu bar item names. */
921 xg_modify_menubar_widgets (menubar_widget
,
925 G_CALLBACK (menubar_selection_callback
),
926 G_CALLBACK (popup_deactivate_callback
),
927 G_CALLBACK (menu_highlight_callback
));
932 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
933 G_CALLBACK (menubar_selection_callback
),
934 G_CALLBACK (popup_deactivate_callback
),
935 G_CALLBACK (menu_highlight_callback
));
937 f
->output_data
.x
->menubar_widget
= menubar_widget
;
941 #else /* not USE_GTK */
944 /* Disable resizing (done for Motif!) */
945 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
947 /* The third arg is DEEP_P, which says to consider the entire
948 menu trees we supply, rather than just the menu bar item names. */
949 lw_modify_all_widgets (id
, first_wv
, deep_p
);
951 /* Re-enable the edit widget to resize. */
952 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
956 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
957 XtTranslations override
= XtParseTranslationTable (menuOverride
);
960 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
962 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
964 f
->output_data
.x
->column_widget
,
966 popup_activate_callback
,
967 menubar_selection_callback
,
968 popup_deactivate_callback
,
969 menu_highlight_callback
);
970 f
->output_data
.x
->menubar_widget
= menubar_widget
;
972 /* Make menu pop down on C-g. */
973 XtOverrideTranslations (menubar_widget
, override
);
978 if (f
->output_data
.x
->menubar_widget
)
979 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
982 = (f
->output_data
.x
->menubar_widget
983 ? (f
->output_data
.x
->menubar_widget
->core
.height
985 /* Damn me... With Lucid I get a core.border_width of 1
986 only the first time this is called and an ibw of 1 every
987 time this is called. So the first time this is called I
988 was off by one. Fix that here by never adding
989 core.border_width for Lucid. */
990 + f
->output_data
.x
->menubar_widget
->core
.border_width
991 #endif /* USE_LUCID */
996 /* Experimentally, we now get the right results
997 for -geometry -0-0 without this. 24 Aug 96, rms.
998 Maybe so, but the menu bar size is missing the pixels so the
999 WM size hints are off by these pixels. Jan D, oct 2009. */
1000 if (FRAME_EXTERNAL_MENU_BAR (f
))
1004 XtVaGetValues (f
->output_data
.x
->column_widget
,
1005 XtNinternalBorderWidth
, &ibw
, NULL
);
1006 menubar_size
+= ibw
;
1008 #endif /* USE_LUCID */
1010 FRAME_MENUBAR_HEIGHT (f
) = menubar_size
;
1012 #endif /* not USE_GTK */
1014 free_menubar_widget_value_tree (first_wv
);
1015 update_frame_menubar (f
);
1018 xg_crazy_callback_abort
= false;
1024 /* Called from Fx_create_frame to create the initial menubar of a frame
1025 before it is mapped, so that the window is mapped with the menubar already
1026 there instead of us tacking it on later and thrashing the window after it
1030 initialize_frame_menubar (struct frame
*f
)
1032 /* This function is called before the first chance to redisplay
1033 the frame. It has to be, so the frame will have the right size. */
1034 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
1035 set_frame_menubar (f
, true, true);
1039 /* Get rid of the menu bar of frame F, and free its storage.
1040 This is used when deleting a frame, and when turning off the menu bar.
1041 For GTK this function is in gtkutil.c. */
1045 free_frame_menubar (struct frame
*f
)
1047 Widget menubar_widget
;
1049 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1050 If we want to preserve the old height, calculate it now so we can
1051 restore it below. */
1052 int old_height
= FRAME_TEXT_HEIGHT (f
) + FRAME_MENUBAR_HEIGHT (f
);
1055 eassert (FRAME_X_P (f
));
1057 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1059 FRAME_MENUBAR_HEIGHT (f
) = 0;
1064 /* Removing the menu bar magically changes the shell widget's x
1065 and y position of (0, 0) which, when the menu bar is turned
1066 on again, leads to pull-down menus appearing in strange
1067 positions near the upper-left corner of the display. This
1068 happens only with some window managers like twm and ctwm,
1069 but not with other like Motif's mwm or kwm, because the
1070 latter generate ConfigureNotify events when the menu bar
1071 is switched off, which fixes the shell position. */
1072 Position x0
, y0
, x1
, y1
;
1078 if (f
->output_data
.x
->widget
)
1079 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1082 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1083 f
->output_data
.x
->menubar_widget
= NULL
;
1085 if (f
->output_data
.x
->widget
)
1088 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1089 if (x1
== 0 && y1
== 0)
1090 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1091 if (frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1092 adjust_frame_size (f
, -1, old_height
, 1, false, Qfree_frame_menubar_1
);
1094 adjust_frame_size (f
, -1, -1, 2, false, Qfree_frame_menubar_1
);
1096 adjust_frame_size (f
, -1, -1, 2, false, Qfree_frame_menubar_1
);
1097 #endif /* USE_MOTIF */
1102 if (WINDOWP (FRAME_ROOT_WINDOW (f
))
1103 && frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1104 adjust_frame_size (f
, -1, old_height
, 1, false, Qfree_frame_menubar_2
);
1111 #endif /* not USE_GTK */
1113 #endif /* USE_X_TOOLKIT || USE_GTK */
1115 /* x_menu_show actually displays a menu using the panes and items in menu_items
1116 and returns the value selected from it.
1117 There are two versions of x_menu_show, one for Xt and one for Xlib.
1118 Both assume input is blocked by the caller. */
1120 /* F is the frame the menu is for.
1121 X and Y are the frame-relative specified position,
1122 relative to the inside upper left corner of the frame F.
1123 Bitfield MENUFLAGS bits are:
1124 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1125 MENU_KEYMAPS is set if this menu was specified with keymaps;
1126 in that case, we return a list containing the chosen item's value
1127 and perhaps also the pane's prefix.
1128 TITLE is the specified menu title.
1129 ERROR is a place to store an error message string in case of failure.
1130 (We return nil on failure, but the value doesn't actually matter.) */
1132 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1134 /* The item selected in the popup menu. */
1135 static Lisp_Object
*volatile menu_item_selection
;
1139 /* Used when position a popup menu. See menu_position_func and
1140 create_and_show_popup_menu below. */
1141 struct next_popup_x_y
1148 /* The menu position function to use if we are not putting a popup
1149 menu where the pointer is.
1150 MENU is the menu to pop up.
1151 X and Y shall on exit contain x/y where the menu shall pop up.
1152 PUSH_IN is not documented in the GTK manual.
1153 USER_DATA is any data passed in when calling gtk_menu_popup.
1154 Here it points to a struct next_popup_x_y where the coordinates
1155 to store in *X and *Y are as well as the frame for the popup.
1157 Here only X and Y are used. */
1159 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1161 struct next_popup_x_y
*data
= user_data
;
1169 Lisp_Object frame
, workarea
;
1171 XSETFRAME (frame
, data
->f
);
1174 scale
= xg_get_scale (data
->f
);
1176 /* TODO: Get the monitor workarea directly without calculating other
1177 items in x-display-monitor-attributes-list. */
1178 workarea
= call3 (Qframe_monitor_workarea
,
1180 make_number (data
->x
),
1181 make_number (data
->y
));
1183 if (CONSP (workarea
))
1187 min_x
= XINT (XCAR (workarea
));
1188 min_y
= XINT (Fnth (make_number (1), workarea
));
1189 max_x
= min_x
+ XINT (Fnth (make_number (2), workarea
));
1190 max_y
= min_y
+ XINT (Fnth (make_number (3), workarea
));
1193 if (max_x
< 0 || max_y
< 0)
1195 struct x_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (data
->f
);
1197 max_x
= x_display_pixel_width (dpyinfo
);
1198 max_y
= x_display_pixel_height (dpyinfo
);
1201 /* frame-monitor-workarea and {x,y}_display_pixel_width/height all
1202 return device pixels, but GTK wants scaled pixels. The positions
1203 passed in via data were already scaled for us. */
1211 /* Check if there is room for the menu. If not, adjust x/y so that
1212 the menu is fully visible. gtk_widget_get_preferred_size returns
1213 scaled pixels, so there is no need to apply the scaling
1215 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1216 if (data
->x
+ req
.width
> max_x
)
1217 *x
-= data
->x
+ req
.width
- max_x
;
1218 if (data
->y
+ req
.height
> max_y
)
1219 *y
-= data
->y
+ req
.height
- max_y
;
1223 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1225 xg_menu_item_cb_data
*cb_data
= client_data
;
1227 if (xg_crazy_callback_abort
) return;
1228 if (cb_data
) menu_item_selection
= cb_data
->call_data
;
1232 pop_down_menu (void *arg
)
1234 popup_activated_flag
= 0;
1236 gtk_widget_destroy (GTK_WIDGET (arg
));
1240 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1242 menu_item_selection will be set to the selection. */
1244 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1245 int x
, int y
, bool for_click
)
1249 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1250 struct next_popup_x_y popup_x_y
;
1251 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1252 bool use_pos_func
= ! for_click
;
1255 /* Always use position function for Gtk3. Otherwise menus may become
1256 too small to show anything. */
1257 use_pos_func
= true;
1260 eassert (FRAME_X_P (f
));
1262 xg_crazy_callback_abort
= true;
1263 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1264 G_CALLBACK (popup_selection_callback
),
1265 G_CALLBACK (popup_deactivate_callback
),
1266 G_CALLBACK (menu_highlight_callback
));
1267 xg_crazy_callback_abort
= false;
1271 Window dummy_window
;
1273 /* Not invoked by a click. pop up at x/y. */
1274 pos_func
= menu_position_func
;
1276 /* Adjust coordinates to be root-window-relative. */
1278 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
1280 /* From-window, to-window. */
1282 FRAME_DISPLAY_INFO (f
)->root_window
,
1284 /* From-position, to-position. */
1290 /* Use window scaling factor to adjust position for hidpi screens. */
1291 x
/= xg_get_scale (f
);
1292 y
/= xg_get_scale (f
);
1299 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1304 for (i
= 0; i
< 5; i
++)
1305 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1307 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1311 /* Display the menu. */
1312 gtk_widget_show_all (menu
);
1314 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1315 FRAME_DISPLAY_INFO (f
)->last_user_time
);
1317 record_unwind_protect_ptr (pop_down_menu
, menu
);
1319 if (gtk_widget_get_mapped (menu
))
1321 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1322 two. show_help_echo uses this to detect popup menus. */
1323 popup_activated_flag
= 1;
1324 /* Process events that apply to the menu. */
1325 popup_widget_loop (true, menu
);
1328 unbind_to (specpdl_count
, Qnil
);
1330 /* Must reset this manually because the button release event is not passed
1331 to Emacs event loop. */
1332 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1335 #else /* not USE_GTK */
1337 /* We need a unique id for each widget handled by the Lucid Widget
1340 For the main windows, and popup menus, we use this counter, which we
1341 increment each time after use. This starts from WIDGET_ID_TICK_START.
1343 For menu bars, we use numbers starting at 0, counted in
1344 next_menubar_widget_id. */
1345 LWLIB_ID widget_id_tick
;
1348 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1350 menu_item_selection
= client_data
;
1353 /* ID is the LWLIB ID of the dialog box. */
1356 pop_down_menu (int id
)
1359 lw_destroy_all_widgets ((LWLIB_ID
) id
);
1361 popup_activated_flag
= 0;
1364 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1366 menu_item_selection will be set to the selection. */
1368 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1369 int x
, int y
, bool for_click
)
1375 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1378 Window dummy_window
;
1380 eassert (FRAME_X_P (f
));
1383 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1386 menu_id
= widget_id_tick
++;
1387 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1388 f
->output_data
.x
->widget
, true, 0,
1389 popup_selection_callback
,
1390 popup_deactivate_callback
,
1391 menu_highlight_callback
);
1393 event
->type
= ButtonPress
;
1395 event
->send_event
= false;
1396 event
->display
= FRAME_X_DISPLAY (f
);
1397 event
->time
= CurrentTime
;
1398 event
->root
= FRAME_DISPLAY_INFO (f
)->root_window
;
1399 event
->window
= event
->subwindow
= event
->root
;
1403 /* Adjust coordinates to be root-window-relative. */
1405 x
+= FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f
);
1406 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
1408 /* From-window, to-window. */
1410 FRAME_DISPLAY_INFO (f
)->root_window
,
1412 /* From-position, to-position. */
1424 for (i
= 0; i
< 5; i
++)
1425 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1428 /* Don't allow any geometry request from the user. */
1429 XtSetArg (av
[ac
], (char *) XtNgeometry
, 0); ac
++;
1430 XtSetValues (menu
, av
, ac
);
1432 /* Display the menu. */
1433 lw_popup_menu (menu
, &dummy
);
1434 popup_activated_flag
= 1;
1435 x_activate_timeout_atimer ();
1438 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1440 record_unwind_protect_int (pop_down_menu
, (int) menu_id
);
1442 /* Process events that apply to the menu. */
1443 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), menu_id
, true);
1445 unbind_to (specpdl_count
, Qnil
);
1449 #endif /* not USE_GTK */
1452 cleanup_widget_value_tree (void *arg
)
1454 free_menubar_widget_value_tree (arg
);
1458 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
1459 Lisp_Object title
, const char **error_name
)
1462 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1463 widget_value
**submenu_stack
1464 = alloca (menu_items_used
* sizeof *submenu_stack
);
1465 Lisp_Object
*subprefix_stack
1466 = alloca (menu_items_used
* sizeof *subprefix_stack
);
1467 int submenu_depth
= 0;
1469 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1471 eassert (FRAME_X_P (f
));
1475 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1477 *error_name
= "Empty menu";
1483 /* Create a tree of widget_value objects
1484 representing the panes and their items. */
1485 wv
= make_widget_value ("menu", NULL
, true, Qnil
);
1486 wv
->button_type
= BUTTON_TYPE_NONE
;
1488 bool first_pane
= true;
1490 /* Loop over all panes and items, filling in the tree. */
1492 while (i
< menu_items_used
)
1494 if (EQ (AREF (menu_items
, i
), Qnil
))
1496 submenu_stack
[submenu_depth
++] = save_wv
;
1502 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1505 save_wv
= submenu_stack
[--submenu_depth
];
1509 else if (EQ (AREF (menu_items
, i
), Qt
)
1510 && submenu_depth
!= 0)
1511 i
+= MENU_ITEMS_PANE_LENGTH
;
1512 /* Ignore a nil in the item list.
1513 It's meaningful only for dialog boxes. */
1514 else if (EQ (AREF (menu_items
, i
), Qquote
))
1516 else if (EQ (AREF (menu_items
, i
), Qt
))
1518 /* Create a new pane. */
1519 Lisp_Object pane_name
, prefix
;
1520 const char *pane_string
;
1522 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1523 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1525 #ifndef HAVE_MULTILINGUAL_MENU
1526 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1528 pane_name
= ENCODE_MENU_STRING (pane_name
);
1529 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1532 pane_string
= (NILP (pane_name
)
1533 ? "" : SSDATA (pane_name
));
1534 /* If there is just one top-level pane, put all its items directly
1535 under the top-level menu. */
1536 if (menu_items_n_panes
== 1)
1539 /* If the pane has a meaningful name,
1540 make the pane a top-level menu item
1541 with its items as a submenu beneath it. */
1542 if (!(menuflags
& MENU_KEYMAPS
) && strcmp (pane_string
, ""))
1544 wv
= make_widget_value (pane_string
, NULL
, true, Qnil
);
1548 first_wv
->contents
= wv
;
1549 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
1551 wv
->button_type
= BUTTON_TYPE_NONE
;
1555 else if (first_pane
)
1561 i
+= MENU_ITEMS_PANE_LENGTH
;
1565 /* Create a new item within current pane. */
1566 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1567 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1568 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1569 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1570 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1571 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1572 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1573 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1575 #ifndef HAVE_MULTILINGUAL_MENU
1576 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1578 item_name
= ENCODE_MENU_STRING (item_name
);
1579 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1582 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1584 descrip
= ENCODE_MENU_STRING (descrip
);
1585 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1587 #endif /* not HAVE_MULTILINGUAL_MENU */
1589 wv
= make_widget_value (SSDATA (item_name
), NULL
, !NILP (enable
),
1590 STRINGP (help
) ? help
: Qnil
);
1594 save_wv
->contents
= wv
;
1595 if (!NILP (descrip
))
1596 wv
->key
= SSDATA (descrip
);
1597 /* If this item has a null value,
1598 make the call_data null so that it won't display a box
1599 when the mouse is on it. */
1600 wv
->call_data
= !NILP (def
) ? aref_addr (menu_items
, i
) : 0;
1603 wv
->button_type
= BUTTON_TYPE_NONE
;
1604 else if (EQ (type
, QCtoggle
))
1605 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1606 else if (EQ (type
, QCradio
))
1607 wv
->button_type
= BUTTON_TYPE_RADIO
;
1611 wv
->selected
= !NILP (selected
);
1615 i
+= MENU_ITEMS_ITEM_LENGTH
;
1619 /* Deal with the title, if it is non-nil. */
1622 widget_value
*wv_title
;
1623 widget_value
*wv_sep1
= make_widget_value ("--", NULL
, false, Qnil
);
1624 widget_value
*wv_sep2
= make_widget_value ("--", NULL
, false, Qnil
);
1626 wv_sep2
->next
= first_wv
->contents
;
1627 wv_sep1
->next
= wv_sep2
;
1629 #ifndef HAVE_MULTILINGUAL_MENU
1630 if (STRING_MULTIBYTE (title
))
1631 title
= ENCODE_MENU_STRING (title
);
1634 wv_title
= make_widget_value (SSDATA (title
), NULL
, true, Qnil
);
1635 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1636 wv_title
->next
= wv_sep1
;
1637 first_wv
->contents
= wv_title
;
1640 /* No selection has been chosen yet. */
1641 menu_item_selection
= 0;
1643 /* Make sure to free the widget_value objects we used to specify the
1644 contents even with longjmp. */
1645 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1647 /* Actually create and show the menu until popped down. */
1648 create_and_show_popup_menu (f
, first_wv
, x
, y
,
1649 menuflags
& MENU_FOR_CLICK
);
1651 unbind_to (specpdl_count
, Qnil
);
1653 /* Find the selected item, and its pane, to return
1654 the proper value. */
1655 if (menu_item_selection
!= 0)
1657 Lisp_Object prefix
, entry
;
1659 prefix
= entry
= Qnil
;
1661 while (i
< menu_items_used
)
1663 if (EQ (AREF (menu_items
, i
), Qnil
))
1665 subprefix_stack
[submenu_depth
++] = prefix
;
1669 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1671 prefix
= subprefix_stack
[--submenu_depth
];
1674 else if (EQ (AREF (menu_items
, i
), Qt
))
1677 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1678 i
+= MENU_ITEMS_PANE_LENGTH
;
1680 /* Ignore a nil in the item list.
1681 It's meaningful only for dialog boxes. */
1682 else if (EQ (AREF (menu_items
, i
), Qquote
))
1687 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1688 if (menu_item_selection
== aref_addr (menu_items
, i
))
1690 if (menuflags
& MENU_KEYMAPS
)
1694 entry
= list1 (entry
);
1696 entry
= Fcons (prefix
, entry
);
1697 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1698 if (!NILP (subprefix_stack
[j
]))
1699 entry
= Fcons (subprefix_stack
[j
], entry
);
1704 i
+= MENU_ITEMS_ITEM_LENGTH
;
1708 else if (!(menuflags
& MENU_FOR_CLICK
))
1711 /* Make "Cancel" equivalent to C-g. */
1721 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1723 /* Treat the pointer as an integer. There's no problem
1724 as long as pointers have enough bits to hold small integers. */
1725 if ((intptr_t) client_data
!= -1)
1726 menu_item_selection
= client_data
;
1728 popup_activated_flag
= 0;
1731 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1733 menu_item_selection will be set to the selection. */
1735 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1739 eassert (FRAME_X_P (f
));
1741 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1742 G_CALLBACK (dialog_selection_callback
),
1743 G_CALLBACK (popup_deactivate_callback
),
1748 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1749 record_unwind_protect_ptr (pop_down_menu
, menu
);
1751 /* Display the menu. */
1752 gtk_widget_show_all (menu
);
1754 /* Process events that apply to the menu. */
1755 popup_widget_loop (true, menu
);
1757 unbind_to (specpdl_count
, Qnil
);
1761 #else /* not USE_GTK */
1763 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1765 /* Treat the pointer as an integer. There's no problem
1766 as long as pointers have enough bits to hold small integers. */
1767 if ((intptr_t) client_data
!= -1)
1768 menu_item_selection
= client_data
;
1771 lw_destroy_all_widgets (id
);
1773 popup_activated_flag
= 0;
1777 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1779 menu_item_selection will be set to the selection. */
1781 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1785 eassert (FRAME_X_P (f
));
1787 dialog_id
= widget_id_tick
++;
1789 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1791 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1792 f
->output_data
.x
->widget
, true, 0,
1793 dialog_selection_callback
, 0, 0);
1794 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1795 /* Display the dialog box. */
1796 lw_pop_up_all_widgets (dialog_id
);
1797 popup_activated_flag
= 1;
1798 x_activate_timeout_atimer ();
1800 /* Process events that apply to the dialog box.
1801 Also handle timers. */
1803 ptrdiff_t count
= SPECPDL_INDEX ();
1805 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1807 record_unwind_protect_int (pop_down_menu
, (int) dialog_id
);
1809 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), dialog_id
, true);
1811 unbind_to (count
, Qnil
);
1815 #endif /* not USE_GTK */
1817 static const char * button_names
[] = {
1818 "button1", "button2", "button3", "button4", "button5",
1819 "button6", "button7", "button8", "button9", "button10" };
1822 x_dialog_show (struct frame
*f
, Lisp_Object title
,
1823 Lisp_Object header
, const char **error_name
)
1825 int i
, nb_buttons
=0;
1826 char dialog_name
[6];
1828 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1830 /* Number of elements seen so far, before boundary. */
1832 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1833 bool boundary_seen
= false;
1835 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1837 eassert (FRAME_X_P (f
));
1841 if (menu_items_n_panes
> 1)
1843 *error_name
= "Multiple panes in dialog box";
1847 /* Create a tree of widget_value objects
1848 representing the text label and buttons. */
1850 Lisp_Object pane_name
;
1851 const char *pane_string
;
1852 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1853 pane_string
= (NILP (pane_name
)
1854 ? "" : SSDATA (pane_name
));
1855 prev_wv
= make_widget_value ("message", (char *) pane_string
, true, Qnil
);
1858 /* Loop over all panes and items, filling in the tree. */
1859 i
= MENU_ITEMS_PANE_LENGTH
;
1860 while (i
< menu_items_used
)
1863 /* Create a new item within current pane. */
1864 Lisp_Object item_name
, enable
, descrip
;
1865 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1866 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1868 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1870 if (NILP (item_name
))
1872 free_menubar_widget_value_tree (first_wv
);
1873 *error_name
= "Submenu in dialog items";
1876 if (EQ (item_name
, Qquote
))
1878 /* This is the boundary between left-side elts
1879 and right-side elts. Stop incrementing right_count. */
1880 boundary_seen
= true;
1884 if (nb_buttons
>= 9)
1886 free_menubar_widget_value_tree (first_wv
);
1887 *error_name
= "Too many dialog items";
1891 wv
= make_widget_value (button_names
[nb_buttons
],
1893 !NILP (enable
), Qnil
);
1895 if (!NILP (descrip
))
1896 wv
->key
= SSDATA (descrip
);
1897 wv
->call_data
= aref_addr (menu_items
, i
);
1900 if (! boundary_seen
)
1904 i
+= MENU_ITEMS_ITEM_LENGTH
;
1907 /* If the boundary was not specified,
1908 by default put half on the left and half on the right. */
1909 if (! boundary_seen
)
1910 left_count
= nb_buttons
- nb_buttons
/ 2;
1912 wv
= make_widget_value (dialog_name
, NULL
, false, Qnil
);
1914 /* Frame title: 'Q' = Question, 'I' = Information.
1915 Can also have 'E' = Error if, one day, we want
1916 a popup for errors. */
1918 dialog_name
[0] = 'Q';
1920 dialog_name
[0] = 'I';
1922 /* Dialog boxes use a really stupid name encoding
1923 which specifies how many buttons to use
1924 and how many buttons are on the right. */
1925 dialog_name
[1] = '0' + nb_buttons
;
1926 dialog_name
[2] = 'B';
1927 dialog_name
[3] = 'R';
1928 /* Number of buttons to put on the right. */
1929 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1931 wv
->contents
= first_wv
;
1935 /* No selection has been chosen yet. */
1936 menu_item_selection
= 0;
1938 /* Make sure to free the widget_value objects we used to specify the
1939 contents even with longjmp. */
1940 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1942 /* Actually create and show the dialog. */
1943 create_and_show_dialog (f
, first_wv
);
1945 unbind_to (specpdl_count
, Qnil
);
1947 /* Find the selected item, and its pane, to return
1948 the proper value. */
1949 if (menu_item_selection
!= 0)
1952 while (i
< menu_items_used
)
1956 if (EQ (AREF (menu_items
, i
), Qt
))
1957 i
+= MENU_ITEMS_PANE_LENGTH
;
1958 else if (EQ (AREF (menu_items
, i
), Qquote
))
1960 /* This is the boundary between left-side elts and
1967 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1968 if (menu_item_selection
== aref_addr (menu_items
, i
))
1970 i
+= MENU_ITEMS_ITEM_LENGTH
;
1975 /* Make "Cancel" equivalent to C-g. */
1982 xw_popup_dialog (struct frame
*f
, Lisp_Object header
, Lisp_Object contents
)
1985 const char *error_name
;
1986 Lisp_Object selection
;
1987 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1989 check_window_system (f
);
1991 /* Decode the dialog items from what was specified. */
1992 title
= Fcar (contents
);
1993 CHECK_STRING (title
);
1994 record_unwind_protect_void (unuse_menu_items
);
1996 if (NILP (Fcar (Fcdr (contents
))))
1997 /* No buttons specified, add an "Ok" button so users can pop down
1998 the dialog. Also, the lesstif/motif version crashes if there are
2000 contents
= list2 (title
, Fcons (build_string ("Ok"), Qt
));
2002 list_of_panes (list1 (contents
));
2004 /* Display them in a dialog box. */
2006 selection
= x_dialog_show (f
, title
, header
, &error_name
);
2009 unbind_to (specpdl_count
, Qnil
);
2010 discard_menu_items ();
2012 if (error_name
) error ("%s", error_name
);
2016 #else /* not USE_X_TOOLKIT && not USE_GTK */
2018 /* The frame of the last activated non-toolkit menu bar.
2019 Used to generate menu help events. */
2021 static struct frame
*menu_help_frame
;
2024 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2026 PANE is the pane number, and ITEM is the menu item number in
2027 the menu (currently not used).
2029 This cannot be done with generating a HELP_EVENT because
2030 XMenuActivate contains a loop that doesn't let Emacs process
2034 menu_help_callback (char const *help_string
, int pane
, int item
)
2036 Lisp_Object
*first_item
;
2037 Lisp_Object pane_name
;
2038 Lisp_Object menu_object
;
2040 first_item
= XVECTOR (menu_items
)->contents
;
2041 if (EQ (first_item
[0], Qt
))
2042 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2043 else if (EQ (first_item
[0], Qquote
))
2044 /* This shouldn't happen, see x_menu_show. */
2045 pane_name
= empty_unibyte_string
;
2047 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2049 /* (menu-item MENU-NAME PANE-NUMBER) */
2050 menu_object
= list3 (Qmenu_item
, pane_name
, make_number (pane
));
2051 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2052 Qnil
, menu_object
, make_number (item
));
2056 pop_down_menu (Lisp_Object arg
)
2058 struct frame
*f
= XSAVE_POINTER (arg
, 0);
2059 XMenu
*menu
= XSAVE_POINTER (arg
, 1);
2063 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2064 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2066 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2068 #ifdef HAVE_X_WINDOWS
2069 /* Assume the mouse has moved out of the X window.
2070 If it has actually moved in, we will get an EnterNotify. */
2071 x_mouse_leave (FRAME_DISPLAY_INFO (f
));
2073 /* State that no mouse buttons are now held.
2074 (The oldXMenu code doesn't track this info for us.)
2075 That is not necessarily true, but the fiction leads to reasonable
2076 results, and it is a pain to ask which are actually held now. */
2077 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
2079 #endif /* HAVE_X_WINDOWS */
2086 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
2087 Lisp_Object title
, const char **error_name
)
2091 int pane
, selidx
, lpane
, status
;
2092 Lisp_Object entry
= Qnil
;
2093 Lisp_Object pane_prefix
;
2095 int ulx
, uly
, width
, height
;
2096 int dispwidth
, dispheight
;
2097 int i
, j
, lines
, maxlines
;
2100 unsigned int dummy_uint
;
2101 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2103 eassert (FRAME_X_P (f
) || FRAME_MSDOS_P (f
));
2106 if (menu_items_n_panes
== 0)
2109 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2111 *error_name
= "Empty menu";
2118 /* Figure out which root window F is on. */
2119 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2120 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2121 &dummy_uint
, &dummy_uint
);
2123 /* Make the menu on that window. */
2124 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2127 *error_name
= "Can't create menu";
2131 /* Don't GC while we prepare and show the menu,
2132 because we give the oldxmenu library pointers to the
2133 contents of strings. */
2134 inhibit_garbage_collection ();
2136 #ifdef HAVE_X_WINDOWS
2138 /* Adjust coordinates to relative to the outer (window manager) window. */
2139 int left_off
, top_off
;
2141 x_real_pos_and_offsets (f
, &left_off
, NULL
, &top_off
, NULL
,
2142 NULL
, NULL
, NULL
, NULL
, NULL
);
2147 #endif /* HAVE_X_WINDOWS */
2152 /* Create all the necessary panes and their items. */
2153 maxwidth
= maxlines
= lines
= i
= 0;
2155 while (i
< menu_items_used
)
2157 if (EQ (AREF (menu_items
, i
), Qt
))
2159 /* Create a new pane. */
2160 Lisp_Object pane_name
, prefix
;
2161 const char *pane_string
;
2163 maxlines
= max (maxlines
, lines
);
2165 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2166 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2167 pane_string
= (NILP (pane_name
)
2168 ? "" : SSDATA (pane_name
));
2169 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
2172 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, true);
2173 if (lpane
== XM_FAILURE
)
2175 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2176 *error_name
= "Can't create pane";
2179 i
+= MENU_ITEMS_PANE_LENGTH
;
2181 /* Find the width of the widest item in this pane. */
2183 while (j
< menu_items_used
)
2186 item
= AREF (menu_items
, j
);
2194 width
= SBYTES (item
);
2195 if (width
> maxwidth
)
2198 j
+= MENU_ITEMS_ITEM_LENGTH
;
2201 /* Ignore a nil in the item list.
2202 It's meaningful only for dialog boxes. */
2203 else if (EQ (AREF (menu_items
, i
), Qquote
))
2207 /* Create a new item within current pane. */
2208 Lisp_Object item_name
, enable
, descrip
, help
;
2210 char const *help_string
;
2212 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2213 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2215 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2216 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2217 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2219 if (!NILP (descrip
))
2221 item_data
= SAFE_ALLOCA (maxwidth
+ SBYTES (descrip
) + 1);
2222 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2223 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2225 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2226 item_data
[j
+ SBYTES (descrip
)] = 0;
2229 item_data
= SSDATA (item_name
);
2231 if (lpane
== XM_FAILURE
2232 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2233 menu
, lpane
, 0, item_data
,
2234 !NILP (enable
), help_string
)
2237 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2238 *error_name
= "Can't add selection to menu";
2241 i
+= MENU_ITEMS_ITEM_LENGTH
;
2246 maxlines
= max (maxlines
, lines
);
2248 /* All set and ready to fly. */
2249 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2250 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2251 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2252 x
= min (x
, dispwidth
);
2253 y
= min (y
, dispheight
);
2256 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2257 &ulx
, &uly
, &width
, &height
);
2258 if (ulx
+width
> dispwidth
)
2260 x
-= (ulx
+ width
) - dispwidth
;
2261 ulx
= dispwidth
- width
;
2263 if (uly
+height
> dispheight
)
2265 y
-= (uly
+ height
) - dispheight
;
2266 uly
= dispheight
- height
;
2268 #ifndef HAVE_X_WINDOWS
2269 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2271 /* Move the menu away of the echo area, to avoid overwriting the
2272 menu with help echo messages or vice versa. */
2273 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2275 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2276 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2285 if (ulx
< 0) x
-= ulx
;
2286 if (uly
< 0) y
-= uly
;
2288 if (!(menuflags
& MENU_FOR_CLICK
))
2290 /* If position was not given by a mouse click, adjust so upper left
2291 corner of the menu as a whole ends up at given coordinates. This
2292 is what x-popup-menu says in its documentation. */
2294 y
+= 1.5*height
/(maxlines
+2);
2297 XMenuSetAEQ (menu
, true);
2298 XMenuSetFreeze (menu
, true);
2302 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2305 record_unwind_protect (pop_down_menu
, make_save_ptr_ptr (f
, menu
));
2307 /* Help display under X won't work because XMenuActivate contains
2308 a loop that doesn't give Emacs a chance to process it. */
2309 menu_help_frame
= f
;
2310 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2311 x
, y
, ButtonReleaseMask
, &datap
,
2312 menu_help_callback
);
2319 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2322 /* Find the item number SELIDX in pane number PANE. */
2324 while (i
< menu_items_used
)
2326 if (EQ (AREF (menu_items
, i
), Qt
))
2330 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2332 i
+= MENU_ITEMS_PANE_LENGTH
;
2341 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2342 if (menuflags
& MENU_KEYMAPS
)
2344 entry
= list1 (entry
);
2345 if (!NILP (pane_prefix
))
2346 entry
= Fcons (pane_prefix
, entry
);
2352 i
+= MENU_ITEMS_ITEM_LENGTH
;
2358 *error_name
= "Can't activate menu";
2362 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2363 the menu was invoked with a mouse event as POSITION). */
2364 if (!(menuflags
& MENU_FOR_CLICK
))
2375 return unbind_to (specpdl_count
, entry
);
2378 #endif /* not USE_X_TOOLKIT */
2381 /* Detect if a dialog or menu has been posted. MSDOS has its own
2382 implementation on msdos.c. */
2385 popup_activated (void)
2387 return popup_activated_flag
;
2389 #endif /* not MSDOS */
2391 /* The following is used by delayed window autoselection. */
2393 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2394 doc
: /* Return t if a menu or popup dialog is active. */)
2397 return (popup_activated ()) ? Qt
: Qnil
;
2401 syms_of_xmenu (void)
2403 #ifdef USE_X_TOOLKIT
2404 enum { WIDGET_ID_TICK_START
= 1 << 16 };
2405 widget_id_tick
= WIDGET_ID_TICK_START
;
2406 next_menubar_widget_id
= 1;
2409 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2410 defsubr (&Smenu_or_popup_active_p
);
2413 DEFSYM (Qframe_monitor_workarea
, "frame-monitor-workarea");
2416 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2417 defsubr (&Sx_menu_bar_open_internal
);
2418 Ffset (intern_c_string ("accelerate-menu"),
2419 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));