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
));
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. */
641 /* For reasons I don't know Lucid wants to add one pixel to the frame
642 height when adding the menu bar. Compensate that here. */
643 new_height
= FRAME_TEXT_HEIGHT (f
) - 1;
645 #endif /* USE_LUCID */
646 adjust_frame_size (f
, -1, new_height
, 2, false, Qmenu_bar_lines
);
653 apply_systemfont_to_dialog (Widget w
)
655 const char *fn
= xsettings_get_system_normal_font ();
658 XrmDatabase db
= XtDatabase (XtDisplay (w
));
660 XrmPutStringResource (&db
, "*dialog.font", fn
);
665 apply_systemfont_to_menu (struct frame
*f
, Widget w
)
667 const char *fn
= xsettings_get_system_normal_font ();
671 XrmDatabase db
= XtDatabase (XtDisplay (w
));
674 XrmPutStringResource (&db
, "*menubar*font", fn
);
675 XrmPutStringResource (&db
, "*popup*font", fn
);
682 /* Set the contents of the menubar widgets of frame F.
683 The argument FIRST_TIME is currently ignored;
684 it is set the first time this is called, from initialize_frame_menubar. */
687 set_frame_menubar (struct frame
*f
, bool first_time
, bool deep_p
)
689 xt_or_gtk_widget menubar_widget
, old_widget
;
694 widget_value
*wv
, *first_wv
, *prev_wv
= 0;
696 int *submenu_start
, *submenu_end
;
697 bool *submenu_top_level_items
;
698 int *submenu_n_panes
;
700 eassert (FRAME_X_P (f
));
702 menubar_widget
= old_widget
= f
->output_data
.x
->menubar_widget
;
704 XSETFRAME (Vmenu_updating_frame
, f
);
707 if (f
->output_data
.x
->id
== 0)
708 f
->output_data
.x
->id
= next_menubar_widget_id
++;
709 id
= f
->output_data
.x
->id
;
712 if (! menubar_widget
)
714 /* Make the first call for any given frame always go deep. */
715 else if (!f
->output_data
.x
->saved_menu_event
&& !deep_p
)
718 f
->output_data
.x
->saved_menu_event
= xmalloc (sizeof (XEvent
));
719 f
->output_data
.x
->saved_menu_event
->type
= 0;
724 /* Make a widget-value tree representing the entire menu trees. */
726 struct buffer
*prev
= current_buffer
;
728 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
729 int previous_menu_items_used
= f
->menu_bar_items_used
;
730 Lisp_Object
*previous_items
731 = alloca (previous_menu_items_used
* sizeof *previous_items
);
734 /* If we are making a new widget, its contents are empty,
735 do always reinitialize them. */
736 if (! menubar_widget
)
737 previous_menu_items_used
= 0;
739 buffer
= XWINDOW (FRAME_SELECTED_WINDOW (f
))->contents
;
740 specbind (Qinhibit_quit
, Qt
);
741 /* Don't let the debugger step into this code
742 because it is not reentrant. */
743 specbind (Qdebug_on_next_call
, Qnil
);
745 record_unwind_save_match_data ();
746 if (NILP (Voverriding_local_map_menu_flag
))
748 specbind (Qoverriding_terminal_local_map
, Qnil
);
749 specbind (Qoverriding_local_map
, Qnil
);
752 set_buffer_internal_1 (XBUFFER (buffer
));
754 /* Run the Lucid hook. */
755 safe_run_hooks (Qactivate_menubar_hook
);
757 /* If it has changed current-menubar from previous value,
758 really recompute the menubar from the value. */
759 if (! NILP (Vlucid_menu_bar_dirty_flag
))
760 call0 (Qrecompute_lucid_menubar
);
761 safe_run_hooks (Qmenu_bar_update_hook
);
762 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
764 items
= FRAME_MENU_BAR_ITEMS (f
);
766 /* Save the frame's previous menu bar contents data. */
767 if (previous_menu_items_used
)
768 memcpy (previous_items
, XVECTOR (f
->menu_bar_vector
)->contents
,
769 previous_menu_items_used
* word_size
);
771 /* Fill in menu_items with the current menu bar contents.
772 This can evaluate Lisp code. */
775 menu_items
= f
->menu_bar_vector
;
776 menu_items_allocated
= VECTORP (menu_items
) ? ASIZE (menu_items
) : 0;
777 subitems
= ASIZE (items
) / 4;
778 submenu_start
= alloca ((subitems
+ 1) * sizeof *submenu_start
);
779 submenu_end
= alloca (subitems
* sizeof *submenu_end
);
780 submenu_n_panes
= alloca (subitems
* sizeof *submenu_n_panes
);
781 submenu_top_level_items
= alloca (subitems
782 * sizeof *submenu_top_level_items
);
784 for (i
= 0; i
< subitems
; i
++)
786 Lisp_Object key
, string
, maps
;
788 key
= AREF (items
, 4 * i
);
789 string
= AREF (items
, 4 * i
+ 1);
790 maps
= AREF (items
, 4 * i
+ 2);
794 submenu_start
[i
] = menu_items_used
;
796 menu_items_n_panes
= 0;
797 submenu_top_level_items
[i
]
798 = parse_single_submenu (key
, string
, maps
);
799 submenu_n_panes
[i
] = menu_items_n_panes
;
801 submenu_end
[i
] = menu_items_used
;
804 submenu_start
[i
] = -1;
805 finish_menu_items ();
807 /* Convert menu_items into widget_value trees
808 to display the menu. This cannot evaluate Lisp code. */
810 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
811 wv
->button_type
= BUTTON_TYPE_NONE
;
814 for (i
= 0; submenu_start
[i
] >= 0; i
++)
816 menu_items_n_panes
= submenu_n_panes
[i
];
817 wv
= digest_single_submenu (submenu_start
[i
], submenu_end
[i
],
818 submenu_top_level_items
[i
]);
822 first_wv
->contents
= wv
;
823 /* Don't set wv->name here; GC during the loop might relocate it. */
825 wv
->button_type
= BUTTON_TYPE_NONE
;
829 set_buffer_internal_1 (prev
);
831 /* If there has been no change in the Lisp-level contents
832 of the menu bar, skip redisplaying it. Just exit. */
834 /* Compare the new menu items with the ones computed last time. */
835 for (i
= 0; i
< previous_menu_items_used
; i
++)
836 if (menu_items_used
== i
837 || (!EQ (previous_items
[i
], AREF (menu_items
, i
))))
839 if (i
== menu_items_used
&& i
== previous_menu_items_used
&& i
!= 0)
841 /* The menu items have not changed. Don't bother updating
842 the menus in any form, since it would be a no-op. */
843 free_menubar_widget_value_tree (first_wv
);
844 discard_menu_items ();
845 unbind_to (specpdl_count
, Qnil
);
849 /* The menu items are different, so store them in the frame. */
850 fset_menu_bar_vector (f
, menu_items
);
851 f
->menu_bar_items_used
= menu_items_used
;
853 /* This undoes save_menu_items. */
854 unbind_to (specpdl_count
, Qnil
);
856 /* Now GC cannot happen during the lifetime of the widget_value,
857 so it's safe to store data from a Lisp_String. */
858 wv
= first_wv
->contents
;
859 for (i
= 0; i
< ASIZE (items
); i
+= 4)
862 string
= AREF (items
, i
+ 1);
865 wv
->name
= SSDATA (string
);
866 update_submenu_strings (wv
->contents
);
873 /* Make a widget-value tree containing
874 just the top level menu bar strings. */
876 wv
= make_widget_value ("menubar", NULL
, true, Qnil
);
877 wv
->button_type
= BUTTON_TYPE_NONE
;
880 items
= FRAME_MENU_BAR_ITEMS (f
);
881 for (i
= 0; i
< ASIZE (items
); i
+= 4)
885 string
= AREF (items
, i
+ 1);
889 wv
= make_widget_value (SSDATA (string
), NULL
, true, Qnil
);
890 wv
->button_type
= BUTTON_TYPE_NONE
;
891 /* This prevents lwlib from assuming this
892 menu item is really supposed to be empty. */
893 /* The intptr_t cast avoids a warning.
894 This value just has to be different from small integers. */
895 wv
->call_data
= (void *) (intptr_t) (-1);
900 first_wv
->contents
= wv
;
904 /* Forget what we thought we knew about what is in the
905 detailed contents of the menu bar menus.
906 Changing the top level always destroys the contents. */
907 f
->menu_bar_items_used
= 0;
910 /* Create or update the menu bar widget. */
915 xg_crazy_callback_abort
= true;
918 /* The fourth arg is DEEP_P, which says to consider the entire
919 menu trees we supply, rather than just the menu bar item names. */
920 xg_modify_menubar_widgets (menubar_widget
,
924 G_CALLBACK (menubar_selection_callback
),
925 G_CALLBACK (popup_deactivate_callback
),
926 G_CALLBACK (menu_highlight_callback
));
931 = xg_create_widget ("menubar", "menubar", f
, first_wv
,
932 G_CALLBACK (menubar_selection_callback
),
933 G_CALLBACK (popup_deactivate_callback
),
934 G_CALLBACK (menu_highlight_callback
));
936 f
->output_data
.x
->menubar_widget
= menubar_widget
;
940 #else /* not USE_GTK */
943 /* Disable resizing (done for Motif!) */
944 lw_allow_resizing (f
->output_data
.x
->widget
, False
);
946 /* The third arg is DEEP_P, which says to consider the entire
947 menu trees we supply, rather than just the menu bar item names. */
948 lw_modify_all_widgets (id
, first_wv
, deep_p
);
950 /* Re-enable the edit widget to resize. */
951 lw_allow_resizing (f
->output_data
.x
->widget
, True
);
955 char menuOverride
[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
956 XtTranslations override
= XtParseTranslationTable (menuOverride
);
959 apply_systemfont_to_menu (f
, f
->output_data
.x
->column_widget
);
961 menubar_widget
= lw_create_widget ("menubar", "menubar", id
,
963 f
->output_data
.x
->column_widget
,
965 popup_activate_callback
,
966 menubar_selection_callback
,
967 popup_deactivate_callback
,
968 menu_highlight_callback
);
969 f
->output_data
.x
->menubar_widget
= menubar_widget
;
971 /* Make menu pop down on C-g. */
972 XtOverrideTranslations (menubar_widget
, override
);
977 if (f
->output_data
.x
->menubar_widget
)
978 XtRealizeWidget (f
->output_data
.x
->menubar_widget
);
981 = (f
->output_data
.x
->menubar_widget
982 ? (f
->output_data
.x
->menubar_widget
->core
.height
983 + f
->output_data
.x
->menubar_widget
->core
.border_width
)
987 /* Experimentally, we now get the right results
988 for -geometry -0-0 without this. 24 Aug 96, rms.
989 Maybe so, but the menu bar size is missing the pixels so the
990 WM size hints are off by these pixels. Jan D, oct 2009. */
991 if (FRAME_EXTERNAL_MENU_BAR (f
))
994 XtVaGetValues (f
->output_data
.x
->column_widget
,
995 XtNinternalBorderWidth
, &ibw
, NULL
);
998 #endif /* USE_LUCID */
1000 FRAME_MENUBAR_HEIGHT (f
) = menubar_size
;
1002 #endif /* not USE_GTK */
1004 free_menubar_widget_value_tree (first_wv
);
1005 update_frame_menubar (f
);
1008 xg_crazy_callback_abort
= false;
1014 /* Called from Fx_create_frame to create the initial menubar of a frame
1015 before it is mapped, so that the window is mapped with the menubar already
1016 there instead of us tacking it on later and thrashing the window after it
1020 initialize_frame_menubar (struct frame
*f
)
1022 /* This function is called before the first chance to redisplay
1023 the frame. It has to be, so the frame will have the right size. */
1024 fset_menu_bar_items (f
, menu_bar_items (FRAME_MENU_BAR_ITEMS (f
)));
1025 set_frame_menubar (f
, true, true);
1029 /* Get rid of the menu bar of frame F, and free its storage.
1030 This is used when deleting a frame, and when turning off the menu bar.
1031 For GTK this function is in gtkutil.c. */
1035 free_frame_menubar (struct frame
*f
)
1037 Widget menubar_widget
;
1039 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1040 If we want to preserve the old height, calculate it now so we can
1041 restore it below. */
1042 int old_height
= FRAME_TEXT_HEIGHT (f
) + FRAME_MENUBAR_HEIGHT (f
);
1045 eassert (FRAME_X_P (f
));
1047 menubar_widget
= f
->output_data
.x
->menubar_widget
;
1049 FRAME_MENUBAR_HEIGHT (f
) = 0;
1054 /* Removing the menu bar magically changes the shell widget's x
1055 and y position of (0, 0) which, when the menu bar is turned
1056 on again, leads to pull-down menus appearing in strange
1057 positions near the upper-left corner of the display. This
1058 happens only with some window managers like twm and ctwm,
1059 but not with other like Motif's mwm or kwm, because the
1060 latter generate ConfigureNotify events when the menu bar
1061 is switched off, which fixes the shell position. */
1062 Position x0
, y0
, x1
, y1
;
1068 if (f
->output_data
.x
->widget
)
1069 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x0
, XtNy
, &y0
, NULL
);
1072 lw_destroy_all_widgets ((LWLIB_ID
) f
->output_data
.x
->id
);
1073 f
->output_data
.x
->menubar_widget
= NULL
;
1075 if (f
->output_data
.x
->widget
)
1077 int new_height
= -1;
1079 XtVaGetValues (f
->output_data
.x
->widget
, XtNx
, &x1
, XtNy
, &y1
, NULL
);
1080 if (x1
== 0 && y1
== 0)
1081 XtVaSetValues (f
->output_data
.x
->widget
, XtNx
, x0
, XtNy
, y0
, NULL
);
1082 if (frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1083 new_height
= old_height
;
1084 #endif /* USE_MOTIF */
1085 adjust_frame_size (f
, -1, new_height
, 2, false, Qmenu_bar_lines
);
1090 if (frame_inhibit_resize (f
, false, Qmenu_bar_lines
))
1091 adjust_frame_size (f
, -1, old_height
, 1, false, Qmenu_bar_lines
);
1098 #endif /* not USE_GTK */
1100 #endif /* USE_X_TOOLKIT || USE_GTK */
1102 /* x_menu_show actually displays a menu using the panes and items in menu_items
1103 and returns the value selected from it.
1104 There are two versions of x_menu_show, one for Xt and one for Xlib.
1105 Both assume input is blocked by the caller. */
1107 /* F is the frame the menu is for.
1108 X and Y are the frame-relative specified position,
1109 relative to the inside upper left corner of the frame F.
1110 Bitfield MENUFLAGS bits are:
1111 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1112 MENU_KEYMAPS is set if this menu was specified with keymaps;
1113 in that case, we return a list containing the chosen item's value
1114 and perhaps also the pane's prefix.
1115 TITLE is the specified menu title.
1116 ERROR is a place to store an error message string in case of failure.
1117 (We return nil on failure, but the value doesn't actually matter.) */
1119 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1121 /* The item selected in the popup menu. */
1122 static Lisp_Object
*volatile menu_item_selection
;
1126 /* Used when position a popup menu. See menu_position_func and
1127 create_and_show_popup_menu below. */
1128 struct next_popup_x_y
1135 /* The menu position function to use if we are not putting a popup
1136 menu where the pointer is.
1137 MENU is the menu to pop up.
1138 X and Y shall on exit contain x/y where the menu shall pop up.
1139 PUSH_IN is not documented in the GTK manual.
1140 USER_DATA is any data passed in when calling gtk_menu_popup.
1141 Here it points to a struct next_popup_x_y where the coordinates
1142 to store in *X and *Y are as well as the frame for the popup.
1144 Here only X and Y are used. */
1146 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
, gpointer user_data
)
1148 struct next_popup_x_y
*data
= user_data
;
1150 struct x_display_info
*dpyinfo
= FRAME_DISPLAY_INFO (data
->f
);
1151 int disp_width
= x_display_pixel_width (dpyinfo
);
1152 int disp_height
= x_display_pixel_height (dpyinfo
);
1157 /* Check if there is room for the menu. If not, adjust x/y so that
1158 the menu is fully visible. */
1159 gtk_widget_get_preferred_size (GTK_WIDGET (menu
), NULL
, &req
);
1160 if (data
->x
+ req
.width
> disp_width
)
1161 *x
-= data
->x
+ req
.width
- disp_width
;
1162 if (data
->y
+ req
.height
> disp_height
)
1163 *y
-= data
->y
+ req
.height
- disp_height
;
1167 popup_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1169 xg_menu_item_cb_data
*cb_data
= client_data
;
1171 if (xg_crazy_callback_abort
) return;
1172 if (cb_data
) menu_item_selection
= cb_data
->call_data
;
1176 pop_down_menu (void *arg
)
1178 popup_activated_flag
= 0;
1180 gtk_widget_destroy (GTK_WIDGET (arg
));
1184 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1186 menu_item_selection will be set to the selection. */
1188 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1189 int x
, int y
, bool for_click
)
1193 GtkMenuPositionFunc pos_func
= 0; /* Pop up at pointer. */
1194 struct next_popup_x_y popup_x_y
;
1195 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1196 bool use_pos_func
= ! for_click
;
1199 /* Always use position function for Gtk3. Otherwise menus may become
1200 too small to show anything. */
1201 use_pos_func
= true;
1204 eassert (FRAME_X_P (f
));
1206 xg_crazy_callback_abort
= true;
1207 menu
= xg_create_widget ("popup", first_wv
->name
, f
, first_wv
,
1208 G_CALLBACK (popup_selection_callback
),
1209 G_CALLBACK (popup_deactivate_callback
),
1210 G_CALLBACK (menu_highlight_callback
));
1211 xg_crazy_callback_abort
= false;
1215 /* Not invoked by a click. pop up at x/y. */
1216 pos_func
= menu_position_func
;
1218 /* Adjust coordinates to be root-window-relative. */
1219 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1220 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1226 i
= 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1231 for (i
= 0; i
< 5; i
++)
1232 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1234 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1238 /* Display the menu. */
1239 gtk_widget_show_all (menu
);
1241 gtk_menu_popup (GTK_MENU (menu
), 0, 0, pos_func
, &popup_x_y
, i
,
1242 FRAME_DISPLAY_INFO (f
)->last_user_time
);
1244 record_unwind_protect_ptr (pop_down_menu
, menu
);
1246 if (gtk_widget_get_mapped (menu
))
1248 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1249 two. show_help_echo uses this to detect popup menus. */
1250 popup_activated_flag
= 1;
1251 /* Process events that apply to the menu. */
1252 popup_widget_loop (true, menu
);
1255 unbind_to (specpdl_count
, Qnil
);
1257 /* Must reset this manually because the button release event is not passed
1258 to Emacs event loop. */
1259 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1262 #else /* not USE_GTK */
1264 /* We need a unique id for each widget handled by the Lucid Widget
1267 For the main windows, and popup menus, we use this counter, which we
1268 increment each time after use. This starts from WIDGET_ID_TICK_START.
1270 For menu bars, we use numbers starting at 0, counted in
1271 next_menubar_widget_id. */
1272 LWLIB_ID widget_id_tick
;
1275 popup_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1277 menu_item_selection
= client_data
;
1280 /* ID is the LWLIB ID of the dialog box. */
1283 pop_down_menu (int id
)
1286 lw_destroy_all_widgets ((LWLIB_ID
) id
);
1288 popup_activated_flag
= 0;
1291 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1293 menu_item_selection will be set to the selection. */
1295 create_and_show_popup_menu (struct frame
*f
, widget_value
*first_wv
,
1296 int x
, int y
, bool for_click
)
1302 XButtonPressedEvent
*event
= &(dummy
.xbutton
);
1306 eassert (FRAME_X_P (f
));
1309 apply_systemfont_to_menu (f
, f
->output_data
.x
->widget
);
1312 menu_id
= widget_id_tick
++;
1313 menu
= lw_create_widget ("popup", first_wv
->name
, menu_id
, first_wv
,
1314 f
->output_data
.x
->widget
, true, 0,
1315 popup_selection_callback
,
1316 popup_deactivate_callback
,
1317 menu_highlight_callback
);
1319 event
->type
= ButtonPress
;
1321 event
->send_event
= false;
1322 event
->display
= FRAME_X_DISPLAY (f
);
1323 event
->time
= CurrentTime
;
1324 event
->root
= FRAME_DISPLAY_INFO (f
)->root_window
;
1325 event
->window
= event
->subwindow
= event
->root
;
1329 /* Adjust coordinates to be root-window-relative. */
1330 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1331 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1338 for (i
= 0; i
< 5; i
++)
1339 if (FRAME_DISPLAY_INFO (f
)->grabbed
& (1 << i
))
1342 /* Don't allow any geometry request from the user. */
1343 XtSetArg (av
[ac
], XtNgeometry
, 0); ac
++;
1344 XtSetValues (menu
, av
, ac
);
1346 /* Display the menu. */
1347 lw_popup_menu (menu
, &dummy
);
1348 popup_activated_flag
= 1;
1349 x_activate_timeout_atimer ();
1352 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1354 record_unwind_protect_int (pop_down_menu
, (int) menu_id
);
1356 /* Process events that apply to the menu. */
1357 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), menu_id
, true);
1359 unbind_to (specpdl_count
, Qnil
);
1363 #endif /* not USE_GTK */
1366 cleanup_widget_value_tree (void *arg
)
1368 free_menubar_widget_value_tree (arg
);
1372 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
1373 Lisp_Object title
, const char **error_name
)
1376 widget_value
*wv
, *save_wv
= 0, *first_wv
= 0, *prev_wv
= 0;
1377 widget_value
**submenu_stack
1378 = alloca (menu_items_used
* sizeof *submenu_stack
);
1379 Lisp_Object
*subprefix_stack
1380 = alloca (menu_items_used
* sizeof *subprefix_stack
);
1381 int submenu_depth
= 0;
1383 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1385 eassert (FRAME_X_P (f
));
1389 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
1391 *error_name
= "Empty menu";
1397 /* Create a tree of widget_value objects
1398 representing the panes and their items. */
1399 wv
= make_widget_value ("menu", NULL
, true, Qnil
);
1400 wv
->button_type
= BUTTON_TYPE_NONE
;
1402 bool first_pane
= true;
1404 /* Loop over all panes and items, filling in the tree. */
1406 while (i
< menu_items_used
)
1408 if (EQ (AREF (menu_items
, i
), Qnil
))
1410 submenu_stack
[submenu_depth
++] = save_wv
;
1416 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1419 save_wv
= submenu_stack
[--submenu_depth
];
1423 else if (EQ (AREF (menu_items
, i
), Qt
)
1424 && submenu_depth
!= 0)
1425 i
+= MENU_ITEMS_PANE_LENGTH
;
1426 /* Ignore a nil in the item list.
1427 It's meaningful only for dialog boxes. */
1428 else if (EQ (AREF (menu_items
, i
), Qquote
))
1430 else if (EQ (AREF (menu_items
, i
), Qt
))
1432 /* Create a new pane. */
1433 Lisp_Object pane_name
, prefix
;
1434 const char *pane_string
;
1436 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
1437 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1439 #ifndef HAVE_MULTILINGUAL_MENU
1440 if (STRINGP (pane_name
) && STRING_MULTIBYTE (pane_name
))
1442 pane_name
= ENCODE_MENU_STRING (pane_name
);
1443 ASET (menu_items
, i
+ MENU_ITEMS_PANE_NAME
, pane_name
);
1446 pane_string
= (NILP (pane_name
)
1447 ? "" : SSDATA (pane_name
));
1448 /* If there is just one top-level pane, put all its items directly
1449 under the top-level menu. */
1450 if (menu_items_n_panes
== 1)
1453 /* If the pane has a meaningful name,
1454 make the pane a top-level menu item
1455 with its items as a submenu beneath it. */
1456 if (!(menuflags
& MENU_KEYMAPS
) && strcmp (pane_string
, ""))
1458 wv
= make_widget_value (pane_string
, NULL
, true, Qnil
);
1462 first_wv
->contents
= wv
;
1463 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
1465 wv
->button_type
= BUTTON_TYPE_NONE
;
1469 else if (first_pane
)
1475 i
+= MENU_ITEMS_PANE_LENGTH
;
1479 /* Create a new item within current pane. */
1480 Lisp_Object item_name
, enable
, descrip
, def
, type
, selected
, help
;
1481 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1482 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1483 descrip
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1484 def
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_DEFINITION
);
1485 type
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_TYPE
);
1486 selected
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_SELECTED
);
1487 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
1489 #ifndef HAVE_MULTILINGUAL_MENU
1490 if (STRINGP (item_name
) && STRING_MULTIBYTE (item_name
))
1492 item_name
= ENCODE_MENU_STRING (item_name
);
1493 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
, item_name
);
1496 if (STRINGP (descrip
) && STRING_MULTIBYTE (descrip
))
1498 descrip
= ENCODE_MENU_STRING (descrip
);
1499 ASET (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
, descrip
);
1501 #endif /* not HAVE_MULTILINGUAL_MENU */
1503 wv
= make_widget_value (SSDATA (item_name
), NULL
, !NILP (enable
),
1504 STRINGP (help
) ? help
: Qnil
);
1508 save_wv
->contents
= wv
;
1509 if (!NILP (descrip
))
1510 wv
->key
= SSDATA (descrip
);
1511 /* If this item has a null value,
1512 make the call_data null so that it won't display a box
1513 when the mouse is on it. */
1514 wv
->call_data
= !NILP (def
) ? aref_addr (menu_items
, i
) : 0;
1517 wv
->button_type
= BUTTON_TYPE_NONE
;
1518 else if (EQ (type
, QCtoggle
))
1519 wv
->button_type
= BUTTON_TYPE_TOGGLE
;
1520 else if (EQ (type
, QCradio
))
1521 wv
->button_type
= BUTTON_TYPE_RADIO
;
1525 wv
->selected
= !NILP (selected
);
1529 i
+= MENU_ITEMS_ITEM_LENGTH
;
1533 /* Deal with the title, if it is non-nil. */
1536 widget_value
*wv_title
;
1537 widget_value
*wv_sep1
= make_widget_value ("--", NULL
, false, Qnil
);
1538 widget_value
*wv_sep2
= make_widget_value ("--", NULL
, false, Qnil
);
1540 wv_sep2
->next
= first_wv
->contents
;
1541 wv_sep1
->next
= wv_sep2
;
1543 #ifndef HAVE_MULTILINGUAL_MENU
1544 if (STRING_MULTIBYTE (title
))
1545 title
= ENCODE_MENU_STRING (title
);
1548 wv_title
= make_widget_value (SSDATA (title
), NULL
, true, Qnil
);
1549 wv_title
->button_type
= BUTTON_TYPE_NONE
;
1550 wv_title
->next
= wv_sep1
;
1551 first_wv
->contents
= wv_title
;
1554 /* No selection has been chosen yet. */
1555 menu_item_selection
= 0;
1557 /* Make sure to free the widget_value objects we used to specify the
1558 contents even with longjmp. */
1559 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1561 /* Actually create and show the menu until popped down. */
1562 create_and_show_popup_menu (f
, first_wv
, x
, y
,
1563 menuflags
& MENU_FOR_CLICK
);
1565 unbind_to (specpdl_count
, Qnil
);
1567 /* Find the selected item, and its pane, to return
1568 the proper value. */
1569 if (menu_item_selection
!= 0)
1571 Lisp_Object prefix
, entry
;
1573 prefix
= entry
= Qnil
;
1575 while (i
< menu_items_used
)
1577 if (EQ (AREF (menu_items
, i
), Qnil
))
1579 subprefix_stack
[submenu_depth
++] = prefix
;
1583 else if (EQ (AREF (menu_items
, i
), Qlambda
))
1585 prefix
= subprefix_stack
[--submenu_depth
];
1588 else if (EQ (AREF (menu_items
, i
), Qt
))
1591 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
1592 i
+= MENU_ITEMS_PANE_LENGTH
;
1594 /* Ignore a nil in the item list.
1595 It's meaningful only for dialog boxes. */
1596 else if (EQ (AREF (menu_items
, i
), Qquote
))
1601 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1602 if (menu_item_selection
== aref_addr (menu_items
, i
))
1604 if (menuflags
& MENU_KEYMAPS
)
1608 entry
= list1 (entry
);
1610 entry
= Fcons (prefix
, entry
);
1611 for (j
= submenu_depth
- 1; j
>= 0; j
--)
1612 if (!NILP (subprefix_stack
[j
]))
1613 entry
= Fcons (subprefix_stack
[j
], entry
);
1618 i
+= MENU_ITEMS_ITEM_LENGTH
;
1622 else if (!(menuflags
& MENU_FOR_CLICK
))
1625 /* Make "Cancel" equivalent to C-g. */
1626 Fsignal (Qquit
, Qnil
);
1635 dialog_selection_callback (GtkWidget
*widget
, gpointer client_data
)
1637 /* Treat the pointer as an integer. There's no problem
1638 as long as pointers have enough bits to hold small integers. */
1639 if ((intptr_t) client_data
!= -1)
1640 menu_item_selection
= client_data
;
1642 popup_activated_flag
= 0;
1645 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1647 menu_item_selection will be set to the selection. */
1649 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1653 eassert (FRAME_X_P (f
));
1655 menu
= xg_create_widget ("dialog", first_wv
->name
, f
, first_wv
,
1656 G_CALLBACK (dialog_selection_callback
),
1657 G_CALLBACK (popup_deactivate_callback
),
1662 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1663 record_unwind_protect_ptr (pop_down_menu
, menu
);
1665 /* Display the menu. */
1666 gtk_widget_show_all (menu
);
1668 /* Process events that apply to the menu. */
1669 popup_widget_loop (true, menu
);
1671 unbind_to (specpdl_count
, Qnil
);
1675 #else /* not USE_GTK */
1677 dialog_selection_callback (Widget widget
, LWLIB_ID id
, XtPointer client_data
)
1679 /* Treat the pointer as an integer. There's no problem
1680 as long as pointers have enough bits to hold small integers. */
1681 if ((intptr_t) client_data
!= -1)
1682 menu_item_selection
= client_data
;
1685 lw_destroy_all_widgets (id
);
1687 popup_activated_flag
= 0;
1691 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1693 menu_item_selection will be set to the selection. */
1695 create_and_show_dialog (struct frame
*f
, widget_value
*first_wv
)
1699 eassert (FRAME_X_P (f
));
1701 dialog_id
= widget_id_tick
++;
1703 apply_systemfont_to_dialog (f
->output_data
.x
->widget
);
1705 lw_create_widget (first_wv
->name
, "dialog", dialog_id
, first_wv
,
1706 f
->output_data
.x
->widget
, true, 0,
1707 dialog_selection_callback
, 0, 0);
1708 lw_modify_all_widgets (dialog_id
, first_wv
->contents
, True
);
1709 /* Display the dialog box. */
1710 lw_pop_up_all_widgets (dialog_id
);
1711 popup_activated_flag
= 1;
1712 x_activate_timeout_atimer ();
1714 /* Process events that apply to the dialog box.
1715 Also handle timers. */
1717 ptrdiff_t count
= SPECPDL_INDEX ();
1719 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1721 record_unwind_protect_int (pop_down_menu
, (int) dialog_id
);
1723 popup_get_selection (0, FRAME_DISPLAY_INFO (f
), dialog_id
, true);
1725 unbind_to (count
, Qnil
);
1729 #endif /* not USE_GTK */
1731 static const char * button_names
[] = {
1732 "button1", "button2", "button3", "button4", "button5",
1733 "button6", "button7", "button8", "button9", "button10" };
1736 x_dialog_show (struct frame
*f
, Lisp_Object title
,
1737 Lisp_Object header
, const char **error_name
)
1739 int i
, nb_buttons
=0;
1740 char dialog_name
[6];
1742 widget_value
*wv
, *first_wv
= 0, *prev_wv
= 0;
1744 /* Number of elements seen so far, before boundary. */
1746 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1747 bool boundary_seen
= false;
1749 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1751 eassert (FRAME_X_P (f
));
1755 if (menu_items_n_panes
> 1)
1757 *error_name
= "Multiple panes in dialog box";
1761 /* Create a tree of widget_value objects
1762 representing the text label and buttons. */
1764 Lisp_Object pane_name
;
1765 const char *pane_string
;
1766 pane_name
= AREF (menu_items
, MENU_ITEMS_PANE_NAME
);
1767 pane_string
= (NILP (pane_name
)
1768 ? "" : SSDATA (pane_name
));
1769 prev_wv
= make_widget_value ("message", (char *) pane_string
, true, Qnil
);
1772 /* Loop over all panes and items, filling in the tree. */
1773 i
= MENU_ITEMS_PANE_LENGTH
;
1774 while (i
< menu_items_used
)
1777 /* Create a new item within current pane. */
1778 Lisp_Object item_name
, enable
, descrip
;
1779 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
1780 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
1782 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
1784 if (NILP (item_name
))
1786 free_menubar_widget_value_tree (first_wv
);
1787 *error_name
= "Submenu in dialog items";
1790 if (EQ (item_name
, Qquote
))
1792 /* This is the boundary between left-side elts
1793 and right-side elts. Stop incrementing right_count. */
1794 boundary_seen
= true;
1798 if (nb_buttons
>= 9)
1800 free_menubar_widget_value_tree (first_wv
);
1801 *error_name
= "Too many dialog items";
1805 wv
= make_widget_value (button_names
[nb_buttons
],
1807 !NILP (enable
), Qnil
);
1809 if (!NILP (descrip
))
1810 wv
->key
= SSDATA (descrip
);
1811 wv
->call_data
= aref_addr (menu_items
, i
);
1814 if (! boundary_seen
)
1818 i
+= MENU_ITEMS_ITEM_LENGTH
;
1821 /* If the boundary was not specified,
1822 by default put half on the left and half on the right. */
1823 if (! boundary_seen
)
1824 left_count
= nb_buttons
- nb_buttons
/ 2;
1826 wv
= make_widget_value (dialog_name
, NULL
, false, Qnil
);
1828 /* Frame title: 'Q' = Question, 'I' = Information.
1829 Can also have 'E' = Error if, one day, we want
1830 a popup for errors. */
1832 dialog_name
[0] = 'Q';
1834 dialog_name
[0] = 'I';
1836 /* Dialog boxes use a really stupid name encoding
1837 which specifies how many buttons to use
1838 and how many buttons are on the right. */
1839 dialog_name
[1] = '0' + nb_buttons
;
1840 dialog_name
[2] = 'B';
1841 dialog_name
[3] = 'R';
1842 /* Number of buttons to put on the right. */
1843 dialog_name
[4] = '0' + nb_buttons
- left_count
;
1845 wv
->contents
= first_wv
;
1849 /* No selection has been chosen yet. */
1850 menu_item_selection
= 0;
1852 /* Make sure to free the widget_value objects we used to specify the
1853 contents even with longjmp. */
1854 record_unwind_protect_ptr (cleanup_widget_value_tree
, first_wv
);
1856 /* Actually create and show the dialog. */
1857 create_and_show_dialog (f
, first_wv
);
1859 unbind_to (specpdl_count
, Qnil
);
1861 /* Find the selected item, and its pane, to return
1862 the proper value. */
1863 if (menu_item_selection
!= 0)
1866 while (i
< menu_items_used
)
1870 if (EQ (AREF (menu_items
, i
), Qt
))
1871 i
+= MENU_ITEMS_PANE_LENGTH
;
1872 else if (EQ (AREF (menu_items
, i
), Qquote
))
1874 /* This is the boundary between left-side elts and
1881 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
1882 if (menu_item_selection
== aref_addr (menu_items
, i
))
1884 i
+= MENU_ITEMS_ITEM_LENGTH
;
1889 /* Make "Cancel" equivalent to C-g. */
1890 Fsignal (Qquit
, Qnil
);
1896 xw_popup_dialog (struct frame
*f
, Lisp_Object header
, Lisp_Object contents
)
1899 const char *error_name
;
1900 Lisp_Object selection
;
1901 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
1903 check_window_system (f
);
1905 /* Decode the dialog items from what was specified. */
1906 title
= Fcar (contents
);
1907 CHECK_STRING (title
);
1908 record_unwind_protect_void (unuse_menu_items
);
1910 if (NILP (Fcar (Fcdr (contents
))))
1911 /* No buttons specified, add an "Ok" button so users can pop down
1912 the dialog. Also, the lesstif/motif version crashes if there are
1914 contents
= list2 (title
, Fcons (build_string ("Ok"), Qt
));
1916 list_of_panes (list1 (contents
));
1918 /* Display them in a dialog box. */
1920 selection
= x_dialog_show (f
, title
, header
, &error_name
);
1923 unbind_to (specpdl_count
, Qnil
);
1924 discard_menu_items ();
1926 if (error_name
) error ("%s", error_name
);
1930 #else /* not USE_X_TOOLKIT && not USE_GTK */
1932 /* The frame of the last activated non-toolkit menu bar.
1933 Used to generate menu help events. */
1935 static struct frame
*menu_help_frame
;
1938 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1940 PANE is the pane number, and ITEM is the menu item number in
1941 the menu (currently not used).
1943 This cannot be done with generating a HELP_EVENT because
1944 XMenuActivate contains a loop that doesn't let Emacs process
1948 menu_help_callback (char const *help_string
, int pane
, int item
)
1950 Lisp_Object
*first_item
;
1951 Lisp_Object pane_name
;
1952 Lisp_Object menu_object
;
1954 first_item
= XVECTOR (menu_items
)->contents
;
1955 if (EQ (first_item
[0], Qt
))
1956 pane_name
= first_item
[MENU_ITEMS_PANE_NAME
];
1957 else if (EQ (first_item
[0], Qquote
))
1958 /* This shouldn't happen, see x_menu_show. */
1959 pane_name
= empty_unibyte_string
;
1961 pane_name
= first_item
[MENU_ITEMS_ITEM_NAME
];
1963 /* (menu-item MENU-NAME PANE-NUMBER) */
1964 menu_object
= list3 (Qmenu_item
, pane_name
, make_number (pane
));
1965 show_help_echo (help_string
? build_string (help_string
) : Qnil
,
1966 Qnil
, menu_object
, make_number (item
));
1970 pop_down_menu (Lisp_Object arg
)
1972 struct frame
*f
= XSAVE_POINTER (arg
, 0);
1973 XMenu
*menu
= XSAVE_POINTER (arg
, 1);
1977 XUngrabPointer (FRAME_X_DISPLAY (f
), CurrentTime
);
1978 XUngrabKeyboard (FRAME_X_DISPLAY (f
), CurrentTime
);
1980 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
1982 #ifdef HAVE_X_WINDOWS
1983 /* Assume the mouse has moved out of the X window.
1984 If it has actually moved in, we will get an EnterNotify. */
1985 x_mouse_leave (FRAME_DISPLAY_INFO (f
));
1987 /* State that no mouse buttons are now held.
1988 (The oldXMenu code doesn't track this info for us.)
1989 That is not necessarily true, but the fiction leads to reasonable
1990 results, and it is a pain to ask which are actually held now. */
1991 FRAME_DISPLAY_INFO (f
)->grabbed
= 0;
1993 #endif /* HAVE_X_WINDOWS */
2000 x_menu_show (struct frame
*f
, int x
, int y
, int menuflags
,
2001 Lisp_Object title
, const char **error_name
)
2005 int pane
, selidx
, lpane
, status
;
2006 Lisp_Object entry
= Qnil
;
2007 Lisp_Object pane_prefix
;
2009 int ulx
, uly
, width
, height
;
2010 int dispwidth
, dispheight
;
2011 int i
, j
, lines
, maxlines
;
2014 unsigned int dummy_uint
;
2015 ptrdiff_t specpdl_count
= SPECPDL_INDEX ();
2017 eassert (FRAME_X_P (f
) || FRAME_MSDOS_P (f
));
2020 if (menu_items_n_panes
== 0)
2023 if (menu_items_used
<= MENU_ITEMS_PANE_LENGTH
)
2025 *error_name
= "Empty menu";
2032 /* Figure out which root window F is on. */
2033 XGetGeometry (FRAME_X_DISPLAY (f
), FRAME_X_WINDOW (f
), &root
,
2034 &dummy_int
, &dummy_int
, &dummy_uint
, &dummy_uint
,
2035 &dummy_uint
, &dummy_uint
);
2037 /* Make the menu on that window. */
2038 menu
= XMenuCreate (FRAME_X_DISPLAY (f
), root
, "emacs");
2041 *error_name
= "Can't create menu";
2045 /* Don't GC while we prepare and show the menu,
2046 because we give the oldxmenu library pointers to the
2047 contents of strings. */
2048 inhibit_garbage_collection ();
2050 #ifdef HAVE_X_WINDOWS
2051 /* Adjust coordinates to relative to the outer (window manager) window. */
2052 x
+= FRAME_OUTER_TO_INNER_DIFF_X (f
);
2053 y
+= FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2054 #endif /* HAVE_X_WINDOWS */
2056 /* Adjust coordinates to be root-window-relative. */
2060 /* Create all the necessary panes and their items. */
2061 maxwidth
= maxlines
= lines
= i
= 0;
2063 while (i
< menu_items_used
)
2065 if (EQ (AREF (menu_items
, i
), Qt
))
2067 /* Create a new pane. */
2068 Lisp_Object pane_name
, prefix
;
2069 const char *pane_string
;
2071 maxlines
= max (maxlines
, lines
);
2073 pane_name
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_NAME
);
2074 prefix
= AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2075 pane_string
= (NILP (pane_name
)
2076 ? "" : SSDATA (pane_name
));
2077 if ((menuflags
& MENU_KEYMAPS
) && !NILP (prefix
))
2080 lpane
= XMenuAddPane (FRAME_X_DISPLAY (f
), menu
, pane_string
, true);
2081 if (lpane
== XM_FAILURE
)
2083 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2084 *error_name
= "Can't create pane";
2087 i
+= MENU_ITEMS_PANE_LENGTH
;
2089 /* Find the width of the widest item in this pane. */
2091 while (j
< menu_items_used
)
2094 item
= AREF (menu_items
, j
);
2102 width
= SBYTES (item
);
2103 if (width
> maxwidth
)
2106 j
+= MENU_ITEMS_ITEM_LENGTH
;
2109 /* Ignore a nil in the item list.
2110 It's meaningful only for dialog boxes. */
2111 else if (EQ (AREF (menu_items
, i
), Qquote
))
2115 /* Create a new item within current pane. */
2116 Lisp_Object item_name
, enable
, descrip
, help
;
2118 char const *help_string
;
2120 item_name
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_NAME
);
2121 enable
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_ENABLE
);
2123 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_EQUIV_KEY
);
2124 help
= AREF (menu_items
, i
+ MENU_ITEMS_ITEM_HELP
);
2125 help_string
= STRINGP (help
) ? SSDATA (help
) : NULL
;
2127 if (!NILP (descrip
))
2129 item_data
= SAFE_ALLOCA (maxwidth
+ SBYTES (descrip
) + 1);
2130 memcpy (item_data
, SSDATA (item_name
), SBYTES (item_name
));
2131 for (j
= SCHARS (item_name
); j
< maxwidth
; j
++)
2133 memcpy (item_data
+ j
, SSDATA (descrip
), SBYTES (descrip
));
2134 item_data
[j
+ SBYTES (descrip
)] = 0;
2137 item_data
= SSDATA (item_name
);
2139 if (lpane
== XM_FAILURE
2140 || (XMenuAddSelection (FRAME_X_DISPLAY (f
),
2141 menu
, lpane
, 0, item_data
,
2142 !NILP (enable
), help_string
)
2145 XMenuDestroy (FRAME_X_DISPLAY (f
), menu
);
2146 *error_name
= "Can't add selection to menu";
2149 i
+= MENU_ITEMS_ITEM_LENGTH
;
2154 maxlines
= max (maxlines
, lines
);
2156 /* All set and ready to fly. */
2157 XMenuRecompute (FRAME_X_DISPLAY (f
), menu
);
2158 dispwidth
= DisplayWidth (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2159 dispheight
= DisplayHeight (FRAME_X_DISPLAY (f
), FRAME_X_SCREEN_NUMBER (f
));
2160 x
= min (x
, dispwidth
);
2161 y
= min (y
, dispheight
);
2164 XMenuLocate (FRAME_X_DISPLAY (f
), menu
, 0, 0, x
, y
,
2165 &ulx
, &uly
, &width
, &height
);
2166 if (ulx
+width
> dispwidth
)
2168 x
-= (ulx
+ width
) - dispwidth
;
2169 ulx
= dispwidth
- width
;
2171 if (uly
+height
> dispheight
)
2173 y
-= (uly
+ height
) - dispheight
;
2174 uly
= dispheight
- height
;
2176 #ifndef HAVE_X_WINDOWS
2177 if (FRAME_HAS_MINIBUF_P (f
) && uly
+height
> dispheight
- 1)
2179 /* Move the menu away of the echo area, to avoid overwriting the
2180 menu with help echo messages or vice versa. */
2181 if (BUFFERP (echo_area_buffer
[0]) && WINDOWP (echo_area_window
))
2183 y
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2184 uly
-= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window
));
2193 if (ulx
< 0) x
-= ulx
;
2194 if (uly
< 0) y
-= uly
;
2196 if (!(menuflags
& MENU_FOR_CLICK
))
2198 /* If position was not given by a mouse click, adjust so upper left
2199 corner of the menu as a whole ends up at given coordinates. This
2200 is what x-popup-menu says in its documentation. */
2202 y
+= 1.5*height
/(maxlines
+2);
2205 XMenuSetAEQ (menu
, true);
2206 XMenuSetFreeze (menu
, true);
2210 XMenuActivateSetWaitFunction (x_menu_wait_for_event
, FRAME_X_DISPLAY (f
));
2213 record_unwind_protect (pop_down_menu
, make_save_ptr_ptr (f
, menu
));
2215 /* Help display under X won't work because XMenuActivate contains
2216 a loop that doesn't give Emacs a chance to process it. */
2217 menu_help_frame
= f
;
2218 status
= XMenuActivate (FRAME_X_DISPLAY (f
), menu
, &pane
, &selidx
,
2219 x
, y
, ButtonReleaseMask
, &datap
,
2220 menu_help_callback
);
2227 fprintf (stderr
, "pane= %d line = %d\n", panes
, selidx
);
2230 /* Find the item number SELIDX in pane number PANE. */
2232 while (i
< menu_items_used
)
2234 if (EQ (AREF (menu_items
, i
), Qt
))
2238 = AREF (menu_items
, i
+ MENU_ITEMS_PANE_PREFIX
);
2240 i
+= MENU_ITEMS_PANE_LENGTH
;
2249 = AREF (menu_items
, i
+ MENU_ITEMS_ITEM_VALUE
);
2250 if (menuflags
& MENU_KEYMAPS
)
2252 entry
= list1 (entry
);
2253 if (!NILP (pane_prefix
))
2254 entry
= Fcons (pane_prefix
, entry
);
2260 i
+= MENU_ITEMS_ITEM_LENGTH
;
2266 *error_name
= "Can't activate menu";
2270 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2271 the menu was invoked with a mouse event as POSITION). */
2272 if (!(menuflags
& MENU_FOR_CLICK
))
2275 Fsignal (Qquit
, Qnil
);
2283 return unbind_to (specpdl_count
, entry
);
2286 #endif /* not USE_X_TOOLKIT */
2289 /* Detect if a dialog or menu has been posted. MSDOS has its own
2290 implementation on msdos.c. */
2293 popup_activated (void)
2295 return popup_activated_flag
;
2297 #endif /* not MSDOS */
2299 /* The following is used by delayed window autoselection. */
2301 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p
, Smenu_or_popup_active_p
, 0, 0, 0,
2302 doc
: /* Return t if a menu or popup dialog is active. */)
2305 return (popup_activated ()) ? Qt
: Qnil
;
2309 syms_of_xmenu (void)
2311 #ifdef USE_X_TOOLKIT
2312 enum { WIDGET_ID_TICK_START
= 1 << 16 };
2313 widget_id_tick
= WIDGET_ID_TICK_START
;
2314 next_menubar_widget_id
= 1;
2317 DEFSYM (Qdebug_on_next_call
, "debug-on-next-call");
2318 defsubr (&Smenu_or_popup_active_p
);
2320 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2321 defsubr (&Sx_menu_bar_open_internal
);
2322 Ffset (intern_c_string ("accelerate-menu"),
2323 intern_c_string (Sx_menu_bar_open_internal
.symbol_name
));