make the minibuffer mutex recursive.
[emacs.git] / src / xmenu.c
blob2c2cb5ed5301fe0a79dcb6915a65c2b8b76ef93c
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.
5 This file is part of GNU Emacs.
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.
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.
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/>. */
20 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
27 /* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
30 /* Rewritten for clarity and GC protection by rms in Feb 94. */
32 #include <config.h>
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
39 #include <stdio.h>
40 #include <setjmp.h>
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"
54 #ifdef MSDOS
55 #include "msdos.h"
56 #endif
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
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
70 #include "dispextern.h"
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 */
98 #ifdef USE_GTK
99 #include "gtkutil.h"
100 #endif
102 #include "menu.h"
104 #ifndef TRUE
105 #define TRUE 1
106 #define FALSE 0
107 #endif /* no TRUE */
109 Lisp_Object Qdebug_on_next_call;
111 extern Lisp_Object Qmenu_bar;
113 extern Lisp_Object QCtoggle, QCradio;
115 extern Lisp_Object impl_Voverriding_local_map;
116 extern Lisp_Object impl_Voverriding_local_map_menu_flag;
118 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
120 extern Lisp_Object Qmenu_bar_update_hook;
122 #ifdef USE_X_TOOLKIT
123 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
124 extern XtAppContext Xt_app_con;
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 */
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
138 static int update_frame_menubar P_ ((struct frame *));
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;
144 static int next_menubar_widget_id;
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
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.
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>. */
159 int pending_menu_activation;
161 #ifdef USE_X_TOOLKIT
163 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
165 static struct frame *
166 menubar_id_to_frame (id)
167 LWLIB_ID id;
169 Lisp_Object tail, frame;
170 FRAME_PTR f;
172 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
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;
183 return 0;
186 #endif
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;
202 Window root, dummy_window;
203 int dummy;
205 if (! FRAME_X_P (f))
206 abort ();
208 BLOCK_INPUT;
210 XQueryPointer (FRAME_X_DISPLAY (f),
211 DefaultRootWindow (FRAME_X_DISPLAY (f)),
213 /* The root window which contains the pointer. */
214 &root,
216 /* Window pointer is on, not used */
217 &dummy_window,
219 /* The position on that root window. */
220 x, y,
222 /* x/y in dummy_window coordinates, not used. */
223 &dummy, &dummy,
225 /* Modifier keys and pointer buttons, about which
226 we don't care. */
227 (unsigned int *) &dummy);
229 UNBLOCK_INPUT;
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);
237 #endif /* HAVE_X_WINDOWS */
239 #ifdef HAVE_MENUS
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.
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.
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.)
258 If HEADER is non-nil, the frame title for the box is "Information",
259 otherwise it is "Question".
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;
267 FRAME_PTR f = NULL;
268 Lisp_Object window;
270 check_x ();
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))))
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;
285 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
287 if (new_f != 0)
288 XSETFRAME (window, new_f);
289 else
290 window = selected_window;
291 #endif
292 window = selected_window;
294 else if (CONSP (position))
296 Lisp_Object tem;
297 tem = Fcar (position);
298 if (CONSP (tem))
299 window = Fcar (Fcdr (position));
300 else
302 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
303 window = Fcar (tem); /* POSN_WINDOW (tem) */
306 else if (WINDOWP (position) || FRAMEP (position))
307 window = position;
308 else
309 window = Qnil;
311 /* Decode where to put the menu. */
313 if (FRAMEP (window))
314 f = XFRAME (window);
315 else if (WINDOWP (window))
317 CHECK_LIVE_WINDOW (window);
318 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
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);
325 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
326 error ("Can not put X dialog on this terminal");
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.
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);
339 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
340 /* Display a menu with these alternatives
341 in the middle of frame F. */
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));
349 return Fx_popup_menu (newpos,
350 Fcons (Fcar (contents), Fcons (contents, Qnil)));
352 #else
354 Lisp_Object title;
355 char *error_name;
356 Lisp_Object selection;
357 int specpdl_count = SPECPDL_INDEX ();
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);
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));
370 list_of_panes (Fcons (contents, Qnil));
372 /* Display them in a dialog box. */
373 BLOCK_INPUT;
374 selection = xdialog_show (f, 0, title, header, &error_name);
375 UNBLOCK_INPUT;
377 unbind_to (specpdl_count, Qnil);
378 discard_menu_items ();
380 if (error_name) error (error_name);
381 return selection;
383 #endif
387 #ifndef MSDOS
389 /* Set menu_items_inuse so no other popup menu or dialog is created. */
391 void
392 x_menu_set_in_use (in_use)
393 int in_use;
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
403 /* Wait for an X event to arrive or for a timer to expire. */
405 void
406 x_menu_wait_for_event (void *data)
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. */
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
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;
430 FD_ZERO (&read_fds);
431 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
433 int fd = ConnectionNumber (dpyinfo->display);
434 FD_SET (fd, &read_fds);
435 if (fd > n) n = fd;
436 XFlush (dpyinfo->display);
439 if (secs < 0 && usecs < 0)
440 ntp = 0;
441 else
442 ntp = &next_time;
444 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
447 #endif /* ! MSDOS */
450 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
452 #ifdef USE_X_TOOLKIT
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.
458 NOTE: All calls to popup_get_selection should be protected
459 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
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;
468 XEvent event;
470 while (popup_activated_flag)
472 if (initial_event)
474 event = *initial_event;
475 initial_event = 0;
477 else
479 if (do_timers) x_menu_wait_for_event (0);
480 XtAppNextEvent (Xt_app_con, &event);
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)
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
501 /* Pop down on C-g and Escape. */
502 else if (event.type == KeyPress
503 && dpyinfo->display == event.xbutton.display)
505 KeySym keysym = XLookupKeysym (&event.xkey, 0);
507 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
508 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
509 popup_activated_flag = 0;
512 x_dispatch_event (&event, event.xany.display);
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.
522 If FRAME is nil or not given, use the selected frame. */)
523 (frame)
524 Lisp_Object frame;
526 XEvent ev;
527 FRAME_PTR f = check_x_frame (frame);
528 Widget menubar;
529 BLOCK_INPUT;
531 if (FRAME_EXTERNAL_MENU_BAR (f))
532 set_frame_menubar (f, 0, 1);
534 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
535 if (menubar)
537 Window child;
538 int error_p = 0;
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;
550 #ifdef USE_MOTIF
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]);
560 #endif
562 XTranslateCoordinates (FRAME_X_DISPLAY (f),
563 /* From-window, to-window. */
564 ev.xbutton.window, ev.xbutton.root,
566 /* From-position, to-position. */
567 ev.xbutton.x, ev.xbutton.y,
568 &ev.xbutton.x_root, &ev.xbutton.y_root,
570 /* Child of win. */
571 &child);
572 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
573 x_uncatch_errors ();
575 if (! error_p)
577 ev.type = ButtonPress;
578 ev.xbutton.state = 0;
580 XtDispatchEvent (&ev);
581 ev.xbutton.type = ButtonRelease;
582 ev.xbutton.state = Button1Mask;
583 XtDispatchEvent (&ev);
587 UNBLOCK_INPUT;
589 return Qnil;
591 #endif /* USE_X_TOOLKIT */
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.
601 If FRAME is nil or not given, use the selected frame. */)
602 (frame)
603 Lisp_Object frame;
605 GtkWidget *menubar;
606 FRAME_PTR f;
608 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
609 BLOCK_INPUT. */
611 BLOCK_INPUT;
612 f = check_x_frame (frame);
614 if (FRAME_EXTERNAL_MENU_BAR (f))
615 set_frame_menubar (f, 0, 1);
617 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
618 if (menubar)
620 /* Activate the first menu. */
621 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
623 if (children)
625 g_signal_emit_by_name (children->data, "activate_item");
626 popup_activated_flag = 1;
627 g_list_free (children);
630 UNBLOCK_INPUT;
632 return Qnil;
635 /* Loop util popup_activated_flag is set to zero in a callback.
636 Used for popup menus and dialogs. */
638 static void
639 popup_widget_loop (do_timers, widget)
640 int do_timers;
641 GtkWidget *widget;
643 ++popup_activated_flag;
645 /* Process events in the Gtk event loop until done. */
646 while (popup_activated_flag)
648 if (do_timers) x_menu_wait_for_event (0);
649 gtk_main_iteration ();
652 #endif
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.
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.
662 But first we recompute the menu bar contents (the whole tree).
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. */
668 void
669 x_activate_menubar (f)
670 FRAME_PTR f;
672 if (! FRAME_X_P (f))
673 abort ();
675 if (!f->output_data.x->saved_menu_event->type)
676 return;
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
684 set_frame_menubar (f, 0, 1);
685 BLOCK_INPUT;
686 #ifdef USE_GTK
687 XPutBackEvent (f->output_data.x->display_info->display,
688 f->output_data.x->saved_menu_event);
689 popup_activated_flag = 1;
690 #else
691 XtDispatchEvent (f->output_data.x->saved_menu_event);
692 #endif
693 UNBLOCK_INPUT;
694 #ifdef USE_MOTIF
695 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
696 pending_menu_activation = 1;
697 #endif
699 /* Ignore this if we get it a second time. */
700 f->output_data.x->saved_menu_event->type = 0;
703 /* This callback is invoked when the user selects a menubar cascade
704 pushbutton, but before the pulldown menu is posted. */
706 #ifndef USE_GTK
707 static void
708 popup_activate_callback (widget, id, client_data)
709 Widget widget;
710 LWLIB_ID id;
711 XtPointer client_data;
713 popup_activated_flag = 1;
714 #ifdef USE_X_TOOLKIT
715 x_activate_timeout_atimer ();
716 #endif
718 #endif
720 /* This callback is invoked when a dialog or menu is finished being
721 used and has been unposted. */
723 #ifdef USE_GTK
724 static void
725 popup_deactivate_callback (widget, client_data)
726 GtkWidget *widget;
727 gpointer client_data;
729 popup_activated_flag = 0;
731 #else
732 static void
733 popup_deactivate_callback (widget, id, client_data)
734 Widget widget;
735 LWLIB_ID id;
736 XtPointer client_data;
738 popup_activated_flag = 0;
740 #endif
743 /* Function that finds the frame for WIDGET and shows the HELP text
744 for that widget.
745 F is the frame if known, or NULL if not known. */
746 static void
747 show_help_event (f, widget, help)
748 FRAME_PTR f;
749 xt_or_gtk_widget widget;
750 Lisp_Object help;
752 Lisp_Object frame;
754 if (f)
756 XSETFRAME (frame, f);
757 kbd_buffer_store_help_event (frame, help);
759 else
761 #if 0 /* This code doesn't do anything useful. ++kfs */
762 /* WIDGET is the popup menu. It's parent is the frame's
763 widget. See which frame that is. */
764 xt_or_gtk_widget frame_widget = XtParent (widget);
765 Lisp_Object tail;
767 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
769 frame = XCAR (tail);
770 if (FRAMEP (frame)
771 && (f = XFRAME (frame),
772 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
773 break;
775 #endif
776 show_help_echo (help, Qnil, Qnil, Qnil, 1);
780 /* Callback called when menu items are highlighted/unhighlighted
781 while moving the mouse over them. WIDGET is the menu bar or menu
782 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
783 the data structure for the menu item, or null in case of
784 unhighlighting. */
786 #ifdef USE_GTK
787 void
788 menu_highlight_callback (widget, call_data)
789 GtkWidget *widget;
790 gpointer call_data;
792 xg_menu_item_cb_data *cb_data;
793 Lisp_Object help;
795 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
796 XG_ITEM_DATA);
797 if (! cb_data) return;
799 help = call_data ? cb_data->help : Qnil;
801 /* If popup_activated_flag is greater than 1 we are in a popup menu.
802 Don't show help for them, they won't appear before the
803 popup is popped down. */
804 if (popup_activated_flag <= 1)
805 show_help_event (cb_data->cl_data->f, widget, help);
807 #else
808 void
809 menu_highlight_callback (widget, id, call_data)
810 Widget widget;
811 LWLIB_ID id;
812 void *call_data;
814 struct frame *f;
815 Lisp_Object help;
817 widget_value *wv = (widget_value *) call_data;
819 help = wv ? wv->help : Qnil;
821 /* Determine the frame for the help event. */
822 f = menubar_id_to_frame (id);
824 show_help_event (f, widget, help);
826 #endif
828 #ifdef USE_GTK
829 /* Gtk calls callbacks just because we tell it what item should be
830 selected in a radio group. If this variable is set to a non-zero
831 value, we are creating menus and don't want callbacks right now.
833 static int xg_crazy_callback_abort;
835 /* This callback is called from the menu bar pulldown menu
836 when the user makes a selection.
837 Figure out what the user chose
838 and put the appropriate events into the keyboard buffer. */
839 static void
840 menubar_selection_callback (widget, client_data)
841 GtkWidget *widget;
842 gpointer client_data;
844 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
846 if (xg_crazy_callback_abort)
847 return;
849 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
850 return;
852 /* For a group of radio buttons, GTK calls the selection callback first
853 for the item that was active before the selection and then for the one that
854 is active after the selection. For C-h k this means we get the help on
855 the deselected item and then the selected item is executed. Prevent that
856 by ignoring the non-active item. */
857 if (GTK_IS_RADIO_MENU_ITEM (widget)
858 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
859 return;
861 /* When a menu is popped down, X generates a focus event (i.e. focus
862 goes back to the frame below the menu). Since GTK buffers events,
863 we force it out here before the menu selection event. Otherwise
864 sit-for will exit at once if the focus event follows the menu selection
865 event. */
867 BLOCK_INPUT;
868 while (gtk_events_pending ())
869 gtk_main_iteration ();
870 UNBLOCK_INPUT;
872 find_and_call_menu_selection (cb_data->cl_data->f,
873 cb_data->cl_data->menu_bar_items_used,
874 cb_data->cl_data->menu_bar_vector,
875 cb_data->call_data);
878 #else /* not USE_GTK */
880 /* This callback is called from the menu bar pulldown menu
881 when the user makes a selection.
882 Figure out what the user chose
883 and put the appropriate events into the keyboard buffer. */
884 static void
885 menubar_selection_callback (widget, id, client_data)
886 Widget widget;
887 LWLIB_ID id;
888 XtPointer client_data;
890 FRAME_PTR f;
892 f = menubar_id_to_frame (id);
893 if (!f)
894 return;
895 find_and_call_menu_selection (f, f->menu_bar_items_used,
896 f->menu_bar_vector, client_data);
898 #endif /* not USE_GTK */
900 /* Recompute all the widgets of frame F, when the menu bar has been
901 changed. Value is non-zero if widgets were updated. */
903 static int
904 update_frame_menubar (f)
905 FRAME_PTR f;
907 #ifdef USE_GTK
908 return xg_update_frame_menubar (f);
909 #else
910 struct x_output *x;
911 int columns, rows;
913 if (! FRAME_X_P (f))
914 abort ();
916 x = f->output_data.x;
918 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
919 return 0;
921 BLOCK_INPUT;
922 /* Save the size of the frame because the pane widget doesn't accept
923 to resize itself. So force it. */
924 columns = FRAME_COLS (f);
925 rows = FRAME_LINES (f);
927 /* Do the voodoo which means "I'm changing lots of things, don't try
928 to refigure sizes until I'm done." */
929 lw_refigure_widget (x->column_widget, False);
931 /* The order in which children are managed is the top to bottom
932 order in which they are displayed in the paned window. First,
933 remove the text-area widget. */
934 XtUnmanageChild (x->edit_widget);
936 /* Remove the menubar that is there now, and put up the menubar that
937 should be there. */
938 XtManageChild (x->menubar_widget);
939 XtMapWidget (x->menubar_widget);
940 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
942 /* Re-manage the text-area widget, and then thrash the sizes. */
943 XtManageChild (x->edit_widget);
944 lw_refigure_widget (x->column_widget, True);
946 /* Force the pane widget to resize itself with the right values. */
947 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
948 UNBLOCK_INPUT;
949 #endif
950 return 1;
953 /* Set the contents of the menubar widgets of frame F.
954 The argument FIRST_TIME is currently ignored;
955 it is set the first time this is called, from initialize_frame_menubar. */
957 void
958 set_frame_menubar (f, first_time, deep_p)
959 FRAME_PTR f;
960 int first_time;
961 int deep_p;
963 xt_or_gtk_widget menubar_widget;
964 #ifdef USE_X_TOOLKIT
965 LWLIB_ID id;
966 #endif
967 Lisp_Object items;
968 widget_value *wv, *first_wv, *prev_wv = 0;
969 int i, last_i = 0;
970 int *submenu_start, *submenu_end;
971 int *submenu_top_level_items, *submenu_n_panes;
973 if (! FRAME_X_P (f))
974 abort ();
976 menubar_widget = f->output_data.x->menubar_widget;
978 XSETFRAME (Vmenu_updating_frame, f);
980 #ifdef USE_X_TOOLKIT
981 if (f->output_data.x->id == 0)
982 f->output_data.x->id = next_menubar_widget_id++;
983 id = f->output_data.x->id;
984 #endif
986 if (! menubar_widget)
987 deep_p = 1;
988 else if (pending_menu_activation && !deep_p)
989 deep_p = 1;
990 /* Make the first call for any given frame always go deep. */
991 else if (!f->output_data.x->saved_menu_event && !deep_p)
993 deep_p = 1;
994 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
995 f->output_data.x->saved_menu_event->type = 0;
998 #ifdef USE_GTK
999 /* If we have detached menus, we must update deep so detached menus
1000 also gets updated. */
1001 deep_p = deep_p || xg_have_tear_offs ();
1002 #endif
1004 if (deep_p)
1006 /* Make a widget-value tree representing the entire menu trees. */
1008 struct buffer *prev = current_buffer;
1009 Lisp_Object buffer;
1010 int specpdl_count = SPECPDL_INDEX ();
1011 int previous_menu_items_used = f->menu_bar_items_used;
1012 Lisp_Object *previous_items
1013 = (Lisp_Object *) alloca (previous_menu_items_used
1014 * sizeof (Lisp_Object));
1016 /* If we are making a new widget, its contents are empty,
1017 do always reinitialize them. */
1018 if (! menubar_widget)
1019 previous_menu_items_used = 0;
1021 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1022 specbind (Qinhibit_quit, Qt);
1023 /* Don't let the debugger step into this code
1024 because it is not reentrant. */
1025 specbind (Qdebug_on_next_call, Qnil);
1027 record_unwind_save_match_data ();
1028 if (NILP (Voverriding_local_map_menu_flag))
1030 specbind (Qoverriding_terminal_local_map, Qnil);
1031 specbind (Qoverriding_local_map, Qnil);
1034 set_buffer_internal_1 (XBUFFER (buffer));
1036 /* Run the Lucid hook. */
1037 safe_run_hooks (Qactivate_menubar_hook);
1039 /* If it has changed current-menubar from previous value,
1040 really recompute the menubar from the value. */
1041 if (! NILP (Vlucid_menu_bar_dirty_flag))
1042 call0 (Qrecompute_lucid_menubar);
1043 safe_run_hooks (Qmenu_bar_update_hook);
1044 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1046 items = FRAME_MENU_BAR_ITEMS (f);
1048 /* Save the frame's previous menu bar contents data. */
1049 if (previous_menu_items_used)
1050 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1051 previous_menu_items_used * sizeof (Lisp_Object));
1053 /* Fill in menu_items with the current menu bar contents.
1054 This can evaluate Lisp code. */
1055 save_menu_items ();
1057 menu_items = f->menu_bar_vector;
1058 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1059 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1060 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1061 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1062 submenu_top_level_items
1063 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1064 init_menu_items ();
1065 for (i = 0; i < XVECTOR (items)->size; i += 4)
1067 Lisp_Object key, string, maps;
1069 last_i = i;
1071 key = XVECTOR (items)->contents[i];
1072 string = XVECTOR (items)->contents[i + 1];
1073 maps = XVECTOR (items)->contents[i + 2];
1074 if (NILP (string))
1075 break;
1077 submenu_start[i] = menu_items_used;
1079 menu_items_n_panes = 0;
1080 submenu_top_level_items[i]
1081 = parse_single_submenu (key, string, maps);
1082 submenu_n_panes[i] = menu_items_n_panes;
1084 submenu_end[i] = menu_items_used;
1087 finish_menu_items ();
1089 /* Convert menu_items into widget_value trees
1090 to display the menu. This cannot evaluate Lisp code. */
1092 wv = xmalloc_widget_value ();
1093 wv->name = "menubar";
1094 wv->value = 0;
1095 wv->enabled = 1;
1096 wv->button_type = BUTTON_TYPE_NONE;
1097 wv->help = Qnil;
1098 first_wv = wv;
1100 for (i = 0; i < last_i; i += 4)
1102 menu_items_n_panes = submenu_n_panes[i];
1103 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1104 submenu_top_level_items[i]);
1105 if (prev_wv)
1106 prev_wv->next = wv;
1107 else
1108 first_wv->contents = wv;
1109 /* Don't set wv->name here; GC during the loop might relocate it. */
1110 wv->enabled = 1;
1111 wv->button_type = BUTTON_TYPE_NONE;
1112 prev_wv = wv;
1115 set_buffer_internal_1 (prev);
1117 /* If there has been no change in the Lisp-level contents
1118 of the menu bar, skip redisplaying it. Just exit. */
1120 /* Compare the new menu items with the ones computed last time. */
1121 for (i = 0; i < previous_menu_items_used; i++)
1122 if (menu_items_used == i
1123 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1124 break;
1125 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1127 /* The menu items have not changed. Don't bother updating
1128 the menus in any form, since it would be a no-op. */
1129 free_menubar_widget_value_tree (first_wv);
1130 discard_menu_items ();
1131 unbind_to (specpdl_count, Qnil);
1132 return;
1135 /* The menu items are different, so store them in the frame. */
1136 f->menu_bar_vector = menu_items;
1137 f->menu_bar_items_used = menu_items_used;
1139 /* This undoes save_menu_items. */
1140 unbind_to (specpdl_count, Qnil);
1142 /* Now GC cannot happen during the lifetime of the widget_value,
1143 so it's safe to store data from a Lisp_String. */
1144 wv = first_wv->contents;
1145 for (i = 0; i < XVECTOR (items)->size; i += 4)
1147 Lisp_Object string;
1148 string = XVECTOR (items)->contents[i + 1];
1149 if (NILP (string))
1150 break;
1151 wv->name = (char *) SDATA (string);
1152 update_submenu_strings (wv->contents);
1153 wv = wv->next;
1157 else
1159 /* Make a widget-value tree containing
1160 just the top level menu bar strings. */
1162 wv = xmalloc_widget_value ();
1163 wv->name = "menubar";
1164 wv->value = 0;
1165 wv->enabled = 1;
1166 wv->button_type = BUTTON_TYPE_NONE;
1167 wv->help = Qnil;
1168 first_wv = wv;
1170 items = FRAME_MENU_BAR_ITEMS (f);
1171 for (i = 0; i < XVECTOR (items)->size; i += 4)
1173 Lisp_Object string;
1175 string = XVECTOR (items)->contents[i + 1];
1176 if (NILP (string))
1177 break;
1179 wv = xmalloc_widget_value ();
1180 wv->name = (char *) SDATA (string);
1181 wv->value = 0;
1182 wv->enabled = 1;
1183 wv->button_type = BUTTON_TYPE_NONE;
1184 wv->help = Qnil;
1185 /* This prevents lwlib from assuming this
1186 menu item is really supposed to be empty. */
1187 /* The EMACS_INT cast avoids a warning.
1188 This value just has to be different from small integers. */
1189 wv->call_data = (void *) (EMACS_INT) (-1);
1191 if (prev_wv)
1192 prev_wv->next = wv;
1193 else
1194 first_wv->contents = wv;
1195 prev_wv = wv;
1198 /* Forget what we thought we knew about what is in the
1199 detailed contents of the menu bar menus.
1200 Changing the top level always destroys the contents. */
1201 f->menu_bar_items_used = 0;
1204 /* Create or update the menu bar widget. */
1206 BLOCK_INPUT;
1208 #ifdef USE_GTK
1209 xg_crazy_callback_abort = 1;
1210 if (menubar_widget)
1212 /* The fourth arg is DEEP_P, which says to consider the entire
1213 menu trees we supply, rather than just the menu bar item names. */
1214 xg_modify_menubar_widgets (menubar_widget,
1216 first_wv,
1217 deep_p,
1218 G_CALLBACK (menubar_selection_callback),
1219 G_CALLBACK (popup_deactivate_callback),
1220 G_CALLBACK (menu_highlight_callback));
1222 else
1224 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1226 menubar_widget
1227 = xg_create_widget ("menubar", "menubar", f, first_wv,
1228 G_CALLBACK (menubar_selection_callback),
1229 G_CALLBACK (popup_deactivate_callback),
1230 G_CALLBACK (menu_highlight_callback));
1232 f->output_data.x->menubar_widget = menubar_widget;
1236 #else /* not USE_GTK */
1237 if (menubar_widget)
1239 /* Disable resizing (done for Motif!) */
1240 lw_allow_resizing (f->output_data.x->widget, False);
1242 /* The third arg is DEEP_P, which says to consider the entire
1243 menu trees we supply, rather than just the menu bar item names. */
1244 lw_modify_all_widgets (id, first_wv, deep_p);
1246 /* Re-enable the edit widget to resize. */
1247 lw_allow_resizing (f->output_data.x->widget, True);
1249 else
1251 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1252 XtTranslations override = XtParseTranslationTable (menuOverride);
1254 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1255 f->output_data.x->column_widget,
1257 popup_activate_callback,
1258 menubar_selection_callback,
1259 popup_deactivate_callback,
1260 menu_highlight_callback);
1261 f->output_data.x->menubar_widget = menubar_widget;
1263 /* Make menu pop down on C-g. */
1264 XtOverrideTranslations (menubar_widget, override);
1268 int menubar_size
1269 = (f->output_data.x->menubar_widget
1270 ? (f->output_data.x->menubar_widget->core.height
1271 + f->output_data.x->menubar_widget->core.border_width)
1272 : 0);
1274 #if 1 /* Experimentally, we now get the right results
1275 for -geometry -0-0 without this. 24 Aug 96, rms.
1276 Maybe so, but the menu bar size is missing the pixels so the
1277 WM size hints are off by theses pixel. Jan D, oct 2009. */
1278 #ifdef USE_LUCID
1279 if (FRAME_EXTERNAL_MENU_BAR (f))
1281 Dimension ibw = 0;
1282 XtVaGetValues (f->output_data.x->column_widget,
1283 XtNinternalBorderWidth, &ibw, NULL);
1284 menubar_size += ibw;
1286 #endif /* USE_LUCID */
1287 #endif /* 1 */
1289 f->output_data.x->menubar_height = menubar_size;
1291 #endif /* not USE_GTK */
1293 free_menubar_widget_value_tree (first_wv);
1294 update_frame_menubar (f);
1296 #ifdef USE_GTK
1297 xg_crazy_callback_abort = 0;
1298 #endif
1300 UNBLOCK_INPUT;
1303 /* Called from Fx_create_frame to create the initial menubar of a frame
1304 before it is mapped, so that the window is mapped with the menubar already
1305 there instead of us tacking it on later and thrashing the window after it
1306 is visible. */
1308 void
1309 initialize_frame_menubar (f)
1310 FRAME_PTR f;
1312 /* This function is called before the first chance to redisplay
1313 the frame. It has to be, so the frame will have the right size. */
1314 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1315 set_frame_menubar (f, 1, 1);
1319 /* Get rid of the menu bar of frame F, and free its storage.
1320 This is used when deleting a frame, and when turning off the menu bar.
1321 For GTK this function is in gtkutil.c. */
1323 #ifndef USE_GTK
1324 void
1325 free_frame_menubar (f)
1326 FRAME_PTR f;
1328 Widget menubar_widget;
1330 if (! FRAME_X_P (f))
1331 abort ();
1333 menubar_widget = f->output_data.x->menubar_widget;
1335 f->output_data.x->menubar_height = 0;
1337 if (menubar_widget)
1339 #ifdef USE_MOTIF
1340 /* Removing the menu bar magically changes the shell widget's x
1341 and y position of (0, 0) which, when the menu bar is turned
1342 on again, leads to pull-down menuss appearing in strange
1343 positions near the upper-left corner of the display. This
1344 happens only with some window managers like twm and ctwm,
1345 but not with other like Motif's mwm or kwm, because the
1346 latter generate ConfigureNotify events when the menu bar
1347 is switched off, which fixes the shell position. */
1348 Position x0, y0, x1, y1;
1349 #endif
1351 BLOCK_INPUT;
1353 #ifdef USE_MOTIF
1354 if (f->output_data.x->widget)
1355 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1356 #endif
1358 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1359 f->output_data.x->menubar_widget = NULL;
1361 #ifdef USE_MOTIF
1362 if (f->output_data.x->widget)
1364 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1365 if (x1 == 0 && y1 == 0)
1366 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1368 #endif
1370 UNBLOCK_INPUT;
1373 #endif /* not USE_GTK */
1375 #endif /* USE_X_TOOLKIT || USE_GTK */
1377 /* xmenu_show actually displays a menu using the panes and items in menu_items
1378 and returns the value selected from it.
1379 There are two versions of xmenu_show, one for Xt and one for Xlib.
1380 Both assume input is blocked by the caller. */
1382 /* F is the frame the menu is for.
1383 X and Y are the frame-relative specified position,
1384 relative to the inside upper left corner of the frame F.
1385 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1386 KEYMAPS is 1 if this menu was specified with keymaps;
1387 in that case, we return a list containing the chosen item's value
1388 and perhaps also the pane's prefix.
1389 TITLE is the specified menu title.
1390 ERROR is a place to store an error message string in case of failure.
1391 (We return nil on failure, but the value doesn't actually matter.) */
1393 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1395 /* The item selected in the popup menu. */
1396 static Lisp_Object *volatile menu_item_selection;
1398 #ifdef USE_GTK
1400 /* Used when position a popup menu. See menu_position_func and
1401 create_and_show_popup_menu below. */
1402 struct next_popup_x_y
1404 FRAME_PTR f;
1405 int x;
1406 int y;
1409 /* The menu position function to use if we are not putting a popup
1410 menu where the pointer is.
1411 MENU is the menu to pop up.
1412 X and Y shall on exit contain x/y where the menu shall pop up.
1413 PUSH_IN is not documented in the GTK manual.
1414 USER_DATA is any data passed in when calling gtk_menu_popup.
1415 Here it points to a struct next_popup_x_y where the coordinates
1416 to store in *X and *Y are as well as the frame for the popup.
1418 Here only X and Y are used. */
1419 static void
1420 menu_position_func (menu, x, y, push_in, user_data)
1421 GtkMenu *menu;
1422 gint *x;
1423 gint *y;
1424 gboolean *push_in;
1425 gpointer user_data;
1427 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1428 GtkRequisition req;
1429 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1430 int disp_width = x_display_pixel_width (dpyinfo);
1431 int disp_height = x_display_pixel_height (dpyinfo);
1433 *x = data->x;
1434 *y = data->y;
1436 /* Check if there is room for the menu. If not, adjust x/y so that
1437 the menu is fully visible. */
1438 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1439 if (data->x + req.width > disp_width)
1440 *x -= data->x + req.width - disp_width;
1441 if (data->y + req.height > disp_height)
1442 *y -= data->y + req.height - disp_height;
1445 static void
1446 popup_selection_callback (widget, client_data)
1447 GtkWidget *widget;
1448 gpointer client_data;
1450 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1452 if (xg_crazy_callback_abort) return;
1453 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1456 static Lisp_Object
1457 pop_down_menu (arg)
1458 Lisp_Object arg;
1460 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1462 popup_activated_flag = 0;
1463 BLOCK_INPUT;
1464 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1465 UNBLOCK_INPUT;
1466 return Qnil;
1469 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1470 menu pops down.
1471 menu_item_selection will be set to the selection. */
1472 static void
1473 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1474 FRAME_PTR f;
1475 widget_value *first_wv;
1476 int x;
1477 int y;
1478 int for_click;
1479 EMACS_UINT timestamp;
1481 int i;
1482 GtkWidget *menu;
1483 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1484 struct next_popup_x_y popup_x_y;
1485 int specpdl_count = SPECPDL_INDEX ();
1487 if (! FRAME_X_P (f))
1488 abort ();
1490 xg_crazy_callback_abort = 1;
1491 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1492 G_CALLBACK (popup_selection_callback),
1493 G_CALLBACK (popup_deactivate_callback),
1494 G_CALLBACK (menu_highlight_callback));
1495 xg_crazy_callback_abort = 0;
1497 if (! for_click)
1499 /* Not invoked by a click. pop up at x/y. */
1500 pos_func = menu_position_func;
1502 /* Adjust coordinates to be root-window-relative. */
1503 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1504 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1506 popup_x_y.x = x;
1507 popup_x_y.y = y;
1508 popup_x_y.f = f;
1510 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1512 else
1514 for (i = 0; i < 5; i++)
1515 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1516 break;
1519 /* Display the menu. */
1520 gtk_widget_show_all (menu);
1522 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1523 timestamp > 0 ? timestamp : gtk_get_current_event_time());
1525 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1527 if (GTK_WIDGET_MAPPED (menu))
1529 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1530 two. show_help_echo uses this to detect popup menus. */
1531 popup_activated_flag = 1;
1532 /* Process events that apply to the menu. */
1533 popup_widget_loop (1, menu);
1536 unbind_to (specpdl_count, Qnil);
1538 /* Must reset this manually because the button release event is not passed
1539 to Emacs event loop. */
1540 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1543 #else /* not USE_GTK */
1545 /* We need a unique id for each widget handled by the Lucid Widget
1546 library.
1548 For the main windows, and popup menus, we use this counter,
1549 which we increment each time after use. This starts from 1<<16.
1551 For menu bars, we use numbers starting at 0, counted in
1552 next_menubar_widget_id. */
1553 LWLIB_ID widget_id_tick;
1555 static void
1556 popup_selection_callback (widget, id, client_data)
1557 Widget widget;
1558 LWLIB_ID id;
1559 XtPointer client_data;
1561 menu_item_selection = (Lisp_Object *) client_data;
1564 /* ARG is the LWLIB ID of the dialog box, represented
1565 as a Lisp object as (HIGHPART . LOWPART). */
1567 static Lisp_Object
1568 pop_down_menu (arg)
1569 Lisp_Object arg;
1571 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1572 | XINT (XCDR (arg)));
1574 BLOCK_INPUT;
1575 lw_destroy_all_widgets (id);
1576 UNBLOCK_INPUT;
1577 popup_activated_flag = 0;
1579 return Qnil;
1582 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1583 menu pops down.
1584 menu_item_selection will be set to the selection. */
1585 static void
1586 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1587 FRAME_PTR f;
1588 widget_value *first_wv;
1589 int x;
1590 int y;
1591 int for_click;
1592 EMACS_UINT timestamp;
1594 int i;
1595 Arg av[2];
1596 int ac = 0;
1597 XButtonPressedEvent dummy;
1598 LWLIB_ID menu_id;
1599 Widget menu;
1601 if (! FRAME_X_P (f))
1602 abort ();
1604 menu_id = widget_id_tick++;
1605 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1606 f->output_data.x->widget, 1, 0,
1607 popup_selection_callback,
1608 popup_deactivate_callback,
1609 menu_highlight_callback);
1611 dummy.type = ButtonPress;
1612 dummy.serial = 0;
1613 dummy.send_event = 0;
1614 dummy.display = FRAME_X_DISPLAY (f);
1615 dummy.time = CurrentTime;
1616 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1617 dummy.window = dummy.root;
1618 dummy.subwindow = dummy.root;
1619 dummy.x = x;
1620 dummy.y = y;
1622 /* Adjust coordinates to be root-window-relative. */
1623 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1624 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1626 dummy.x_root = x;
1627 dummy.y_root = y;
1629 dummy.state = 0;
1630 dummy.button = 0;
1631 for (i = 0; i < 5; i++)
1632 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1633 dummy.button = i;
1635 /* Don't allow any geometry request from the user. */
1636 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1637 XtSetValues (menu, av, ac);
1639 /* Display the menu. */
1640 lw_popup_menu (menu, (XEvent *) &dummy);
1641 popup_activated_flag = 1;
1642 x_activate_timeout_atimer ();
1645 int fact = 4 * sizeof (LWLIB_ID);
1646 int specpdl_count = SPECPDL_INDEX ();
1647 record_unwind_protect (pop_down_menu,
1648 Fcons (make_number (menu_id >> (fact)),
1649 make_number (menu_id & ~(-1 << (fact)))));
1651 /* Process events that apply to the menu. */
1652 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1654 unbind_to (specpdl_count, Qnil);
1658 #endif /* not USE_GTK */
1660 Lisp_Object
1661 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
1662 Lisp_Object title, char **error, EMACS_UINT timestamp)
1664 int i;
1665 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1666 widget_value **submenu_stack
1667 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1668 Lisp_Object *subprefix_stack
1669 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1670 int submenu_depth = 0;
1672 int first_pane;
1674 if (! FRAME_X_P (f))
1675 abort ();
1677 *error = NULL;
1679 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1681 *error = "Empty menu";
1682 return Qnil;
1685 /* Create a tree of widget_value objects
1686 representing the panes and their items. */
1687 wv = xmalloc_widget_value ();
1688 wv->name = "menu";
1689 wv->value = 0;
1690 wv->enabled = 1;
1691 wv->button_type = BUTTON_TYPE_NONE;
1692 wv->help =Qnil;
1693 first_wv = wv;
1694 first_pane = 1;
1696 /* Loop over all panes and items, filling in the tree. */
1697 i = 0;
1698 while (i < menu_items_used)
1700 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1702 submenu_stack[submenu_depth++] = save_wv;
1703 save_wv = prev_wv;
1704 prev_wv = 0;
1705 first_pane = 1;
1706 i++;
1708 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1710 prev_wv = save_wv;
1711 save_wv = submenu_stack[--submenu_depth];
1712 first_pane = 0;
1713 i++;
1715 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1716 && submenu_depth != 0)
1717 i += MENU_ITEMS_PANE_LENGTH;
1718 /* Ignore a nil in the item list.
1719 It's meaningful only for dialog boxes. */
1720 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1721 i += 1;
1722 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1724 /* Create a new pane. */
1725 Lisp_Object pane_name, prefix;
1726 char *pane_string;
1728 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1729 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1731 #ifndef HAVE_MULTILINGUAL_MENU
1732 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1734 pane_name = ENCODE_MENU_STRING (pane_name);
1735 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1737 #endif
1738 pane_string = (NILP (pane_name)
1739 ? "" : (char *) SDATA (pane_name));
1740 /* If there is just one top-level pane, put all its items directly
1741 under the top-level menu. */
1742 if (menu_items_n_panes == 1)
1743 pane_string = "";
1745 /* If the pane has a meaningful name,
1746 make the pane a top-level menu item
1747 with its items as a submenu beneath it. */
1748 if (!keymaps && strcmp (pane_string, ""))
1750 wv = xmalloc_widget_value ();
1751 if (save_wv)
1752 save_wv->next = wv;
1753 else
1754 first_wv->contents = wv;
1755 wv->name = pane_string;
1756 if (keymaps && !NILP (prefix))
1757 wv->name++;
1758 wv->value = 0;
1759 wv->enabled = 1;
1760 wv->button_type = BUTTON_TYPE_NONE;
1761 wv->help = Qnil;
1762 save_wv = wv;
1763 prev_wv = 0;
1765 else if (first_pane)
1767 save_wv = wv;
1768 prev_wv = 0;
1770 first_pane = 0;
1771 i += MENU_ITEMS_PANE_LENGTH;
1773 else
1775 /* Create a new item within current pane. */
1776 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1777 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1778 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1779 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1780 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1781 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1782 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1783 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1785 #ifndef HAVE_MULTILINGUAL_MENU
1786 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1788 item_name = ENCODE_MENU_STRING (item_name);
1789 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1792 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1794 descrip = ENCODE_MENU_STRING (descrip);
1795 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1797 #endif /* not HAVE_MULTILINGUAL_MENU */
1799 wv = xmalloc_widget_value ();
1800 if (prev_wv)
1801 prev_wv->next = wv;
1802 else
1803 save_wv->contents = wv;
1804 wv->name = (char *) SDATA (item_name);
1805 if (!NILP (descrip))
1806 wv->key = (char *) SDATA (descrip);
1807 wv->value = 0;
1808 /* If this item has a null value,
1809 make the call_data null so that it won't display a box
1810 when the mouse is on it. */
1811 wv->call_data
1812 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
1813 wv->enabled = !NILP (enable);
1815 if (NILP (type))
1816 wv->button_type = BUTTON_TYPE_NONE;
1817 else if (EQ (type, QCtoggle))
1818 wv->button_type = BUTTON_TYPE_TOGGLE;
1819 else if (EQ (type, QCradio))
1820 wv->button_type = BUTTON_TYPE_RADIO;
1821 else
1822 abort ();
1824 wv->selected = !NILP (selected);
1826 if (! STRINGP (help))
1827 help = Qnil;
1829 wv->help = help;
1831 prev_wv = wv;
1833 i += MENU_ITEMS_ITEM_LENGTH;
1837 /* Deal with the title, if it is non-nil. */
1838 if (!NILP (title))
1840 widget_value *wv_title = xmalloc_widget_value ();
1841 widget_value *wv_sep1 = xmalloc_widget_value ();
1842 widget_value *wv_sep2 = xmalloc_widget_value ();
1844 wv_sep2->name = "--";
1845 wv_sep2->next = first_wv->contents;
1846 wv_sep2->help = Qnil;
1848 wv_sep1->name = "--";
1849 wv_sep1->next = wv_sep2;
1850 wv_sep1->help = Qnil;
1852 #ifndef HAVE_MULTILINGUAL_MENU
1853 if (STRING_MULTIBYTE (title))
1854 title = ENCODE_MENU_STRING (title);
1855 #endif
1857 wv_title->name = (char *) SDATA (title);
1858 wv_title->enabled = TRUE;
1859 wv_title->button_type = BUTTON_TYPE_NONE;
1860 wv_title->help = Qnil;
1861 wv_title->next = wv_sep1;
1862 first_wv->contents = wv_title;
1865 /* No selection has been chosen yet. */
1866 menu_item_selection = 0;
1868 /* Actually create and show the menu until popped down. */
1869 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
1871 /* Free the widget_value objects we used to specify the contents. */
1872 free_menubar_widget_value_tree (first_wv);
1874 /* Find the selected item, and its pane, to return
1875 the proper value. */
1876 if (menu_item_selection != 0)
1878 Lisp_Object prefix, entry;
1880 prefix = entry = Qnil;
1881 i = 0;
1882 while (i < menu_items_used)
1884 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1886 subprefix_stack[submenu_depth++] = prefix;
1887 prefix = entry;
1888 i++;
1890 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1892 prefix = subprefix_stack[--submenu_depth];
1893 i++;
1895 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1897 prefix
1898 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1899 i += MENU_ITEMS_PANE_LENGTH;
1901 /* Ignore a nil in the item list.
1902 It's meaningful only for dialog boxes. */
1903 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1904 i += 1;
1905 else
1907 entry
1908 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1909 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1911 if (keymaps != 0)
1913 int j;
1915 entry = Fcons (entry, Qnil);
1916 if (!NILP (prefix))
1917 entry = Fcons (prefix, entry);
1918 for (j = submenu_depth - 1; j >= 0; j--)
1919 if (!NILP (subprefix_stack[j]))
1920 entry = Fcons (subprefix_stack[j], entry);
1922 return entry;
1924 i += MENU_ITEMS_ITEM_LENGTH;
1928 else if (!for_click)
1929 /* Make "Cancel" equivalent to C-g. */
1930 Fsignal (Qquit, Qnil);
1932 return Qnil;
1935 #ifdef USE_GTK
1936 static void
1937 dialog_selection_callback (widget, client_data)
1938 GtkWidget *widget;
1939 gpointer client_data;
1941 /* The EMACS_INT cast avoids a warning. There's no problem
1942 as long as pointers have enough bits to hold small integers. */
1943 if ((int) (EMACS_INT) client_data != -1)
1944 menu_item_selection = (Lisp_Object *) client_data;
1946 popup_activated_flag = 0;
1949 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1950 dialog pops down.
1951 menu_item_selection will be set to the selection. */
1952 static void
1953 create_and_show_dialog (f, first_wv)
1954 FRAME_PTR f;
1955 widget_value *first_wv;
1957 GtkWidget *menu;
1959 if (! FRAME_X_P (f))
1960 abort ();
1962 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1963 G_CALLBACK (dialog_selection_callback),
1964 G_CALLBACK (popup_deactivate_callback),
1967 if (menu)
1969 int specpdl_count = SPECPDL_INDEX ();
1970 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1972 /* Display the menu. */
1973 gtk_widget_show_all (menu);
1975 /* Process events that apply to the menu. */
1976 popup_widget_loop (1, menu);
1978 unbind_to (specpdl_count, Qnil);
1982 #else /* not USE_GTK */
1983 static void
1984 dialog_selection_callback (widget, id, client_data)
1985 Widget widget;
1986 LWLIB_ID id;
1987 XtPointer client_data;
1989 /* The EMACS_INT cast avoids a warning. There's no problem
1990 as long as pointers have enough bits to hold small integers. */
1991 if ((int) (EMACS_INT) client_data != -1)
1992 menu_item_selection = (Lisp_Object *) client_data;
1994 BLOCK_INPUT;
1995 lw_destroy_all_widgets (id);
1996 UNBLOCK_INPUT;
1997 popup_activated_flag = 0;
2001 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2002 dialog pops down.
2003 menu_item_selection will be set to the selection. */
2004 static void
2005 create_and_show_dialog (f, first_wv)
2006 FRAME_PTR f;
2007 widget_value *first_wv;
2009 LWLIB_ID dialog_id;
2011 if (!FRAME_X_P (f))
2012 abort();
2014 dialog_id = widget_id_tick++;
2015 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2016 f->output_data.x->widget, 1, 0,
2017 dialog_selection_callback, 0, 0);
2018 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2020 /* Display the dialog box. */
2021 lw_pop_up_all_widgets (dialog_id);
2022 popup_activated_flag = 1;
2023 x_activate_timeout_atimer ();
2025 /* Process events that apply to the dialog box.
2026 Also handle timers. */
2028 int count = SPECPDL_INDEX ();
2029 int fact = 4 * sizeof (LWLIB_ID);
2031 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2032 record_unwind_protect (pop_down_menu,
2033 Fcons (make_number (dialog_id >> (fact)),
2034 make_number (dialog_id & ~(-1 << (fact)))));
2036 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2037 dialog_id, 1);
2039 unbind_to (count, Qnil);
2043 #endif /* not USE_GTK */
2045 static char * button_names [] = {
2046 "button1", "button2", "button3", "button4", "button5",
2047 "button6", "button7", "button8", "button9", "button10" };
2049 static Lisp_Object
2050 xdialog_show (f, keymaps, title, header, error_name)
2051 FRAME_PTR f;
2052 int keymaps;
2053 Lisp_Object title, header;
2054 char **error_name;
2056 int i, nb_buttons=0;
2057 char dialog_name[6];
2059 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2061 /* Number of elements seen so far, before boundary. */
2062 int left_count = 0;
2063 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2064 int boundary_seen = 0;
2066 if (! FRAME_X_P (f))
2067 abort ();
2069 *error_name = NULL;
2071 if (menu_items_n_panes > 1)
2073 *error_name = "Multiple panes in dialog box";
2074 return Qnil;
2077 /* Create a tree of widget_value objects
2078 representing the text label and buttons. */
2080 Lisp_Object pane_name, prefix;
2081 char *pane_string;
2082 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2083 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2084 pane_string = (NILP (pane_name)
2085 ? "" : (char *) SDATA (pane_name));
2086 prev_wv = xmalloc_widget_value ();
2087 prev_wv->value = pane_string;
2088 if (keymaps && !NILP (prefix))
2089 prev_wv->name++;
2090 prev_wv->enabled = 1;
2091 prev_wv->name = "message";
2092 prev_wv->help = Qnil;
2093 first_wv = prev_wv;
2095 /* Loop over all panes and items, filling in the tree. */
2096 i = MENU_ITEMS_PANE_LENGTH;
2097 while (i < menu_items_used)
2100 /* Create a new item within current pane. */
2101 Lisp_Object item_name, enable, descrip;
2102 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2103 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2104 descrip
2105 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2107 if (NILP (item_name))
2109 free_menubar_widget_value_tree (first_wv);
2110 *error_name = "Submenu in dialog items";
2111 return Qnil;
2113 if (EQ (item_name, Qquote))
2115 /* This is the boundary between left-side elts
2116 and right-side elts. Stop incrementing right_count. */
2117 boundary_seen = 1;
2118 i++;
2119 continue;
2121 if (nb_buttons >= 9)
2123 free_menubar_widget_value_tree (first_wv);
2124 *error_name = "Too many dialog items";
2125 return Qnil;
2128 wv = xmalloc_widget_value ();
2129 prev_wv->next = wv;
2130 wv->name = (char *) button_names[nb_buttons];
2131 if (!NILP (descrip))
2132 wv->key = (char *) SDATA (descrip);
2133 wv->value = (char *) SDATA (item_name);
2134 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2135 wv->enabled = !NILP (enable);
2136 wv->help = Qnil;
2137 prev_wv = wv;
2139 if (! boundary_seen)
2140 left_count++;
2142 nb_buttons++;
2143 i += MENU_ITEMS_ITEM_LENGTH;
2146 /* If the boundary was not specified,
2147 by default put half on the left and half on the right. */
2148 if (! boundary_seen)
2149 left_count = nb_buttons - nb_buttons / 2;
2151 wv = xmalloc_widget_value ();
2152 wv->name = dialog_name;
2153 wv->help = Qnil;
2155 /* Frame title: 'Q' = Question, 'I' = Information.
2156 Can also have 'E' = Error if, one day, we want
2157 a popup for errors. */
2158 if (NILP(header))
2159 dialog_name[0] = 'Q';
2160 else
2161 dialog_name[0] = 'I';
2163 /* Dialog boxes use a really stupid name encoding
2164 which specifies how many buttons to use
2165 and how many buttons are on the right. */
2166 dialog_name[1] = '0' + nb_buttons;
2167 dialog_name[2] = 'B';
2168 dialog_name[3] = 'R';
2169 /* Number of buttons to put on the right. */
2170 dialog_name[4] = '0' + nb_buttons - left_count;
2171 dialog_name[5] = 0;
2172 wv->contents = first_wv;
2173 first_wv = wv;
2176 /* No selection has been chosen yet. */
2177 menu_item_selection = 0;
2179 /* Actually create and show the dialog. */
2180 create_and_show_dialog (f, first_wv);
2182 /* Free the widget_value objects we used to specify the contents. */
2183 free_menubar_widget_value_tree (first_wv);
2185 /* Find the selected item, and its pane, to return
2186 the proper value. */
2187 if (menu_item_selection != 0)
2189 Lisp_Object prefix;
2191 prefix = Qnil;
2192 i = 0;
2193 while (i < menu_items_used)
2195 Lisp_Object entry;
2197 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2199 prefix
2200 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2201 i += MENU_ITEMS_PANE_LENGTH;
2203 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2205 /* This is the boundary between left-side elts and
2206 right-side elts. */
2207 ++i;
2209 else
2211 entry
2212 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2213 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2215 if (keymaps != 0)
2217 entry = Fcons (entry, Qnil);
2218 if (!NILP (prefix))
2219 entry = Fcons (prefix, entry);
2221 return entry;
2223 i += MENU_ITEMS_ITEM_LENGTH;
2227 else
2228 /* Make "Cancel" equivalent to C-g. */
2229 Fsignal (Qquit, Qnil);
2231 return Qnil;
2234 #else /* not USE_X_TOOLKIT && not USE_GTK */
2236 /* The frame of the last activated non-toolkit menu bar.
2237 Used to generate menu help events. */
2239 static struct frame *menu_help_frame;
2242 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2244 PANE is the pane number, and ITEM is the menu item number in
2245 the menu (currently not used).
2247 This cannot be done with generating a HELP_EVENT because
2248 XMenuActivate contains a loop that doesn't let Emacs process
2249 keyboard events. */
2251 static void
2252 menu_help_callback (help_string, pane, item)
2253 char *help_string;
2254 int pane, item;
2256 extern Lisp_Object Qmenu_item;
2257 Lisp_Object *first_item;
2258 Lisp_Object pane_name;
2259 Lisp_Object menu_object;
2261 first_item = XVECTOR (menu_items)->contents;
2262 if (EQ (first_item[0], Qt))
2263 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2264 else if (EQ (first_item[0], Qquote))
2265 /* This shouldn't happen, see xmenu_show. */
2266 pane_name = empty_unibyte_string;
2267 else
2268 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2270 /* (menu-item MENU-NAME PANE-NUMBER) */
2271 menu_object = Fcons (Qmenu_item,
2272 Fcons (pane_name,
2273 Fcons (make_number (pane), Qnil)));
2274 show_help_echo (help_string ? build_string (help_string) : Qnil,
2275 Qnil, menu_object, make_number (item), 1);
2278 static Lisp_Object
2279 pop_down_menu (arg)
2280 Lisp_Object arg;
2282 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2283 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2285 FRAME_PTR f = p1->pointer;
2286 XMenu *menu = p2->pointer;
2288 BLOCK_INPUT;
2289 #ifndef MSDOS
2290 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2291 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2292 #endif
2293 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2295 #ifdef HAVE_X_WINDOWS
2296 /* Assume the mouse has moved out of the X window.
2297 If it has actually moved in, we will get an EnterNotify. */
2298 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2300 /* State that no mouse buttons are now held.
2301 (The oldXMenu code doesn't track this info for us.)
2302 That is not necessarily true, but the fiction leads to reasonable
2303 results, and it is a pain to ask which are actually held now. */
2304 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2306 #endif /* HAVE_X_WINDOWS */
2308 UNBLOCK_INPUT;
2310 return Qnil;
2314 Lisp_Object
2315 xmenu_show (f, x, y, for_click, keymaps, title, error, timestamp)
2316 FRAME_PTR f;
2317 int x, y;
2318 int for_click;
2319 int keymaps;
2320 Lisp_Object title;
2321 char **error;
2322 EMACS_UINT timestamp;
2324 Window root;
2325 XMenu *menu;
2326 int pane, selidx, lpane, status;
2327 Lisp_Object entry, pane_prefix;
2328 char *datap;
2329 int ulx, uly, width, height;
2330 int dispwidth, dispheight;
2331 int i, j, lines, maxlines;
2332 int maxwidth;
2333 int dummy_int;
2334 unsigned int dummy_uint;
2335 int specpdl_count = SPECPDL_INDEX ();
2337 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2338 abort ();
2340 *error = 0;
2341 if (menu_items_n_panes == 0)
2342 return Qnil;
2344 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2346 *error = "Empty menu";
2347 return Qnil;
2350 /* Figure out which root window F is on. */
2351 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2352 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2353 &dummy_uint, &dummy_uint);
2355 /* Make the menu on that window. */
2356 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2357 if (menu == NULL)
2359 *error = "Can't create menu";
2360 return Qnil;
2363 /* Don't GC while we prepare and show the menu,
2364 because we give the oldxmenu library pointers to the
2365 contents of strings. */
2366 inhibit_garbage_collection ();
2368 #ifdef HAVE_X_WINDOWS
2369 /* Adjust coordinates to relative to the outer (window manager) window. */
2370 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2371 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2372 #endif /* HAVE_X_WINDOWS */
2374 /* Adjust coordinates to be root-window-relative. */
2375 x += f->left_pos;
2376 y += f->top_pos;
2378 /* Create all the necessary panes and their items. */
2379 maxlines = lines = i = 0;
2380 while (i < menu_items_used)
2382 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2384 /* Create a new pane. */
2385 Lisp_Object pane_name, prefix;
2386 char *pane_string;
2388 maxlines = max (maxlines, lines);
2389 lines = 0;
2390 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2391 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2392 pane_string = (NILP (pane_name)
2393 ? "" : (char *) SDATA (pane_name));
2394 if (keymaps && !NILP (prefix))
2395 pane_string++;
2397 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2398 if (lpane == XM_FAILURE)
2400 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2401 *error = "Can't create pane";
2402 return Qnil;
2404 i += MENU_ITEMS_PANE_LENGTH;
2406 /* Find the width of the widest item in this pane. */
2407 maxwidth = 0;
2408 j = i;
2409 while (j < menu_items_used)
2411 Lisp_Object item;
2412 item = XVECTOR (menu_items)->contents[j];
2413 if (EQ (item, Qt))
2414 break;
2415 if (NILP (item))
2417 j++;
2418 continue;
2420 width = SBYTES (item);
2421 if (width > maxwidth)
2422 maxwidth = width;
2424 j += MENU_ITEMS_ITEM_LENGTH;
2427 /* Ignore a nil in the item list.
2428 It's meaningful only for dialog boxes. */
2429 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2430 i += 1;
2431 else
2433 /* Create a new item within current pane. */
2434 Lisp_Object item_name, enable, descrip, help;
2435 unsigned char *item_data;
2436 char *help_string;
2438 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2439 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2440 descrip
2441 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2442 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2443 help_string = STRINGP (help) ? SDATA (help) : NULL;
2445 if (!NILP (descrip))
2447 int gap = maxwidth - SBYTES (item_name);
2448 /* if alloca is fast, use that to make the space,
2449 to reduce gc needs. */
2450 item_data
2451 = (unsigned char *) alloca (maxwidth
2452 + SBYTES (descrip) + 1);
2453 bcopy (SDATA (item_name), item_data,
2454 SBYTES (item_name));
2455 for (j = SCHARS (item_name); j < maxwidth; j++)
2456 item_data[j] = ' ';
2457 bcopy (SDATA (descrip), item_data + j,
2458 SBYTES (descrip));
2459 item_data[j + SBYTES (descrip)] = 0;
2461 else
2462 item_data = SDATA (item_name);
2464 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2465 menu, lpane, 0, item_data,
2466 !NILP (enable), help_string)
2467 == XM_FAILURE)
2469 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2470 *error = "Can't add selection to menu";
2471 return Qnil;
2473 i += MENU_ITEMS_ITEM_LENGTH;
2474 lines++;
2478 maxlines = max (maxlines, lines);
2480 /* All set and ready to fly. */
2481 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2482 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2483 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2484 x = min (x, dispwidth);
2485 y = min (y, dispheight);
2486 x = max (x, 1);
2487 y = max (y, 1);
2488 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2489 &ulx, &uly, &width, &height);
2490 if (ulx+width > dispwidth)
2492 x -= (ulx + width) - dispwidth;
2493 ulx = dispwidth - width;
2495 if (uly+height > dispheight)
2497 y -= (uly + height) - dispheight;
2498 uly = dispheight - height;
2500 #ifndef HAVE_X_WINDOWS
2501 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2503 /* Move the menu away of the echo area, to avoid overwriting the
2504 menu with help echo messages or vice versa. */
2505 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2507 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2508 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2510 else
2512 y--;
2513 uly--;
2516 #endif
2517 if (ulx < 0) x -= ulx;
2518 if (uly < 0) y -= uly;
2520 if (! for_click)
2522 /* If position was not given by a mouse click, adjust so upper left
2523 corner of the menu as a whole ends up at given coordinates. This
2524 is what x-popup-menu says in its documentation. */
2525 x += width/2;
2526 y += 1.5*height/(maxlines+2);
2529 XMenuSetAEQ (menu, TRUE);
2530 XMenuSetFreeze (menu, TRUE);
2531 pane = selidx = 0;
2533 #ifndef MSDOS
2534 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2535 #endif
2537 record_unwind_protect (pop_down_menu,
2538 Fcons (make_save_value (f, 0),
2539 make_save_value (menu, 0)));
2541 /* Help display under X won't work because XMenuActivate contains
2542 a loop that doesn't give Emacs a chance to process it. */
2543 menu_help_frame = f;
2544 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2545 x, y, ButtonReleaseMask, &datap,
2546 menu_help_callback);
2548 switch (status)
2550 case XM_SUCCESS:
2551 #ifdef XDEBUG
2552 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2553 #endif
2555 /* Find the item number SELIDX in pane number PANE. */
2556 i = 0;
2557 while (i < menu_items_used)
2559 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2561 if (pane == 0)
2562 pane_prefix
2563 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2564 pane--;
2565 i += MENU_ITEMS_PANE_LENGTH;
2567 else
2569 if (pane == -1)
2571 if (selidx == 0)
2573 entry
2574 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2575 if (keymaps != 0)
2577 entry = Fcons (entry, Qnil);
2578 if (!NILP (pane_prefix))
2579 entry = Fcons (pane_prefix, entry);
2581 break;
2583 selidx--;
2585 i += MENU_ITEMS_ITEM_LENGTH;
2588 break;
2590 case XM_FAILURE:
2591 *error = "Can't activate menu";
2592 case XM_IA_SELECT:
2593 entry = Qnil;
2594 break;
2595 case XM_NO_SELECT:
2596 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2597 the menu was invoked with a mouse event as POSITION). */
2598 if (! for_click)
2599 Fsignal (Qquit, Qnil);
2600 entry = Qnil;
2601 break;
2604 unbind_to (specpdl_count, Qnil);
2606 return entry;
2609 #endif /* not USE_X_TOOLKIT */
2611 #endif /* HAVE_MENUS */
2613 /* Detect if a dialog or menu has been posted. */
2616 popup_activated ()
2618 return popup_activated_flag;
2621 /* The following is used by delayed window autoselection. */
2623 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2624 doc: /* Return t if a menu or popup dialog is active. */)
2627 #ifdef HAVE_MENUS
2628 return (popup_activated ()) ? Qt : Qnil;
2629 #else
2630 return Qnil;
2631 #endif /* HAVE_MENUS */
2634 void
2635 syms_of_xmenu ()
2637 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
2638 staticpro (&Qdebug_on_next_call);
2640 #ifdef USE_X_TOOLKIT
2641 widget_id_tick = (1<<16);
2642 next_menubar_widget_id = 1;
2643 #endif
2645 defsubr (&Smenu_or_popup_active_p);
2647 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2648 defsubr (&Sx_menu_bar_open_internal);
2649 Ffset (intern_c_string ("accelerate-menu"),
2650 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2651 #endif
2653 #ifdef HAVE_MENUS
2654 defsubr (&Sx_popup_dialog);
2655 #endif
2658 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2659 (do not change this comment) */