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