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