]> code.delx.au - gnu-emacs/blob - src/xmenu.c
Merge from emacs-24; up to 2014-06-01T23:37:59Z!eggert@cs.ucla.edu
[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 /* x_menu_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 = make_widget_value ("menubar", NULL, true, Qnil);
886 wv->button_type = BUTTON_TYPE_NONE;
887 first_wv = wv;
888
889 for (i = 0; submenu_start[i] >= 0; i++)
890 {
891 menu_items_n_panes = submenu_n_panes[i];
892 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
893 submenu_top_level_items[i]);
894 if (prev_wv)
895 prev_wv->next = wv;
896 else
897 first_wv->contents = wv;
898 /* Don't set wv->name here; GC during the loop might relocate it. */
899 wv->enabled = 1;
900 wv->button_type = BUTTON_TYPE_NONE;
901 prev_wv = wv;
902 }
903
904 set_buffer_internal_1 (prev);
905
906 /* If there has been no change in the Lisp-level contents
907 of the menu bar, skip redisplaying it. Just exit. */
908
909 /* Compare the new menu items with the ones computed last time. */
910 for (i = 0; i < previous_menu_items_used; i++)
911 if (menu_items_used == i
912 || (!EQ (previous_items[i], AREF (menu_items, i))))
913 break;
914 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
915 {
916 /* The menu items have not changed. Don't bother updating
917 the menus in any form, since it would be a no-op. */
918 free_menubar_widget_value_tree (first_wv);
919 discard_menu_items ();
920 unbind_to (specpdl_count, Qnil);
921 return;
922 }
923
924 /* The menu items are different, so store them in the frame. */
925 fset_menu_bar_vector (f, menu_items);
926 f->menu_bar_items_used = menu_items_used;
927
928 /* This undoes save_menu_items. */
929 unbind_to (specpdl_count, Qnil);
930
931 /* Now GC cannot happen during the lifetime of the widget_value,
932 so it's safe to store data from a Lisp_String. */
933 wv = first_wv->contents;
934 for (i = 0; i < ASIZE (items); i += 4)
935 {
936 Lisp_Object string;
937 string = AREF (items, i + 1);
938 if (NILP (string))
939 break;
940 wv->name = SSDATA (string);
941 update_submenu_strings (wv->contents);
942 wv = wv->next;
943 }
944
945 }
946 else
947 {
948 /* Make a widget-value tree containing
949 just the top level menu bar strings. */
950
951 wv = make_widget_value ("menubar", NULL, true, Qnil);
952 wv->button_type = BUTTON_TYPE_NONE;
953 first_wv = wv;
954
955 items = FRAME_MENU_BAR_ITEMS (f);
956 for (i = 0; i < ASIZE (items); i += 4)
957 {
958 Lisp_Object string;
959
960 string = AREF (items, i + 1);
961 if (NILP (string))
962 break;
963
964 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
965 wv->button_type = BUTTON_TYPE_NONE;
966 /* This prevents lwlib from assuming this
967 menu item is really supposed to be empty. */
968 /* The intptr_t cast avoids a warning.
969 This value just has to be different from small integers. */
970 wv->call_data = (void *) (intptr_t) (-1);
971
972 if (prev_wv)
973 prev_wv->next = wv;
974 else
975 first_wv->contents = wv;
976 prev_wv = wv;
977 }
978
979 /* Forget what we thought we knew about what is in the
980 detailed contents of the menu bar menus.
981 Changing the top level always destroys the contents. */
982 f->menu_bar_items_used = 0;
983 }
984
985 /* Create or update the menu bar widget. */
986
987 block_input ();
988
989 #ifdef USE_GTK
990 xg_crazy_callback_abort = 1;
991 if (menubar_widget)
992 {
993 /* The fourth arg is DEEP_P, which says to consider the entire
994 menu trees we supply, rather than just the menu bar item names. */
995 xg_modify_menubar_widgets (menubar_widget,
996 f,
997 first_wv,
998 deep_p,
999 G_CALLBACK (menubar_selection_callback),
1000 G_CALLBACK (popup_deactivate_callback),
1001 G_CALLBACK (menu_highlight_callback));
1002 }
1003 else
1004 {
1005 menubar_widget
1006 = xg_create_widget ("menubar", "menubar", f, first_wv,
1007 G_CALLBACK (menubar_selection_callback),
1008 G_CALLBACK (popup_deactivate_callback),
1009 G_CALLBACK (menu_highlight_callback));
1010
1011 f->output_data.x->menubar_widget = menubar_widget;
1012 }
1013
1014
1015 #else /* not USE_GTK */
1016 if (menubar_widget)
1017 {
1018 /* Disable resizing (done for Motif!) */
1019 lw_allow_resizing (f->output_data.x->widget, False);
1020
1021 /* The third arg is DEEP_P, which says to consider the entire
1022 menu trees we supply, rather than just the menu bar item names. */
1023 lw_modify_all_widgets (id, first_wv, deep_p);
1024
1025 /* Re-enable the edit widget to resize. */
1026 lw_allow_resizing (f->output_data.x->widget, True);
1027 }
1028 else
1029 {
1030 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1031 XtTranslations override = XtParseTranslationTable (menuOverride);
1032
1033 #ifdef USE_LUCID
1034 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
1035 #endif
1036 menubar_widget = lw_create_widget ("menubar", "menubar", id,
1037 first_wv,
1038 f->output_data.x->column_widget,
1039 0,
1040 popup_activate_callback,
1041 menubar_selection_callback,
1042 popup_deactivate_callback,
1043 menu_highlight_callback);
1044 f->output_data.x->menubar_widget = menubar_widget;
1045
1046 /* Make menu pop down on C-g. */
1047 XtOverrideTranslations (menubar_widget, override);
1048 }
1049
1050 {
1051 int menubar_size;
1052 if (f->output_data.x->menubar_widget)
1053 XtRealizeWidget (f->output_data.x->menubar_widget);
1054
1055 menubar_size
1056 = (f->output_data.x->menubar_widget
1057 ? (f->output_data.x->menubar_widget->core.height
1058 + f->output_data.x->menubar_widget->core.border_width)
1059 : 0);
1060
1061 #if 1 /* Experimentally, we now get the right results
1062 for -geometry -0-0 without this. 24 Aug 96, rms.
1063 Maybe so, but the menu bar size is missing the pixels so the
1064 WM size hints are off by these pixels. Jan D, oct 2009. */
1065 #ifdef USE_LUCID
1066 if (FRAME_EXTERNAL_MENU_BAR (f))
1067 {
1068 Dimension ibw = 0;
1069 XtVaGetValues (f->output_data.x->column_widget,
1070 XtNinternalBorderWidth, &ibw, NULL);
1071 menubar_size += ibw;
1072 }
1073 #endif /* USE_LUCID */
1074 #endif /* 1 */
1075
1076 f->output_data.x->menubar_height = menubar_size;
1077 }
1078 #endif /* not USE_GTK */
1079
1080 free_menubar_widget_value_tree (first_wv);
1081 update_frame_menubar (f);
1082
1083 #ifdef USE_GTK
1084 xg_crazy_callback_abort = 0;
1085 #endif
1086
1087 unblock_input ();
1088 }
1089
1090 /* Called from Fx_create_frame to create the initial menubar of a frame
1091 before it is mapped, so that the window is mapped with the menubar already
1092 there instead of us tacking it on later and thrashing the window after it
1093 is visible. */
1094
1095 void
1096 initialize_frame_menubar (struct frame *f)
1097 {
1098 /* This function is called before the first chance to redisplay
1099 the frame. It has to be, so the frame will have the right size. */
1100 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1101 set_frame_menubar (f, 1, 1);
1102 }
1103
1104
1105 /* Get rid of the menu bar of frame F, and free its storage.
1106 This is used when deleting a frame, and when turning off the menu bar.
1107 For GTK this function is in gtkutil.c. */
1108
1109 #ifndef USE_GTK
1110 void
1111 free_frame_menubar (struct frame *f)
1112 {
1113 Widget menubar_widget;
1114
1115 eassert (FRAME_X_P (f));
1116
1117 menubar_widget = f->output_data.x->menubar_widget;
1118
1119 f->output_data.x->menubar_height = 0;
1120
1121 if (menubar_widget)
1122 {
1123 #ifdef USE_MOTIF
1124 /* Removing the menu bar magically changes the shell widget's x
1125 and y position of (0, 0) which, when the menu bar is turned
1126 on again, leads to pull-down menus appearing in strange
1127 positions near the upper-left corner of the display. This
1128 happens only with some window managers like twm and ctwm,
1129 but not with other like Motif's mwm or kwm, because the
1130 latter generate ConfigureNotify events when the menu bar
1131 is switched off, which fixes the shell position. */
1132 Position x0, y0, x1, y1;
1133 #endif
1134
1135 block_input ();
1136
1137 #ifdef USE_MOTIF
1138 if (f->output_data.x->widget)
1139 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1140 #endif
1141
1142 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1143 f->output_data.x->menubar_widget = NULL;
1144
1145 if (f->output_data.x->widget)
1146 {
1147 #ifdef USE_MOTIF
1148 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1149 if (x1 == 0 && y1 == 0)
1150 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1151 #endif
1152 x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
1153 }
1154 unblock_input ();
1155 }
1156 }
1157 #endif /* not USE_GTK */
1158
1159 #endif /* USE_X_TOOLKIT || USE_GTK */
1160 \f
1161 /* x_menu_show actually displays a menu using the panes and items in menu_items
1162 and returns the value selected from it.
1163 There are two versions of x_menu_show, one for Xt and one for Xlib.
1164 Both assume input is blocked by the caller. */
1165
1166 /* F is the frame the menu is for.
1167 X and Y are the frame-relative specified position,
1168 relative to the inside upper left corner of the frame F.
1169 Bitfield MENUFLAGS bits are:
1170 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1171 MENU_KEYMAPS is set if this menu was specified with keymaps;
1172 in that case, we return a list containing the chosen item's value
1173 and perhaps also the pane's prefix.
1174 TITLE is the specified menu title.
1175 ERROR is a place to store an error message string in case of failure.
1176 (We return nil on failure, but the value doesn't actually matter.) */
1177
1178 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1179
1180 /* The item selected in the popup menu. */
1181 static Lisp_Object *volatile menu_item_selection;
1182
1183 #ifdef USE_GTK
1184
1185 /* Used when position a popup menu. See menu_position_func and
1186 create_and_show_popup_menu below. */
1187 struct next_popup_x_y
1188 {
1189 struct frame *f;
1190 int x;
1191 int y;
1192 };
1193
1194 /* The menu position function to use if we are not putting a popup
1195 menu where the pointer is.
1196 MENU is the menu to pop up.
1197 X and Y shall on exit contain x/y where the menu shall pop up.
1198 PUSH_IN is not documented in the GTK manual.
1199 USER_DATA is any data passed in when calling gtk_menu_popup.
1200 Here it points to a struct next_popup_x_y where the coordinates
1201 to store in *X and *Y are as well as the frame for the popup.
1202
1203 Here only X and Y are used. */
1204 static void
1205 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1206 {
1207 struct next_popup_x_y *data = user_data;
1208 GtkRequisition req;
1209 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1210 int disp_width = x_display_pixel_width (dpyinfo);
1211 int disp_height = x_display_pixel_height (dpyinfo);
1212
1213 *x = data->x;
1214 *y = data->y;
1215
1216 /* Check if there is room for the menu. If not, adjust x/y so that
1217 the menu is fully visible. */
1218 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1219 if (data->x + req.width > disp_width)
1220 *x -= data->x + req.width - disp_width;
1221 if (data->y + req.height > disp_height)
1222 *y -= data->y + req.height - disp_height;
1223 }
1224
1225 static void
1226 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1227 {
1228 xg_menu_item_cb_data *cb_data = client_data;
1229
1230 if (xg_crazy_callback_abort) return;
1231 if (cb_data) menu_item_selection = cb_data->call_data;
1232 }
1233
1234 static void
1235 pop_down_menu (void *arg)
1236 {
1237 popup_activated_flag = 0;
1238 block_input ();
1239 gtk_widget_destroy (GTK_WIDGET (arg));
1240 unblock_input ();
1241 }
1242
1243 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1244 menu pops down.
1245 menu_item_selection will be set to the selection. */
1246 static void
1247 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1248 int x, int y, bool for_click)
1249 {
1250 int i;
1251 GtkWidget *menu;
1252 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1253 struct next_popup_x_y popup_x_y;
1254 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1255 bool use_pos_func = ! for_click;
1256
1257 #ifdef HAVE_GTK3
1258 /* Always use position function for Gtk3. Otherwise menus may become
1259 too small to show anything. */
1260 use_pos_func = 1;
1261 #endif
1262
1263 eassert (FRAME_X_P (f));
1264
1265 xg_crazy_callback_abort = 1;
1266 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1267 G_CALLBACK (popup_selection_callback),
1268 G_CALLBACK (popup_deactivate_callback),
1269 G_CALLBACK (menu_highlight_callback));
1270 xg_crazy_callback_abort = 0;
1271
1272 if (use_pos_func)
1273 {
1274 /* Not invoked by a click. pop up at x/y. */
1275 pos_func = menu_position_func;
1276
1277 /* Adjust coordinates to be root-window-relative. */
1278 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1279 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1280
1281 popup_x_y.x = x;
1282 popup_x_y.y = y;
1283 popup_x_y.f = f;
1284
1285 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1286 }
1287
1288 if (for_click)
1289 {
1290 for (i = 0; i < 5; i++)
1291 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1292 break;
1293 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1294 if (i == 5) i = 0;
1295 }
1296
1297 /* Display the menu. */
1298 gtk_widget_show_all (menu);
1299
1300 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1301 FRAME_DISPLAY_INFO (f)->last_user_time);
1302
1303 record_unwind_protect_ptr (pop_down_menu, menu);
1304
1305 if (gtk_widget_get_mapped (menu))
1306 {
1307 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1308 two. show_help_echo uses this to detect popup menus. */
1309 popup_activated_flag = 1;
1310 /* Process events that apply to the menu. */
1311 popup_widget_loop (1, menu);
1312 }
1313
1314 unbind_to (specpdl_count, Qnil);
1315
1316 /* Must reset this manually because the button release event is not passed
1317 to Emacs event loop. */
1318 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1319 }
1320
1321 #else /* not USE_GTK */
1322
1323 /* We need a unique id for each widget handled by the Lucid Widget
1324 library.
1325
1326 For the main windows, and popup menus, we use this counter,
1327 which we increment each time after use. This starts from 1<<16.
1328
1329 For menu bars, we use numbers starting at 0, counted in
1330 next_menubar_widget_id. */
1331 LWLIB_ID widget_id_tick;
1332
1333 static void
1334 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1335 {
1336 menu_item_selection = client_data;
1337 }
1338
1339 /* ARG is the LWLIB ID of the dialog box, represented
1340 as a Lisp object as (HIGHPART . LOWPART). */
1341
1342 static void
1343 pop_down_menu (Lisp_Object arg)
1344 {
1345 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1346 | XINT (XCDR (arg)));
1347
1348 block_input ();
1349 lw_destroy_all_widgets (id);
1350 unblock_input ();
1351 popup_activated_flag = 0;
1352 }
1353
1354 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1355 menu pops down.
1356 menu_item_selection will be set to the selection. */
1357 static void
1358 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1359 int x, int y, bool for_click)
1360 {
1361 int i;
1362 Arg av[2];
1363 int ac = 0;
1364 XEvent dummy;
1365 XButtonPressedEvent *event = &(dummy.xbutton);
1366 LWLIB_ID menu_id;
1367 Widget menu;
1368
1369 eassert (FRAME_X_P (f));
1370
1371 #ifdef USE_LUCID
1372 apply_systemfont_to_menu (f, f->output_data.x->widget);
1373 #endif
1374
1375 menu_id = widget_id_tick++;
1376 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1377 f->output_data.x->widget, 1, 0,
1378 popup_selection_callback,
1379 popup_deactivate_callback,
1380 menu_highlight_callback);
1381
1382 event->type = ButtonPress;
1383 event->serial = 0;
1384 event->send_event = 0;
1385 event->display = FRAME_X_DISPLAY (f);
1386 event->time = CurrentTime;
1387 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1388 event->window = event->subwindow = event->root;
1389 event->x = x;
1390 event->y = y;
1391
1392 /* Adjust coordinates to be root-window-relative. */
1393 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1394 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1395
1396 event->x_root = x;
1397 event->y_root = y;
1398
1399 event->state = 0;
1400 event->button = 0;
1401 for (i = 0; i < 5; i++)
1402 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1403 event->button = i;
1404
1405 /* Don't allow any geometry request from the user. */
1406 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1407 XtSetValues (menu, av, ac);
1408
1409 /* Display the menu. */
1410 lw_popup_menu (menu, &dummy);
1411 popup_activated_flag = 1;
1412 x_activate_timeout_atimer ();
1413
1414 {
1415 int fact = 4 * sizeof (LWLIB_ID);
1416 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1417 record_unwind_protect (pop_down_menu,
1418 Fcons (make_number (menu_id >> (fact)),
1419 make_number (menu_id & ~(-1 << (fact)))));
1420
1421 /* Process events that apply to the menu. */
1422 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, 1);
1423
1424 unbind_to (specpdl_count, Qnil);
1425 }
1426 }
1427
1428 #endif /* not USE_GTK */
1429
1430 static void
1431 cleanup_widget_value_tree (void *arg)
1432 {
1433 free_menubar_widget_value_tree (arg);
1434 }
1435
1436 Lisp_Object
1437 x_menu_show (struct frame *f, int x, int y, int menuflags,
1438 Lisp_Object title, const char **error_name)
1439 {
1440 int i;
1441 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1442 widget_value **submenu_stack
1443 = alloca (menu_items_used * sizeof *submenu_stack);
1444 Lisp_Object *subprefix_stack
1445 = alloca (menu_items_used * sizeof *subprefix_stack);
1446 int submenu_depth = 0;
1447
1448 int first_pane;
1449
1450 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1451
1452 eassert (FRAME_X_P (f));
1453
1454 *error_name = NULL;
1455
1456 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1457 {
1458 *error_name = "Empty menu";
1459 return Qnil;
1460 }
1461
1462 block_input ();
1463
1464 /* Create a tree of widget_value objects
1465 representing the panes and their items. */
1466 wv = make_widget_value ("menu", NULL, true, Qnil);
1467 wv->button_type = BUTTON_TYPE_NONE;
1468 first_wv = wv;
1469 first_pane = 1;
1470
1471 /* Loop over all panes and items, filling in the tree. */
1472 i = 0;
1473 while (i < menu_items_used)
1474 {
1475 if (EQ (AREF (menu_items, i), Qnil))
1476 {
1477 submenu_stack[submenu_depth++] = save_wv;
1478 save_wv = prev_wv;
1479 prev_wv = 0;
1480 first_pane = 1;
1481 i++;
1482 }
1483 else if (EQ (AREF (menu_items, i), Qlambda))
1484 {
1485 prev_wv = save_wv;
1486 save_wv = submenu_stack[--submenu_depth];
1487 first_pane = 0;
1488 i++;
1489 }
1490 else if (EQ (AREF (menu_items, i), Qt)
1491 && submenu_depth != 0)
1492 i += MENU_ITEMS_PANE_LENGTH;
1493 /* Ignore a nil in the item list.
1494 It's meaningful only for dialog boxes. */
1495 else if (EQ (AREF (menu_items, i), Qquote))
1496 i += 1;
1497 else if (EQ (AREF (menu_items, i), Qt))
1498 {
1499 /* Create a new pane. */
1500 Lisp_Object pane_name, prefix;
1501 const char *pane_string;
1502
1503 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1504 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1505
1506 #ifndef HAVE_MULTILINGUAL_MENU
1507 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1508 {
1509 pane_name = ENCODE_MENU_STRING (pane_name);
1510 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1511 }
1512 #endif
1513 pane_string = (NILP (pane_name)
1514 ? "" : SSDATA (pane_name));
1515 /* If there is just one top-level pane, put all its items directly
1516 under the top-level menu. */
1517 if (menu_items_n_panes == 1)
1518 pane_string = "";
1519
1520 /* If the pane has a meaningful name,
1521 make the pane a top-level menu item
1522 with its items as a submenu beneath it. */
1523 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1524 {
1525 wv = make_widget_value (pane_string, NULL, true, Qnil);
1526 if (save_wv)
1527 save_wv->next = wv;
1528 else
1529 first_wv->contents = wv;
1530 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1531 wv->name++;
1532 wv->button_type = BUTTON_TYPE_NONE;
1533 save_wv = wv;
1534 prev_wv = 0;
1535 }
1536 else if (first_pane)
1537 {
1538 save_wv = wv;
1539 prev_wv = 0;
1540 }
1541 first_pane = 0;
1542 i += MENU_ITEMS_PANE_LENGTH;
1543 }
1544 else
1545 {
1546 /* Create a new item within current pane. */
1547 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1548 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1549 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1550 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1551 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1552 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1553 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1554 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1555
1556 #ifndef HAVE_MULTILINGUAL_MENU
1557 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1558 {
1559 item_name = ENCODE_MENU_STRING (item_name);
1560 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1561 }
1562
1563 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1564 {
1565 descrip = ENCODE_MENU_STRING (descrip);
1566 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1567 }
1568 #endif /* not HAVE_MULTILINGUAL_MENU */
1569
1570 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1571 STRINGP (help) ? help : Qnil);
1572 if (prev_wv)
1573 prev_wv->next = wv;
1574 else
1575 save_wv->contents = wv;
1576 if (!NILP (descrip))
1577 wv->key = SSDATA (descrip);
1578 /* If this item has a null value,
1579 make the call_data null so that it won't display a box
1580 when the mouse is on it. */
1581 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1582
1583 if (NILP (type))
1584 wv->button_type = BUTTON_TYPE_NONE;
1585 else if (EQ (type, QCtoggle))
1586 wv->button_type = BUTTON_TYPE_TOGGLE;
1587 else if (EQ (type, QCradio))
1588 wv->button_type = BUTTON_TYPE_RADIO;
1589 else
1590 emacs_abort ();
1591
1592 wv->selected = !NILP (selected);
1593
1594 prev_wv = wv;
1595
1596 i += MENU_ITEMS_ITEM_LENGTH;
1597 }
1598 }
1599
1600 /* Deal with the title, if it is non-nil. */
1601 if (!NILP (title))
1602 {
1603 widget_value *wv_title;
1604 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1605 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1606
1607 wv_sep2->next = first_wv->contents;
1608 wv_sep1->next = wv_sep2;
1609
1610 #ifndef HAVE_MULTILINGUAL_MENU
1611 if (STRING_MULTIBYTE (title))
1612 title = ENCODE_MENU_STRING (title);
1613 #endif
1614
1615 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1616 wv_title->button_type = BUTTON_TYPE_NONE;
1617 wv_title->next = wv_sep1;
1618 first_wv->contents = wv_title;
1619 }
1620
1621 /* No selection has been chosen yet. */
1622 menu_item_selection = 0;
1623
1624 /* Make sure to free the widget_value objects we used to specify the
1625 contents even with longjmp. */
1626 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1627
1628 /* Actually create and show the menu until popped down. */
1629 create_and_show_popup_menu (f, first_wv, x, y,
1630 menuflags & MENU_FOR_CLICK);
1631
1632 unbind_to (specpdl_count, Qnil);
1633
1634 /* Find the selected item, and its pane, to return
1635 the proper value. */
1636 if (menu_item_selection != 0)
1637 {
1638 Lisp_Object prefix, entry;
1639
1640 prefix = entry = Qnil;
1641 i = 0;
1642 while (i < menu_items_used)
1643 {
1644 if (EQ (AREF (menu_items, i), Qnil))
1645 {
1646 subprefix_stack[submenu_depth++] = prefix;
1647 prefix = entry;
1648 i++;
1649 }
1650 else if (EQ (AREF (menu_items, i), Qlambda))
1651 {
1652 prefix = subprefix_stack[--submenu_depth];
1653 i++;
1654 }
1655 else if (EQ (AREF (menu_items, i), Qt))
1656 {
1657 prefix
1658 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1659 i += MENU_ITEMS_PANE_LENGTH;
1660 }
1661 /* Ignore a nil in the item list.
1662 It's meaningful only for dialog boxes. */
1663 else if (EQ (AREF (menu_items, i), Qquote))
1664 i += 1;
1665 else
1666 {
1667 entry
1668 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1669 if (menu_item_selection == aref_addr (menu_items, i))
1670 {
1671 if (menuflags & MENU_KEYMAPS)
1672 {
1673 int j;
1674
1675 entry = list1 (entry);
1676 if (!NILP (prefix))
1677 entry = Fcons (prefix, entry);
1678 for (j = submenu_depth - 1; j >= 0; j--)
1679 if (!NILP (subprefix_stack[j]))
1680 entry = Fcons (subprefix_stack[j], entry);
1681 }
1682 unblock_input ();
1683 return entry;
1684 }
1685 i += MENU_ITEMS_ITEM_LENGTH;
1686 }
1687 }
1688 }
1689 else if (!(menuflags & MENU_FOR_CLICK))
1690 {
1691 unblock_input ();
1692 /* Make "Cancel" equivalent to C-g. */
1693 Fsignal (Qquit, Qnil);
1694 }
1695
1696 unblock_input ();
1697 return Qnil;
1698 }
1699 \f
1700 #ifdef USE_GTK
1701 static void
1702 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1703 {
1704 /* Treat the pointer as an integer. There's no problem
1705 as long as pointers have enough bits to hold small integers. */
1706 if ((intptr_t) client_data != -1)
1707 menu_item_selection = client_data;
1708
1709 popup_activated_flag = 0;
1710 }
1711
1712 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1713 dialog pops down.
1714 menu_item_selection will be set to the selection. */
1715 static void
1716 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1717 {
1718 GtkWidget *menu;
1719
1720 eassert (FRAME_X_P (f));
1721
1722 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1723 G_CALLBACK (dialog_selection_callback),
1724 G_CALLBACK (popup_deactivate_callback),
1725 0);
1726
1727 if (menu)
1728 {
1729 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1730 record_unwind_protect_ptr (pop_down_menu, menu);
1731
1732 /* Display the menu. */
1733 gtk_widget_show_all (menu);
1734
1735 /* Process events that apply to the menu. */
1736 popup_widget_loop (1, menu);
1737
1738 unbind_to (specpdl_count, Qnil);
1739 }
1740 }
1741
1742 #else /* not USE_GTK */
1743 static void
1744 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1745 {
1746 /* Treat the pointer as an integer. There's no problem
1747 as long as pointers have enough bits to hold small integers. */
1748 if ((intptr_t) client_data != -1)
1749 menu_item_selection = client_data;
1750
1751 block_input ();
1752 lw_destroy_all_widgets (id);
1753 unblock_input ();
1754 popup_activated_flag = 0;
1755 }
1756
1757
1758 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1759 dialog pops down.
1760 menu_item_selection will be set to the selection. */
1761 static void
1762 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1763 {
1764 LWLIB_ID dialog_id;
1765
1766 eassert (FRAME_X_P (f));
1767
1768 dialog_id = widget_id_tick++;
1769 #ifdef USE_LUCID
1770 apply_systemfont_to_dialog (f->output_data.x->widget);
1771 #endif
1772 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1773 f->output_data.x->widget, 1, 0,
1774 dialog_selection_callback, 0, 0);
1775 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1776 /* Display the dialog box. */
1777 lw_pop_up_all_widgets (dialog_id);
1778 popup_activated_flag = 1;
1779 x_activate_timeout_atimer ();
1780
1781 /* Process events that apply to the dialog box.
1782 Also handle timers. */
1783 {
1784 ptrdiff_t count = SPECPDL_INDEX ();
1785 int fact = 4 * sizeof (LWLIB_ID);
1786
1787 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1788 record_unwind_protect (pop_down_menu,
1789 Fcons (make_number (dialog_id >> (fact)),
1790 make_number (dialog_id & ~(-1 << (fact)))));
1791
1792 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, 1);
1793
1794 unbind_to (count, Qnil);
1795 }
1796 }
1797
1798 #endif /* not USE_GTK */
1799
1800 static const char * button_names [] = {
1801 "button1", "button2", "button3", "button4", "button5",
1802 "button6", "button7", "button8", "button9", "button10" };
1803
1804 static Lisp_Object
1805 x_dialog_show (struct frame *f, Lisp_Object title,
1806 Lisp_Object header, const char **error_name)
1807 {
1808 int i, nb_buttons=0;
1809 char dialog_name[6];
1810
1811 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1812
1813 /* Number of elements seen so far, before boundary. */
1814 int left_count = 0;
1815 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1816 int boundary_seen = 0;
1817
1818 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1819
1820 eassert (FRAME_X_P (f));
1821
1822 *error_name = NULL;
1823
1824 if (menu_items_n_panes > 1)
1825 {
1826 *error_name = "Multiple panes in dialog box";
1827 return Qnil;
1828 }
1829
1830 /* Create a tree of widget_value objects
1831 representing the text label and buttons. */
1832 {
1833 Lisp_Object pane_name;
1834 const char *pane_string;
1835 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1836 pane_string = (NILP (pane_name)
1837 ? "" : SSDATA (pane_name));
1838 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1839 first_wv = prev_wv;
1840
1841 /* Loop over all panes and items, filling in the tree. */
1842 i = MENU_ITEMS_PANE_LENGTH;
1843 while (i < menu_items_used)
1844 {
1845
1846 /* Create a new item within current pane. */
1847 Lisp_Object item_name, enable, descrip;
1848 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1849 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1850 descrip
1851 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1852
1853 if (NILP (item_name))
1854 {
1855 free_menubar_widget_value_tree (first_wv);
1856 *error_name = "Submenu in dialog items";
1857 return Qnil;
1858 }
1859 if (EQ (item_name, Qquote))
1860 {
1861 /* This is the boundary between left-side elts
1862 and right-side elts. Stop incrementing right_count. */
1863 boundary_seen = 1;
1864 i++;
1865 continue;
1866 }
1867 if (nb_buttons >= 9)
1868 {
1869 free_menubar_widget_value_tree (first_wv);
1870 *error_name = "Too many dialog items";
1871 return Qnil;
1872 }
1873
1874 wv = make_widget_value (button_names[nb_buttons],
1875 SSDATA (item_name),
1876 !NILP (enable), Qnil);
1877 prev_wv->next = wv;
1878 if (!NILP (descrip))
1879 wv->key = SSDATA (descrip);
1880 wv->call_data = aref_addr (menu_items, i);
1881 prev_wv = wv;
1882
1883 if (! boundary_seen)
1884 left_count++;
1885
1886 nb_buttons++;
1887 i += MENU_ITEMS_ITEM_LENGTH;
1888 }
1889
1890 /* If the boundary was not specified,
1891 by default put half on the left and half on the right. */
1892 if (! boundary_seen)
1893 left_count = nb_buttons - nb_buttons / 2;
1894
1895 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1896
1897 /* Frame title: 'Q' = Question, 'I' = Information.
1898 Can also have 'E' = Error if, one day, we want
1899 a popup for errors. */
1900 if (NILP (header))
1901 dialog_name[0] = 'Q';
1902 else
1903 dialog_name[0] = 'I';
1904
1905 /* Dialog boxes use a really stupid name encoding
1906 which specifies how many buttons to use
1907 and how many buttons are on the right. */
1908 dialog_name[1] = '0' + nb_buttons;
1909 dialog_name[2] = 'B';
1910 dialog_name[3] = 'R';
1911 /* Number of buttons to put on the right. */
1912 dialog_name[4] = '0' + nb_buttons - left_count;
1913 dialog_name[5] = 0;
1914 wv->contents = first_wv;
1915 first_wv = wv;
1916 }
1917
1918 /* No selection has been chosen yet. */
1919 menu_item_selection = 0;
1920
1921 /* Make sure to free the widget_value objects we used to specify the
1922 contents even with longjmp. */
1923 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1924
1925 /* Actually create and show the dialog. */
1926 create_and_show_dialog (f, first_wv);
1927
1928 unbind_to (specpdl_count, Qnil);
1929
1930 /* Find the selected item, and its pane, to return
1931 the proper value. */
1932 if (menu_item_selection != 0)
1933 {
1934 i = 0;
1935 while (i < menu_items_used)
1936 {
1937 Lisp_Object entry;
1938
1939 if (EQ (AREF (menu_items, i), Qt))
1940 i += MENU_ITEMS_PANE_LENGTH;
1941 else if (EQ (AREF (menu_items, i), Qquote))
1942 {
1943 /* This is the boundary between left-side elts and
1944 right-side elts. */
1945 ++i;
1946 }
1947 else
1948 {
1949 entry
1950 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1951 if (menu_item_selection == aref_addr (menu_items, i))
1952 return entry;
1953 i += MENU_ITEMS_ITEM_LENGTH;
1954 }
1955 }
1956 }
1957 else
1958 /* Make "Cancel" equivalent to C-g. */
1959 Fsignal (Qquit, Qnil);
1960
1961 return Qnil;
1962 }
1963
1964 Lisp_Object
1965 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1966 {
1967 Lisp_Object title;
1968 const char *error_name;
1969 Lisp_Object selection;
1970 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1971
1972 check_window_system (f);
1973
1974 /* Decode the dialog items from what was specified. */
1975 title = Fcar (contents);
1976 CHECK_STRING (title);
1977 record_unwind_protect_void (unuse_menu_items);
1978
1979 if (NILP (Fcar (Fcdr (contents))))
1980 /* No buttons specified, add an "Ok" button so users can pop down
1981 the dialog. Also, the lesstif/motif version crashes if there are
1982 no buttons. */
1983 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1984
1985 list_of_panes (list1 (contents));
1986
1987 /* Display them in a dialog box. */
1988 block_input ();
1989 selection = x_dialog_show (f, title, header, &error_name);
1990 unblock_input ();
1991
1992 unbind_to (specpdl_count, Qnil);
1993 discard_menu_items ();
1994
1995 if (error_name) error ("%s", error_name);
1996 return selection;
1997 }
1998
1999 #else /* not USE_X_TOOLKIT && not USE_GTK */
2000
2001 /* The frame of the last activated non-toolkit menu bar.
2002 Used to generate menu help events. */
2003
2004 static struct frame *menu_help_frame;
2005
2006
2007 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2008
2009 PANE is the pane number, and ITEM is the menu item number in
2010 the menu (currently not used).
2011
2012 This cannot be done with generating a HELP_EVENT because
2013 XMenuActivate contains a loop that doesn't let Emacs process
2014 keyboard events. */
2015
2016 static void
2017 menu_help_callback (char const *help_string, int pane, int item)
2018 {
2019 Lisp_Object *first_item;
2020 Lisp_Object pane_name;
2021 Lisp_Object menu_object;
2022
2023 first_item = XVECTOR (menu_items)->contents;
2024 if (EQ (first_item[0], Qt))
2025 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2026 else if (EQ (first_item[0], Qquote))
2027 /* This shouldn't happen, see x_menu_show. */
2028 pane_name = empty_unibyte_string;
2029 else
2030 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2031
2032 /* (menu-item MENU-NAME PANE-NUMBER) */
2033 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
2034 show_help_echo (help_string ? build_string (help_string) : Qnil,
2035 Qnil, menu_object, make_number (item));
2036 }
2037
2038 static void
2039 pop_down_menu (Lisp_Object arg)
2040 {
2041 struct frame *f = XSAVE_POINTER (arg, 0);
2042 XMenu *menu = XSAVE_POINTER (arg, 1);
2043
2044 block_input ();
2045 #ifndef MSDOS
2046 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2047 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2048 #endif
2049 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2050
2051 #ifdef HAVE_X_WINDOWS
2052 /* Assume the mouse has moved out of the X window.
2053 If it has actually moved in, we will get an EnterNotify. */
2054 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2055
2056 /* State that no mouse buttons are now held.
2057 (The oldXMenu code doesn't track this info for us.)
2058 That is not necessarily true, but the fiction leads to reasonable
2059 results, and it is a pain to ask which are actually held now. */
2060 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2061
2062 #endif /* HAVE_X_WINDOWS */
2063
2064 unblock_input ();
2065 }
2066
2067
2068 Lisp_Object
2069 x_menu_show (struct frame *f, int x, int y, int menuflags,
2070 Lisp_Object title, const char **error_name)
2071 {
2072 Window root;
2073 XMenu *menu;
2074 int pane, selidx, lpane, status;
2075 Lisp_Object entry, pane_prefix;
2076 char *datap;
2077 int ulx, uly, width, height;
2078 int dispwidth, dispheight;
2079 int i, j, lines, maxlines;
2080 int maxwidth;
2081 int dummy_int;
2082 unsigned int dummy_uint;
2083 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2084
2085 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2086
2087 *error_name = 0;
2088 if (menu_items_n_panes == 0)
2089 return Qnil;
2090
2091 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2092 {
2093 *error_name = "Empty menu";
2094 return Qnil;
2095 }
2096
2097 block_input ();
2098
2099 /* Figure out which root window F is on. */
2100 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2101 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2102 &dummy_uint, &dummy_uint);
2103
2104 /* Make the menu on that window. */
2105 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2106 if (menu == NULL)
2107 {
2108 *error_name = "Can't create menu";
2109 unblock_input ();
2110 return Qnil;
2111 }
2112
2113 /* Don't GC while we prepare and show the menu,
2114 because we give the oldxmenu library pointers to the
2115 contents of strings. */
2116 inhibit_garbage_collection ();
2117
2118 #ifdef HAVE_X_WINDOWS
2119 /* Adjust coordinates to relative to the outer (window manager) window. */
2120 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2121 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2122 #endif /* HAVE_X_WINDOWS */
2123
2124 /* Adjust coordinates to be root-window-relative. */
2125 x += f->left_pos;
2126 y += f->top_pos;
2127
2128 /* Create all the necessary panes and their items. */
2129 maxwidth = maxlines = lines = i = 0;
2130 lpane = XM_FAILURE;
2131 while (i < menu_items_used)
2132 {
2133 if (EQ (AREF (menu_items, i), Qt))
2134 {
2135 /* Create a new pane. */
2136 Lisp_Object pane_name, prefix;
2137 const char *pane_string;
2138
2139 maxlines = max (maxlines, lines);
2140 lines = 0;
2141 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2142 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2143 pane_string = (NILP (pane_name)
2144 ? "" : SSDATA (pane_name));
2145 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2146 pane_string++;
2147
2148 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2149 if (lpane == XM_FAILURE)
2150 {
2151 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2152 *error_name = "Can't create pane";
2153 unblock_input ();
2154 return Qnil;
2155 }
2156 i += MENU_ITEMS_PANE_LENGTH;
2157
2158 /* Find the width of the widest item in this pane. */
2159 j = i;
2160 while (j < menu_items_used)
2161 {
2162 Lisp_Object item;
2163 item = AREF (menu_items, j);
2164 if (EQ (item, Qt))
2165 break;
2166 if (NILP (item))
2167 {
2168 j++;
2169 continue;
2170 }
2171 width = SBYTES (item);
2172 if (width > maxwidth)
2173 maxwidth = width;
2174
2175 j += MENU_ITEMS_ITEM_LENGTH;
2176 }
2177 }
2178 /* Ignore a nil in the item list.
2179 It's meaningful only for dialog boxes. */
2180 else if (EQ (AREF (menu_items, i), Qquote))
2181 i += 1;
2182 else
2183 {
2184 /* Create a new item within current pane. */
2185 Lisp_Object item_name, enable, descrip, help;
2186 char *item_data;
2187 char const *help_string;
2188
2189 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2190 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2191 descrip
2192 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2193 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2194 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2195
2196 if (!NILP (descrip))
2197 {
2198 /* if alloca is fast, use that to make the space,
2199 to reduce gc needs. */
2200 item_data = alloca (maxwidth + SBYTES (descrip) + 1);
2201 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2202 for (j = SCHARS (item_name); j < maxwidth; j++)
2203 item_data[j] = ' ';
2204 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2205 item_data[j + SBYTES (descrip)] = 0;
2206 }
2207 else
2208 item_data = SSDATA (item_name);
2209
2210 if (lpane == XM_FAILURE
2211 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2212 menu, lpane, 0, item_data,
2213 !NILP (enable), help_string)
2214 == XM_FAILURE))
2215 {
2216 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2217 *error_name = "Can't add selection to menu";
2218 unblock_input ();
2219 return Qnil;
2220 }
2221 i += MENU_ITEMS_ITEM_LENGTH;
2222 lines++;
2223 }
2224 }
2225
2226 maxlines = max (maxlines, lines);
2227
2228 /* All set and ready to fly. */
2229 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2230 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2231 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2232 x = min (x, dispwidth);
2233 y = min (y, dispheight);
2234 x = max (x, 1);
2235 y = max (y, 1);
2236 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2237 &ulx, &uly, &width, &height);
2238 if (ulx+width > dispwidth)
2239 {
2240 x -= (ulx + width) - dispwidth;
2241 ulx = dispwidth - width;
2242 }
2243 if (uly+height > dispheight)
2244 {
2245 y -= (uly + height) - dispheight;
2246 uly = dispheight - height;
2247 }
2248 #ifndef HAVE_X_WINDOWS
2249 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2250 {
2251 /* Move the menu away of the echo area, to avoid overwriting the
2252 menu with help echo messages or vice versa. */
2253 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2254 {
2255 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2256 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2257 }
2258 else
2259 {
2260 y--;
2261 uly--;
2262 }
2263 }
2264 #endif
2265 if (ulx < 0) x -= ulx;
2266 if (uly < 0) y -= uly;
2267
2268 if (!(menuflags & MENU_FOR_CLICK))
2269 {
2270 /* If position was not given by a mouse click, adjust so upper left
2271 corner of the menu as a whole ends up at given coordinates. This
2272 is what x-popup-menu says in its documentation. */
2273 x += width/2;
2274 y += 1.5*height/(maxlines+2);
2275 }
2276
2277 XMenuSetAEQ (menu, TRUE);
2278 XMenuSetFreeze (menu, TRUE);
2279 pane = selidx = 0;
2280
2281 #ifndef MSDOS
2282 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2283 #endif
2284
2285 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2286
2287 /* Help display under X won't work because XMenuActivate contains
2288 a loop that doesn't give Emacs a chance to process it. */
2289 menu_help_frame = f;
2290 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2291 x, y, ButtonReleaseMask, &datap,
2292 menu_help_callback);
2293 entry = pane_prefix = Qnil;
2294
2295 switch (status)
2296 {
2297 case XM_SUCCESS:
2298 #ifdef XDEBUG
2299 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2300 #endif
2301
2302 /* Find the item number SELIDX in pane number PANE. */
2303 i = 0;
2304 while (i < menu_items_used)
2305 {
2306 if (EQ (AREF (menu_items, i), Qt))
2307 {
2308 if (pane == 0)
2309 pane_prefix
2310 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2311 pane--;
2312 i += MENU_ITEMS_PANE_LENGTH;
2313 }
2314 else
2315 {
2316 if (pane == -1)
2317 {
2318 if (selidx == 0)
2319 {
2320 entry
2321 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2322 if (menuflags & MENU_KEYMAPS)
2323 {
2324 entry = list1 (entry);
2325 if (!NILP (pane_prefix))
2326 entry = Fcons (pane_prefix, entry);
2327 }
2328 break;
2329 }
2330 selidx--;
2331 }
2332 i += MENU_ITEMS_ITEM_LENGTH;
2333 }
2334 }
2335 break;
2336
2337 case XM_FAILURE:
2338 *error_name = "Can't activate menu";
2339 case XM_IA_SELECT:
2340 break;
2341 case XM_NO_SELECT:
2342 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2343 the menu was invoked with a mouse event as POSITION). */
2344 if (!(menuflags & MENU_FOR_CLICK))
2345 {
2346 unblock_input ();
2347 Fsignal (Qquit, Qnil);
2348 }
2349 break;
2350 }
2351
2352 unblock_input ();
2353 unbind_to (specpdl_count, Qnil);
2354
2355 return entry;
2356 }
2357
2358 #endif /* not USE_X_TOOLKIT */
2359
2360 #ifndef MSDOS
2361 /* Detect if a dialog or menu has been posted. MSDOS has its own
2362 implementation on msdos.c. */
2363
2364 int ATTRIBUTE_CONST
2365 popup_activated (void)
2366 {
2367 return popup_activated_flag;
2368 }
2369 #endif /* not MSDOS */
2370
2371 /* The following is used by delayed window autoselection. */
2372
2373 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2374 doc: /* Return t if a menu or popup dialog is active. */)
2375 (void)
2376 {
2377 return (popup_activated ()) ? Qt : Qnil;
2378 }
2379 \f
2380 void
2381 syms_of_xmenu (void)
2382 {
2383 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2384
2385 #ifdef USE_X_TOOLKIT
2386 widget_id_tick = (1<<16);
2387 next_menubar_widget_id = 1;
2388 #endif
2389
2390 defsubr (&Smenu_or_popup_active_p);
2391
2392 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2393 defsubr (&Sx_menu_bar_open_internal);
2394 Ffset (intern_c_string ("accelerate-menu"),
2395 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2396 #endif
2397 }