1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
41 #include "termhooks.h"
43 #include "blockinput.h"
44 #include "character.h"
48 #include "sysselect.h"
55 /* This may include sys/types.h, and that somehow loses
56 if this is not done before the other system files. */
60 /* Load sys/types.h if not already loaded.
61 In some systems loading it twice is suicidal. */
63 #include <sys/types.h>
66 #include "dispextern.h"
69 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
70 code accepts the Emacs internal encoding. */
71 #undef HAVE_MULTILINGUAL_MENU
75 #include <X11/IntrinsicP.h>
76 #include <X11/CoreP.h>
77 #include <X11/StringDefs.h>
78 #include <X11/Shell.h>
80 #include "xsettings.h"
81 #include "../lwlib/xlwmenu.h"
83 #include <X11/Xaw3d/Paned.h>
84 #else /* !HAVE_XAW3D */
85 #include <X11/Xaw/Paned.h>
86 #endif /* HAVE_XAW3D */
87 #endif /* USE_LUCID */
89 #include "../lwlib/lwlib.h"
91 #else /* not USE_X_TOOLKIT */
93 #include "../oldXMenu/XMenu.h"
95 #endif /* not USE_X_TOOLKIT */
96 #endif /* HAVE_X_WINDOWS */
101 #include "xgselect.h"
108 /* Flag which when set indicates a dialog or menu has been posted by
109 Xt on behalf of one of the widget sets. */
110 static int popup_activated_flag
;
115 static LWLIB_ID next_menubar_widget_id
;
117 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
119 static struct frame
*
120 menubar_id_to_frame (LWLIB_ID id
)
122 Lisp_Object tail
, frame
;
125 FOR_EACH_FRAME (tail
, frame
)
128 if (!FRAME_WINDOW_P (f
))
130 if (f
->output_data
.x
->id
== id
)
140 #if defined USE_GTK || defined USE_MOTIF
142 /* Set menu_items_inuse so no other popup menu or dialog is created. */
145 x_menu_set_in_use (bool in_use
)
147 menu_items_inuse
= in_use
? Qt
: Qnil
;
148 popup_activated_flag
= in_use
;
150 if (popup_activated_flag
)
151 x_activate_timeout_atimer ();
157 /* Wait for an X event to arrive or for a timer to expire. */
160 x_menu_wait_for_event (void *data
)
162 /* Another way to do this is to register a timer callback, that can be
163 done in GTK and Xt. But we have to do it like this when using only X
164 anyway, and with callbacks we would have three variants for timer handling
165 instead of the small ifdefs below. */
169 ! XtAppPending (Xt_app_con
)
170 #elif defined USE_GTK
171 ! gtk_events_pending ()
177 struct timespec next_time
= timer_check (), *ntp
;
179 struct x_display_info
*dpyinfo
;
183 for (dpyinfo
= x_display_list
; dpyinfo
; dpyinfo
= dpyinfo
->next
)
185 int fd
= ConnectionNumber (dpyinfo
->display
);
186 FD_SET (fd
, &read_fds
);
188 XFlush (dpyinfo
->display
);
191 if (! timespec_valid_p (next_time
))
196 #if defined USE_GTK && defined HAVE_GTK3
197 /* Gtk3 have arrows on menus when they don't fit. When the
198 pointer is over an arrow, a timeout scrolls it a bit. Use
199 xg_select so that timeout gets triggered. */
200 xg_select (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
202 pselect (n
+ 1, &read_fds
, NULL
, NULL
, ntp
, NULL
);
209 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
213 /* Loop in Xt until the menu pulldown or dialog popup has been
214 popped down (deactivated). This is used for x-popup-menu
215 and x-popup-dialog; it is not used for the menu bar.
217 NOTE: All calls to popup_get_selection should be protected
218 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
221 popup_get_selection (XEvent
*initial_event
, struct x_display_info
*dpyinfo
,
222 LWLIB_ID id
, bool do_timers
)
226 while (popup_activated_flag
)
230 event
= *initial_event
;
235 if (do_timers
) x_menu_wait_for_event (0);
236 XtAppNextEvent (Xt_app_con
, &event
);
239 /* Make sure we don't consider buttons grabbed after menu goes.
240 And make sure to deactivate for any ButtonRelease,
241 even if XtDispatchEvent doesn't do that. */
242 if (event
.type
== ButtonRelease
243 && dpyinfo
->display
== event
.xbutton
.display
)
245 dpyinfo
->grabbed
&= ~(1 << event
.xbutton
.button
);
246 #ifdef USE_MOTIF /* Pretending that the event came from a
247 Btn1Down seems the only way to convince Motif to
248 activate its callbacks; setting the XmNmenuPost
249 isn't working. --marcus@sysc.pdx.edu. */
250 event
.xbutton
.button
= 1;
251 /* Motif only pops down menus when no Ctrl, Alt or Mod
252 key is pressed and the button is released. So reset key state
253 so Motif thinks this is the case. */
254 event
.xbutton
.state
= 0;
257 /* Pop down on C-g and Escape. */
258 else if (event
.type
== KeyPress
259 && dpyinfo
->display
== event
.xbutton
.display
)
261 KeySym keysym
= XLookupKeysym (&event
.xkey
, 0);
263 if ((keysym
== XK_g
&& (event
.xkey
.state
& ControlMask
) != 0)
264 || keysym
== XK_Escape
) /* Any escape, ignore modifiers. */
265 popup_activated_flag
= 0;
268 x_dispatch_event (&event
, event
.xany
.display
);
272 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
273 doc
: /* Start key navigation of the menu bar in FRAME.
274 This initially opens the first menu bar item and you can then navigate with the
275 arrow keys, select a menu entry with the return key or cancel with the
276 escape key. If FRAME has no menu bar this function does nothing.
278 If FRAME is nil or not given, use the selected frame. */)
282 struct frame
*f
= decode_window_system_frame (frame
);
286 if (FRAME_EXTERNAL_MENU_BAR (f
))
287 set_frame_menubar (f
, false, true);
289 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
293 bool error_p
= false;
295 x_catch_errors (FRAME_X_DISPLAY (f
));
296 memset (&ev
, 0, sizeof ev
);
297 ev
.xbutton
.display
= FRAME_X_DISPLAY (f
);
298 ev
.xbutton
.window
= XtWindow (menubar
);
299 ev
.xbutton
.root
= FRAME_DISPLAY_INFO (f
)->root_window
;
300 ev
.xbutton
.time
= XtLastTimestampProcessed (FRAME_X_DISPLAY (f
));
301 ev
.xbutton
.button
= Button1
;
302 ev
.xbutton
.x
= ev
.xbutton
.y
= FRAME_MENUBAR_HEIGHT (f
) / 2;
303 ev
.xbutton
.same_screen
= True
;
310 XtSetArg (al
[0], XtNchildren
, &list
);
311 XtSetArg (al
[1], XtNnumChildren
, &nr
);
312 XtGetValues (menubar
, al
, 2);
313 ev
.xbutton
.window
= XtWindow (list
[0]);
317 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
318 /* From-window, to-window. */
319 ev
.xbutton
.window
, ev
.xbutton
.root
,
321 /* From-position, to-position. */
322 ev
.xbutton
.x
, ev
.xbutton
.y
,
323 &ev
.xbutton
.x_root
, &ev
.xbutton
.y_root
,
327 error_p
= x_had_errors_p (FRAME_X_DISPLAY (f
));
328 x_uncatch_errors_after_check ();
332 ev
.type
= ButtonPress
;
333 ev
.xbutton
.state
= 0;
335 XtDispatchEvent (&ev
);
336 ev
.xbutton
.type
= ButtonRelease
;
337 ev
.xbutton
.state
= Button1Mask
;
338 XtDispatchEvent (&ev
);
346 #endif /* USE_X_TOOLKIT */
350 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal
, Sx_menu_bar_open_internal
, 0, 1, "i",
351 doc
: /* Start key navigation of the menu bar in FRAME.
352 This initially opens the first menu bar item and you can then navigate with the
353 arrow keys, select a menu entry with the return key or cancel with the
354 escape key. If FRAME has no menu bar this function does nothing.
356 If FRAME is nil or not given, use the selected frame. */)
363 f
= decode_window_system_frame (frame
);
365 if (FRAME_EXTERNAL_MENU_BAR (f
))
366 set_frame_menubar (f
, false, true);
368 menubar
= FRAME_X_OUTPUT (f
)->menubar_widget
;
371 /* Activate the first menu. */
372 GList
*children
= gtk_container_get_children (GTK_CONTAINER (menubar
));
376 g_signal_emit_by_name (children
->data
, "activate_item");
377 popup_activated_flag
= 1;
378 g_list_free (children
);
386 /* Loop util popup_activated_flag is set to zero in a callback.
387 Used for popup menus and dialogs. */
390 popup_widget_loop (bool do_timers
, GtkWidget
*widget
)
392 ++popup_activated_flag
;
394 /* Process events in the Gtk event loop until done. */
395 while (popup_activated_flag
)
397 if (do_timers
) x_menu_wait_for_event (0);
398 gtk_main_iteration ();
403 /* Activate the menu bar of frame F.
404 This is called from keyboard.c when it gets the
405 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
407 To activate the menu bar, we use the X button-press event
408 that was saved in saved_menu_event.
409 That makes the toolkit do its thing.
411 But first we recompute the menu bar contents (the whole tree).
413 The reason for saving the button event until here, instead of
414 passing it to the toolkit right away, is that we can safely
415 execute Lisp code. */
418 x_activate_menubar (struct frame
*f
)
420 eassert (FRAME_X_P (f
));
422 if (!f
->output_data
.x
->saved_menu_event
->type
)
426 if (! xg_win_to_widget (FRAME_X_DISPLAY (f
),
427 f
->output_data
.x
->saved_menu_event
->xany
.window
))
431 set_frame_menubar (f
, false, true);
433 popup_activated_flag
= 1;
435 XPutBackEvent (f
->output_data
.x
->display_info
->display
,
436 f
->output_data
.x
->saved_menu_event
);
438 XtDispatchEvent (f
->output_data
.x
->saved_menu_event
);
442 /* Ignore this if we get it a second time. */
443 f
->output_data
.x
->saved_menu_event
->type
= 0;
446 /* This callback is invoked when the user selects a menubar cascade
447 pushbutton, but before the pulldown menu is posted. */
451 popup_activate_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
453 popup_activated_flag
= 1;
454 x_activate_timeout_atimer ();
458 /* This callback is invoked when a dialog or menu is finished being
459 used and has been unposted. */
462 popup_deactivate_callback (
464 GtkWidget
*widget
, gpointer client_data
466 Widget widget
, LWLIB_ID id
, XtPointer client_data
470 popup_activated_flag
= 0;
474 /* Function that finds the frame for WIDGET and shows the HELP text
476 F is the frame if known, or NULL if not known. */
478 show_help_event (struct frame
*f
, xt_or_gtk_widget widget
, Lisp_Object help
)
484 XSETFRAME (frame
, f
);
485 kbd_buffer_store_help_event (frame
, help
);
488 show_help_echo (help
, Qnil
, Qnil
, Qnil
);
491 /* Callback called when menu items are highlighted/unhighlighted
492 while moving the mouse over them. WIDGET is the menu bar or menu
493 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
494 the data structure for the menu item, or null in case of
499 menu_highlight_callback (GtkWidget
*widget
, gpointer call_data
)
501 xg_menu_item_cb_data
*cb_data
;
504 cb_data
= g_object_get_data (G_OBJECT (widget
), XG_ITEM_DATA
);
505 if (! cb_data
) return;
507 help
= call_data
? cb_data
->help
: Qnil
;
509 /* If popup_activated_flag is greater than 1 we are in a popup menu.
510 Don't pass the frame to show_help_event for those.
511 Passing frame creates an Emacs event. As we are looping in
512 popup_widget_loop, it won't be handled. Passing NULL shows the tip
513 directly without using an Emacs event. This is what the Lucid code
515 show_help_event (popup_activated_flag
<= 1 ? cb_data
->cl_data
->f
: NULL
,
520 menu_highlight_callback (Widget widget
, LWLIB_ID id
, void *call_data
)
522 widget_value
*wv
= call_data
;
523 Lisp_Object help
= wv
? wv
->help
: Qnil
;
525 /* Determine the frame for the help event. */
526 struct frame
*f
= menubar_id_to_frame (id
);
528 show_help_event (f
, widget
, help
);
533 /* Gtk calls callbacks just because we tell it what item should be
534 selected in a radio group. If this variable is set to a non-zero
535 value, we are creating menus and don't want callbacks right now.
537 static bool xg_crazy_callback_abort
;
539 /* This callback is called from the menu bar pulldown menu
540 when the user makes a selection.
541 Figure out what the user chose
542 and put the appropriate events into the keyboard buffer. */
544 menubar_selection_callback (GtkWidget
*widget
, gpointer client_data
)
546 xg_menu_item_cb_data
*cb_data
= client_data
;
548 if (xg_crazy_callback_abort
)
551 if (! cb_data
|| ! cb_data
->cl_data
|| ! cb_data
->cl_data
->f
)
554 /* For a group of radio buttons, GTK calls the selection callback first
555 for the item that was active before the selection and then for the one that
556 is active after the selection. For C-h k this means we get the help on
557 the deselected item and then the selected item is executed. Prevent that
558 by ignoring the non-active item. */
559 if (GTK_IS_RADIO_MENU_ITEM (widget
)
560 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget
)))
563 /* When a menu is popped down, X generates a focus event (i.e. focus
564 goes back to the frame below the menu). Since GTK buffers events,
565 we force it out here before the menu selection event. Otherwise
566 sit-for will exit at once if the focus event follows the menu selection
570 while (gtk_events_pending ())
571 gtk_main_iteration ();
574 find_and_call_menu_selection (cb_data
->cl_data
->f
,
575 cb_data
->cl_data
->menu_bar_items_used
,
576 cb_data
->cl_data
->menu_bar_vector
,
580 #else /* not USE_GTK */
582 /* This callback is called from the menu bar pulldown menu
583 when the user makes a selection.
584 Figure out what the user chose
585 and put the appropriate events into the keyboard buffer. */
587 menubar_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
591 f
= menubar_id_to_frame (id
);
594 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
595 f
->menu_bar_vector
, client_data
);
597 #endif /* not USE_GTK */
599 /* Recompute all the widgets of frame F, when the menu bar has been
603 update_frame_menubar (struct frame
*f
)
606 xg_update_frame_menubar (f
);
610 eassert (FRAME_X_P (f
));
612 x
= f
->output_data
.x
;
614 if (!x
->menubar_widget
|| XtIsManaged (x
->menubar_widget
))
619 /* Do the voodoo which means "I'm changing lots of things, don't try
620 to refigure sizes until I'm done." */
621 lw_refigure_widget (x
->column_widget
, False
);
623 /* The order in which children are managed is the top to bottom
624 order in which they are displayed in the paned window. First,
625 remove the text-area widget. */
626 XtUnmanageChild (x
->edit_widget
);
628 /* Remove the menubar that is there now, and put up the menubar that
630 XtManageChild (x
->menubar_widget
);
631 XtMapWidget (x
->menubar_widget
);
632 XtVaSetValues (x
->menubar_widget
, XtNmappedWhenManaged
, 1, NULL
);
634 /* Re-manage the text-area widget, and then thrash the sizes. */
635 XtManageChild (x
->edit_widget
);
636 lw_refigure_widget (x
->column_widget
, True
);
638 /* Force the pane widget to resize itself. */
639 adjust_frame_size (f
, -1, -1, 2, false, Qupdate_frame_menubar
);
646 apply_systemfont_to_dialog (Widget w
)
648 const char *fn
= xsettings_get_system_normal_font ();
651 XrmDatabase db
= XtDatabase (XtDisplay (w
));
653 XrmPutStringResource (&db
, "*dialog.font", fn
);
658 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
660 const char *fn
= xsettings_get_system_normal_font ();
664 XrmDatabase db
= XtDatabase (XtDisplay (w
));
667 XrmPutStringResource (&db
, "*menubar*font", fn
);
668 XrmPutStringResource (&db
, "*popup*font", fn
);
675 /* Set the contents of the menubar widgets of frame F.
676 The argument FIRST_TIME is currently ignored;
677 it is set the first time this is called, from initialize_frame_menubar. */
680 set_frame_menubar (struct frame
*f
, bool first_time
, bool deep_p
)
682 xt_or_gtk_widget menubar_widget
, old_widget
;
687 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
689 int *submenu_start
, *submenu_end
;
690 bool *submenu_top_level_items
;
691 int *submenu_n_panes
;
693 eassert (FRAME_X_P (f
));
695 menubar_widget
= old_widget
= f
->output_data
.x
->menubar_widget
;
697 XSETFRAME (Vmenu_updating_frame
, f
);
700 if (f
->output_data
.x
->id
== 0)
701 f
->output_data
.x
->id
= next_menubar_widget_id
++;
702 id
= f
->output_data
.x
->id
;
705 if (! menubar_widget
)
707 /* Make the first call for any given frame always go deep. */
708 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
711 f
->output_data
.x
->saved_menu_event
= xmalloc (sizeof (XEvent
));
712 f
->output_data
.x
->saved_menu_event
->type
= 0;
717 /* Make a widget-value tree representing the entire menu trees. */
719 struct buffer
*prev
= current_buffer
;
721 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
722 int previous_menu_items_used
= f
->menu_bar_items_used
;
723 Lisp_Object
*previous_items
724 = alloca (previous_menu_items_used
* sizeof *previous_items
);
727 /* If we are making a new widget, its contents are empty,
728 do always reinitialize them. */
729 if (! menubar_widget
)
730 previous_menu_items_used
= 0;
732 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->contents
;
733 specbind (Qinhibit_quit
, Qt
);
734 /* Don't let the debugger step into this code
735 because it is not reentrant. */
736 specbind (Qdebug_on_next_call
, Qnil
);
738 record_unwind_save_match_data ();
739 if (NILP (Voverriding_local_map_menu_flag
))
741 specbind (Qoverriding_terminal_local_map
, Qnil
);
742 specbind (Qoverriding_local_map
, Qnil
);
745 set_buffer_internal_1 (XBUFFER (buffer
));
747 /* Run the Lucid hook. */
748 safe_run_hooks (Qactivate_menubar_hook
);
750 /* If it has changed current-menubar from previous value,
751 really recompute the menubar from the value. */
752 if (! NILP (Vlucid_menu_bar_dirty_flag
))
753 call0 (Qrecompute_lucid_menubar
);
754 safe_run_hooks (Qmenu_bar_update_hook
);
755 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
757 items
= FRAME_MENU_BAR_ITEMS (f
);
759 /* Save the frame's previous menu bar contents data. */
760 if (previous_menu_items_used
)
761 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
762 previous_menu_items_used
* word_size
);
764 /* Fill in menu_items with the current menu bar contents.
765 This can evaluate Lisp code. */
768 menu_items
= f
->menu_bar_vector
;
769 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
770 subitems
= ASIZE (items
) / 4;
771 submenu_start
= alloca ((subitems
+ 1) * sizeof *submenu_start
);
772 submenu_end
= alloca (subitems
* sizeof *submenu_end
);
773 submenu_n_panes
= alloca (subitems
* sizeof *submenu_n_panes
);
774 submenu_top_level_items
= alloca (subitems
775 * sizeof *submenu_top_level_items
);
777 for (i
= 0; i
< subitems
; i
++)
779 Lisp_Object key
, string
, maps
;
781 key
= AREF (items
, 4 * i
);
782 string
= AREF (items
, 4 * i
+ 1);
783 maps
= AREF (items
, 4 * i
+ 2);
787 submenu_start
[i
] = menu_items_used
;
789 menu_items_n_panes
= 0;
790 submenu_top_level_items
[i
]
791 = parse_single_submenu (key
, string
, maps
);
792 submenu_n_panes
[i
] = menu_items_n_panes
;
794 submenu_end
[i
] = menu_items_used
;
797 submenu_start
[i
] = -1;
798 finish_menu_items ();
800 /* Convert menu_items into widget_value trees
801 to display the menu. This cannot evaluate Lisp code. */
803 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
804 wv
->button_type
= BUTTON_TYPE_NONE
;
807 for (i
= 0; submenu_start
[i
] >= 0; i
++)
809 menu_items_n_panes
= submenu_n_panes
[i
];
810 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
811 submenu_top_level_items
[i
]);
815 first_wv
->contents
= wv
;
816 /* Don't set wv->name here; GC during the loop might relocate it. */
818 wv
->button_type
= BUTTON_TYPE_NONE
;
822 set_buffer_internal_1 (prev
);
824 /* If there has been no change in the Lisp-level contents
825 of the menu bar, skip redisplaying it. Just exit. */
827 /* Compare the new menu items with the ones computed last time. */
828 for (i
= 0; i
< previous_menu_items_used
; i
++)
829 if (menu_items_used
== i
830 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
832 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
834 /* The menu items have not changed. Don't bother updating
835 the menus in any form, since it would be a no-op. */
836 free_menubar_widget_value_tree (first_wv
);
837 discard_menu_items ();
838 unbind_to (specpdl_count
, Qnil
);
842 /* The menu items are different, so store them in the frame. */
843 fset_menu_bar_vector (f
, menu_items
);
844 f
->menu_bar_items_used
= menu_items_used
;
846 /* This undoes save_menu_items. */
847 unbind_to (specpdl_count
, Qnil
);
849 /* Now GC cannot happen during the lifetime of the widget_value,
850 so it's safe to store data from a Lisp_String. */
851 wv
= first_wv
->contents
;
852 for (i
= 0; i
< ASIZE (items
); i
+= 4)
855 string
= AREF (items
, i
+ 1);
858 wv
->name
= SSDATA (string
);
859 update_submenu_strings (wv
->contents
);
866 /* Make a widget-value tree containing
867 just the top level menu bar strings. */
869 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
870 wv
->button_type
= BUTTON_TYPE_NONE
;
873 items
= FRAME_MENU_BAR_ITEMS (f
);
874 for (i
= 0; i
< ASIZE (items
); i
+= 4)
878 string
= AREF (items
, i
+ 1);
882 wv
= make_widget_value (SSDATA (string
), NULL
, true, Qnil
);
883 wv
->button_type
= BUTTON_TYPE_NONE
;
884 /* This prevents lwlib from assuming this
885 menu item is really supposed to be empty. */
886 /* The intptr_t cast avoids a warning.
887 This value just has to be different from small integers. */
888 wv
->call_data
= (void *) (intptr_t) (-1);
893 first_wv
->contents
= wv
;
897 /* Forget what we thought we knew about what is in the
898 detailed contents of the menu bar menus.
899 Changing the top level always destroys the contents. */
900 f
->menu_bar_items_used
= 0;
903 /* Create or update the menu bar widget. */
908 xg_crazy_callback_abort
= true;
911 /* The fourth arg is DEEP_P, which says to consider the entire
912 menu trees we supply, rather than just the menu bar item names. */
913 xg_modify_menubar_widgets (menubar_widget
,
917 G_CALLBACK (menubar_selection_callback
),
918 G_CALLBACK (popup_deactivate_callback
),
919 G_CALLBACK (menu_highlight_callback
));
924 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
925 G_CALLBACK (menubar_selection_callback
),
926 G_CALLBACK (popup_deactivate_callback
),
927 G_CALLBACK (menu_highlight_callback
));
929 f
->output_data
.x
->menubar_widget
= menubar_widget
;
933 #else /* not USE_GTK */
936 /* Disable resizing (done for Motif!) */
937 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
939 /* The third arg is DEEP_P, which says to consider the entire
940 menu trees we supply, rather than just the menu bar item names. */
941 lw_modify_all_widgets (id
, first_wv
, deep_p
);
943 /* Re-enable the edit widget to resize. */
944 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
948 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
949 XtTranslations override
= XtParseTranslationTable (menuOverride
);
952 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
954 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
956 f
->output_data
.x
->column_widget
,
958 popup_activate_callback
,
959 menubar_selection_callback
,
960 popup_deactivate_callback
,
961 menu_highlight_callback
);
962 f
->output_data
.x
->menubar_widget
= menubar_widget
;
964 /* Make menu pop down on C-g. */
965 XtOverrideTranslations (menubar_widget
, override
);
970 if (f
->output_data
.x
->menubar_widget
)
971 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
974 = (f
->output_data
.x
->menubar_widget
975 ? (f
->output_data
.x
->menubar_widget
->core
.height
977 /* Damn me... With Lucid I get a core.border_width of 1
978 only the first time this is called and an ibw of 1 every
979 time this is called. So the first time this is called I
980 was off by one. Fix that here by never adding
981 core.border_width for Lucid. */
982 + f
->output_data
.x
->menubar_widget
->core
.border_width
983 #endif /* USE_LUCID */
988 /* Experimentally, we now get the right results
989 for -geometry -0-0 without this. 24 Aug 96, rms.
990 Maybe so, but the menu bar size is missing the pixels so the
991 WM size hints are off by these pixels. Jan D, oct 2009. */
992 if (FRAME_EXTERNAL_MENU_BAR (f
))
996 XtVaGetValues (f
->output_data
.x
->column_widget
,
997 XtNinternalBorderWidth
, &ibw
, NULL
);
1000 #endif /* USE_LUCID */
1002 FRAME_MENUBAR_HEIGHT (f
) = menubar_size
;
1004 #endif /* not USE_GTK */
1006 free_menubar_widget_value_tree (first_wv
);
1007 update_frame_menubar (f
);
1010 xg_crazy_callback_abort
= false;
1016 /* Called from Fx_create_frame to create the initial menubar of a frame
1017 before it is mapped, so that the window is mapped with the menubar already
1018 there instead of us tacking it on later and thrashing the window after it
1022 initialize_frame_menubar (struct frame
*f
)
1024 /* This function is called before the first chance to redisplay
1025 the frame. It has to be, so the frame will have the right size. */
1026 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
1027 set_frame_menubar (f
, true, true);
1031 /* Get rid of the menu bar of frame F, and free its storage.
1032 This is used when deleting a frame, and when turning off the menu bar.
1033 For GTK this function is in gtkutil.c. */
1037 free_frame_menubar (struct frame
*f
)
1039 Widget menubar_widget
;
1041 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1042 If we want to preserve the old height, calculate it now so we can
1043 restore it below. */
1044 int old_height
= FRAME_TEXT_HEIGHT (f
) + FRAME_MENUBAR_HEIGHT (f
);
1047 eassert (FRAME_X_P (f
));
1049 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1051 FRAME_MENUBAR_HEIGHT (f
) = 0;
1056 /* Removing the menu bar magically changes the shell widget's x
1057 and y position of (0, 0) which, when the menu bar is turned
1058 on again, leads to pull-down menus appearing in strange
1059 positions near the upper-left corner of the display. This
1060 happens only with some window managers like twm and ctwm,
1061 but not with other like Motif's mwm or kwm, because the
1062 latter generate ConfigureNotify events when the menu bar
1063 is switched off, which fixes the shell position. */
1064 Position x0
, y0
, x1
, y1
;
1070 if (f
->output_data
.x
->widget
)
1071 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1074 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1075 f
->output_data
.x
->menubar_widget
= NULL
;
1077 if (f
->output_data
.x
->widget
)
1080 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1081 if (x1
== 0 && y1
== 0)
1082 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1083 if (frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1084 adjust_frame_size (f
, -1, old_height
, 1, false, Qfree_frame_menubar_1
);
1086 adjust_frame_size (f
, -1, -1, 2, false, Qfree_frame_menubar_1
);
1088 adjust_frame_size (f
, -1, -1, 2, false, Qfree_frame_menubar_1
);
1089 #endif /* USE_MOTIF */
1094 if (WINDOWP (FRAME_ROOT_WINDOW (f
))
1095 && frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1096 adjust_frame_size (f
, -1, old_height
, 1, false, Qfree_frame_menubar_2
);
1103 #endif /* not USE_GTK */
1105 #endif /* USE_X_TOOLKIT || USE_GTK */
1107 /* x_menu_show actually displays a menu using the panes and items in menu_items
1108 and returns the value selected from it.
1109 There are two versions of x_menu_show, one for Xt and one for Xlib.
1110 Both assume input is blocked by the caller. */
1112 /* F is the frame the menu is for.
1113 X and Y are the frame-relative specified position,
1114 relative to the inside upper left corner of the frame F.
1115 Bitfield MENUFLAGS bits are:
1116 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1117 MENU_KEYMAPS is set if this menu was specified with keymaps;
1118 in that case, we return a list containing the chosen item's value
1119 and perhaps also the pane's prefix.
1120 TITLE is the specified menu title.
1121 ERROR is a place to store an error message string in case of failure.
1122 (We return nil on failure, but the value doesn't actually matter.) */
1124 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1126 /* The item selected in the popup menu. */
1127 static Lisp_Object
*volatile menu_item_selection
;
1131 /* Used when position a popup menu. See menu_position_func and
1132 create_and_show_popup_menu below. */
1133 struct next_popup_x_y
1140 /* The menu position function to use if we are not putting a popup
1141 menu where the pointer is.
1142 MENU is the menu to pop up.
1143 X and Y shall on exit contain x/y where the menu shall pop up.
1144 PUSH_IN is not documented in the GTK manual.
1145 USER_DATA is any data passed in when calling gtk_menu_popup.
1146 Here it points to a struct next_popup_x_y where the coordinates
1147 to store in *X and *Y are as well as the frame for the popup.
1149 Here only X and Y are used. */
1151 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1153 struct next_popup_x_y
*data
= user_data
;
1155 struct x_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (data
->f
);
1156 int disp_width
= x_display_pixel_width (dpyinfo
);
1157 int disp_height
= x_display_pixel_height (dpyinfo
);
1162 /* Check if there is room for the menu. If not, adjust x/y so that
1163 the menu is fully visible. */
1164 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1165 if (data
->x
+ req
.width
> disp_width
)
1166 *x
-= data
->x
+ req
.width
- disp_width
;
1167 if (data
->y
+ req
.height
> disp_height
)
1168 *y
-= data
->y
+ req
.height
- disp_height
;
1172 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1174 xg_menu_item_cb_data
*cb_data
= client_data
;
1176 if (xg_crazy_callback_abort
) return;
1177 if (cb_data
) menu_item_selection
= cb_data
->call_data
;
1181 pop_down_menu (void *arg
)
1183 popup_activated_flag
= 0;
1185 gtk_widget_destroy (GTK_WIDGET (arg
));
1189 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1191 menu_item_selection will be set to the selection. */
1193 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1194 int x
, int y
, bool for_click
)
1198 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1199 struct next_popup_x_y popup_x_y
;
1200 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1201 bool use_pos_func
= ! for_click
;
1204 /* Always use position function for Gtk3. Otherwise menus may become
1205 too small to show anything. */
1206 use_pos_func
= true;
1209 eassert (FRAME_X_P (f
));
1211 xg_crazy_callback_abort
= true;
1212 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1213 G_CALLBACK (popup_selection_callback
),
1214 G_CALLBACK (popup_deactivate_callback
),
1215 G_CALLBACK (menu_highlight_callback
));
1216 xg_crazy_callback_abort
= false;
1220 Window dummy_window
;
1222 /* Not invoked by a click. pop up at x/y. */
1223 pos_func
= menu_position_func
;
1225 /* Adjust coordinates to be root-window-relative. */
1227 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
1229 /* From-window, to-window. */
1231 FRAME_DISPLAY_INFO (f
)->root_window
,
1233 /* From-position, to-position. */
1243 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1248 for (i
= 0; i
< 5; i
++)
1249 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1251 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1255 /* Display the menu. */
1256 gtk_widget_show_all (menu
);
1258 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1259 FRAME_DISPLAY_INFO (f
)->last_user_time
);
1261 record_unwind_protect_ptr (pop_down_menu
, menu
);
1263 if (gtk_widget_get_mapped (menu
))
1265 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1266 two. show_help_echo uses this to detect popup menus. */
1267 popup_activated_flag
= 1;
1268 /* Process events that apply to the menu. */
1269 popup_widget_loop (true, menu
);
1272 unbind_to (specpdl_count
, Qnil
);
1274 /* Must reset this manually because the button release event is not passed
1275 to Emacs event loop. */
1276 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1279 #else /* not USE_GTK */
1281 /* We need a unique id for each widget handled by the Lucid Widget
1284 For the main windows, and popup menus, we use this counter, which we
1285 increment each time after use. This starts from WIDGET_ID_TICK_START.
1287 For menu bars, we use numbers starting at 0, counted in
1288 next_menubar_widget_id. */
1289 LWLIB_ID widget_id_tick
;
1292 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1294 menu_item_selection
= client_data
;
1297 /* ID is the LWLIB ID of the dialog box. */
1300 pop_down_menu (int id
)
1303 lw_destroy_all_widgets ((LWLIB_ID
) id
);
1305 popup_activated_flag
= 0;
1308 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1310 menu_item_selection will be set to the selection. */
1312 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1313 int x
, int y
, bool for_click
)
1319 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1322 Window dummy_window
;
1324 eassert (FRAME_X_P (f
));
1327 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1330 menu_id
= widget_id_tick
++;
1331 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1332 f
->output_data
.x
->widget
, true, 0,
1333 popup_selection_callback
,
1334 popup_deactivate_callback
,
1335 menu_highlight_callback
);
1337 event
->type
= ButtonPress
;
1339 event
->send_event
= false;
1340 event
->display
= FRAME_X_DISPLAY (f
);
1341 event
->time
= CurrentTime
;
1342 event
->root
= FRAME_DISPLAY_INFO (f
)->root_window
;
1343 event
->window
= event
->subwindow
= event
->root
;
1347 /* Adjust coordinates to be root-window-relative. */
1349 x
+= FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f
);
1350 XTranslateCoordinates (FRAME_X_DISPLAY (f
),
1352 /* From-window, to-window. */
1354 FRAME_DISPLAY_INFO (f
)->root_window
,
1356 /* From-position, to-position. */
1368 for (i
= 0; i
< 5; i
++)
1369 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1372 /* Don't allow any geometry request from the user. */
1373 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1374 XtSetValues (menu
, av
, ac
);
1376 /* Display the menu. */
1377 lw_popup_menu (menu
, &dummy
);
1378 popup_activated_flag
= 1;
1379 x_activate_timeout_atimer ();
1382 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1384 record_unwind_protect_int (pop_down_menu
, (int) menu_id
);
1386 /* Process events that apply to the menu. */
1387 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), menu_id
, true);
1389 unbind_to (specpdl_count
, Qnil
);
1393 #endif /* not USE_GTK */
1396 cleanup_widget_value_tree (void *arg
)
1398 free_menubar_widget_value_tree (arg
);
1402 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
1403 Lisp_Object title
, const char **error_name
)
1406 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1407 widget_value
**submenu_stack
1408 = alloca (menu_items_used
* sizeof *submenu_stack
);
1409 Lisp_Object
*subprefix_stack
1410 = alloca (menu_items_used
* sizeof *subprefix_stack
);
1411 int submenu_depth
= 0;
1413 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1415 eassert (FRAME_X_P (f
));
1419 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1421 *error_name
= "Empty menu";
1427 /* Create a tree of widget_value objects
1428 representing the panes and their items. */
1429 wv
= make_widget_value ("menu", NULL
, true, Qnil
);
1430 wv
->button_type
= BUTTON_TYPE_NONE
;
1432 bool first_pane
= true;
1434 /* Loop over all panes and items, filling in the tree. */
1436 while (i
< menu_items_used
)
1438 if (EQ (AREF (menu_items
, i
), Qnil
))
1440 submenu_stack
[submenu_depth
++] = save_wv
;
1446 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1449 save_wv
= submenu_stack
[--submenu_depth
];
1453 else if (EQ (AREF (menu_items
, i
), Qt
)
1454 && submenu_depth
!= 0)
1455 i
+= MENU_ITEMS_PANE_LENGTH
;
1456 /* Ignore a nil in the item list.
1457 It's meaningful only for dialog boxes. */
1458 else if (EQ (AREF (menu_items
, i
), Qquote
))
1460 else if (EQ (AREF (menu_items
, i
), Qt
))
1462 /* Create a new pane. */
1463 Lisp_Object pane_name
, prefix
;
1464 const char *pane_string
;
1466 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1467 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1469 #ifndef HAVE_MULTILINGUAL_MENU
1470 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1472 pane_name
= ENCODE_MENU_STRING (pane_name
);
1473 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1476 pane_string
= (NILP (pane_name
)
1477 ? "" : SSDATA (pane_name
));
1478 /* If there is just one top-level pane, put all its items directly
1479 under the top-level menu. */
1480 if (menu_items_n_panes
== 1)
1483 /* If the pane has a meaningful name,
1484 make the pane a top-level menu item
1485 with its items as a submenu beneath it. */
1486 if (!(menuflags
& MENU_KEYMAPS
) && strcmp (pane_string
, ""))
1488 wv
= make_widget_value (pane_string
, NULL
, true, Qnil
);
1492 first_wv
->contents
= wv
;
1493 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
1495 wv
->button_type
= BUTTON_TYPE_NONE
;
1499 else if (first_pane
)
1505 i
+= MENU_ITEMS_PANE_LENGTH
;
1509 /* Create a new item within current pane. */
1510 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1511 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1512 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1513 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1514 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1515 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1516 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1517 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1519 #ifndef HAVE_MULTILINGUAL_MENU
1520 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1522 item_name
= ENCODE_MENU_STRING (item_name
);
1523 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1526 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1528 descrip
= ENCODE_MENU_STRING (descrip
);
1529 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1531 #endif /* not HAVE_MULTILINGUAL_MENU */
1533 wv
= make_widget_value (SSDATA (item_name
), NULL
, !NILP (enable
),
1534 STRINGP (help
) ? help
: Qnil
);
1538 save_wv
->contents
= wv
;
1539 if (!NILP (descrip
))
1540 wv
->key
= SSDATA (descrip
);
1541 /* If this item has a null value,
1542 make the call_data null so that it won't display a box
1543 when the mouse is on it. */
1544 wv
->call_data
= !NILP (def
) ? aref_addr (menu_items
, i
) : 0;
1547 wv
->button_type
= BUTTON_TYPE_NONE
;
1548 else if (EQ (type
, QCtoggle
))
1549 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1550 else if (EQ (type
, QCradio
))
1551 wv
->button_type
= BUTTON_TYPE_RADIO
;
1555 wv
->selected
= !NILP (selected
);
1559 i
+= MENU_ITEMS_ITEM_LENGTH
;
1563 /* Deal with the title, if it is non-nil. */
1566 widget_value
*wv_title
;
1567 widget_value
*wv_sep1
= make_widget_value ("--", NULL
, false, Qnil
);
1568 widget_value
*wv_sep2
= make_widget_value ("--", NULL
, false, Qnil
);
1570 wv_sep2
->next
= first_wv
->contents
;
1571 wv_sep1
->next
= wv_sep2
;
1573 #ifndef HAVE_MULTILINGUAL_MENU
1574 if (STRING_MULTIBYTE (title
))
1575 title
= ENCODE_MENU_STRING (title
);
1578 wv_title
= make_widget_value (SSDATA (title
), NULL
, true, Qnil
);
1579 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1580 wv_title
->next
= wv_sep1
;
1581 first_wv
->contents
= wv_title
;
1584 /* No selection has been chosen yet. */
1585 menu_item_selection
= 0;
1587 /* Make sure to free the widget_value objects we used to specify the
1588 contents even with longjmp. */
1589 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1591 /* Actually create and show the menu until popped down. */
1592 create_and_show_popup_menu (f
, first_wv
, x
, y
,
1593 menuflags
& MENU_FOR_CLICK
);
1595 unbind_to (specpdl_count
, Qnil
);
1597 /* Find the selected item, and its pane, to return
1598 the proper value. */
1599 if (menu_item_selection
!= 0)
1601 Lisp_Object prefix
, entry
;
1603 prefix
= entry
= Qnil
;
1605 while (i
< menu_items_used
)
1607 if (EQ (AREF (menu_items
, i
), Qnil
))
1609 subprefix_stack
[submenu_depth
++] = prefix
;
1613 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1615 prefix
= subprefix_stack
[--submenu_depth
];
1618 else if (EQ (AREF (menu_items
, i
), Qt
))
1621 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1622 i
+= MENU_ITEMS_PANE_LENGTH
;
1624 /* Ignore a nil in the item list.
1625 It's meaningful only for dialog boxes. */
1626 else if (EQ (AREF (menu_items
, i
), Qquote
))
1631 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1632 if (menu_item_selection
== aref_addr (menu_items
, i
))
1634 if (menuflags
& MENU_KEYMAPS
)
1638 entry
= list1 (entry
);
1640 entry
= Fcons (prefix
, entry
);
1641 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1642 if (!NILP (subprefix_stack
[j
]))
1643 entry
= Fcons (subprefix_stack
[j
], entry
);
1648 i
+= MENU_ITEMS_ITEM_LENGTH
;
1652 else if (!(menuflags
& MENU_FOR_CLICK
))
1655 /* Make "Cancel" equivalent to C-g. */
1656 Fsignal (Qquit
, Qnil
);
1665 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1667 /* Treat the pointer as an integer. There's no problem
1668 as long as pointers have enough bits to hold small integers. */
1669 if ((intptr_t) client_data
!= -1)
1670 menu_item_selection
= client_data
;
1672 popup_activated_flag
= 0;
1675 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1677 menu_item_selection will be set to the selection. */
1679 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1683 eassert (FRAME_X_P (f
));
1685 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1686 G_CALLBACK (dialog_selection_callback
),
1687 G_CALLBACK (popup_deactivate_callback
),
1692 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1693 record_unwind_protect_ptr (pop_down_menu
, menu
);
1695 /* Display the menu. */
1696 gtk_widget_show_all (menu
);
1698 /* Process events that apply to the menu. */
1699 popup_widget_loop (true, menu
);
1701 unbind_to (specpdl_count
, Qnil
);
1705 #else /* not USE_GTK */
1707 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1709 /* Treat the pointer as an integer. There's no problem
1710 as long as pointers have enough bits to hold small integers. */
1711 if ((intptr_t) client_data
!= -1)
1712 menu_item_selection
= client_data
;
1715 lw_destroy_all_widgets (id
);
1717 popup_activated_flag
= 0;
1721 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1723 menu_item_selection will be set to the selection. */
1725 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1729 eassert (FRAME_X_P (f
));
1731 dialog_id
= widget_id_tick
++;
1733 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1735 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1736 f
->output_data
.x
->widget
, true, 0,
1737 dialog_selection_callback
, 0, 0);
1738 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1739 /* Display the dialog box. */
1740 lw_pop_up_all_widgets (dialog_id
);
1741 popup_activated_flag
= 1;
1742 x_activate_timeout_atimer ();
1744 /* Process events that apply to the dialog box.
1745 Also handle timers. */
1747 ptrdiff_t count
= SPECPDL_INDEX ();
1749 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1751 record_unwind_protect_int (pop_down_menu
, (int) dialog_id
);
1753 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), dialog_id
, true);
1755 unbind_to (count
, Qnil
);
1759 #endif /* not USE_GTK */
1761 static const char * button_names
[] = {
1762 "button1", "button2", "button3", "button4", "button5",
1763 "button6", "button7", "button8", "button9", "button10" };
1766 x_dialog_show (struct frame
*f
, Lisp_Object title
,
1767 Lisp_Object header
, const char **error_name
)
1769 int i
, nb_buttons
=0;
1770 char dialog_name
[6];
1772 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1774 /* Number of elements seen so far, before boundary. */
1776 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1777 bool boundary_seen
= false;
1779 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1781 eassert (FRAME_X_P (f
));
1785 if (menu_items_n_panes
> 1)
1787 *error_name
= "Multiple panes in dialog box";
1791 /* Create a tree of widget_value objects
1792 representing the text label and buttons. */
1794 Lisp_Object pane_name
;
1795 const char *pane_string
;
1796 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1797 pane_string
= (NILP (pane_name
)
1798 ? "" : SSDATA (pane_name
));
1799 prev_wv
= make_widget_value ("message", (char *) pane_string
, true, Qnil
);
1802 /* Loop over all panes and items, filling in the tree. */
1803 i
= MENU_ITEMS_PANE_LENGTH
;
1804 while (i
< menu_items_used
)
1807 /* Create a new item within current pane. */
1808 Lisp_Object item_name
, enable
, descrip
;
1809 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1810 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1812 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1814 if (NILP (item_name
))
1816 free_menubar_widget_value_tree (first_wv
);
1817 *error_name
= "Submenu in dialog items";
1820 if (EQ (item_name
, Qquote
))
1822 /* This is the boundary between left-side elts
1823 and right-side elts. Stop incrementing right_count. */
1824 boundary_seen
= true;
1828 if (nb_buttons
>= 9)
1830 free_menubar_widget_value_tree (first_wv
);
1831 *error_name
= "Too many dialog items";
1835 wv
= make_widget_value (button_names
[nb_buttons
],
1837 !NILP (enable
), Qnil
);
1839 if (!NILP (descrip
))
1840 wv
->key
= SSDATA (descrip
);
1841 wv
->call_data
= aref_addr (menu_items
, i
);
1844 if (! boundary_seen
)
1848 i
+= MENU_ITEMS_ITEM_LENGTH
;
1851 /* If the boundary was not specified,
1852 by default put half on the left and half on the right. */
1853 if (! boundary_seen
)
1854 left_count
= nb_buttons
- nb_buttons
/ 2;
1856 wv
= make_widget_value (dialog_name
, NULL
, false, Qnil
);
1858 /* Frame title: 'Q' = Question, 'I' = Information.
1859 Can also have 'E' = Error if, one day, we want
1860 a popup for errors. */
1862 dialog_name
[0] = 'Q';
1864 dialog_name
[0] = 'I';
1866 /* Dialog boxes use a really stupid name encoding
1867 which specifies how many buttons to use
1868 and how many buttons are on the right. */
1869 dialog_name
[1] = '0' + nb_buttons
;
1870 dialog_name
[2] = 'B';
1871 dialog_name
[3] = 'R';
1872 /* Number of buttons to put on the right. */
1873 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1875 wv
->contents
= first_wv
;
1879 /* No selection has been chosen yet. */
1880 menu_item_selection
= 0;
1882 /* Make sure to free the widget_value objects we used to specify the
1883 contents even with longjmp. */
1884 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1886 /* Actually create and show the dialog. */
1887 create_and_show_dialog (f
, first_wv
);
1889 unbind_to (specpdl_count
, Qnil
);
1891 /* Find the selected item, and its pane, to return
1892 the proper value. */
1893 if (menu_item_selection
!= 0)
1896 while (i
< menu_items_used
)
1900 if (EQ (AREF (menu_items
, i
), Qt
))
1901 i
+= MENU_ITEMS_PANE_LENGTH
;
1902 else if (EQ (AREF (menu_items
, i
), Qquote
))
1904 /* This is the boundary between left-side elts and
1911 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1912 if (menu_item_selection
== aref_addr (menu_items
, i
))
1914 i
+= MENU_ITEMS_ITEM_LENGTH
;
1919 /* Make "Cancel" equivalent to C-g. */
1920 Fsignal (Qquit
, Qnil
);
1926 xw_popup_dialog (struct frame
*f
, Lisp_Object header
, Lisp_Object contents
)
1929 const char *error_name
;
1930 Lisp_Object selection
;
1931 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1933 check_window_system (f
);
1935 /* Decode the dialog items from what was specified. */
1936 title
= Fcar (contents
);
1937 CHECK_STRING (title
);
1938 record_unwind_protect_void (unuse_menu_items
);
1940 if (NILP (Fcar (Fcdr (contents
))))
1941 /* No buttons specified, add an "Ok" button so users can pop down
1942 the dialog. Also, the lesstif/motif version crashes if there are
1944 contents
= list2 (title
, Fcons (build_string ("Ok"), Qt
));
1946 list_of_panes (list1 (contents
));
1948 /* Display them in a dialog box. */
1950 selection
= x_dialog_show (f
, title
, header
, &error_name
);
1953 unbind_to (specpdl_count
, Qnil
);
1954 discard_menu_items ();
1956 if (error_name
) error ("%s", error_name
);
1960 #else /* not USE_X_TOOLKIT && not USE_GTK */
1962 /* The frame of the last activated non-toolkit menu bar.
1963 Used to generate menu help events. */
1965 static struct frame
*menu_help_frame
;
1968 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1970 PANE is the pane number, and ITEM is the menu item number in
1971 the menu (currently not used).
1973 This cannot be done with generating a HELP_EVENT because
1974 XMenuActivate contains a loop that doesn't let Emacs process
1978 menu_help_callback (char const *help_string
, int pane
, int item
)
1980 Lisp_Object
*first_item
;
1981 Lisp_Object pane_name
;
1982 Lisp_Object menu_object
;
1984 first_item
= XVECTOR (menu_items
)->contents
;
1985 if (EQ (first_item
[0], Qt
))
1986 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
1987 else if (EQ (first_item
[0], Qquote
))
1988 /* This shouldn't happen, see x_menu_show. */
1989 pane_name
= empty_unibyte_string
;
1991 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
1993 /* (menu-item MENU-NAME PANE-NUMBER) */
1994 menu_object
= list3 (Qmenu_item
, pane_name
, make_number (pane
));
1995 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
1996 Qnil
, menu_object
, make_number (item
));
2000 pop_down_menu (Lisp_Object arg
)
2002 struct frame
*f
= XSAVE_POINTER (arg
, 0);
2003 XMenu
*menu
= XSAVE_POINTER (arg
, 1);
2007 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
2008 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
2010 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2012 #ifdef HAVE_X_WINDOWS
2013 /* Assume the mouse has moved out of the X window.
2014 If it has actually moved in, we will get an EnterNotify. */
2015 x_mouse_leave (FRAME_DISPLAY_INFO (f
));
2017 /* State that no mouse buttons are now held.
2018 (The oldXMenu code doesn't track this info for us.)
2019 That is not necessarily true, but the fiction leads to reasonable
2020 results, and it is a pain to ask which are actually held now. */
2021 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
2023 #endif /* HAVE_X_WINDOWS */
2030 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
2031 Lisp_Object title
, const char **error_name
)
2035 int pane
, selidx
, lpane
, status
;
2036 Lisp_Object entry
= Qnil
;
2037 Lisp_Object pane_prefix
;
2039 int ulx
, uly
, width
, height
;
2040 int dispwidth
, dispheight
;
2041 int i
, j
, lines
, maxlines
;
2044 unsigned int dummy_uint
;
2045 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2047 eassert (FRAME_X_P (f
) || FRAME_MSDOS_P (f
));
2050 if (menu_items_n_panes
== 0)
2053 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2055 *error_name
= "Empty menu";
2062 /* Figure out which root window F is on. */
2063 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2064 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2065 &dummy_uint
, &dummy_uint
);
2067 /* Make the menu on that window. */
2068 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2071 *error_name
= "Can't create menu";
2075 /* Don't GC while we prepare and show the menu,
2076 because we give the oldxmenu library pointers to the
2077 contents of strings. */
2078 inhibit_garbage_collection ();
2080 #ifdef HAVE_X_WINDOWS
2082 /* Adjust coordinates to relative to the outer (window manager) window. */
2083 int left_off
, top_off
;
2085 x_real_pos_and_offsets (f
, &left_off
, NULL
, &top_off
, NULL
,
2086 NULL
, NULL
, NULL
, NULL
, NULL
);
2091 #endif /* HAVE_X_WINDOWS */
2096 /* Create all the necessary panes and their items. */
2097 maxwidth
= maxlines
= lines
= i
= 0;
2099 while (i
< menu_items_used
)
2101 if (EQ (AREF (menu_items
, i
), Qt
))
2103 /* Create a new pane. */
2104 Lisp_Object pane_name
, prefix
;
2105 const char *pane_string
;
2107 maxlines
= max (maxlines
, lines
);
2109 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2110 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2111 pane_string
= (NILP (pane_name
)
2112 ? "" : SSDATA (pane_name
));
2113 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
2116 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, true);
2117 if (lpane
== XM_FAILURE
)
2119 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2120 *error_name
= "Can't create pane";
2123 i
+= MENU_ITEMS_PANE_LENGTH
;
2125 /* Find the width of the widest item in this pane. */
2127 while (j
< menu_items_used
)
2130 item
= AREF (menu_items
, j
);
2138 width
= SBYTES (item
);
2139 if (width
> maxwidth
)
2142 j
+= MENU_ITEMS_ITEM_LENGTH
;
2145 /* Ignore a nil in the item list.
2146 It's meaningful only for dialog boxes. */
2147 else if (EQ (AREF (menu_items
, i
), Qquote
))
2151 /* Create a new item within current pane. */
2152 Lisp_Object item_name
, enable
, descrip
, help
;
2154 char const *help_string
;
2156 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2157 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2159 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2160 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2161 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2163 if (!NILP (descrip
))
2165 item_data
= SAFE_ALLOCA (maxwidth
+ SBYTES (descrip
) + 1);
2166 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2167 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2169 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2170 item_data
[j
+ SBYTES (descrip
)] = 0;
2173 item_data
= SSDATA (item_name
);
2175 if (lpane
== XM_FAILURE
2176 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2177 menu
, lpane
, 0, item_data
,
2178 !NILP (enable
), help_string
)
2181 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2182 *error_name
= "Can't add selection to menu";
2185 i
+= MENU_ITEMS_ITEM_LENGTH
;
2190 maxlines
= max (maxlines
, lines
);
2192 /* All set and ready to fly. */
2193 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2194 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2195 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2196 x
= min (x
, dispwidth
);
2197 y
= min (y
, dispheight
);
2200 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2201 &ulx
, &uly
, &width
, &height
);
2202 if (ulx
+width
> dispwidth
)
2204 x
-= (ulx
+ width
) - dispwidth
;
2205 ulx
= dispwidth
- width
;
2207 if (uly
+height
> dispheight
)
2209 y
-= (uly
+ height
) - dispheight
;
2210 uly
= dispheight
- height
;
2212 #ifndef HAVE_X_WINDOWS
2213 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2215 /* Move the menu away of the echo area, to avoid overwriting the
2216 menu with help echo messages or vice versa. */
2217 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2219 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2220 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2229 if (ulx
< 0) x
-= ulx
;
2230 if (uly
< 0) y
-= uly
;
2232 if (!(menuflags
& MENU_FOR_CLICK
))
2234 /* If position was not given by a mouse click, adjust so upper left
2235 corner of the menu as a whole ends up at given coordinates. This
2236 is what x-popup-menu says in its documentation. */
2238 y
+= 1.5*height
/(maxlines
+2);
2241 XMenuSetAEQ (menu
, true);
2242 XMenuSetFreeze (menu
, true);
2246 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2249 record_unwind_protect (pop_down_menu
, make_save_ptr_ptr (f
, menu
));
2251 /* Help display under X won't work because XMenuActivate contains
2252 a loop that doesn't give Emacs a chance to process it. */
2253 menu_help_frame
= f
;
2254 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2255 x
, y
, ButtonReleaseMask
, &datap
,
2256 menu_help_callback
);
2263 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2266 /* Find the item number SELIDX in pane number PANE. */
2268 while (i
< menu_items_used
)
2270 if (EQ (AREF (menu_items
, i
), Qt
))
2274 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2276 i
+= MENU_ITEMS_PANE_LENGTH
;
2285 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2286 if (menuflags
& MENU_KEYMAPS
)
2288 entry
= list1 (entry
);
2289 if (!NILP (pane_prefix
))
2290 entry
= Fcons (pane_prefix
, entry
);
2296 i
+= MENU_ITEMS_ITEM_LENGTH
;
2302 *error_name
= "Can't activate menu";
2306 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2307 the menu was invoked with a mouse event as POSITION). */
2308 if (!(menuflags
& MENU_FOR_CLICK
))
2311 Fsignal (Qquit
, Qnil
);
2319 return unbind_to (specpdl_count
, entry
);
2322 #endif /* not USE_X_TOOLKIT */
2325 /* Detect if a dialog or menu has been posted. MSDOS has its own
2326 implementation on msdos.c. */
2329 popup_activated (void)
2331 return popup_activated_flag
;
2333 #endif /* not MSDOS */
2335 /* The following is used by delayed window autoselection. */
2337 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2338 doc
: /* Return t if a menu or popup dialog is active. */)
2341 return (popup_activated ()) ? Qt
: Qnil
;
2345 syms_of_xmenu (void)
2347 #ifdef USE_X_TOOLKIT
2348 enum { WIDGET_ID_TICK_START
= 1 << 16 };
2349 widget_id_tick
= WIDGET_ID_TICK_START
;
2350 next_menubar_widget_id
= 1;
2353 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2354 defsubr (&Smenu_or_popup_active_p
);
2356 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2357 defsubr (&Sx_menu_bar_open_internal
);
2358 Ffset (intern_c_string ("accelerate-menu"),
2359 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));