1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2018 Free Software
10 This file is part of GNU Emacs.
12 GNU Emacs is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or (at
15 your option) any later version.
17 GNU Emacs is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25 /* X pop-up deck-of-cards menu facility for GNU Emacs.
29 /* Modified by Fred Pierresteguy on December 93
30 to make the popup menus and menubar use the Xt. */
32 /* Rewritten for clarity and GC protection by rms in Feb 94. */
42 #include "termhooks.h"
44 #include "blockinput.h"
47 #include "sysselect.h"
54 /* This may include sys/types.h, and that somehow loses
55 if this is not done before the other system files. */
59 /* Load sys/types.h if not already loaded.
60 In some systems loading it twice is suicidal. */
62 #include <sys/types.h>
66 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
67 code accepts the Emacs internal encoding. */
68 #undef HAVE_MULTILINGUAL_MENU
72 #include <X11/IntrinsicP.h>
73 #include <X11/CoreP.h>
74 #include <X11/StringDefs.h>
75 #include <X11/Shell.h>
77 #include "xsettings.h"
78 #include "../lwlib/xlwmenu.h"
80 #include <X11/Xaw3d/Paned.h>
81 #else /* !HAVE_XAW3D */
82 #include <X11/Xaw/Paned.h>
83 #endif /* HAVE_XAW3D */
84 #endif /* USE_LUCID */
86 #include "../lwlib/lwlib.h"
88 #else /* not USE_X_TOOLKIT */
90 #include "../oldXMenu/XMenu.h"
92 #endif /* not USE_X_TOOLKIT */
93 #endif /* HAVE_X_WINDOWS */
105 /* Flag which when set indicates a dialog or menu has been posted by
106 Xt on behalf of one of the widget sets. */
107 static int popup_activated_flag
;
112 static LWLIB_ID next_menubar_widget_id
;
114 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
116 static struct frame
*
117 menubar_id_to_frame (LWLIB_ID id
)
119 Lisp_Object tail
, frame
;
122 FOR_EACH_FRAME (tail
, frame
)
125 if (!FRAME_WINDOW_P (f
))
127 if (f
->output_data
.x
->id
== id
)
137 #if defined USE_GTK || defined USE_MOTIF
139 /* Set menu_items_inuse so no other popup menu or dialog is created. */
142 x_menu_set_in_use (bool in_use
)
144 Lisp_Object frames
, frame
;
146 menu_items_inuse
= in_use
? Qt
: Qnil
;
147 popup_activated_flag
= in_use
;
149 if (popup_activated_flag
)
150 x_activate_timeout_atimer ();
153 /* Don't let frames in `above' z-group obscure popups. */
154 FOR_EACH_FRAME (frames
, frame
)
156 struct frame
*f
= XFRAME (frame
);
158 if (in_use
&& FRAME_Z_GROUP_ABOVE (f
))
159 x_set_z_group (f
, Qabove_suspended
, Qabove
);
160 else if (!in_use
&& FRAME_Z_GROUP_ABOVE_SUSPENDED (f
))
161 x_set_z_group (f
, Qabove
, Qabove_suspended
);
166 /* Wait for an X event to arrive or for a timer to expire. */
169 x_menu_wait_for_event (void *data
)
171 /* Another way to do this is to register a timer callback, that can be
172 done in GTK and Xt. But we have to do it like this when using only X
173 anyway, and with callbacks we would have three variants for timer handling
174 instead of the small ifdefs below. */
178 ! XtAppPending (Xt_app_con
)
179 #elif defined USE_GTK
180 ! gtk_events_pending ()
186 struct timespec next_time
= timer_check (), *ntp
;
188 struct x_display_info
*dpyinfo
;
192 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
194 int fd
= ConnectionNumber (dpyinfo
->display
);
195 FD_SET (fd
, &read_fds
);
197 XFlush (dpyinfo
->display
);
200 if (! timespec_valid_p (next_time
))
205 #if defined USE_GTK && defined HAVE_GTK3
206 /* Gtk3 have arrows on menus when they don't fit. When the
207 pointer is over an arrow, a timeout scrolls it a bit. Use
208 xg_select so that timeout gets triggered. */
209 xg_select (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
211 pselect (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
218 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
222 /* Loop in Xt until the menu pulldown or dialog popup has been
223 popped down (deactivated). This is used for x-popup-menu
224 and x-popup-dialog; it is not used for the menu bar.
226 NOTE: All calls to popup_get_selection should be protected
227 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
230 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
,
231 LWLIB_ID id
, bool do_timers
)
235 while (popup_activated_flag
)
239 event
= *initial_event
;
244 if (do_timers
) x_menu_wait_for_event (0);
245 XtAppNextEvent (Xt_app_con
, &event
);
248 /* Make sure we don't consider buttons grabbed after menu goes.
249 And make sure to deactivate for any ButtonRelease,
250 even if XtDispatchEvent doesn't do that. */
251 if (event
.type
== ButtonRelease
252 && dpyinfo
->display
== event
.xbutton
.display
)
254 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
255 #ifdef USE_MOTIF /* Pretending that the event came from a
256 Btn1Down seems the only way to convince Motif to
257 activate its callbacks; setting the XmNmenuPost
258 isn't working. --marcus@sysc.pdx.edu. */
259 event
.xbutton
.button
= 1;
260 /* Motif only pops down menus when no Ctrl, Alt or Mod
261 key is pressed and the button is released. So reset key state
262 so Motif thinks this is the case. */
263 event
.xbutton
.state
= 0;
266 /* Pop down on C-g and Escape. */
267 else if (event
.type
== KeyPress
268 && dpyinfo
->display
== event
.xbutton
.display
)
270 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
272 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
273 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
274 popup_activated_flag
= 0;
277 x_dispatch_event (&event
, event
.xany
.display
);
281 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
282 doc
: /* SKIP: real doc in USE_GTK definition in xmenu.c. */)
286 struct frame
*f
= decode_window_system_frame (frame
);
290 if (FRAME_EXTERNAL_MENU_BAR (f
))
291 set_frame_menubar (f
, false, true);
293 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
297 bool error_p
= false;
299 x_catch_errors (FRAME_X_DISPLAY (f
));
300 memset (&ev
, 0, sizeof ev
);
301 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
302 ev
.xbutton
.window
= XtWindow (menubar
);
303 ev
.xbutton
.root
= FRAME_DISPLAY_INFO (f
)->root_window
;
304 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
305 ev
.xbutton
.button
= Button1
;
306 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
307 ev
.xbutton
.same_screen
= True
;
314 XtSetArg (al
[0], XtNchildren
, &list
);
315 XtSetArg (al
[1], XtNnumChildren
, &nr
);
316 XtGetValues (menubar
, al
, 2);
317 ev
.xbutton
.window
= XtWindow (list
[0]);
321 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
322 /* From-window, to-window. */
323 ev
.xbutton
.window
, ev
.xbutton
.root
,
325 /* From-position, to-position. */
326 ev
.xbutton
.x
, ev
.xbutton
.y
,
327 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
331 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
332 x_uncatch_errors_after_check ();
336 ev
.type
= ButtonPress
;
337 ev
.xbutton
.state
= 0;
339 XtDispatchEvent (&ev
);
340 ev
.xbutton
.type
= ButtonRelease
;
341 ev
.xbutton
.state
= Button1Mask
;
342 XtDispatchEvent (&ev
);
350 #endif /* USE_X_TOOLKIT */
354 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
355 doc
: /* Start key navigation of the menu bar in FRAME.
356 This initially opens the first menu bar item and you can then navigate with the
357 arrow keys, select a menu entry with the return key or cancel with the
358 escape key. If FRAME has no menu bar this function does nothing.
360 If FRAME is nil or not given, use the selected frame. */)
367 f
= decode_window_system_frame (frame
);
369 if (FRAME_EXTERNAL_MENU_BAR (f
))
370 set_frame_menubar (f
, false, true);
372 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
375 /* Activate the first menu. */
376 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
380 g_signal_emit_by_name (children
->data
, "activate_item");
381 popup_activated_flag
= 1;
382 g_list_free (children
);
390 /* Loop util popup_activated_flag is set to zero in a callback.
391 Used for popup menus and dialogs. */
394 popup_widget_loop (bool do_timers
, GtkWidget
*widget
)
396 ++popup_activated_flag
;
398 /* Process events in the Gtk event loop until done. */
399 while (popup_activated_flag
)
401 if (do_timers
) x_menu_wait_for_event (0);
402 gtk_main_iteration ();
407 /* Activate the menu bar of frame F.
408 This is called from keyboard.c when it gets the
409 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
411 To activate the menu bar, we use the X button-press event
412 that was saved in saved_menu_event.
413 That makes the toolkit do its thing.
415 But first we recompute the menu bar contents (the whole tree).
417 The reason for saving the button event until here, instead of
418 passing it to the toolkit right away, is that we can safely
419 execute Lisp code. */
422 x_activate_menubar (struct frame
*f
)
424 eassert (FRAME_X_P (f
));
426 if (!f
->output_data
.x
->saved_menu_event
->type
)
430 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
431 f
->output_data
.x
->saved_menu_event
->xany
.window
))
435 set_frame_menubar (f
, false, true);
437 popup_activated_flag
= 1;
439 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
440 f
->output_data
.x
->saved_menu_event
);
442 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
446 /* Ignore this if we get it a second time. */
447 f
->output_data
.x
->saved_menu_event
->type
= 0;
450 /* This callback is invoked when the user selects a menubar cascade
451 pushbutton, but before the pulldown menu is posted. */
455 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
457 popup_activated_flag
= 1;
458 x_activate_timeout_atimer ();
462 /* This callback is invoked when a dialog or menu is finished being
463 used and has been unposted. */
466 popup_deactivate_callback (
468 GtkWidget
*widget
, gpointer client_data
470 Widget widget
, LWLIB_ID id
, XtPointer client_data
474 popup_activated_flag
= 0;
478 /* Function that finds the frame for WIDGET and shows the HELP text
480 F is the frame if known, or NULL if not known. */
482 show_help_event (struct frame
*f
, xt_or_gtk_widget widget
, Lisp_Object help
)
488 XSETFRAME (frame
, f
);
489 kbd_buffer_store_help_event (frame
, help
);
492 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
495 /* Callback called when menu items are highlighted/unhighlighted
496 while moving the mouse over them. WIDGET is the menu bar or menu
497 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
498 the data structure for the menu item, or null in case of
503 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
505 xg_menu_item_cb_data
*cb_data
;
508 cb_data
= g_object_get_data (G_OBJECT (widget
), XG_ITEM_DATA
);
509 if (! cb_data
) return;
511 help
= call_data
? cb_data
->help
: Qnil
;
513 /* If popup_activated_flag is greater than 1 we are in a popup menu.
514 Don't pass the frame to show_help_event for those.
515 Passing frame creates an Emacs event. As we are looping in
516 popup_widget_loop, it won't be handled. Passing NULL shows the tip
517 directly without using an Emacs event. This is what the Lucid code
519 show_help_event (popup_activated_flag
<= 1 ? cb_data
->cl_data
->f
: NULL
,
524 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
526 widget_value
*wv
= call_data
;
527 Lisp_Object help
= wv
? wv
->help
: Qnil
;
529 /* Determine the frame for the help event. */
530 struct frame
*f
= menubar_id_to_frame (id
);
532 show_help_event (f
, widget
, help
);
537 /* Gtk calls callbacks just because we tell it what item should be
538 selected in a radio group. If this variable is set to a non-zero
539 value, we are creating menus and don't want callbacks right now.
541 static bool xg_crazy_callback_abort
;
543 /* This callback is called from the menu bar pulldown menu
544 when the user makes a selection.
545 Figure out what the user chose
546 and put the appropriate events into the keyboard buffer. */
548 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
550 xg_menu_item_cb_data
*cb_data
= client_data
;
552 if (xg_crazy_callback_abort
)
555 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
558 /* For a group of radio buttons, GTK calls the selection callback first
559 for the item that was active before the selection and then for the one that
560 is active after the selection. For C-h k this means we get the help on
561 the deselected item and then the selected item is executed. Prevent that
562 by ignoring the non-active item. */
563 if (GTK_IS_RADIO_MENU_ITEM (widget
)
564 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
567 /* When a menu is popped down, X generates a focus event (i.e. focus
568 goes back to the frame below the menu). Since GTK buffers events,
569 we force it out here before the menu selection event. Otherwise
570 sit-for will exit at once if the focus event follows the menu selection
574 while (gtk_events_pending ())
575 gtk_main_iteration ();
578 find_and_call_menu_selection (cb_data
->cl_data
->f
,
579 cb_data
->cl_data
->menu_bar_items_used
,
580 cb_data
->cl_data
->menu_bar_vector
,
584 #else /* not USE_GTK */
586 /* This callback is called from the menu bar pulldown menu
587 when the user makes a selection.
588 Figure out what the user chose
589 and put the appropriate events into the keyboard buffer. */
591 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
595 f
= menubar_id_to_frame (id
);
598 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
599 f
->menu_bar_vector
, client_data
);
601 #endif /* not USE_GTK */
603 /* Recompute all the widgets of frame F, when the menu bar has been
607 update_frame_menubar (struct frame
*f
)
610 xg_update_frame_menubar (f
);
614 eassert (FRAME_X_P (f
));
616 x
= f
->output_data
.x
;
618 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
623 /* Do the voodoo which means "I'm changing lots of things, don't try
624 to refigure sizes until I'm done." */
625 lw_refigure_widget (x
->column_widget
, False
);
627 /* The order in which children are managed is the top to bottom
628 order in which they are displayed in the paned window. First,
629 remove the text-area widget. */
630 XtUnmanageChild (x
->edit_widget
);
632 /* Remove the menubar that is there now, and put up the menubar that
634 XtManageChild (x
->menubar_widget
);
635 XtMapWidget (x
->menubar_widget
);
636 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
638 /* Re-manage the text-area widget, and then thrash the sizes. */
639 XtManageChild (x
->edit_widget
);
640 lw_refigure_widget (x
->column_widget
, True
);
642 /* Force the pane widget to resize itself. */
643 adjust_frame_size (f
, -1, -1, 2, false, Qupdate_frame_menubar
);
650 apply_systemfont_to_dialog (Widget w
)
652 const char *fn
= xsettings_get_system_normal_font ();
655 XrmDatabase db
= XtDatabase (XtDisplay (w
));
657 XrmPutStringResource (&db
, "*dialog.font", fn
);
662 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
664 const char *fn
= xsettings_get_system_normal_font ();
668 XrmDatabase db
= XtDatabase (XtDisplay (w
));
671 XrmPutStringResource (&db
, "*menubar*font", fn
);
672 XrmPutStringResource (&db
, "*popup*font", fn
);
679 /* Set the contents of the menubar widgets of frame F.
680 The argument FIRST_TIME is currently ignored;
681 it is set the first time this is called, from initialize_frame_menubar. */
684 set_frame_menubar (struct frame
*f
, bool first_time
, bool deep_p
)
686 xt_or_gtk_widget menubar_widget
, old_widget
;
691 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
693 int *submenu_start
, *submenu_end
;
694 bool *submenu_top_level_items
;
695 int *submenu_n_panes
;
697 eassert (FRAME_X_P (f
));
699 menubar_widget
= old_widget
= f
->output_data
.x
->menubar_widget
;
701 XSETFRAME (Vmenu_updating_frame
, f
);
704 if (f
->output_data
.x
->id
== 0)
705 f
->output_data
.x
->id
= next_menubar_widget_id
++;
706 id
= f
->output_data
.x
->id
;
709 if (! menubar_widget
)
711 /* Make the first call for any given frame always go deep. */
712 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
715 f
->output_data
.x
->saved_menu_event
= xmalloc (sizeof (XEvent
));
716 f
->output_data
.x
->saved_menu_event
->type
= 0;
721 /* Make a widget-value tree representing the entire menu trees. */
723 struct buffer
*prev
= current_buffer
;
725 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
726 int previous_menu_items_used
= f
->menu_bar_items_used
;
727 Lisp_Object
*previous_items
728 = alloca (previous_menu_items_used
* sizeof *previous_items
);
731 /* If we are making a new widget, its contents are empty,
732 do always reinitialize them. */
733 if (! menubar_widget
)
734 previous_menu_items_used
= 0;
736 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->contents
;
737 specbind (Qinhibit_quit
, Qt
);
738 /* Don't let the debugger step into this code
739 because it is not reentrant. */
740 specbind (Qdebug_on_next_call
, Qnil
);
742 record_unwind_save_match_data ();
743 if (NILP (Voverriding_local_map_menu_flag
))
745 specbind (Qoverriding_terminal_local_map
, Qnil
);
746 specbind (Qoverriding_local_map
, Qnil
);
749 set_buffer_internal_1 (XBUFFER (buffer
));
751 /* Run the Lucid hook. */
752 safe_run_hooks (Qactivate_menubar_hook
);
754 /* If it has changed current-menubar from previous value,
755 really recompute the menubar from the value. */
756 if (! NILP (Vlucid_menu_bar_dirty_flag
))
757 call0 (Qrecompute_lucid_menubar
);
758 safe_run_hooks (Qmenu_bar_update_hook
);
759 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
761 items
= FRAME_MENU_BAR_ITEMS (f
);
763 /* Save the frame's previous menu bar contents data. */
764 if (previous_menu_items_used
)
765 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
766 previous_menu_items_used
* word_size
);
768 /* Fill in menu_items with the current menu bar contents.
769 This can evaluate Lisp code. */
772 menu_items
= f
->menu_bar_vector
;
773 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
774 subitems
= ASIZE (items
) / 4;
775 submenu_start
= alloca ((subitems
+ 1) * sizeof *submenu_start
);
776 submenu_end
= alloca (subitems
* sizeof *submenu_end
);
777 submenu_n_panes
= alloca (subitems
* sizeof *submenu_n_panes
);
778 submenu_top_level_items
= alloca (subitems
779 * sizeof *submenu_top_level_items
);
781 for (i
= 0; i
< subitems
; i
++)
783 Lisp_Object key
, string
, maps
;
785 key
= AREF (items
, 4 * i
);
786 string
= AREF (items
, 4 * i
+ 1);
787 maps
= AREF (items
, 4 * i
+ 2);
791 submenu_start
[i
] = menu_items_used
;
793 menu_items_n_panes
= 0;
794 submenu_top_level_items
[i
]
795 = parse_single_submenu (key
, string
, maps
);
796 submenu_n_panes
[i
] = menu_items_n_panes
;
798 submenu_end
[i
] = menu_items_used
;
801 submenu_start
[i
] = -1;
802 finish_menu_items ();
804 /* Convert menu_items into widget_value trees
805 to display the menu. This cannot evaluate Lisp code. */
807 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
808 wv
->button_type
= BUTTON_TYPE_NONE
;
811 for (i
= 0; submenu_start
[i
] >= 0; i
++)
813 menu_items_n_panes
= submenu_n_panes
[i
];
814 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
815 submenu_top_level_items
[i
]);
819 first_wv
->contents
= wv
;
820 /* Don't set wv->name here; GC during the loop might relocate it. */
822 wv
->button_type
= BUTTON_TYPE_NONE
;
826 set_buffer_internal_1 (prev
);
828 /* If there has been no change in the Lisp-level contents
829 of the menu bar, skip redisplaying it. Just exit. */
831 /* Compare the new menu items with the ones computed last time. */
832 for (i
= 0; i
< previous_menu_items_used
; i
++)
833 if (menu_items_used
== i
834 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
836 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
838 /* The menu items have not changed. Don't bother updating
839 the menus in any form, since it would be a no-op. */
840 free_menubar_widget_value_tree (first_wv
);
841 discard_menu_items ();
842 unbind_to (specpdl_count
, Qnil
);
846 /* The menu items are different, so store them in the frame. */
847 fset_menu_bar_vector (f
, menu_items
);
848 f
->menu_bar_items_used
= menu_items_used
;
850 /* This undoes save_menu_items. */
851 unbind_to (specpdl_count
, Qnil
);
853 /* Now GC cannot happen during the lifetime of the widget_value,
854 so it's safe to store data from a Lisp_String. */
855 wv
= first_wv
->contents
;
856 for (i
= 0; i
< ASIZE (items
); i
+= 4)
859 string
= AREF (items
, i
+ 1);
862 wv
->name
= SSDATA (string
);
863 update_submenu_strings (wv
->contents
);
870 /* Make a widget-value tree containing
871 just the top level menu bar strings. */
873 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
874 wv
->button_type
= BUTTON_TYPE_NONE
;
877 items
= FRAME_MENU_BAR_ITEMS (f
);
878 for (i
= 0; i
< ASIZE (items
); i
+= 4)
882 string
= AREF (items
, i
+ 1);
886 wv
= make_widget_value (SSDATA (string
), NULL
, true, Qnil
);
887 wv
->button_type
= BUTTON_TYPE_NONE
;
888 /* This prevents lwlib from assuming this
889 menu item is really supposed to be empty. */
890 /* The intptr_t cast avoids a warning.
891 This value just has to be different from small integers. */
892 wv
->call_data
= (void *) (intptr_t) (-1);
897 first_wv
->contents
= wv
;
901 /* Forget what we thought we knew about what is in the
902 detailed contents of the menu bar menus.
903 Changing the top level always destroys the contents. */
904 f
->menu_bar_items_used
= 0;
907 /* Create or update the menu bar widget. */
912 xg_crazy_callback_abort
= true;
915 /* The fourth arg is DEEP_P, which says to consider the entire
916 menu trees we supply, rather than just the menu bar item names. */
917 xg_modify_menubar_widgets (menubar_widget
,
921 G_CALLBACK (menubar_selection_callback
),
922 G_CALLBACK (popup_deactivate_callback
),
923 G_CALLBACK (menu_highlight_callback
));
928 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
929 G_CALLBACK (menubar_selection_callback
),
930 G_CALLBACK (popup_deactivate_callback
),
931 G_CALLBACK (menu_highlight_callback
));
933 f
->output_data
.x
->menubar_widget
= menubar_widget
;
937 #else /* not USE_GTK */
940 /* Disable resizing (done for Motif!) */
941 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
943 /* The third arg is DEEP_P, which says to consider the entire
944 menu trees we supply, rather than just the menu bar item names. */
945 lw_modify_all_widgets (id
, first_wv
, deep_p
);
947 /* Re-enable the edit widget to resize. */
948 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
952 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
953 XtTranslations override
= XtParseTranslationTable (menuOverride
);
956 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
958 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
960 f
->output_data
.x
->column_widget
,
962 popup_activate_callback
,
963 menubar_selection_callback
,
964 popup_deactivate_callback
,
965 menu_highlight_callback
);
966 f
->output_data
.x
->menubar_widget
= menubar_widget
;
968 /* Make menu pop down on C-g. */
969 XtOverrideTranslations (menubar_widget
, override
);
974 if (f
->output_data
.x
->menubar_widget
)
975 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
978 = (f
->output_data
.x
->menubar_widget
979 ? (f
->output_data
.x
->menubar_widget
->core
.height
981 /* Damn me... With Lucid I get a core.border_width of 1
982 only the first time this is called and an ibw of 1 every
983 time this is called. So the first time this is called I
984 was off by one. Fix that here by never adding
985 core.border_width for Lucid. */
986 + f
->output_data
.x
->menubar_widget
->core
.border_width
987 #endif /* USE_LUCID */
992 /* Experimentally, we now get the right results
993 for -geometry -0-0 without this. 24 Aug 96, rms.
994 Maybe so, but the menu bar size is missing the pixels so the
995 WM size hints are off by these pixels. Jan D, oct 2009. */
996 if (FRAME_EXTERNAL_MENU_BAR (f
))
1000 XtVaGetValues (f
->output_data
.x
->column_widget
,
1001 XtNinternalBorderWidth
, &ibw
, NULL
);
1002 menubar_size
+= ibw
;
1004 #endif /* USE_LUCID */
1006 FRAME_MENUBAR_HEIGHT (f
) = menubar_size
;
1008 #endif /* not USE_GTK */
1010 free_menubar_widget_value_tree (first_wv
);
1011 update_frame_menubar (f
);
1014 xg_crazy_callback_abort
= false;
1020 /* Called from Fx_create_frame to create the initial menubar of a frame
1021 before it is mapped, so that the window is mapped with the menubar already
1022 there instead of us tacking it on later and thrashing the window after it
1026 initialize_frame_menubar (struct frame
*f
)
1028 /* This function is called before the first chance to redisplay
1029 the frame. It has to be, so the frame will have the right size. */
1030 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
1031 set_frame_menubar (f
, true, true);
1035 /* Get rid of the menu bar of frame F, and free its storage.
1036 This is used when deleting a frame, and when turning off the menu bar.
1037 For GTK this function is in gtkutil.c. */
1041 free_frame_menubar (struct frame
*f
)
1043 Widget menubar_widget
;
1045 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1046 If we want to preserve the old height, calculate it now so we can
1047 restore it below. */
1048 int old_height
= FRAME_TEXT_HEIGHT (f
) + FRAME_MENUBAR_HEIGHT (f
);
1051 eassert (FRAME_X_P (f
));
1053 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1055 FRAME_MENUBAR_HEIGHT (f
) = 0;
1060 /* Removing the menu bar magically changes the shell widget's x
1061 and y position of (0, 0) which, when the menu bar is turned
1062 on again, leads to pull-down menus appearing in strange
1063 positions near the upper-left corner of the display. This
1064 happens only with some window managers like twm and ctwm,
1065 but not with other like Motif's mwm or kwm, because the
1066 latter generate ConfigureNotify events when the menu bar
1067 is switched off, which fixes the shell position. */
1068 Position x0
, y0
, x1
, y1
;
1074 if (f
->output_data
.x
->widget
)
1075 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1078 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1079 f
->output_data
.x
->menubar_widget
= NULL
;
1081 if (f
->output_data
.x
->widget
)
1084 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1085 if (x1
== 0 && y1
== 0)
1086 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1087 if (frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1088 adjust_frame_size (f
, -1, old_height
, 1, false, Qfree_frame_menubar_1
);
1090 adjust_frame_size (f
, -1, -1, 2, false, Qfree_frame_menubar_1
);
1092 adjust_frame_size (f
, -1, -1, 2, false, Qfree_frame_menubar_1
);
1093 #endif /* USE_MOTIF */
1098 if (WINDOWP (FRAME_ROOT_WINDOW (f
))
1099 && frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1100 adjust_frame_size (f
, -1, old_height
, 1, false, Qfree_frame_menubar_2
);
1107 #endif /* not USE_GTK */
1109 #endif /* USE_X_TOOLKIT || USE_GTK */
1111 /* x_menu_show actually displays a menu using the panes and items in menu_items
1112 and returns the value selected from it.
1113 There are two versions of x_menu_show, one for Xt and one for Xlib.
1114 Both assume input is blocked by the caller. */
1116 /* F is the frame the menu is for.
1117 X and Y are the frame-relative specified position,
1118 relative to the inside upper left corner of the frame F.
1119 Bitfield MENUFLAGS bits are:
1120 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1121 MENU_KEYMAPS is set if this menu was specified with keymaps;
1122 in that case, we return a list containing the chosen item's value
1123 and perhaps also the pane's prefix.
1124 TITLE is the specified menu title.
1125 ERROR is a place to store an error message string in case of failure.
1126 (We return nil on failure, but the value doesn't actually matter.) */
1128 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1130 /* The item selected in the popup menu. */
1131 static Lisp_Object
*volatile menu_item_selection
;
1135 /* Used when position a popup menu. See menu_position_func and
1136 create_and_show_popup_menu below. */
1137 struct next_popup_x_y
1144 /* The menu position function to use if we are not putting a popup
1145 menu where the pointer is.
1146 MENU is the menu to pop up.
1147 X and Y shall on exit contain x/y where the menu shall pop up.
1148 PUSH_IN is not documented in the GTK manual.
1149 USER_DATA is any data passed in when calling gtk_menu_popup.
1150 Here it points to a struct next_popup_x_y where the coordinates
1151 to store in *X and *Y are as well as the frame for the popup.
1153 Here only X and Y are used. */
1155 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1157 struct next_popup_x_y
*data
= user_data
;
1162 Lisp_Object frame
, workarea
;
1164 XSETFRAME (frame
, data
->f
);
1166 /* TODO: Get the monitor workarea directly without calculating other
1167 items in x-display-monitor-attributes-list. */
1168 workarea
= call3 (Qframe_monitor_workarea
,
1170 make_number (data
->x
),
1171 make_number (data
->y
));
1173 if (CONSP (workarea
))
1177 min_x
= XINT (XCAR (workarea
));
1178 min_y
= XINT (Fnth (make_number (1), workarea
));
1179 max_x
= min_x
+ XINT (Fnth (make_number (2), workarea
));
1180 max_y
= min_y
+ XINT (Fnth (make_number (3), workarea
));
1183 if (max_x
< 0 || max_y
< 0)
1185 struct x_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (data
->f
);
1187 max_x
= x_display_pixel_width (dpyinfo
);
1188 max_y
= x_display_pixel_height (dpyinfo
);
1194 /* Check if there is room for the menu. If not, adjust x/y so that
1195 the menu is fully visible. */
1196 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1197 if (data
->x
+ req
.width
> max_x
)
1198 *x
-= data
->x
+ req
.width
- max_x
;
1199 if (data
->y
+ req
.height
> max_y
)
1200 *y
-= data
->y
+ req
.height
- max_y
;
1204 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1206 xg_menu_item_cb_data
*cb_data
= client_data
;
1208 if (xg_crazy_callback_abort
) return;
1209 if (cb_data
) menu_item_selection
= cb_data
->call_data
;
1213 pop_down_menu (void *arg
)
1215 popup_activated_flag
= 0;
1217 gtk_widget_destroy (GTK_WIDGET (arg
));
1221 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1223 menu_item_selection will be set to the selection. */
1225 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1226 int x
, int y
, bool for_click
)
1230 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1231 struct next_popup_x_y popup_x_y
;
1232 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1233 bool use_pos_func
= ! for_click
;
1236 /* Always use position function for Gtk3. Otherwise menus may become
1237 too small to show anything. */
1238 use_pos_func
= true;
1241 eassert (FRAME_X_P (f
));
1243 xg_crazy_callback_abort
= true;
1244 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1245 G_CALLBACK (popup_selection_callback
),
1246 G_CALLBACK (popup_deactivate_callback
),
1247 G_CALLBACK (menu_highlight_callback
));
1248 xg_crazy_callback_abort
= false;
1252 Window dummy_window
;
1254 /* Not invoked by a click. pop up at x/y. */
1255 pos_func
= menu_position_func
;
1257 /* Adjust coordinates to be root-window-relative. */
1259 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
1261 /* From-window, to-window. */
1263 FRAME_DISPLAY_INFO (f
)->root_window
,
1265 /* From-position, to-position. */
1271 /* Use window scaling factor to adjust position for hidpi screens. */
1272 x
/= xg_get_scale (f
);
1273 y
/= xg_get_scale (f
);
1280 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1285 for (i
= 0; i
< 5; i
++)
1286 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1288 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1292 /* Display the menu. */
1293 gtk_widget_show_all (menu
);
1295 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1296 FRAME_DISPLAY_INFO (f
)->last_user_time
);
1298 record_unwind_protect_ptr (pop_down_menu
, menu
);
1300 if (gtk_widget_get_mapped (menu
))
1302 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1303 two. show_help_echo uses this to detect popup menus. */
1304 popup_activated_flag
= 1;
1305 /* Process events that apply to the menu. */
1306 popup_widget_loop (true, menu
);
1309 unbind_to (specpdl_count
, Qnil
);
1311 /* Must reset this manually because the button release event is not passed
1312 to Emacs event loop. */
1313 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1316 #else /* not USE_GTK */
1318 /* We need a unique id for each widget handled by the Lucid Widget
1321 For the main windows, and popup menus, we use this counter, which we
1322 increment each time after use. This starts from WIDGET_ID_TICK_START.
1324 For menu bars, we use numbers starting at 0, counted in
1325 next_menubar_widget_id. */
1326 LWLIB_ID widget_id_tick
;
1329 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1331 menu_item_selection
= client_data
;
1334 /* ID is the LWLIB ID of the dialog box. */
1337 pop_down_menu (int id
)
1340 lw_destroy_all_widgets ((LWLIB_ID
) id
);
1342 popup_activated_flag
= 0;
1345 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1347 menu_item_selection will be set to the selection. */
1349 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1350 int x
, int y
, bool for_click
)
1356 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1359 Window dummy_window
;
1361 eassert (FRAME_X_P (f
));
1364 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1367 menu_id
= widget_id_tick
++;
1368 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1369 f
->output_data
.x
->widget
, true, 0,
1370 popup_selection_callback
,
1371 popup_deactivate_callback
,
1372 menu_highlight_callback
);
1374 event
->type
= ButtonPress
;
1376 event
->send_event
= false;
1377 event
->display
= FRAME_X_DISPLAY (f
);
1378 event
->time
= CurrentTime
;
1379 event
->root
= FRAME_DISPLAY_INFO (f
)->root_window
;
1380 event
->window
= event
->subwindow
= event
->root
;
1384 /* Adjust coordinates to be root-window-relative. */
1386 x
+= FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f
);
1387 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
1389 /* From-window, to-window. */
1391 FRAME_DISPLAY_INFO (f
)->root_window
,
1393 /* From-position, to-position. */
1405 for (i
= 0; i
< 5; i
++)
1406 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1409 /* Don't allow any geometry request from the user. */
1410 XtSetArg (av
[ac
], (char *) XtNgeometry
, 0); ac
++;
1411 XtSetValues (menu
, av
, ac
);
1413 /* Display the menu. */
1414 lw_popup_menu (menu
, &dummy
);
1415 popup_activated_flag
= 1;
1416 x_activate_timeout_atimer ();
1419 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1421 record_unwind_protect_int (pop_down_menu
, (int) menu_id
);
1423 /* Process events that apply to the menu. */
1424 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), menu_id
, true);
1426 unbind_to (specpdl_count
, Qnil
);
1430 #endif /* not USE_GTK */
1433 cleanup_widget_value_tree (void *arg
)
1435 free_menubar_widget_value_tree (arg
);
1439 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
1440 Lisp_Object title
, const char **error_name
)
1443 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1444 widget_value
**submenu_stack
1445 = alloca (menu_items_used
* sizeof *submenu_stack
);
1446 Lisp_Object
*subprefix_stack
1447 = alloca (menu_items_used
* sizeof *subprefix_stack
);
1448 int submenu_depth
= 0;
1450 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1452 eassert (FRAME_X_P (f
));
1456 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1458 *error_name
= "Empty menu";
1464 /* Create a tree of widget_value objects
1465 representing the panes and their items. */
1466 wv
= make_widget_value ("menu", NULL
, true, Qnil
);
1467 wv
->button_type
= BUTTON_TYPE_NONE
;
1469 bool first_pane
= true;
1471 /* Loop over all panes and items, filling in the tree. */
1473 while (i
< menu_items_used
)
1475 if (EQ (AREF (menu_items
, i
), Qnil
))
1477 submenu_stack
[submenu_depth
++] = save_wv
;
1483 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1486 save_wv
= submenu_stack
[--submenu_depth
];
1490 else if (EQ (AREF (menu_items
, i
), Qt
)
1491 && submenu_depth
!= 0)
1492 i
+= MENU_ITEMS_PANE_LENGTH
;
1493 /* Ignore a nil in the item list.
1494 It's meaningful only for dialog boxes. */
1495 else if (EQ (AREF (menu_items
, i
), Qquote
))
1497 else if (EQ (AREF (menu_items
, i
), Qt
))
1499 /* Create a new pane. */
1500 Lisp_Object pane_name
, prefix
;
1501 const char *pane_string
;
1503 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1504 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1506 #ifndef HAVE_MULTILINGUAL_MENU
1507 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1509 pane_name
= ENCODE_MENU_STRING (pane_name
);
1510 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1513 pane_string
= (NILP (pane_name
)
1514 ? "" : SSDATA (pane_name
));
1515 /* If there is just one top-level pane, put all its items directly
1516 under the top-level menu. */
1517 if (menu_items_n_panes
== 1)
1520 /* If the pane has a meaningful name,
1521 make the pane a top-level menu item
1522 with its items as a submenu beneath it. */
1523 if (!(menuflags
& MENU_KEYMAPS
) && strcmp (pane_string
, ""))
1525 wv
= make_widget_value (pane_string
, NULL
, true, Qnil
);
1529 first_wv
->contents
= wv
;
1530 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
1532 wv
->button_type
= BUTTON_TYPE_NONE
;
1536 else if (first_pane
)
1542 i
+= MENU_ITEMS_PANE_LENGTH
;
1546 /* Create a new item within current pane. */
1547 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1548 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1549 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1550 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1551 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1552 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1553 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1554 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1556 #ifndef HAVE_MULTILINGUAL_MENU
1557 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1559 item_name
= ENCODE_MENU_STRING (item_name
);
1560 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1563 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1565 descrip
= ENCODE_MENU_STRING (descrip
);
1566 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1568 #endif /* not HAVE_MULTILINGUAL_MENU */
1570 wv
= make_widget_value (SSDATA (item_name
), NULL
, !NILP (enable
),
1571 STRINGP (help
) ? help
: Qnil
);
1575 save_wv
->contents
= wv
;
1576 if (!NILP (descrip
))
1577 wv
->key
= SSDATA (descrip
);
1578 /* If this item has a null value,
1579 make the call_data null so that it won't display a box
1580 when the mouse is on it. */
1581 wv
->call_data
= !NILP (def
) ? aref_addr (menu_items
, i
) : 0;
1584 wv
->button_type
= BUTTON_TYPE_NONE
;
1585 else if (EQ (type
, QCtoggle
))
1586 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1587 else if (EQ (type
, QCradio
))
1588 wv
->button_type
= BUTTON_TYPE_RADIO
;
1592 wv
->selected
= !NILP (selected
);
1596 i
+= MENU_ITEMS_ITEM_LENGTH
;
1600 /* Deal with the title, if it is non-nil. */
1603 widget_value
*wv_title
;
1604 widget_value
*wv_sep1
= make_widget_value ("--", NULL
, false, Qnil
);
1605 widget_value
*wv_sep2
= make_widget_value ("--", NULL
, false, Qnil
);
1607 wv_sep2
->next
= first_wv
->contents
;
1608 wv_sep1
->next
= wv_sep2
;
1610 #ifndef HAVE_MULTILINGUAL_MENU
1611 if (STRING_MULTIBYTE (title
))
1612 title
= ENCODE_MENU_STRING (title
);
1615 wv_title
= make_widget_value (SSDATA (title
), NULL
, true, Qnil
);
1616 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1617 wv_title
->next
= wv_sep1
;
1618 first_wv
->contents
= wv_title
;
1621 /* No selection has been chosen yet. */
1622 menu_item_selection
= 0;
1624 /* Make sure to free the widget_value objects we used to specify the
1625 contents even with longjmp. */
1626 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1628 /* Actually create and show the menu until popped down. */
1629 create_and_show_popup_menu (f
, first_wv
, x
, y
,
1630 menuflags
& MENU_FOR_CLICK
);
1632 unbind_to (specpdl_count
, Qnil
);
1634 /* Find the selected item, and its pane, to return
1635 the proper value. */
1636 if (menu_item_selection
!= 0)
1638 Lisp_Object prefix
, entry
;
1640 prefix
= entry
= Qnil
;
1642 while (i
< menu_items_used
)
1644 if (EQ (AREF (menu_items
, i
), Qnil
))
1646 subprefix_stack
[submenu_depth
++] = prefix
;
1650 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1652 prefix
= subprefix_stack
[--submenu_depth
];
1655 else if (EQ (AREF (menu_items
, i
), Qt
))
1658 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1659 i
+= MENU_ITEMS_PANE_LENGTH
;
1661 /* Ignore a nil in the item list.
1662 It's meaningful only for dialog boxes. */
1663 else if (EQ (AREF (menu_items
, i
), Qquote
))
1668 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1669 if (menu_item_selection
== aref_addr (menu_items
, i
))
1671 if (menuflags
& MENU_KEYMAPS
)
1675 entry
= list1 (entry
);
1677 entry
= Fcons (prefix
, entry
);
1678 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1679 if (!NILP (subprefix_stack
[j
]))
1680 entry
= Fcons (subprefix_stack
[j
], entry
);
1685 i
+= MENU_ITEMS_ITEM_LENGTH
;
1689 else if (!(menuflags
& MENU_FOR_CLICK
))
1692 /* Make "Cancel" equivalent to C-g. */
1702 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1704 /* Treat the pointer as an integer. There's no problem
1705 as long as pointers have enough bits to hold small integers. */
1706 if ((intptr_t) client_data
!= -1)
1707 menu_item_selection
= client_data
;
1709 popup_activated_flag
= 0;
1712 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1714 menu_item_selection will be set to the selection. */
1716 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1720 eassert (FRAME_X_P (f
));
1722 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1723 G_CALLBACK (dialog_selection_callback
),
1724 G_CALLBACK (popup_deactivate_callback
),
1729 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1730 record_unwind_protect_ptr (pop_down_menu
, menu
);
1732 /* Display the menu. */
1733 gtk_widget_show_all (menu
);
1735 /* Process events that apply to the menu. */
1736 popup_widget_loop (true, menu
);
1738 unbind_to (specpdl_count
, Qnil
);
1742 #else /* not USE_GTK */
1744 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1746 /* Treat the pointer as an integer. There's no problem
1747 as long as pointers have enough bits to hold small integers. */
1748 if ((intptr_t) client_data
!= -1)
1749 menu_item_selection
= client_data
;
1752 lw_destroy_all_widgets (id
);
1754 popup_activated_flag
= 0;
1758 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1760 menu_item_selection will be set to the selection. */
1762 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1766 eassert (FRAME_X_P (f
));
1768 dialog_id
= widget_id_tick
++;
1770 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1772 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1773 f
->output_data
.x
->widget
, true, 0,
1774 dialog_selection_callback
, 0, 0);
1775 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1776 /* Display the dialog box. */
1777 lw_pop_up_all_widgets (dialog_id
);
1778 popup_activated_flag
= 1;
1779 x_activate_timeout_atimer ();
1781 /* Process events that apply to the dialog box.
1782 Also handle timers. */
1784 ptrdiff_t count
= SPECPDL_INDEX ();
1786 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1788 record_unwind_protect_int (pop_down_menu
, (int) dialog_id
);
1790 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), dialog_id
, true);
1792 unbind_to (count
, Qnil
);
1796 #endif /* not USE_GTK */
1798 static const char * button_names
[] = {
1799 "button1", "button2", "button3", "button4", "button5",
1800 "button6", "button7", "button8", "button9", "button10" };
1803 x_dialog_show (struct frame
*f
, Lisp_Object title
,
1804 Lisp_Object header
, const char **error_name
)
1806 int i
, nb_buttons
=0;
1807 char dialog_name
[6];
1809 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1811 /* Number of elements seen so far, before boundary. */
1813 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1814 bool boundary_seen
= false;
1816 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1818 eassert (FRAME_X_P (f
));
1822 if (menu_items_n_panes
> 1)
1824 *error_name
= "Multiple panes in dialog box";
1828 /* Create a tree of widget_value objects
1829 representing the text label and buttons. */
1831 Lisp_Object pane_name
;
1832 const char *pane_string
;
1833 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1834 pane_string
= (NILP (pane_name
)
1835 ? "" : SSDATA (pane_name
));
1836 prev_wv
= make_widget_value ("message", (char *) pane_string
, true, Qnil
);
1839 /* Loop over all panes and items, filling in the tree. */
1840 i
= MENU_ITEMS_PANE_LENGTH
;
1841 while (i
< menu_items_used
)
1844 /* Create a new item within current pane. */
1845 Lisp_Object item_name
, enable
, descrip
;
1846 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1847 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1849 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1851 if (NILP (item_name
))
1853 free_menubar_widget_value_tree (first_wv
);
1854 *error_name
= "Submenu in dialog items";
1857 if (EQ (item_name
, Qquote
))
1859 /* This is the boundary between left-side elts
1860 and right-side elts. Stop incrementing right_count. */
1861 boundary_seen
= true;
1865 if (nb_buttons
>= 9)
1867 free_menubar_widget_value_tree (first_wv
);
1868 *error_name
= "Too many dialog items";
1872 wv
= make_widget_value (button_names
[nb_buttons
],
1874 !NILP (enable
), Qnil
);
1876 if (!NILP (descrip
))
1877 wv
->key
= SSDATA (descrip
);
1878 wv
->call_data
= aref_addr (menu_items
, i
);
1881 if (! boundary_seen
)
1885 i
+= MENU_ITEMS_ITEM_LENGTH
;
1888 /* If the boundary was not specified,
1889 by default put half on the left and half on the right. */
1890 if (! boundary_seen
)
1891 left_count
= nb_buttons
- nb_buttons
/ 2;
1893 wv
= make_widget_value (dialog_name
, NULL
, false, Qnil
);
1895 /* Frame title: 'Q' = Question, 'I' = Information.
1896 Can also have 'E' = Error if, one day, we want
1897 a popup for errors. */
1899 dialog_name
[0] = 'Q';
1901 dialog_name
[0] = 'I';
1903 /* Dialog boxes use a really stupid name encoding
1904 which specifies how many buttons to use
1905 and how many buttons are on the right. */
1906 dialog_name
[1] = '0' + nb_buttons
;
1907 dialog_name
[2] = 'B';
1908 dialog_name
[3] = 'R';
1909 /* Number of buttons to put on the right. */
1910 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1912 wv
->contents
= first_wv
;
1916 /* No selection has been chosen yet. */
1917 menu_item_selection
= 0;
1919 /* Make sure to free the widget_value objects we used to specify the
1920 contents even with longjmp. */
1921 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1923 /* Actually create and show the dialog. */
1924 create_and_show_dialog (f
, first_wv
);
1926 unbind_to (specpdl_count
, Qnil
);
1928 /* Find the selected item, and its pane, to return
1929 the proper value. */
1930 if (menu_item_selection
!= 0)
1933 while (i
< menu_items_used
)
1937 if (EQ (AREF (menu_items
, i
), Qt
))
1938 i
+= MENU_ITEMS_PANE_LENGTH
;
1939 else if (EQ (AREF (menu_items
, i
), Qquote
))
1941 /* This is the boundary between left-side elts and
1948 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1949 if (menu_item_selection
== aref_addr (menu_items
, i
))
1951 i
+= MENU_ITEMS_ITEM_LENGTH
;
1956 /* Make "Cancel" equivalent to C-g. */
1963 xw_popup_dialog (struct frame
*f
, Lisp_Object header
, Lisp_Object contents
)
1966 const char *error_name
;
1967 Lisp_Object selection
;
1968 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1970 check_window_system (f
);
1972 /* Decode the dialog items from what was specified. */
1973 title
= Fcar (contents
);
1974 CHECK_STRING (title
);
1975 record_unwind_protect_void (unuse_menu_items
);
1977 if (NILP (Fcar (Fcdr (contents
))))
1978 /* No buttons specified, add an "Ok" button so users can pop down
1979 the dialog. Also, the lesstif/motif version crashes if there are
1981 contents
= list2 (title
, Fcons (build_string ("Ok"), Qt
));
1983 list_of_panes (list1 (contents
));
1985 /* Display them in a dialog box. */
1987 selection
= x_dialog_show (f
, title
, header
, &error_name
);
1990 unbind_to (specpdl_count
, Qnil
);
1991 discard_menu_items ();
1993 if (error_name
) error ("%s", error_name
);
1997 #else /* not USE_X_TOOLKIT && not USE_GTK */
1999 /* The frame of the last activated non-toolkit menu bar.
2000 Used to generate menu help events. */
2002 static struct frame
*menu_help_frame
;
2005 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2007 PANE is the pane number, and ITEM is the menu item number in
2008 the menu (currently not used).
2010 This cannot be done with generating a HELP_EVENT because
2011 XMenuActivate contains a loop that doesn't let Emacs process
2015 menu_help_callback (char const *help_string
, int pane
, int item
)
2017 Lisp_Object
*first_item
;
2018 Lisp_Object pane_name
;
2019 Lisp_Object menu_object
;
2021 first_item
= XVECTOR (menu_items
)->contents
;
2022 if (EQ (first_item
[0], Qt
))
2023 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
2024 else if (EQ (first_item
[0], Qquote
))
2025 /* This shouldn't happen, see x_menu_show. */
2026 pane_name
= empty_unibyte_string
;
2028 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
2030 /* (menu-item MENU-NAME PANE-NUMBER) */
2031 menu_object
= list3 (Qmenu_item
, pane_name
, make_number (pane
));
2032 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
2033 Qnil
, menu_object
, make_number (item
));
2037 pop_down_menu (Lisp_Object arg
)
2039 struct frame
*f
= XSAVE_POINTER (arg
, 0);
2040 XMenu
*menu
= XSAVE_POINTER (arg
, 1);
2044 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2045 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2047 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2049 #ifdef HAVE_X_WINDOWS
2050 /* Assume the mouse has moved out of the X window.
2051 If it has actually moved in, we will get an EnterNotify. */
2052 x_mouse_leave (FRAME_DISPLAY_INFO (f
));
2054 /* State that no mouse buttons are now held.
2055 (The oldXMenu code doesn't track this info for us.)
2056 That is not necessarily true, but the fiction leads to reasonable
2057 results, and it is a pain to ask which are actually held now. */
2058 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
2060 #endif /* HAVE_X_WINDOWS */
2067 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
2068 Lisp_Object title
, const char **error_name
)
2072 int pane
, selidx
, lpane
, status
;
2073 Lisp_Object entry
= Qnil
;
2074 Lisp_Object pane_prefix
;
2076 int ulx
, uly
, width
, height
;
2077 int dispwidth
, dispheight
;
2078 int i
, j
, lines
, maxlines
;
2081 unsigned int dummy_uint
;
2082 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2084 eassert (FRAME_X_P (f
) || FRAME_MSDOS_P (f
));
2087 if (menu_items_n_panes
== 0)
2090 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2092 *error_name
= "Empty menu";
2099 /* Figure out which root window F is on. */
2100 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2101 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2102 &dummy_uint
, &dummy_uint
);
2104 /* Make the menu on that window. */
2105 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2108 *error_name
= "Can't create menu";
2112 /* Don't GC while we prepare and show the menu,
2113 because we give the oldxmenu library pointers to the
2114 contents of strings. */
2115 inhibit_garbage_collection ();
2117 #ifdef HAVE_X_WINDOWS
2119 /* Adjust coordinates to relative to the outer (window manager) window. */
2120 int left_off
, top_off
;
2122 x_real_pos_and_offsets (f
, &left_off
, NULL
, &top_off
, NULL
,
2123 NULL
, NULL
, NULL
, NULL
, NULL
);
2128 #endif /* HAVE_X_WINDOWS */
2133 /* Create all the necessary panes and their items. */
2134 maxwidth
= maxlines
= lines
= i
= 0;
2136 while (i
< menu_items_used
)
2138 if (EQ (AREF (menu_items
, i
), Qt
))
2140 /* Create a new pane. */
2141 Lisp_Object pane_name
, prefix
;
2142 const char *pane_string
;
2144 maxlines
= max (maxlines
, lines
);
2146 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2147 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2148 pane_string
= (NILP (pane_name
)
2149 ? "" : SSDATA (pane_name
));
2150 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
2153 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, true);
2154 if (lpane
== XM_FAILURE
)
2156 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2157 *error_name
= "Can't create pane";
2160 i
+= MENU_ITEMS_PANE_LENGTH
;
2162 /* Find the width of the widest item in this pane. */
2164 while (j
< menu_items_used
)
2167 item
= AREF (menu_items
, j
);
2175 width
= SBYTES (item
);
2176 if (width
> maxwidth
)
2179 j
+= MENU_ITEMS_ITEM_LENGTH
;
2182 /* Ignore a nil in the item list.
2183 It's meaningful only for dialog boxes. */
2184 else if (EQ (AREF (menu_items
, i
), Qquote
))
2188 /* Create a new item within current pane. */
2189 Lisp_Object item_name
, enable
, descrip
, help
;
2191 char const *help_string
;
2193 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2194 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2196 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2197 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2198 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2200 if (!NILP (descrip
))
2202 item_data
= SAFE_ALLOCA (maxwidth
+ SBYTES (descrip
) + 1);
2203 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2204 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2206 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2207 item_data
[j
+ SBYTES (descrip
)] = 0;
2210 item_data
= SSDATA (item_name
);
2212 if (lpane
== XM_FAILURE
2213 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2214 menu
, lpane
, 0, item_data
,
2215 !NILP (enable
), help_string
)
2218 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2219 *error_name
= "Can't add selection to menu";
2222 i
+= MENU_ITEMS_ITEM_LENGTH
;
2227 maxlines
= max (maxlines
, lines
);
2229 /* All set and ready to fly. */
2230 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2231 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2232 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2233 x
= min (x
, dispwidth
);
2234 y
= min (y
, dispheight
);
2237 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2238 &ulx
, &uly
, &width
, &height
);
2239 if (ulx
+width
> dispwidth
)
2241 x
-= (ulx
+ width
) - dispwidth
;
2242 ulx
= dispwidth
- width
;
2244 if (uly
+height
> dispheight
)
2246 y
-= (uly
+ height
) - dispheight
;
2247 uly
= dispheight
- height
;
2249 #ifndef HAVE_X_WINDOWS
2250 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2252 /* Move the menu away of the echo area, to avoid overwriting the
2253 menu with help echo messages or vice versa. */
2254 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2256 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2257 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2266 if (ulx
< 0) x
-= ulx
;
2267 if (uly
< 0) y
-= uly
;
2269 if (!(menuflags
& MENU_FOR_CLICK
))
2271 /* If position was not given by a mouse click, adjust so upper left
2272 corner of the menu as a whole ends up at given coordinates. This
2273 is what x-popup-menu says in its documentation. */
2275 y
+= 1.5*height
/(maxlines
+2);
2278 XMenuSetAEQ (menu
, true);
2279 XMenuSetFreeze (menu
, true);
2283 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2286 record_unwind_protect (pop_down_menu
, make_save_ptr_ptr (f
, menu
));
2288 /* Help display under X won't work because XMenuActivate contains
2289 a loop that doesn't give Emacs a chance to process it. */
2290 menu_help_frame
= f
;
2291 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2292 x
, y
, ButtonReleaseMask
, &datap
,
2293 menu_help_callback
);
2300 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2303 /* Find the item number SELIDX in pane number PANE. */
2305 while (i
< menu_items_used
)
2307 if (EQ (AREF (menu_items
, i
), Qt
))
2311 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2313 i
+= MENU_ITEMS_PANE_LENGTH
;
2322 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2323 if (menuflags
& MENU_KEYMAPS
)
2325 entry
= list1 (entry
);
2326 if (!NILP (pane_prefix
))
2327 entry
= Fcons (pane_prefix
, entry
);
2333 i
+= MENU_ITEMS_ITEM_LENGTH
;
2339 *error_name
= "Can't activate menu";
2343 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2344 the menu was invoked with a mouse event as POSITION). */
2345 if (!(menuflags
& MENU_FOR_CLICK
))
2356 return unbind_to (specpdl_count
, entry
);
2359 #endif /* not USE_X_TOOLKIT */
2362 /* Detect if a dialog or menu has been posted. MSDOS has its own
2363 implementation on msdos.c. */
2366 popup_activated (void)
2368 return popup_activated_flag
;
2370 #endif /* not MSDOS */
2372 /* The following is used by delayed window autoselection. */
2374 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2375 doc
: /* Return t if a menu or popup dialog is active.
2376 \(On MS Windows, this refers to the selected frame.) */)
2379 return (popup_activated ()) ? Qt
: Qnil
;
2383 syms_of_xmenu (void)
2385 #ifdef USE_X_TOOLKIT
2386 enum { WIDGET_ID_TICK_START
= 1 << 16 };
2387 widget_id_tick
= WIDGET_ID_TICK_START
;
2388 next_menubar_widget_id
= 1;
2391 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2392 defsubr (&Smenu_or_popup_active_p
);
2395 DEFSYM (Qframe_monitor_workarea
, "frame-monitor-workarea");
2398 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2399 defsubr (&Sx_menu_bar_open_internal
);
2400 Ffset (intern_c_string ("accelerate-menu"),
2401 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));