Merge from emacs-24; up to 2013-01-03T02:37:57Z!rgm@gnu.org
[bpt/emacs.git] / src / xmenu.c
1 /* X Communication module for terminals which understand the X protocol.
2
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2013 Free Software
4 Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
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.
12
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.
17
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/>. */
20
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 *
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
25 *
26 */
27
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
30
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
32
33 #include <config.h>
34
35 #include <stdio.h>
36
37 #include "lisp.h"
38 #include "keyboard.h"
39 #include "keymap.h"
40 #include "frame.h"
41 #include "termhooks.h"
42 #include "window.h"
43 #include "blockinput.h"
44 #include "character.h"
45 #include "buffer.h"
46 #include "charset.h"
47 #include "coding.h"
48 #include "sysselect.h"
49
50 #ifdef MSDOS
51 #include "msdos.h"
52 #endif
53
54 #ifdef HAVE_X_WINDOWS
55 /* This may include sys/types.h, and that somehow loses
56 if this is not done before the other system files. */
57 #include "xterm.h"
58 #endif
59
60 /* Load sys/types.h if not already loaded.
61 In some systems loading it twice is suicidal. */
62 #ifndef makedev
63 #include <sys/types.h>
64 #endif
65
66 #include "dispextern.h"
67
68 #ifdef HAVE_X_WINDOWS
69 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
70 code accepts the Emacs internal encoding. */
71 #undef HAVE_MULTILINGUAL_MENU
72 #ifdef USE_X_TOOLKIT
73 #include "widget.h"
74 #include <X11/Xlib.h>
75 #include <X11/IntrinsicP.h>
76 #include <X11/CoreP.h>
77 #include <X11/StringDefs.h>
78 #include <X11/Shell.h>
79 #ifdef USE_LUCID
80 #include "xsettings.h"
81 #include "../lwlib/xlwmenu.h"
82 #ifdef HAVE_XAW3D
83 #include <X11/Xaw3d/Paned.h>
84 #else /* !HAVE_XAW3D */
85 #include <X11/Xaw/Paned.h>
86 #endif /* HAVE_XAW3D */
87 #endif /* USE_LUCID */
88 #ifdef USE_MOTIF
89 #include "../lwlib/lwlib.h"
90 #endif
91 #else /* not USE_X_TOOLKIT */
92 #ifndef USE_GTK
93 #include "../oldXMenu/XMenu.h"
94 #endif
95 #endif /* not USE_X_TOOLKIT */
96 #endif /* HAVE_X_WINDOWS */
97
98 #ifdef USE_GTK
99 #include "gtkutil.h"
100 #ifdef HAVE_GTK3
101 #include "xgselect.h"
102 #endif
103 #endif
104
105 #include "menu.h"
106
107 #ifndef TRUE
108 #define TRUE 1
109 #endif /* no TRUE */
110
111 static Lisp_Object Qdebug_on_next_call;
112
113 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
114 static Lisp_Object xdialog_show (struct frame *, bool, Lisp_Object, Lisp_Object,
115 const char **);
116 #endif
117 \f
118 /* Flag which when set indicates a dialog or menu has been posted by
119 Xt on behalf of one of the widget sets. */
120 static int popup_activated_flag;
121
122 \f
123 #ifdef USE_X_TOOLKIT
124
125 static int next_menubar_widget_id;
126
127 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
128
129 static struct frame *
130 menubar_id_to_frame (LWLIB_ID id)
131 {
132 Lisp_Object tail, frame;
133 struct frame *f;
134
135 FOR_EACH_FRAME (tail, frame)
136 {
137 f = XFRAME (frame);
138 if (!FRAME_WINDOW_P (f))
139 continue;
140 if (f->output_data.x->id == id)
141 return f;
142 }
143 return 0;
144 }
145
146 #endif
147 \f
148 #ifdef HAVE_X_WINDOWS
149 /* Return the mouse position in *X and *Y. The coordinates are window
150 relative for the edit window in frame F.
151 This is for Fx_popup_menu. The mouse_position_hook can not
152 be used for X, as it returns window relative coordinates
153 for the window where the mouse is in. This could be the menu bar,
154 the scroll bar or the edit window. Fx_popup_menu needs to be
155 sure it is the edit window. */
156 void
157 mouse_position_for_popup (struct frame *f, int *x, int *y)
158 {
159 Window root, dummy_window;
160 int dummy;
161
162 eassert (FRAME_X_P (f));
163
164 block_input ();
165
166 XQueryPointer (FRAME_X_DISPLAY (f),
167 DefaultRootWindow (FRAME_X_DISPLAY (f)),
168
169 /* The root window which contains the pointer. */
170 &root,
171
172 /* Window pointer is on, not used */
173 &dummy_window,
174
175 /* The position on that root window. */
176 x, y,
177
178 /* x/y in dummy_window coordinates, not used. */
179 &dummy, &dummy,
180
181 /* Modifier keys and pointer buttons, about which
182 we don't care. */
183 (unsigned int *) &dummy);
184
185 unblock_input ();
186
187 /* xmenu_show expects window coordinates, not root window
188 coordinates. Translate. */
189 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
190 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
191 }
192
193 #endif /* HAVE_X_WINDOWS */
194
195 #ifndef MSDOS
196
197 #if defined USE_GTK || defined USE_MOTIF
198
199 /* Set menu_items_inuse so no other popup menu or dialog is created. */
200
201 void
202 x_menu_set_in_use (int in_use)
203 {
204 menu_items_inuse = in_use ? Qt : Qnil;
205 popup_activated_flag = in_use;
206 #ifdef USE_X_TOOLKIT
207 if (popup_activated_flag)
208 x_activate_timeout_atimer ();
209 #endif
210 }
211
212 #endif
213
214 /* Wait for an X event to arrive or for a timer to expire. */
215
216 #ifndef USE_MOTIF
217 static
218 #endif
219 void
220 x_menu_wait_for_event (void *data)
221 {
222 /* Another way to do this is to register a timer callback, that can be
223 done in GTK and Xt. But we have to do it like this when using only X
224 anyway, and with callbacks we would have three variants for timer handling
225 instead of the small ifdefs below. */
226
227 while (
228 #ifdef USE_X_TOOLKIT
229 ! XtAppPending (Xt_app_con)
230 #elif defined USE_GTK
231 ! gtk_events_pending ()
232 #else
233 ! XPending (data)
234 #endif
235 )
236 {
237 struct timespec next_time = timer_check (), *ntp;
238 fd_set read_fds;
239 struct x_display_info *dpyinfo;
240 int n = 0;
241
242 FD_ZERO (&read_fds);
243 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
244 {
245 int fd = ConnectionNumber (dpyinfo->display);
246 FD_SET (fd, &read_fds);
247 if (fd > n) n = fd;
248 XFlush (dpyinfo->display);
249 }
250
251 if (! timespec_valid_p (next_time))
252 ntp = 0;
253 else
254 ntp = &next_time;
255
256 #if defined USE_GTK && defined HAVE_GTK3
257 /* Gtk3 have arrows on menus when they don't fit. When the
258 pointer is over an arrow, a timeout scrolls it a bit. Use
259 xg_select so that timeout gets triggered. */
260 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
261 #else
262 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
263 #endif
264 }
265 }
266 #endif /* ! MSDOS */
267
268 \f
269 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
270
271 #ifdef USE_X_TOOLKIT
272
273 /* Loop in Xt until the menu pulldown or dialog popup has been
274 popped down (deactivated). This is used for x-popup-menu
275 and x-popup-dialog; it is not used for the menu bar.
276
277 NOTE: All calls to popup_get_selection should be protected
278 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
279
280 static void
281 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo, LWLIB_ID id, int do_timers)
282 {
283 XEvent event;
284
285 while (popup_activated_flag)
286 {
287 if (initial_event)
288 {
289 event = *initial_event;
290 initial_event = 0;
291 }
292 else
293 {
294 if (do_timers) x_menu_wait_for_event (0);
295 XtAppNextEvent (Xt_app_con, &event);
296 }
297
298 /* Make sure we don't consider buttons grabbed after menu goes.
299 And make sure to deactivate for any ButtonRelease,
300 even if XtDispatchEvent doesn't do that. */
301 if (event.type == ButtonRelease
302 && dpyinfo->display == event.xbutton.display)
303 {
304 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
305 #ifdef USE_MOTIF /* Pretending that the event came from a
306 Btn1Down seems the only way to convince Motif to
307 activate its callbacks; setting the XmNmenuPost
308 isn't working. --marcus@sysc.pdx.edu. */
309 event.xbutton.button = 1;
310 /* Motif only pops down menus when no Ctrl, Alt or Mod
311 key is pressed and the button is released. So reset key state
312 so Motif thinks this is the case. */
313 event.xbutton.state = 0;
314 #endif
315 }
316 /* Pop down on C-g and Escape. */
317 else if (event.type == KeyPress
318 && dpyinfo->display == event.xbutton.display)
319 {
320 KeySym keysym = XLookupKeysym (&event.xkey, 0);
321
322 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
323 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
324 popup_activated_flag = 0;
325 }
326
327 x_dispatch_event (&event, event.xany.display);
328 }
329 }
330
331 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
332 doc: /* Start key navigation of the menu bar in FRAME.
333 This initially opens the first menu bar item and you can then navigate with the
334 arrow keys, select a menu entry with the return key or cancel with the
335 escape key. If FRAME has no menu bar this function does nothing.
336
337 If FRAME is nil or not given, use the selected frame. */)
338 (Lisp_Object frame)
339 {
340 XEvent ev;
341 struct frame *f = decode_window_system_frame (frame);
342 Widget menubar;
343 block_input ();
344
345 if (FRAME_EXTERNAL_MENU_BAR (f))
346 set_frame_menubar (f, 0, 1);
347
348 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
349 if (menubar)
350 {
351 Window child;
352 bool error_p = 0;
353
354 x_catch_errors (FRAME_X_DISPLAY (f));
355 memset (&ev, 0, sizeof ev);
356 ev.xbutton.display = FRAME_X_DISPLAY (f);
357 ev.xbutton.window = XtWindow (menubar);
358 ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
359 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
360 ev.xbutton.button = Button1;
361 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
362 ev.xbutton.same_screen = True;
363
364 #ifdef USE_MOTIF
365 {
366 Arg al[2];
367 WidgetList list;
368 Cardinal nr;
369 XtSetArg (al[0], XtNchildren, &list);
370 XtSetArg (al[1], XtNnumChildren, &nr);
371 XtGetValues (menubar, al, 2);
372 ev.xbutton.window = XtWindow (list[0]);
373 }
374 #endif
375
376 XTranslateCoordinates (FRAME_X_DISPLAY (f),
377 /* From-window, to-window. */
378 ev.xbutton.window, ev.xbutton.root,
379
380 /* From-position, to-position. */
381 ev.xbutton.x, ev.xbutton.y,
382 &ev.xbutton.x_root, &ev.xbutton.y_root,
383
384 /* Child of win. */
385 &child);
386 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
387 x_uncatch_errors ();
388
389 if (! error_p)
390 {
391 ev.type = ButtonPress;
392 ev.xbutton.state = 0;
393
394 XtDispatchEvent (&ev);
395 ev.xbutton.type = ButtonRelease;
396 ev.xbutton.state = Button1Mask;
397 XtDispatchEvent (&ev);
398 }
399 }
400
401 unblock_input ();
402
403 return Qnil;
404 }
405 #endif /* USE_X_TOOLKIT */
406
407
408 #ifdef USE_GTK
409 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
410 doc: /* Start key navigation of the menu bar in FRAME.
411 This initially opens the first menu bar item and you can then navigate with the
412 arrow keys, select a menu entry with the return key or cancel with the
413 escape key. If FRAME has no menu bar this function does nothing.
414
415 If FRAME is nil or not given, use the selected frame. */)
416 (Lisp_Object frame)
417 {
418 GtkWidget *menubar;
419 struct frame *f;
420
421 block_input ();
422 f = decode_window_system_frame (frame);
423
424 if (FRAME_EXTERNAL_MENU_BAR (f))
425 set_frame_menubar (f, 0, 1);
426
427 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
428 if (menubar)
429 {
430 /* Activate the first menu. */
431 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
432
433 if (children)
434 {
435 g_signal_emit_by_name (children->data, "activate_item");
436 popup_activated_flag = 1;
437 g_list_free (children);
438 }
439 }
440 unblock_input ();
441
442 return Qnil;
443 }
444
445 /* Loop util popup_activated_flag is set to zero in a callback.
446 Used for popup menus and dialogs. */
447
448 static void
449 popup_widget_loop (int do_timers, GtkWidget *widget)
450 {
451 ++popup_activated_flag;
452
453 /* Process events in the Gtk event loop until done. */
454 while (popup_activated_flag)
455 {
456 if (do_timers) x_menu_wait_for_event (0);
457 gtk_main_iteration ();
458 }
459 }
460 #endif
461
462 /* Activate the menu bar of frame F.
463 This is called from keyboard.c when it gets the
464 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
465
466 To activate the menu bar, we use the X button-press event
467 that was saved in saved_menu_event.
468 That makes the toolkit do its thing.
469
470 But first we recompute the menu bar contents (the whole tree).
471
472 The reason for saving the button event until here, instead of
473 passing it to the toolkit right away, is that we can safely
474 execute Lisp code. */
475
476 void
477 x_activate_menubar (struct frame *f)
478 {
479 eassert (FRAME_X_P (f));
480
481 if (!f->output_data.x->saved_menu_event->type)
482 return;
483
484 #ifdef USE_GTK
485 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
486 f->output_data.x->saved_menu_event->xany.window))
487 return;
488 #endif
489
490 set_frame_menubar (f, 0, 1);
491 block_input ();
492 popup_activated_flag = 1;
493 #ifdef USE_GTK
494 XPutBackEvent (f->output_data.x->display_info->display,
495 f->output_data.x->saved_menu_event);
496 #else
497 XtDispatchEvent (f->output_data.x->saved_menu_event);
498 #endif
499 unblock_input ();
500
501 /* Ignore this if we get it a second time. */
502 f->output_data.x->saved_menu_event->type = 0;
503 }
504
505 /* This callback is invoked when the user selects a menubar cascade
506 pushbutton, but before the pulldown menu is posted. */
507
508 #ifndef USE_GTK
509 static void
510 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
511 {
512 popup_activated_flag = 1;
513 #ifdef USE_X_TOOLKIT
514 x_activate_timeout_atimer ();
515 #endif
516 }
517 #endif
518
519 /* This callback is invoked when a dialog or menu is finished being
520 used and has been unposted. */
521
522 static void
523 popup_deactivate_callback (
524 #ifdef USE_GTK
525 GtkWidget *widget, gpointer client_data
526 #else
527 Widget widget, LWLIB_ID id, XtPointer client_data
528 #endif
529 )
530 {
531 popup_activated_flag = 0;
532 }
533
534
535 /* Function that finds the frame for WIDGET and shows the HELP text
536 for that widget.
537 F is the frame if known, or NULL if not known. */
538 static void
539 show_help_event (struct frame *f, xt_or_gtk_widget widget, Lisp_Object help)
540 {
541 Lisp_Object frame;
542
543 if (f)
544 {
545 XSETFRAME (frame, f);
546 kbd_buffer_store_help_event (frame, help);
547 }
548 else
549 {
550 #if 0 /* This code doesn't do anything useful. ++kfs */
551 /* WIDGET is the popup menu. It's parent is the frame's
552 widget. See which frame that is. */
553 xt_or_gtk_widget frame_widget = XtParent (widget);
554 Lisp_Object tail;
555
556 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
557 {
558 frame = XCAR (tail);
559 if (FRAMEP (frame)
560 && (f = XFRAME (frame),
561 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
562 break;
563 }
564 #endif
565 show_help_echo (help, Qnil, Qnil, Qnil);
566 }
567 }
568
569 /* Callback called when menu items are highlighted/unhighlighted
570 while moving the mouse over them. WIDGET is the menu bar or menu
571 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
572 the data structure for the menu item, or null in case of
573 unhighlighting. */
574
575 #ifdef USE_GTK
576 static void
577 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
578 {
579 xg_menu_item_cb_data *cb_data;
580 Lisp_Object help;
581
582 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
583 if (! cb_data) return;
584
585 help = call_data ? cb_data->help : Qnil;
586
587 /* If popup_activated_flag is greater than 1 we are in a popup menu.
588 Don't pass the frame to show_help_event for those.
589 Passing frame creates an Emacs event. As we are looping in
590 popup_widget_loop, it won't be handled. Passing NULL shows the tip
591 directly without using an Emacs event. This is what the Lucid code
592 does below. */
593 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
594 widget, help);
595 }
596 #else
597 static void
598 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
599 {
600 widget_value *wv = call_data;
601 Lisp_Object help = wv ? wv->help : Qnil;
602
603 /* Determine the frame for the help event. */
604 struct frame *f = menubar_id_to_frame (id);
605
606 show_help_event (f, widget, help);
607 }
608 #endif
609
610 #ifdef USE_GTK
611 /* Gtk calls callbacks just because we tell it what item should be
612 selected in a radio group. If this variable is set to a non-zero
613 value, we are creating menus and don't want callbacks right now.
614 */
615 static int xg_crazy_callback_abort;
616
617 /* This callback is called from the menu bar pulldown menu
618 when the user makes a selection.
619 Figure out what the user chose
620 and put the appropriate events into the keyboard buffer. */
621 static void
622 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
623 {
624 xg_menu_item_cb_data *cb_data = client_data;
625
626 if (xg_crazy_callback_abort)
627 return;
628
629 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
630 return;
631
632 /* For a group of radio buttons, GTK calls the selection callback first
633 for the item that was active before the selection and then for the one that
634 is active after the selection. For C-h k this means we get the help on
635 the deselected item and then the selected item is executed. Prevent that
636 by ignoring the non-active item. */
637 if (GTK_IS_RADIO_MENU_ITEM (widget)
638 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
639 return;
640
641 /* When a menu is popped down, X generates a focus event (i.e. focus
642 goes back to the frame below the menu). Since GTK buffers events,
643 we force it out here before the menu selection event. Otherwise
644 sit-for will exit at once if the focus event follows the menu selection
645 event. */
646
647 block_input ();
648 while (gtk_events_pending ())
649 gtk_main_iteration ();
650 unblock_input ();
651
652 find_and_call_menu_selection (cb_data->cl_data->f,
653 cb_data->cl_data->menu_bar_items_used,
654 cb_data->cl_data->menu_bar_vector,
655 cb_data->call_data);
656 }
657
658 #else /* not USE_GTK */
659
660 /* This callback is called from the menu bar pulldown menu
661 when the user makes a selection.
662 Figure out what the user chose
663 and put the appropriate events into the keyboard buffer. */
664 static void
665 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
666 {
667 struct frame *f;
668
669 f = menubar_id_to_frame (id);
670 if (!f)
671 return;
672 find_and_call_menu_selection (f, f->menu_bar_items_used,
673 f->menu_bar_vector, client_data);
674 }
675 #endif /* not USE_GTK */
676 \f
677 /* Recompute all the widgets of frame F, when the menu bar has been
678 changed. */
679
680 static void
681 update_frame_menubar (struct frame *f)
682 {
683 #ifdef USE_GTK
684 xg_update_frame_menubar (f);
685 #else
686 struct x_output *x;
687 int columns, rows;
688
689 eassert (FRAME_X_P (f));
690
691 x = f->output_data.x;
692
693 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
694 return;
695
696 block_input ();
697 /* Save the size of the frame because the pane widget doesn't accept
698 to resize itself. So force it. */
699 columns = FRAME_COLS (f);
700 rows = FRAME_LINES (f);
701
702 /* Do the voodoo which means "I'm changing lots of things, don't try
703 to refigure sizes until I'm done." */
704 lw_refigure_widget (x->column_widget, False);
705
706 /* The order in which children are managed is the top to bottom
707 order in which they are displayed in the paned window. First,
708 remove the text-area widget. */
709 XtUnmanageChild (x->edit_widget);
710
711 /* Remove the menubar that is there now, and put up the menubar that
712 should be there. */
713 XtManageChild (x->menubar_widget);
714 XtMapWidget (x->menubar_widget);
715 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
716
717 /* Re-manage the text-area widget, and then thrash the sizes. */
718 XtManageChild (x->edit_widget);
719 lw_refigure_widget (x->column_widget, True);
720
721 /* Force the pane widget to resize itself with the right values. */
722 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
723 unblock_input ();
724 #endif
725 }
726
727 #ifdef USE_LUCID
728 static void
729 apply_systemfont_to_dialog (Widget w)
730 {
731 const char *fn = xsettings_get_system_normal_font ();
732 if (fn)
733 {
734 XrmDatabase db = XtDatabase (XtDisplay (w));
735 if (db)
736 XrmPutStringResource (&db, "*dialog.font", fn);
737 }
738 }
739
740 static void
741 apply_systemfont_to_menu (struct frame *f, Widget w)
742 {
743 const char *fn = xsettings_get_system_normal_font ();
744
745 if (fn)
746 {
747 XrmDatabase db = XtDatabase (XtDisplay (w));
748 if (db)
749 {
750 XrmPutStringResource (&db, "*menubar*font", fn);
751 XrmPutStringResource (&db, "*popup*font", fn);
752 }
753 }
754 }
755
756 #endif
757
758 /* Set the contents of the menubar widgets of frame F.
759 The argument FIRST_TIME is currently ignored;
760 it is set the first time this is called, from initialize_frame_menubar. */
761
762 void
763 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
764 {
765 xt_or_gtk_widget menubar_widget;
766 #ifdef USE_X_TOOLKIT
767 LWLIB_ID id;
768 #endif
769 Lisp_Object items;
770 widget_value *wv, *first_wv, *prev_wv = 0;
771 int i;
772 int *submenu_start, *submenu_end;
773 bool *submenu_top_level_items;
774 int *submenu_n_panes;
775
776 eassert (FRAME_X_P (f));
777
778 menubar_widget = f->output_data.x->menubar_widget;
779
780 XSETFRAME (Vmenu_updating_frame, f);
781
782 #ifdef USE_X_TOOLKIT
783 if (f->output_data.x->id == 0)
784 f->output_data.x->id = next_menubar_widget_id++;
785 id = f->output_data.x->id;
786 #endif
787
788 if (! menubar_widget)
789 deep_p = 1;
790 /* Make the first call for any given frame always go deep. */
791 else if (!f->output_data.x->saved_menu_event && !deep_p)
792 {
793 deep_p = 1;
794 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
795 f->output_data.x->saved_menu_event->type = 0;
796 }
797
798 #ifdef USE_GTK
799 /* If we have detached menus, we must update deep so detached menus
800 also gets updated. */
801 deep_p = deep_p || xg_have_tear_offs ();
802 #endif
803
804 if (deep_p)
805 {
806 /* Make a widget-value tree representing the entire menu trees. */
807
808 struct buffer *prev = current_buffer;
809 Lisp_Object buffer;
810 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
811 int previous_menu_items_used = f->menu_bar_items_used;
812 Lisp_Object *previous_items
813 = alloca (previous_menu_items_used * sizeof *previous_items);
814 int subitems;
815
816 /* If we are making a new widget, its contents are empty,
817 do always reinitialize them. */
818 if (! menubar_widget)
819 previous_menu_items_used = 0;
820
821 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
822 specbind (Qinhibit_quit, Qt);
823 /* Don't let the debugger step into this code
824 because it is not reentrant. */
825 specbind (Qdebug_on_next_call, Qnil);
826
827 record_unwind_save_match_data ();
828 if (NILP (Voverriding_local_map_menu_flag))
829 {
830 specbind (Qoverriding_terminal_local_map, Qnil);
831 specbind (Qoverriding_local_map, Qnil);
832 }
833
834 set_buffer_internal_1 (XBUFFER (buffer));
835
836 /* Run the Lucid hook. */
837 safe_run_hooks (Qactivate_menubar_hook);
838
839 /* If it has changed current-menubar from previous value,
840 really recompute the menubar from the value. */
841 if (! NILP (Vlucid_menu_bar_dirty_flag))
842 call0 (Qrecompute_lucid_menubar);
843 safe_run_hooks (Qmenu_bar_update_hook);
844 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
845
846 items = FRAME_MENU_BAR_ITEMS (f);
847
848 /* Save the frame's previous menu bar contents data. */
849 if (previous_menu_items_used)
850 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
851 previous_menu_items_used * word_size);
852
853 /* Fill in menu_items with the current menu bar contents.
854 This can evaluate Lisp code. */
855 save_menu_items ();
856
857 menu_items = f->menu_bar_vector;
858 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
859 subitems = ASIZE (items) / 4;
860 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
861 submenu_end = alloca (subitems * sizeof *submenu_end);
862 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
863 submenu_top_level_items = alloca (subitems
864 * sizeof *submenu_top_level_items);
865 init_menu_items ();
866 for (i = 0; i < subitems; i++)
867 {
868 Lisp_Object key, string, maps;
869
870 key = AREF (items, 4 * i);
871 string = AREF (items, 4 * i + 1);
872 maps = AREF (items, 4 * i + 2);
873 if (NILP (string))
874 break;
875
876 submenu_start[i] = menu_items_used;
877
878 menu_items_n_panes = 0;
879 submenu_top_level_items[i]
880 = parse_single_submenu (key, string, maps);
881 submenu_n_panes[i] = menu_items_n_panes;
882
883 submenu_end[i] = menu_items_used;
884 }
885
886 submenu_start[i] = -1;
887 finish_menu_items ();
888
889 /* Convert menu_items into widget_value trees
890 to display the menu. This cannot evaluate Lisp code. */
891
892 wv = xmalloc_widget_value ();
893 wv->name = "menubar";
894 wv->value = 0;
895 wv->enabled = 1;
896 wv->button_type = BUTTON_TYPE_NONE;
897 wv->help = Qnil;
898 first_wv = wv;
899
900 for (i = 0; submenu_start[i] >= 0; i++)
901 {
902 menu_items_n_panes = submenu_n_panes[i];
903 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
904 submenu_top_level_items[i]);
905 if (prev_wv)
906 prev_wv->next = wv;
907 else
908 first_wv->contents = wv;
909 /* Don't set wv->name here; GC during the loop might relocate it. */
910 wv->enabled = 1;
911 wv->button_type = BUTTON_TYPE_NONE;
912 prev_wv = wv;
913 }
914
915 set_buffer_internal_1 (prev);
916
917 /* If there has been no change in the Lisp-level contents
918 of the menu bar, skip redisplaying it. Just exit. */
919
920 /* Compare the new menu items with the ones computed last time. */
921 for (i = 0; i < previous_menu_items_used; i++)
922 if (menu_items_used == i
923 || (!EQ (previous_items[i], AREF (menu_items, i))))
924 break;
925 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
926 {
927 /* The menu items have not changed. Don't bother updating
928 the menus in any form, since it would be a no-op. */
929 free_menubar_widget_value_tree (first_wv);
930 discard_menu_items ();
931 unbind_to (specpdl_count, Qnil);
932 return;
933 }
934
935 /* The menu items are different, so store them in the frame. */
936 fset_menu_bar_vector (f, menu_items);
937 f->menu_bar_items_used = menu_items_used;
938
939 /* This undoes save_menu_items. */
940 unbind_to (specpdl_count, Qnil);
941
942 /* Now GC cannot happen during the lifetime of the widget_value,
943 so it's safe to store data from a Lisp_String. */
944 wv = first_wv->contents;
945 for (i = 0; i < ASIZE (items); i += 4)
946 {
947 Lisp_Object string;
948 string = AREF (items, i + 1);
949 if (NILP (string))
950 break;
951 wv->name = SSDATA (string);
952 update_submenu_strings (wv->contents);
953 wv = wv->next;
954 }
955
956 }
957 else
958 {
959 /* Make a widget-value tree containing
960 just the top level menu bar strings. */
961
962 wv = xmalloc_widget_value ();
963 wv->name = "menubar";
964 wv->value = 0;
965 wv->enabled = 1;
966 wv->button_type = BUTTON_TYPE_NONE;
967 wv->help = Qnil;
968 first_wv = wv;
969
970 items = FRAME_MENU_BAR_ITEMS (f);
971 for (i = 0; i < ASIZE (items); i += 4)
972 {
973 Lisp_Object string;
974
975 string = AREF (items, i + 1);
976 if (NILP (string))
977 break;
978
979 wv = xmalloc_widget_value ();
980 wv->name = SSDATA (string);
981 wv->value = 0;
982 wv->enabled = 1;
983 wv->button_type = BUTTON_TYPE_NONE;
984 wv->help = Qnil;
985 /* This prevents lwlib from assuming this
986 menu item is really supposed to be empty. */
987 /* The intptr_t cast avoids a warning.
988 This value just has to be different from small integers. */
989 wv->call_data = (void *) (intptr_t) (-1);
990
991 if (prev_wv)
992 prev_wv->next = wv;
993 else
994 first_wv->contents = wv;
995 prev_wv = wv;
996 }
997
998 /* Forget what we thought we knew about what is in the
999 detailed contents of the menu bar menus.
1000 Changing the top level always destroys the contents. */
1001 f->menu_bar_items_used = 0;
1002 }
1003
1004 /* Create or update the menu bar widget. */
1005
1006 block_input ();
1007
1008 #ifdef USE_GTK
1009 xg_crazy_callback_abort = 1;
1010 if (menubar_widget)
1011 {
1012 /* The fourth arg is DEEP_P, which says to consider the entire
1013 menu trees we supply, rather than just the menu bar item names. */
1014 xg_modify_menubar_widgets (menubar_widget,
1015 f,
1016 first_wv,
1017 deep_p,
1018 G_CALLBACK (menubar_selection_callback),
1019 G_CALLBACK (popup_deactivate_callback),
1020 G_CALLBACK (menu_highlight_callback));
1021 }
1022 else
1023 {
1024 menubar_widget
1025 = xg_create_widget ("menubar", "menubar", f, first_wv,
1026 G_CALLBACK (menubar_selection_callback),
1027 G_CALLBACK (popup_deactivate_callback),
1028 G_CALLBACK (menu_highlight_callback));
1029
1030 f->output_data.x->menubar_widget = menubar_widget;
1031 }
1032
1033
1034 #else /* not USE_GTK */
1035 if (menubar_widget)
1036 {
1037 /* Disable resizing (done for Motif!) */
1038 lw_allow_resizing (f->output_data.x->widget, False);
1039
1040 /* The third arg is DEEP_P, which says to consider the entire
1041 menu trees we supply, rather than just the menu bar item names. */
1042 lw_modify_all_widgets (id, first_wv, deep_p);
1043
1044 /* Re-enable the edit widget to resize. */
1045 lw_allow_resizing (f->output_data.x->widget, True);
1046 }
1047 else
1048 {
1049 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1050 XtTranslations override = XtParseTranslationTable (menuOverride);
1051
1052 #ifdef USE_LUCID
1053 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
1054 #endif
1055 menubar_widget = lw_create_widget ("menubar", "menubar", id,
1056 first_wv,
1057 f->output_data.x->column_widget,
1058 0,
1059 popup_activate_callback,
1060 menubar_selection_callback,
1061 popup_deactivate_callback,
1062 menu_highlight_callback);
1063 f->output_data.x->menubar_widget = menubar_widget;
1064
1065 /* Make menu pop down on C-g. */
1066 XtOverrideTranslations (menubar_widget, override);
1067 }
1068
1069 {
1070 int menubar_size;
1071 if (f->output_data.x->menubar_widget)
1072 XtRealizeWidget (f->output_data.x->menubar_widget);
1073
1074 menubar_size
1075 = (f->output_data.x->menubar_widget
1076 ? (f->output_data.x->menubar_widget->core.height
1077 + f->output_data.x->menubar_widget->core.border_width)
1078 : 0);
1079
1080 #if 1 /* Experimentally, we now get the right results
1081 for -geometry -0-0 without this. 24 Aug 96, rms.
1082 Maybe so, but the menu bar size is missing the pixels so the
1083 WM size hints are off by these pixels. Jan D, oct 2009. */
1084 #ifdef USE_LUCID
1085 if (FRAME_EXTERNAL_MENU_BAR (f))
1086 {
1087 Dimension ibw = 0;
1088 XtVaGetValues (f->output_data.x->column_widget,
1089 XtNinternalBorderWidth, &ibw, NULL);
1090 menubar_size += ibw;
1091 }
1092 #endif /* USE_LUCID */
1093 #endif /* 1 */
1094
1095 f->output_data.x->menubar_height = menubar_size;
1096 }
1097 #endif /* not USE_GTK */
1098
1099 free_menubar_widget_value_tree (first_wv);
1100 update_frame_menubar (f);
1101
1102 #ifdef USE_GTK
1103 xg_crazy_callback_abort = 0;
1104 #endif
1105
1106 unblock_input ();
1107 }
1108
1109 /* Called from Fx_create_frame to create the initial menubar of a frame
1110 before it is mapped, so that the window is mapped with the menubar already
1111 there instead of us tacking it on later and thrashing the window after it
1112 is visible. */
1113
1114 void
1115 initialize_frame_menubar (struct frame *f)
1116 {
1117 /* This function is called before the first chance to redisplay
1118 the frame. It has to be, so the frame will have the right size. */
1119 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1120 set_frame_menubar (f, 1, 1);
1121 }
1122
1123
1124 /* Get rid of the menu bar of frame F, and free its storage.
1125 This is used when deleting a frame, and when turning off the menu bar.
1126 For GTK this function is in gtkutil.c. */
1127
1128 #ifndef USE_GTK
1129 void
1130 free_frame_menubar (struct frame *f)
1131 {
1132 Widget menubar_widget;
1133
1134 eassert (FRAME_X_P (f));
1135
1136 menubar_widget = f->output_data.x->menubar_widget;
1137
1138 f->output_data.x->menubar_height = 0;
1139
1140 if (menubar_widget)
1141 {
1142 #ifdef USE_MOTIF
1143 /* Removing the menu bar magically changes the shell widget's x
1144 and y position of (0, 0) which, when the menu bar is turned
1145 on again, leads to pull-down menus appearing in strange
1146 positions near the upper-left corner of the display. This
1147 happens only with some window managers like twm and ctwm,
1148 but not with other like Motif's mwm or kwm, because the
1149 latter generate ConfigureNotify events when the menu bar
1150 is switched off, which fixes the shell position. */
1151 Position x0, y0, x1, y1;
1152 #endif
1153
1154 block_input ();
1155
1156 #ifdef USE_MOTIF
1157 if (f->output_data.x->widget)
1158 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1159 #endif
1160
1161 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1162 f->output_data.x->menubar_widget = NULL;
1163
1164 if (f->output_data.x->widget)
1165 {
1166 #ifdef USE_MOTIF
1167 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1168 if (x1 == 0 && y1 == 0)
1169 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1170 #endif
1171 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1172 }
1173 unblock_input ();
1174 }
1175 }
1176 #endif /* not USE_GTK */
1177
1178 #endif /* USE_X_TOOLKIT || USE_GTK */
1179 \f
1180 /* xmenu_show actually displays a menu using the panes and items in menu_items
1181 and returns the value selected from it.
1182 There are two versions of xmenu_show, one for Xt and one for Xlib.
1183 Both assume input is blocked by the caller. */
1184
1185 /* F is the frame the menu is for.
1186 X and Y are the frame-relative specified position,
1187 relative to the inside upper left corner of the frame F.
1188 FOR_CLICK is true if this menu was invoked for a mouse click.
1189 KEYMAPS is true if this menu was specified with keymaps;
1190 in that case, we return a list containing the chosen item's value
1191 and perhaps also the pane's prefix.
1192 TITLE is the specified menu title.
1193 ERROR is a place to store an error message string in case of failure.
1194 (We return nil on failure, but the value doesn't actually matter.) */
1195
1196 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1197
1198 /* The item selected in the popup menu. */
1199 static Lisp_Object *volatile menu_item_selection;
1200
1201 #ifdef USE_GTK
1202
1203 /* Used when position a popup menu. See menu_position_func and
1204 create_and_show_popup_menu below. */
1205 struct next_popup_x_y
1206 {
1207 struct frame *f;
1208 int x;
1209 int y;
1210 };
1211
1212 /* The menu position function to use if we are not putting a popup
1213 menu where the pointer is.
1214 MENU is the menu to pop up.
1215 X and Y shall on exit contain x/y where the menu shall pop up.
1216 PUSH_IN is not documented in the GTK manual.
1217 USER_DATA is any data passed in when calling gtk_menu_popup.
1218 Here it points to a struct next_popup_x_y where the coordinates
1219 to store in *X and *Y are as well as the frame for the popup.
1220
1221 Here only X and Y are used. */
1222 static void
1223 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1224 {
1225 struct next_popup_x_y *data = user_data;
1226 GtkRequisition req;
1227 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1228 int disp_width = x_display_pixel_width (dpyinfo);
1229 int disp_height = x_display_pixel_height (dpyinfo);
1230
1231 *x = data->x;
1232 *y = data->y;
1233
1234 /* Check if there is room for the menu. If not, adjust x/y so that
1235 the menu is fully visible. */
1236 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1237 if (data->x + req.width > disp_width)
1238 *x -= data->x + req.width - disp_width;
1239 if (data->y + req.height > disp_height)
1240 *y -= data->y + req.height - disp_height;
1241 }
1242
1243 static void
1244 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1245 {
1246 xg_menu_item_cb_data *cb_data = client_data;
1247
1248 if (xg_crazy_callback_abort) return;
1249 if (cb_data) menu_item_selection = cb_data->call_data;
1250 }
1251
1252 static void
1253 pop_down_menu (void *arg)
1254 {
1255 popup_activated_flag = 0;
1256 block_input ();
1257 gtk_widget_destroy (GTK_WIDGET (arg));
1258 unblock_input ();
1259 }
1260
1261 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1262 menu pops down.
1263 menu_item_selection will be set to the selection. */
1264 static void
1265 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1266 int x, int y, bool for_click)
1267 {
1268 int i;
1269 GtkWidget *menu;
1270 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1271 struct next_popup_x_y popup_x_y;
1272 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1273 bool use_pos_func = ! for_click;
1274
1275 #ifdef HAVE_GTK3
1276 /* Always use position function for Gtk3. Otherwise menus may become
1277 too small to show anything. */
1278 use_pos_func = 1;
1279 #endif
1280
1281 eassert (FRAME_X_P (f));
1282
1283 xg_crazy_callback_abort = 1;
1284 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1285 G_CALLBACK (popup_selection_callback),
1286 G_CALLBACK (popup_deactivate_callback),
1287 G_CALLBACK (menu_highlight_callback));
1288 xg_crazy_callback_abort = 0;
1289
1290 if (use_pos_func)
1291 {
1292 /* Not invoked by a click. pop up at x/y. */
1293 pos_func = menu_position_func;
1294
1295 /* Adjust coordinates to be root-window-relative. */
1296 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1297 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1298
1299 popup_x_y.x = x;
1300 popup_x_y.y = y;
1301 popup_x_y.f = f;
1302
1303 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1304 }
1305
1306 if (for_click)
1307 {
1308 for (i = 0; i < 5; i++)
1309 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1310 break;
1311 }
1312
1313 /* Display the menu. */
1314 gtk_widget_show_all (menu);
1315
1316 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1317 FRAME_DISPLAY_INFO (f)->last_user_time);
1318
1319 record_unwind_protect_ptr (pop_down_menu, menu);
1320
1321 if (gtk_widget_get_mapped (menu))
1322 {
1323 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1324 two. show_help_echo uses this to detect popup menus. */
1325 popup_activated_flag = 1;
1326 /* Process events that apply to the menu. */
1327 popup_widget_loop (1, menu);
1328 }
1329
1330 unbind_to (specpdl_count, Qnil);
1331
1332 /* Must reset this manually because the button release event is not passed
1333 to Emacs event loop. */
1334 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1335 }
1336
1337 #else /* not USE_GTK */
1338
1339 /* We need a unique id for each widget handled by the Lucid Widget
1340 library.
1341
1342 For the main windows, and popup menus, we use this counter,
1343 which we increment each time after use. This starts from 1<<16.
1344
1345 For menu bars, we use numbers starting at 0, counted in
1346 next_menubar_widget_id. */
1347 LWLIB_ID widget_id_tick;
1348
1349 static void
1350 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1351 {
1352 menu_item_selection = client_data;
1353 }
1354
1355 /* ARG is the LWLIB ID of the dialog box, represented
1356 as a Lisp object as (HIGHPART . LOWPART). */
1357
1358 static void
1359 pop_down_menu (Lisp_Object arg)
1360 {
1361 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1362 | XINT (XCDR (arg)));
1363
1364 block_input ();
1365 lw_destroy_all_widgets (id);
1366 unblock_input ();
1367 popup_activated_flag = 0;
1368 }
1369
1370 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1371 menu pops down.
1372 menu_item_selection will be set to the selection. */
1373 static void
1374 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1375 int x, int y, bool for_click)
1376 {
1377 int i;
1378 Arg av[2];
1379 int ac = 0;
1380 XEvent dummy;
1381 XButtonPressedEvent *event = &(dummy.xbutton);
1382 LWLIB_ID menu_id;
1383 Widget menu;
1384
1385 eassert (FRAME_X_P (f));
1386
1387 #ifdef USE_LUCID
1388 apply_systemfont_to_menu (f, f->output_data.x->widget);
1389 #endif
1390
1391 menu_id = widget_id_tick++;
1392 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1393 f->output_data.x->widget, 1, 0,
1394 popup_selection_callback,
1395 popup_deactivate_callback,
1396 menu_highlight_callback);
1397
1398 event->type = ButtonPress;
1399 event->serial = 0;
1400 event->send_event = 0;
1401 event->display = FRAME_X_DISPLAY (f);
1402 event->time = CurrentTime;
1403 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1404 event->window = event->subwindow = event->root;
1405 event->x = x;
1406 event->y = y;
1407
1408 /* Adjust coordinates to be root-window-relative. */
1409 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1410 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1411
1412 event->x_root = x;
1413 event->y_root = y;
1414
1415 event->state = 0;
1416 event->button = 0;
1417 for (i = 0; i < 5; i++)
1418 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1419 event->button = i;
1420
1421 /* Don't allow any geometry request from the user. */
1422 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1423 XtSetValues (menu, av, ac);
1424
1425 /* Display the menu. */
1426 lw_popup_menu (menu, &dummy);
1427 popup_activated_flag = 1;
1428 x_activate_timeout_atimer ();
1429
1430 {
1431 int fact = 4 * sizeof (LWLIB_ID);
1432 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1433 record_unwind_protect (pop_down_menu,
1434 Fcons (make_number (menu_id >> (fact)),
1435 make_number (menu_id & ~(-1 << (fact)))));
1436
1437 /* Process events that apply to the menu. */
1438 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, 1);
1439
1440 unbind_to (specpdl_count, Qnil);
1441 }
1442 }
1443
1444 #endif /* not USE_GTK */
1445
1446 static void
1447 cleanup_widget_value_tree (void *arg)
1448 {
1449 free_menubar_widget_value_tree (arg);
1450 }
1451
1452 Lisp_Object
1453 xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
1454 Lisp_Object title, const char **error_name)
1455 {
1456 int i;
1457 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1458 widget_value **submenu_stack
1459 = alloca (menu_items_used * sizeof *submenu_stack);
1460 Lisp_Object *subprefix_stack
1461 = alloca (menu_items_used * sizeof *subprefix_stack);
1462 int submenu_depth = 0;
1463
1464 int first_pane;
1465
1466 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1467
1468 eassert (FRAME_X_P (f));
1469
1470 *error_name = NULL;
1471
1472 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1473 {
1474 *error_name = "Empty menu";
1475 return Qnil;
1476 }
1477
1478 block_input ();
1479
1480 /* Create a tree of widget_value objects
1481 representing the panes and their items. */
1482 wv = xmalloc_widget_value ();
1483 wv->name = "menu";
1484 wv->value = 0;
1485 wv->enabled = 1;
1486 wv->button_type = BUTTON_TYPE_NONE;
1487 wv->help =Qnil;
1488 first_wv = wv;
1489 first_pane = 1;
1490
1491 /* Loop over all panes and items, filling in the tree. */
1492 i = 0;
1493 while (i < menu_items_used)
1494 {
1495 if (EQ (AREF (menu_items, i), Qnil))
1496 {
1497 submenu_stack[submenu_depth++] = save_wv;
1498 save_wv = prev_wv;
1499 prev_wv = 0;
1500 first_pane = 1;
1501 i++;
1502 }
1503 else if (EQ (AREF (menu_items, i), Qlambda))
1504 {
1505 prev_wv = save_wv;
1506 save_wv = submenu_stack[--submenu_depth];
1507 first_pane = 0;
1508 i++;
1509 }
1510 else if (EQ (AREF (menu_items, i), Qt)
1511 && submenu_depth != 0)
1512 i += MENU_ITEMS_PANE_LENGTH;
1513 /* Ignore a nil in the item list.
1514 It's meaningful only for dialog boxes. */
1515 else if (EQ (AREF (menu_items, i), Qquote))
1516 i += 1;
1517 else if (EQ (AREF (menu_items, i), Qt))
1518 {
1519 /* Create a new pane. */
1520 Lisp_Object pane_name, prefix;
1521 const char *pane_string;
1522
1523 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1524 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1525
1526 #ifndef HAVE_MULTILINGUAL_MENU
1527 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1528 {
1529 pane_name = ENCODE_MENU_STRING (pane_name);
1530 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1531 }
1532 #endif
1533 pane_string = (NILP (pane_name)
1534 ? "" : SSDATA (pane_name));
1535 /* If there is just one top-level pane, put all its items directly
1536 under the top-level menu. */
1537 if (menu_items_n_panes == 1)
1538 pane_string = "";
1539
1540 /* If the pane has a meaningful name,
1541 make the pane a top-level menu item
1542 with its items as a submenu beneath it. */
1543 if (!keymaps && strcmp (pane_string, ""))
1544 {
1545 wv = xmalloc_widget_value ();
1546 if (save_wv)
1547 save_wv->next = wv;
1548 else
1549 first_wv->contents = wv;
1550 wv->name = (char *) pane_string;
1551 if (keymaps && !NILP (prefix))
1552 wv->name++;
1553 wv->value = 0;
1554 wv->enabled = 1;
1555 wv->button_type = BUTTON_TYPE_NONE;
1556 wv->help = Qnil;
1557 save_wv = wv;
1558 prev_wv = 0;
1559 }
1560 else if (first_pane)
1561 {
1562 save_wv = wv;
1563 prev_wv = 0;
1564 }
1565 first_pane = 0;
1566 i += MENU_ITEMS_PANE_LENGTH;
1567 }
1568 else
1569 {
1570 /* Create a new item within current pane. */
1571 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1572 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1573 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1574 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1575 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1576 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1577 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1578 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1579
1580 #ifndef HAVE_MULTILINGUAL_MENU
1581 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1582 {
1583 item_name = ENCODE_MENU_STRING (item_name);
1584 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1585 }
1586
1587 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1588 {
1589 descrip = ENCODE_MENU_STRING (descrip);
1590 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1591 }
1592 #endif /* not HAVE_MULTILINGUAL_MENU */
1593
1594 wv = xmalloc_widget_value ();
1595 if (prev_wv)
1596 prev_wv->next = wv;
1597 else
1598 save_wv->contents = wv;
1599 wv->name = SSDATA (item_name);
1600 if (!NILP (descrip))
1601 wv->key = SSDATA (descrip);
1602 wv->value = 0;
1603 /* If this item has a null value,
1604 make the call_data null so that it won't display a box
1605 when the mouse is on it. */
1606 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1607 wv->enabled = !NILP (enable);
1608
1609 if (NILP (type))
1610 wv->button_type = BUTTON_TYPE_NONE;
1611 else if (EQ (type, QCtoggle))
1612 wv->button_type = BUTTON_TYPE_TOGGLE;
1613 else if (EQ (type, QCradio))
1614 wv->button_type = BUTTON_TYPE_RADIO;
1615 else
1616 emacs_abort ();
1617
1618 wv->selected = !NILP (selected);
1619
1620 if (! STRINGP (help))
1621 help = Qnil;
1622
1623 wv->help = help;
1624
1625 prev_wv = wv;
1626
1627 i += MENU_ITEMS_ITEM_LENGTH;
1628 }
1629 }
1630
1631 /* Deal with the title, if it is non-nil. */
1632 if (!NILP (title))
1633 {
1634 widget_value *wv_title = xmalloc_widget_value ();
1635 widget_value *wv_sep1 = xmalloc_widget_value ();
1636 widget_value *wv_sep2 = xmalloc_widget_value ();
1637
1638 wv_sep2->name = "--";
1639 wv_sep2->next = first_wv->contents;
1640 wv_sep2->help = Qnil;
1641
1642 wv_sep1->name = "--";
1643 wv_sep1->next = wv_sep2;
1644 wv_sep1->help = Qnil;
1645
1646 #ifndef HAVE_MULTILINGUAL_MENU
1647 if (STRING_MULTIBYTE (title))
1648 title = ENCODE_MENU_STRING (title);
1649 #endif
1650
1651 wv_title->name = SSDATA (title);
1652 wv_title->enabled = TRUE;
1653 wv_title->button_type = BUTTON_TYPE_NONE;
1654 wv_title->help = Qnil;
1655 wv_title->next = wv_sep1;
1656 first_wv->contents = wv_title;
1657 }
1658
1659 /* No selection has been chosen yet. */
1660 menu_item_selection = 0;
1661
1662 /* Make sure to free the widget_value objects we used to specify the
1663 contents even with longjmp. */
1664 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1665
1666 /* Actually create and show the menu until popped down. */
1667 create_and_show_popup_menu (f, first_wv, x, y, for_click);
1668
1669 unbind_to (specpdl_count, Qnil);
1670
1671 /* Find the selected item, and its pane, to return
1672 the proper value. */
1673 if (menu_item_selection != 0)
1674 {
1675 Lisp_Object prefix, entry;
1676
1677 prefix = entry = Qnil;
1678 i = 0;
1679 while (i < menu_items_used)
1680 {
1681 if (EQ (AREF (menu_items, i), Qnil))
1682 {
1683 subprefix_stack[submenu_depth++] = prefix;
1684 prefix = entry;
1685 i++;
1686 }
1687 else if (EQ (AREF (menu_items, i), Qlambda))
1688 {
1689 prefix = subprefix_stack[--submenu_depth];
1690 i++;
1691 }
1692 else if (EQ (AREF (menu_items, i), Qt))
1693 {
1694 prefix
1695 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1696 i += MENU_ITEMS_PANE_LENGTH;
1697 }
1698 /* Ignore a nil in the item list.
1699 It's meaningful only for dialog boxes. */
1700 else if (EQ (AREF (menu_items, i), Qquote))
1701 i += 1;
1702 else
1703 {
1704 entry
1705 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1706 if (menu_item_selection == aref_addr (menu_items, i))
1707 {
1708 if (keymaps)
1709 {
1710 int j;
1711
1712 entry = list1 (entry);
1713 if (!NILP (prefix))
1714 entry = Fcons (prefix, entry);
1715 for (j = submenu_depth - 1; j >= 0; j--)
1716 if (!NILP (subprefix_stack[j]))
1717 entry = Fcons (subprefix_stack[j], entry);
1718 }
1719 unblock_input ();
1720 return entry;
1721 }
1722 i += MENU_ITEMS_ITEM_LENGTH;
1723 }
1724 }
1725 }
1726 else if (!for_click)
1727 {
1728 unblock_input ();
1729 /* Make "Cancel" equivalent to C-g. */
1730 Fsignal (Qquit, Qnil);
1731 }
1732
1733 unblock_input ();
1734 return Qnil;
1735 }
1736 \f
1737 #ifdef USE_GTK
1738 static void
1739 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1740 {
1741 /* Treat the pointer as an integer. There's no problem
1742 as long as pointers have enough bits to hold small integers. */
1743 if ((intptr_t) client_data != -1)
1744 menu_item_selection = client_data;
1745
1746 popup_activated_flag = 0;
1747 }
1748
1749 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1750 dialog pops down.
1751 menu_item_selection will be set to the selection. */
1752 static void
1753 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1754 {
1755 GtkWidget *menu;
1756
1757 eassert (FRAME_X_P (f));
1758
1759 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1760 G_CALLBACK (dialog_selection_callback),
1761 G_CALLBACK (popup_deactivate_callback),
1762 0);
1763
1764 if (menu)
1765 {
1766 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1767 record_unwind_protect_ptr (pop_down_menu, menu);
1768
1769 /* Display the menu. */
1770 gtk_widget_show_all (menu);
1771
1772 /* Process events that apply to the menu. */
1773 popup_widget_loop (1, menu);
1774
1775 unbind_to (specpdl_count, Qnil);
1776 }
1777 }
1778
1779 #else /* not USE_GTK */
1780 static void
1781 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1782 {
1783 /* Treat the pointer as an integer. There's no problem
1784 as long as pointers have enough bits to hold small integers. */
1785 if ((intptr_t) client_data != -1)
1786 menu_item_selection = client_data;
1787
1788 block_input ();
1789 lw_destroy_all_widgets (id);
1790 unblock_input ();
1791 popup_activated_flag = 0;
1792 }
1793
1794
1795 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1796 dialog pops down.
1797 menu_item_selection will be set to the selection. */
1798 static void
1799 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1800 {
1801 LWLIB_ID dialog_id;
1802
1803 eassert (FRAME_X_P (f));
1804
1805 dialog_id = widget_id_tick++;
1806 #ifdef USE_LUCID
1807 apply_systemfont_to_dialog (f->output_data.x->widget);
1808 #endif
1809 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1810 f->output_data.x->widget, 1, 0,
1811 dialog_selection_callback, 0, 0);
1812 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1813 /* Display the dialog box. */
1814 lw_pop_up_all_widgets (dialog_id);
1815 popup_activated_flag = 1;
1816 x_activate_timeout_atimer ();
1817
1818 /* Process events that apply to the dialog box.
1819 Also handle timers. */
1820 {
1821 ptrdiff_t count = SPECPDL_INDEX ();
1822 int fact = 4 * sizeof (LWLIB_ID);
1823
1824 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1825 record_unwind_protect (pop_down_menu,
1826 Fcons (make_number (dialog_id >> (fact)),
1827 make_number (dialog_id & ~(-1 << (fact)))));
1828
1829 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, 1);
1830
1831 unbind_to (count, Qnil);
1832 }
1833 }
1834
1835 #endif /* not USE_GTK */
1836
1837 static const char * button_names [] = {
1838 "button1", "button2", "button3", "button4", "button5",
1839 "button6", "button7", "button8", "button9", "button10" };
1840
1841 static Lisp_Object
1842 xdialog_show (struct frame *f,
1843 bool keymaps,
1844 Lisp_Object title,
1845 Lisp_Object header,
1846 const char **error_name)
1847 {
1848 int i, nb_buttons=0;
1849 char dialog_name[6];
1850
1851 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1852
1853 /* Number of elements seen so far, before boundary. */
1854 int left_count = 0;
1855 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1856 int boundary_seen = 0;
1857
1858 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1859
1860 eassert (FRAME_X_P (f));
1861
1862 *error_name = NULL;
1863
1864 if (menu_items_n_panes > 1)
1865 {
1866 *error_name = "Multiple panes in dialog box";
1867 return Qnil;
1868 }
1869
1870 /* Create a tree of widget_value objects
1871 representing the text label and buttons. */
1872 {
1873 Lisp_Object pane_name, prefix;
1874 const char *pane_string;
1875 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1876 prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX);
1877 pane_string = (NILP (pane_name)
1878 ? "" : SSDATA (pane_name));
1879 prev_wv = xmalloc_widget_value ();
1880 prev_wv->value = (char *) pane_string;
1881 if (keymaps && !NILP (prefix))
1882 prev_wv->name++;
1883 prev_wv->enabled = 1;
1884 prev_wv->name = "message";
1885 prev_wv->help = Qnil;
1886 first_wv = prev_wv;
1887
1888 /* Loop over all panes and items, filling in the tree. */
1889 i = MENU_ITEMS_PANE_LENGTH;
1890 while (i < menu_items_used)
1891 {
1892
1893 /* Create a new item within current pane. */
1894 Lisp_Object item_name, enable, descrip;
1895 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1896 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1897 descrip
1898 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1899
1900 if (NILP (item_name))
1901 {
1902 free_menubar_widget_value_tree (first_wv);
1903 *error_name = "Submenu in dialog items";
1904 return Qnil;
1905 }
1906 if (EQ (item_name, Qquote))
1907 {
1908 /* This is the boundary between left-side elts
1909 and right-side elts. Stop incrementing right_count. */
1910 boundary_seen = 1;
1911 i++;
1912 continue;
1913 }
1914 if (nb_buttons >= 9)
1915 {
1916 free_menubar_widget_value_tree (first_wv);
1917 *error_name = "Too many dialog items";
1918 return Qnil;
1919 }
1920
1921 wv = xmalloc_widget_value ();
1922 prev_wv->next = wv;
1923 wv->name = (char *) button_names[nb_buttons];
1924 if (!NILP (descrip))
1925 wv->key = SSDATA (descrip);
1926 wv->value = SSDATA (item_name);
1927 wv->call_data = aref_addr (menu_items, i);
1928 wv->enabled = !NILP (enable);
1929 wv->help = Qnil;
1930 prev_wv = wv;
1931
1932 if (! boundary_seen)
1933 left_count++;
1934
1935 nb_buttons++;
1936 i += MENU_ITEMS_ITEM_LENGTH;
1937 }
1938
1939 /* If the boundary was not specified,
1940 by default put half on the left and half on the right. */
1941 if (! boundary_seen)
1942 left_count = nb_buttons - nb_buttons / 2;
1943
1944 wv = xmalloc_widget_value ();
1945 wv->name = dialog_name;
1946 wv->help = Qnil;
1947
1948 /* Frame title: 'Q' = Question, 'I' = Information.
1949 Can also have 'E' = Error if, one day, we want
1950 a popup for errors. */
1951 if (NILP (header))
1952 dialog_name[0] = 'Q';
1953 else
1954 dialog_name[0] = 'I';
1955
1956 /* Dialog boxes use a really stupid name encoding
1957 which specifies how many buttons to use
1958 and how many buttons are on the right. */
1959 dialog_name[1] = '0' + nb_buttons;
1960 dialog_name[2] = 'B';
1961 dialog_name[3] = 'R';
1962 /* Number of buttons to put on the right. */
1963 dialog_name[4] = '0' + nb_buttons - left_count;
1964 dialog_name[5] = 0;
1965 wv->contents = first_wv;
1966 first_wv = wv;
1967 }
1968
1969 /* No selection has been chosen yet. */
1970 menu_item_selection = 0;
1971
1972 /* Make sure to free the widget_value objects we used to specify the
1973 contents even with longjmp. */
1974 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1975
1976 /* Actually create and show the dialog. */
1977 create_and_show_dialog (f, first_wv);
1978
1979 unbind_to (specpdl_count, Qnil);
1980
1981 /* Find the selected item, and its pane, to return
1982 the proper value. */
1983 if (menu_item_selection != 0)
1984 {
1985 Lisp_Object prefix;
1986
1987 prefix = Qnil;
1988 i = 0;
1989 while (i < menu_items_used)
1990 {
1991 Lisp_Object entry;
1992
1993 if (EQ (AREF (menu_items, i), Qt))
1994 {
1995 prefix
1996 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1997 i += MENU_ITEMS_PANE_LENGTH;
1998 }
1999 else if (EQ (AREF (menu_items, i), Qquote))
2000 {
2001 /* This is the boundary between left-side elts and
2002 right-side elts. */
2003 ++i;
2004 }
2005 else
2006 {
2007 entry
2008 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2009 if (menu_item_selection == aref_addr (menu_items, i))
2010 {
2011 if (keymaps != 0)
2012 {
2013 entry = list1 (entry);
2014 if (!NILP (prefix))
2015 entry = Fcons (prefix, entry);
2016 }
2017 return entry;
2018 }
2019 i += MENU_ITEMS_ITEM_LENGTH;
2020 }
2021 }
2022 }
2023 else
2024 /* Make "Cancel" equivalent to C-g. */
2025 Fsignal (Qquit, Qnil);
2026
2027 return Qnil;
2028 }
2029
2030 Lisp_Object
2031 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
2032 {
2033 Lisp_Object title;
2034 const char *error_name;
2035 Lisp_Object selection;
2036 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2037
2038 check_window_system (f);
2039
2040 /* Decode the dialog items from what was specified. */
2041 title = Fcar (contents);
2042 CHECK_STRING (title);
2043 record_unwind_protect_void (unuse_menu_items);
2044
2045 if (NILP (Fcar (Fcdr (contents))))
2046 /* No buttons specified, add an "Ok" button so users can pop down
2047 the dialog. Also, the lesstif/motif version crashes if there are
2048 no buttons. */
2049 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
2050
2051 list_of_panes (list1 (contents));
2052
2053 /* Display them in a dialog box. */
2054 block_input ();
2055 selection = xdialog_show (f, 0, title, header, &error_name);
2056 unblock_input ();
2057
2058 unbind_to (specpdl_count, Qnil);
2059 discard_menu_items ();
2060
2061 if (error_name) error ("%s", error_name);
2062 return selection;
2063 }
2064
2065 #else /* not USE_X_TOOLKIT && not USE_GTK */
2066
2067 /* The frame of the last activated non-toolkit menu bar.
2068 Used to generate menu help events. */
2069
2070 static struct frame *menu_help_frame;
2071
2072
2073 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2074
2075 PANE is the pane number, and ITEM is the menu item number in
2076 the menu (currently not used).
2077
2078 This cannot be done with generating a HELP_EVENT because
2079 XMenuActivate contains a loop that doesn't let Emacs process
2080 keyboard events. */
2081
2082 static void
2083 menu_help_callback (char const *help_string, int pane, int item)
2084 {
2085 Lisp_Object *first_item;
2086 Lisp_Object pane_name;
2087 Lisp_Object menu_object;
2088
2089 first_item = XVECTOR (menu_items)->contents;
2090 if (EQ (first_item[0], Qt))
2091 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2092 else if (EQ (first_item[0], Qquote))
2093 /* This shouldn't happen, see xmenu_show. */
2094 pane_name = empty_unibyte_string;
2095 else
2096 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2097
2098 /* (menu-item MENU-NAME PANE-NUMBER) */
2099 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
2100 show_help_echo (help_string ? build_string (help_string) : Qnil,
2101 Qnil, menu_object, make_number (item));
2102 }
2103
2104 static void
2105 pop_down_menu (Lisp_Object arg)
2106 {
2107 struct frame *f = XSAVE_POINTER (arg, 0);
2108 XMenu *menu = XSAVE_POINTER (arg, 1);
2109
2110 block_input ();
2111 #ifndef MSDOS
2112 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2113 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2114 #endif
2115 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2116
2117 #ifdef HAVE_X_WINDOWS
2118 /* Assume the mouse has moved out of the X window.
2119 If it has actually moved in, we will get an EnterNotify. */
2120 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2121
2122 /* State that no mouse buttons are now held.
2123 (The oldXMenu code doesn't track this info for us.)
2124 That is not necessarily true, but the fiction leads to reasonable
2125 results, and it is a pain to ask which are actually held now. */
2126 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2127
2128 #endif /* HAVE_X_WINDOWS */
2129
2130 unblock_input ();
2131 }
2132
2133
2134 Lisp_Object
2135 xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
2136 Lisp_Object title, const char **error_name)
2137 {
2138 Window root;
2139 XMenu *menu;
2140 int pane, selidx, lpane, status;
2141 Lisp_Object entry, pane_prefix;
2142 char *datap;
2143 int ulx, uly, width, height;
2144 int dispwidth, dispheight;
2145 int i, j, lines, maxlines;
2146 int maxwidth;
2147 int dummy_int;
2148 unsigned int dummy_uint;
2149 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2150
2151 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2152
2153 *error_name = 0;
2154 if (menu_items_n_panes == 0)
2155 return Qnil;
2156
2157 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2158 {
2159 *error_name = "Empty menu";
2160 return Qnil;
2161 }
2162
2163 block_input ();
2164
2165 /* Figure out which root window F is on. */
2166 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2167 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2168 &dummy_uint, &dummy_uint);
2169
2170 /* Make the menu on that window. */
2171 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2172 if (menu == NULL)
2173 {
2174 *error_name = "Can't create menu";
2175 unblock_input ();
2176 return Qnil;
2177 }
2178
2179 /* Don't GC while we prepare and show the menu,
2180 because we give the oldxmenu library pointers to the
2181 contents of strings. */
2182 inhibit_garbage_collection ();
2183
2184 #ifdef HAVE_X_WINDOWS
2185 /* Adjust coordinates to relative to the outer (window manager) window. */
2186 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2187 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2188 #endif /* HAVE_X_WINDOWS */
2189
2190 /* Adjust coordinates to be root-window-relative. */
2191 x += f->left_pos;
2192 y += f->top_pos;
2193
2194 /* Create all the necessary panes and their items. */
2195 maxwidth = maxlines = lines = i = 0;
2196 lpane = XM_FAILURE;
2197 while (i < menu_items_used)
2198 {
2199 if (EQ (AREF (menu_items, i), Qt))
2200 {
2201 /* Create a new pane. */
2202 Lisp_Object pane_name, prefix;
2203 const char *pane_string;
2204
2205 maxlines = max (maxlines, lines);
2206 lines = 0;
2207 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2208 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2209 pane_string = (NILP (pane_name)
2210 ? "" : SSDATA (pane_name));
2211 if (keymaps && !NILP (prefix))
2212 pane_string++;
2213
2214 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2215 if (lpane == XM_FAILURE)
2216 {
2217 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2218 *error_name = "Can't create pane";
2219 unblock_input ();
2220 return Qnil;
2221 }
2222 i += MENU_ITEMS_PANE_LENGTH;
2223
2224 /* Find the width of the widest item in this pane. */
2225 j = i;
2226 while (j < menu_items_used)
2227 {
2228 Lisp_Object item;
2229 item = AREF (menu_items, j);
2230 if (EQ (item, Qt))
2231 break;
2232 if (NILP (item))
2233 {
2234 j++;
2235 continue;
2236 }
2237 width = SBYTES (item);
2238 if (width > maxwidth)
2239 maxwidth = width;
2240
2241 j += MENU_ITEMS_ITEM_LENGTH;
2242 }
2243 }
2244 /* Ignore a nil in the item list.
2245 It's meaningful only for dialog boxes. */
2246 else if (EQ (AREF (menu_items, i), Qquote))
2247 i += 1;
2248 else
2249 {
2250 /* Create a new item within current pane. */
2251 Lisp_Object item_name, enable, descrip, help;
2252 char *item_data;
2253 char const *help_string;
2254
2255 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2256 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2257 descrip
2258 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2259 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2260 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2261
2262 if (!NILP (descrip))
2263 {
2264 /* if alloca is fast, use that to make the space,
2265 to reduce gc needs. */
2266 item_data = alloca (maxwidth + SBYTES (descrip) + 1);
2267 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2268 for (j = SCHARS (item_name); j < maxwidth; j++)
2269 item_data[j] = ' ';
2270 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2271 item_data[j + SBYTES (descrip)] = 0;
2272 }
2273 else
2274 item_data = SSDATA (item_name);
2275
2276 if (lpane == XM_FAILURE
2277 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2278 menu, lpane, 0, item_data,
2279 !NILP (enable), help_string)
2280 == XM_FAILURE))
2281 {
2282 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2283 *error_name = "Can't add selection to menu";
2284 unblock_input ();
2285 return Qnil;
2286 }
2287 i += MENU_ITEMS_ITEM_LENGTH;
2288 lines++;
2289 }
2290 }
2291
2292 maxlines = max (maxlines, lines);
2293
2294 /* All set and ready to fly. */
2295 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2296 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2297 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2298 x = min (x, dispwidth);
2299 y = min (y, dispheight);
2300 x = max (x, 1);
2301 y = max (y, 1);
2302 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2303 &ulx, &uly, &width, &height);
2304 if (ulx+width > dispwidth)
2305 {
2306 x -= (ulx + width) - dispwidth;
2307 ulx = dispwidth - width;
2308 }
2309 if (uly+height > dispheight)
2310 {
2311 y -= (uly + height) - dispheight;
2312 uly = dispheight - height;
2313 }
2314 #ifndef HAVE_X_WINDOWS
2315 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2316 {
2317 /* Move the menu away of the echo area, to avoid overwriting the
2318 menu with help echo messages or vice versa. */
2319 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2320 {
2321 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2322 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2323 }
2324 else
2325 {
2326 y--;
2327 uly--;
2328 }
2329 }
2330 #endif
2331 if (ulx < 0) x -= ulx;
2332 if (uly < 0) y -= uly;
2333
2334 if (! for_click)
2335 {
2336 /* If position was not given by a mouse click, adjust so upper left
2337 corner of the menu as a whole ends up at given coordinates. This
2338 is what x-popup-menu says in its documentation. */
2339 x += width/2;
2340 y += 1.5*height/(maxlines+2);
2341 }
2342
2343 XMenuSetAEQ (menu, TRUE);
2344 XMenuSetFreeze (menu, TRUE);
2345 pane = selidx = 0;
2346
2347 #ifndef MSDOS
2348 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2349 #endif
2350
2351 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2352
2353 /* Help display under X won't work because XMenuActivate contains
2354 a loop that doesn't give Emacs a chance to process it. */
2355 menu_help_frame = f;
2356 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2357 x, y, ButtonReleaseMask, &datap,
2358 menu_help_callback);
2359 entry = pane_prefix = Qnil;
2360
2361 switch (status)
2362 {
2363 case XM_SUCCESS:
2364 #ifdef XDEBUG
2365 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2366 #endif
2367
2368 /* Find the item number SELIDX in pane number PANE. */
2369 i = 0;
2370 while (i < menu_items_used)
2371 {
2372 if (EQ (AREF (menu_items, i), Qt))
2373 {
2374 if (pane == 0)
2375 pane_prefix
2376 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2377 pane--;
2378 i += MENU_ITEMS_PANE_LENGTH;
2379 }
2380 else
2381 {
2382 if (pane == -1)
2383 {
2384 if (selidx == 0)
2385 {
2386 entry
2387 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2388 if (keymaps)
2389 {
2390 entry = list1 (entry);
2391 if (!NILP (pane_prefix))
2392 entry = Fcons (pane_prefix, entry);
2393 }
2394 break;
2395 }
2396 selidx--;
2397 }
2398 i += MENU_ITEMS_ITEM_LENGTH;
2399 }
2400 }
2401 break;
2402
2403 case XM_FAILURE:
2404 *error_name = "Can't activate menu";
2405 case XM_IA_SELECT:
2406 break;
2407 case XM_NO_SELECT:
2408 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2409 the menu was invoked with a mouse event as POSITION). */
2410 if (! for_click)
2411 {
2412 unblock_input ();
2413 Fsignal (Qquit, Qnil);
2414 }
2415 break;
2416 }
2417
2418 unblock_input ();
2419 unbind_to (specpdl_count, Qnil);
2420
2421 return entry;
2422 }
2423
2424 #endif /* not USE_X_TOOLKIT */
2425
2426 #ifndef MSDOS
2427 /* Detect if a dialog or menu has been posted. MSDOS has its own
2428 implementation on msdos.c. */
2429
2430 int ATTRIBUTE_CONST
2431 popup_activated (void)
2432 {
2433 return popup_activated_flag;
2434 }
2435 #endif /* not MSDOS */
2436
2437 /* The following is used by delayed window autoselection. */
2438
2439 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2440 doc: /* Return t if a menu or popup dialog is active. */)
2441 (void)
2442 {
2443 #ifdef HAVE_MENUS
2444 return (popup_activated ()) ? Qt : Qnil;
2445 #else
2446 return Qnil;
2447 #endif /* HAVE_MENUS */
2448 }
2449 \f
2450 void
2451 syms_of_xmenu (void)
2452 {
2453 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2454
2455 #ifdef USE_X_TOOLKIT
2456 widget_id_tick = (1<<16);
2457 next_menubar_widget_id = 1;
2458 #endif
2459
2460 defsubr (&Smenu_or_popup_active_p);
2461
2462 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2463 defsubr (&Sx_menu_bar_open_internal);
2464 Ffset (intern_c_string ("accelerate-menu"),
2465 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2466 #endif
2467 }