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