* s/netbsd.h (AMPERSAND_FULL_NAME): Remove (defined in AH_BOTTOM).
[emacs.git] / src / xmenu.c
blob796dd3093e8ba68e029c396afa74f4c498bf80bb
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 #include "xsettings.h"
85 #include "../lwlib/xlwmenu.h"
86 #ifdef HAVE_XAW3D
87 #include <X11/Xaw3d/Paned.h>
88 #else /* !HAVE_XAW3D */
89 #include <X11/Xaw/Paned.h>
90 #endif /* HAVE_XAW3D */
91 #endif /* USE_LUCID */
92 #include "../lwlib/lwlib.h"
93 #else /* not USE_X_TOOLKIT */
94 #ifndef USE_GTK
95 #include "../oldXMenu/XMenu.h"
96 #endif
97 #endif /* not USE_X_TOOLKIT */
98 #endif /* HAVE_X_WINDOWS */
100 #ifdef USE_GTK
101 #include "gtkutil.h"
102 #endif
104 #include "menu.h"
106 #ifndef TRUE
107 #define TRUE 1
108 #define FALSE 0
109 #endif /* no TRUE */
111 Lisp_Object Qdebug_on_next_call;
113 extern Lisp_Object Qmenu_bar;
115 extern Lisp_Object QCtoggle, QCradio;
117 extern Lisp_Object Voverriding_local_map;
118 extern Lisp_Object Voverriding_local_map_menu_flag;
120 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
122 extern Lisp_Object Qmenu_bar_update_hook;
124 #ifdef USE_X_TOOLKIT
125 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
126 extern XtAppContext Xt_app_con;
128 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
129 char **));
130 static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
131 LWLIB_ID, int));
132 #endif /* USE_X_TOOLKIT */
134 #ifdef USE_GTK
135 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
136 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
137 char **));
138 #endif
140 static int update_frame_menubar P_ ((struct frame *));
142 /* Flag which when set indicates a dialog or menu has been posted by
143 Xt on behalf of one of the widget sets. */
144 static int popup_activated_flag;
146 static int next_menubar_widget_id;
148 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
149 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
150 extern widget_value *xmalloc_widget_value P_ ((void));
151 extern widget_value *digest_single_submenu P_ ((int, int, int));
152 #endif
154 /* This is set nonzero after the user activates the menu bar, and set
155 to zero again after the menu bars are redisplayed by prepare_menu_bar.
156 While it is nonzero, all calls to set_frame_menubar go deep.
158 I don't understand why this is needed, but it does seem to be
159 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
161 int pending_menu_activation;
163 #ifdef USE_X_TOOLKIT
165 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
167 static struct frame *
168 menubar_id_to_frame (id)
169 LWLIB_ID id;
171 Lisp_Object tail, frame;
172 FRAME_PTR f;
174 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
176 frame = XCAR (tail);
177 if (!FRAMEP (frame))
178 continue;
179 f = XFRAME (frame);
180 if (!FRAME_WINDOW_P (f))
181 continue;
182 if (f->output_data.x->id == id)
183 return f;
185 return 0;
188 #endif
190 #ifdef HAVE_X_WINDOWS
191 /* Return the mouse position in *X and *Y. The coordinates are window
192 relative for the edit window in frame F.
193 This is for Fx_popup_menu. The mouse_position_hook can not
194 be used for X, as it returns window relative coordinates
195 for the window where the mouse is in. This could be the menu bar,
196 the scroll bar or the edit window. Fx_popup_menu needs to be
197 sure it is the edit window. */
198 void
199 mouse_position_for_popup (f, x, y)
200 FRAME_PTR f;
201 int *x;
202 int *y;
204 Window root, dummy_window;
205 int dummy;
207 if (! FRAME_X_P (f))
208 abort ();
210 BLOCK_INPUT;
212 XQueryPointer (FRAME_X_DISPLAY (f),
213 DefaultRootWindow (FRAME_X_DISPLAY (f)),
215 /* The root window which contains the pointer. */
216 &root,
218 /* Window pointer is on, not used */
219 &dummy_window,
221 /* The position on that root window. */
222 x, y,
224 /* x/y in dummy_window coordinates, not used. */
225 &dummy, &dummy,
227 /* Modifier keys and pointer buttons, about which
228 we don't care. */
229 (unsigned int *) &dummy);
231 UNBLOCK_INPUT;
233 /* xmenu_show expects window coordinates, not root window
234 coordinates. Translate. */
235 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
236 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
239 #endif /* HAVE_X_WINDOWS */
241 #ifdef HAVE_MENUS
243 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
244 doc: /* Pop up a dialog box and return user's selection.
245 POSITION specifies which frame to use.
246 This is normally a mouse button event or a window or frame.
247 If POSITION is t, it means to use the frame the mouse is on.
248 The dialog box appears in the middle of the specified frame.
250 CONTENTS specifies the alternatives to display in the dialog box.
251 It is a list of the form (DIALOG ITEM1 ITEM2...).
252 Each ITEM is a cons cell (STRING . VALUE).
253 The return value is VALUE from the chosen item.
255 An ITEM may also be just a string--that makes a nonselectable item.
256 An ITEM may also be nil--that means to put all preceding items
257 on the left of the dialog box and all following items on the right.
258 \(By default, approximately half appear on each side.)
260 If HEADER is non-nil, the frame title for the box is "Information",
261 otherwise it is "Question".
263 If the user gets rid of the dialog box without making a valid choice,
264 for instance using the window manager, then this produces a quit and
265 `x-popup-dialog' does not return. */)
266 (position, contents, header)
267 Lisp_Object position, contents, header;
269 FRAME_PTR f = NULL;
270 Lisp_Object window;
272 check_x ();
274 /* Decode the first argument: find the window or frame to use. */
275 if (EQ (position, Qt)
276 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
277 || EQ (XCAR (position), Qtool_bar))))
279 #if 0 /* Using the frame the mouse is on may not be right. */
280 /* Use the mouse's current position. */
281 FRAME_PTR new_f = SELECTED_FRAME ();
282 Lisp_Object bar_window;
283 enum scroll_bar_part part;
284 unsigned long time;
285 Lisp_Object x, y;
287 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
289 if (new_f != 0)
290 XSETFRAME (window, new_f);
291 else
292 window = selected_window;
293 #endif
294 window = selected_window;
296 else if (CONSP (position))
298 Lisp_Object tem;
299 tem = Fcar (position);
300 if (CONSP (tem))
301 window = Fcar (Fcdr (position));
302 else
304 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
305 window = Fcar (tem); /* POSN_WINDOW (tem) */
308 else if (WINDOWP (position) || FRAMEP (position))
309 window = position;
310 else
311 window = Qnil;
313 /* Decode where to put the menu. */
315 if (FRAMEP (window))
316 f = XFRAME (window);
317 else if (WINDOWP (window))
319 CHECK_LIVE_WINDOW (window);
320 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
322 else
323 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
324 but I don't want to make one now. */
325 CHECK_WINDOW (window);
327 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
328 error ("Can not put X dialog on this terminal");
330 /* Force a redisplay before showing the dialog. If a frame is created
331 just before showing the dialog, its contents may not have been fully
332 drawn, as this depends on timing of events from the X server. Redisplay
333 is not done when a dialog is shown. If redisplay could be done in the
334 X event loop (i.e. the X event loop does not run in a signal handler)
335 this would not be needed.
337 Do this before creating the widget value that points to Lisp
338 string contents, because Fredisplay may GC and relocate them. */
339 Fredisplay (Qt);
341 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
342 /* Display a menu with these alternatives
343 in the middle of frame F. */
345 Lisp_Object x, y, frame, newpos;
346 XSETFRAME (frame, f);
347 XSETINT (x, x_pixel_width (f) / 2);
348 XSETINT (y, x_pixel_height (f) / 2);
349 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
351 return Fx_popup_menu (newpos,
352 Fcons (Fcar (contents), Fcons (contents, Qnil)));
354 #else
356 Lisp_Object title;
357 char *error_name;
358 Lisp_Object selection;
359 int specpdl_count = SPECPDL_INDEX ();
361 /* Decode the dialog items from what was specified. */
362 title = Fcar (contents);
363 CHECK_STRING (title);
364 record_unwind_protect (unuse_menu_items, Qnil);
366 if (NILP (Fcar (Fcdr (contents))))
367 /* No buttons specified, add an "Ok" button so users can pop down
368 the dialog. Also, the lesstif/motif version crashes if there are
369 no buttons. */
370 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
372 list_of_panes (Fcons (contents, Qnil));
374 /* Display them in a dialog box. */
375 BLOCK_INPUT;
376 selection = xdialog_show (f, 0, title, header, &error_name);
377 UNBLOCK_INPUT;
379 unbind_to (specpdl_count, Qnil);
380 discard_menu_items ();
382 if (error_name) error (error_name);
383 return selection;
385 #endif
389 #ifndef MSDOS
391 /* Set menu_items_inuse so no other popup menu or dialog is created. */
393 void
394 x_menu_set_in_use (in_use)
395 int in_use;
397 menu_items_inuse = in_use ? Qt : Qnil;
398 popup_activated_flag = in_use;
399 #ifdef USE_X_TOOLKIT
400 if (popup_activated_flag)
401 x_activate_timeout_atimer ();
402 #endif
405 /* Wait for an X event to arrive or for a timer to expire. */
407 void
408 x_menu_wait_for_event (void *data)
410 /* Another way to do this is to register a timer callback, that can be
411 done in GTK and Xt. But we have to do it like this when using only X
412 anyway, and with callbacks we would have three variants for timer handling
413 instead of the small ifdefs below. */
415 while (
416 #ifdef USE_X_TOOLKIT
417 ! XtAppPending (Xt_app_con)
418 #elif defined USE_GTK
419 ! gtk_events_pending ()
420 #else
421 ! XPending ((Display*) data)
422 #endif
425 EMACS_TIME next_time = timer_check (1), *ntp;
426 long secs = EMACS_SECS (next_time);
427 long usecs = EMACS_USECS (next_time);
428 SELECT_TYPE read_fds;
429 struct x_display_info *dpyinfo;
430 int n = 0;
432 FD_ZERO (&read_fds);
433 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
435 int fd = ConnectionNumber (dpyinfo->display);
436 FD_SET (fd, &read_fds);
437 if (fd > n) n = fd;
438 XFlush (dpyinfo->display);
441 if (secs < 0 && usecs < 0)
442 ntp = 0;
443 else
444 ntp = &next_time;
446 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
449 #endif /* ! MSDOS */
452 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
454 #ifdef USE_X_TOOLKIT
456 /* Loop in Xt until the menu pulldown or dialog popup has been
457 popped down (deactivated). This is used for x-popup-menu
458 and x-popup-dialog; it is not used for the menu bar.
460 NOTE: All calls to popup_get_selection should be protected
461 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
463 static void
464 popup_get_selection (initial_event, dpyinfo, id, do_timers)
465 XEvent *initial_event;
466 struct x_display_info *dpyinfo;
467 LWLIB_ID id;
468 int do_timers;
470 XEvent event;
472 while (popup_activated_flag)
474 if (initial_event)
476 event = *initial_event;
477 initial_event = 0;
479 else
481 if (do_timers) x_menu_wait_for_event (0);
482 XtAppNextEvent (Xt_app_con, &event);
485 /* Make sure we don't consider buttons grabbed after menu goes.
486 And make sure to deactivate for any ButtonRelease,
487 even if XtDispatchEvent doesn't do that. */
488 if (event.type == ButtonRelease
489 && dpyinfo->display == event.xbutton.display)
491 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
492 #ifdef USE_MOTIF /* Pretending that the event came from a
493 Btn1Down seems the only way to convince Motif to
494 activate its callbacks; setting the XmNmenuPost
495 isn't working. --marcus@sysc.pdx.edu. */
496 event.xbutton.button = 1;
497 /* Motif only pops down menus when no Ctrl, Alt or Mod
498 key is pressed and the button is released. So reset key state
499 so Motif thinks this is the case. */
500 event.xbutton.state = 0;
501 #endif
503 /* Pop down on C-g and Escape. */
504 else if (event.type == KeyPress
505 && dpyinfo->display == event.xbutton.display)
507 KeySym keysym = XLookupKeysym (&event.xkey, 0);
509 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
510 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
511 popup_activated_flag = 0;
514 x_dispatch_event (&event, event.xany.display);
518 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
519 doc: /* Start key navigation of the menu bar in FRAME.
520 This initially opens the first menu bar item and you can then navigate with the
521 arrow keys, select a menu entry with the return key or cancel with the
522 escape key. If FRAME has no menu bar this function does nothing.
524 If FRAME is nil or not given, use the selected frame. */)
525 (frame)
526 Lisp_Object frame;
528 XEvent ev;
529 FRAME_PTR f = check_x_frame (frame);
530 Widget menubar;
531 BLOCK_INPUT;
533 if (FRAME_EXTERNAL_MENU_BAR (f))
534 set_frame_menubar (f, 0, 1);
536 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
537 if (menubar)
539 Window child;
540 int error_p = 0;
542 x_catch_errors (FRAME_X_DISPLAY (f));
543 memset (&ev, 0, sizeof ev);
544 ev.xbutton.display = FRAME_X_DISPLAY (f);
545 ev.xbutton.window = XtWindow (menubar);
546 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
547 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
548 ev.xbutton.button = Button1;
549 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
550 ev.xbutton.same_screen = True;
552 #ifdef USE_MOTIF
554 Arg al[2];
555 WidgetList list;
556 Cardinal nr;
557 XtSetArg (al[0], XtNchildren, &list);
558 XtSetArg (al[1], XtNnumChildren, &nr);
559 XtGetValues (menubar, al, 2);
560 ev.xbutton.window = XtWindow (list[0]);
562 #endif
564 XTranslateCoordinates (FRAME_X_DISPLAY (f),
565 /* From-window, to-window. */
566 ev.xbutton.window, ev.xbutton.root,
568 /* From-position, to-position. */
569 ev.xbutton.x, ev.xbutton.y,
570 &ev.xbutton.x_root, &ev.xbutton.y_root,
572 /* Child of win. */
573 &child);
574 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
575 x_uncatch_errors ();
577 if (! error_p)
579 ev.type = ButtonPress;
580 ev.xbutton.state = 0;
582 XtDispatchEvent (&ev);
583 ev.xbutton.type = ButtonRelease;
584 ev.xbutton.state = Button1Mask;
585 XtDispatchEvent (&ev);
589 UNBLOCK_INPUT;
591 return Qnil;
593 #endif /* USE_X_TOOLKIT */
596 #ifdef USE_GTK
597 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
598 doc: /* Start key navigation of the menu bar in FRAME.
599 This initially opens the first menu bar item and you can then navigate with the
600 arrow keys, select a menu entry with the return key or cancel with the
601 escape key. If FRAME has no menu bar this function does nothing.
603 If FRAME is nil or not given, use the selected frame. */)
604 (frame)
605 Lisp_Object frame;
607 GtkWidget *menubar;
608 FRAME_PTR f;
610 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
611 BLOCK_INPUT. */
613 BLOCK_INPUT;
614 f = check_x_frame (frame);
616 if (FRAME_EXTERNAL_MENU_BAR (f))
617 set_frame_menubar (f, 0, 1);
619 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
620 if (menubar)
622 /* Activate the first menu. */
623 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
625 if (children)
627 g_signal_emit_by_name (children->data, "activate_item");
628 popup_activated_flag = 1;
629 g_list_free (children);
632 UNBLOCK_INPUT;
634 return Qnil;
637 /* Loop util popup_activated_flag is set to zero in a callback.
638 Used for popup menus and dialogs. */
640 static void
641 popup_widget_loop (do_timers, widget)
642 int do_timers;
643 GtkWidget *widget;
645 ++popup_activated_flag;
647 /* Process events in the Gtk event loop until done. */
648 while (popup_activated_flag)
650 if (do_timers) x_menu_wait_for_event (0);
651 gtk_main_iteration ();
654 #endif
656 /* Activate the menu bar of frame F.
657 This is called from keyboard.c when it gets the
658 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
660 To activate the menu bar, we use the X button-press event
661 that was saved in saved_menu_event.
662 That makes the toolkit do its thing.
664 But first we recompute the menu bar contents (the whole tree).
666 The reason for saving the button event until here, instead of
667 passing it to the toolkit right away, is that we can safely
668 execute Lisp code. */
670 void
671 x_activate_menubar (f)
672 FRAME_PTR f;
674 if (! FRAME_X_P (f))
675 abort ();
677 if (!f->output_data.x->saved_menu_event->type)
678 return;
680 #ifdef USE_GTK
681 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
682 f->output_data.x->saved_menu_event->xany.window))
683 return;
684 #endif
686 set_frame_menubar (f, 0, 1);
687 BLOCK_INPUT;
688 #ifdef USE_GTK
689 XPutBackEvent (f->output_data.x->display_info->display,
690 f->output_data.x->saved_menu_event);
691 popup_activated_flag = 1;
692 #else
693 XtDispatchEvent (f->output_data.x->saved_menu_event);
694 #endif
695 UNBLOCK_INPUT;
696 #ifdef USE_MOTIF
697 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
698 pending_menu_activation = 1;
699 #endif
701 /* Ignore this if we get it a second time. */
702 f->output_data.x->saved_menu_event->type = 0;
705 /* This callback is invoked when the user selects a menubar cascade
706 pushbutton, but before the pulldown menu is posted. */
708 #ifndef USE_GTK
709 static void
710 popup_activate_callback (widget, id, client_data)
711 Widget widget;
712 LWLIB_ID id;
713 XtPointer client_data;
715 popup_activated_flag = 1;
716 #ifdef USE_X_TOOLKIT
717 x_activate_timeout_atimer ();
718 #endif
720 #endif
722 /* This callback is invoked when a dialog or menu is finished being
723 used and has been unposted. */
725 #ifdef USE_GTK
726 static void
727 popup_deactivate_callback (widget, client_data)
728 GtkWidget *widget;
729 gpointer client_data;
731 popup_activated_flag = 0;
733 #else
734 static void
735 popup_deactivate_callback (widget, id, client_data)
736 Widget widget;
737 LWLIB_ID id;
738 XtPointer client_data;
740 popup_activated_flag = 0;
742 #endif
745 /* Function that finds the frame for WIDGET and shows the HELP text
746 for that widget.
747 F is the frame if known, or NULL if not known. */
748 static void
749 show_help_event (f, widget, help)
750 FRAME_PTR f;
751 xt_or_gtk_widget widget;
752 Lisp_Object help;
754 Lisp_Object frame;
756 if (f)
758 XSETFRAME (frame, f);
759 kbd_buffer_store_help_event (frame, help);
761 else
763 #if 0 /* This code doesn't do anything useful. ++kfs */
764 /* WIDGET is the popup menu. It's parent is the frame's
765 widget. See which frame that is. */
766 xt_or_gtk_widget frame_widget = XtParent (widget);
767 Lisp_Object tail;
769 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
771 frame = XCAR (tail);
772 if (FRAMEP (frame)
773 && (f = XFRAME (frame),
774 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
775 break;
777 #endif
778 show_help_echo (help, Qnil, Qnil, Qnil, 1);
782 /* Callback called when menu items are highlighted/unhighlighted
783 while moving the mouse over them. WIDGET is the menu bar or menu
784 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
785 the data structure for the menu item, or null in case of
786 unhighlighting. */
788 #ifdef USE_GTK
789 void
790 menu_highlight_callback (widget, call_data)
791 GtkWidget *widget;
792 gpointer call_data;
794 xg_menu_item_cb_data *cb_data;
795 Lisp_Object help;
797 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
798 XG_ITEM_DATA);
799 if (! cb_data) return;
801 help = call_data ? cb_data->help : Qnil;
803 /* If popup_activated_flag is greater than 1 we are in a popup menu.
804 Don't show help for them, they won't appear before the
805 popup is popped down. */
806 if (popup_activated_flag <= 1)
807 show_help_event (cb_data->cl_data->f, widget, help);
809 #else
810 void
811 menu_highlight_callback (widget, id, call_data)
812 Widget widget;
813 LWLIB_ID id;
814 void *call_data;
816 struct frame *f;
817 Lisp_Object help;
819 widget_value *wv = (widget_value *) call_data;
821 help = wv ? wv->help : Qnil;
823 /* Determine the frame for the help event. */
824 f = menubar_id_to_frame (id);
826 show_help_event (f, widget, help);
828 #endif
830 #ifdef USE_GTK
831 /* Gtk calls callbacks just because we tell it what item should be
832 selected in a radio group. If this variable is set to a non-zero
833 value, we are creating menus and don't want callbacks right now.
835 static int xg_crazy_callback_abort;
837 /* This callback is called from the menu bar pulldown menu
838 when the user makes a selection.
839 Figure out what the user chose
840 and put the appropriate events into the keyboard buffer. */
841 static void
842 menubar_selection_callback (widget, client_data)
843 GtkWidget *widget;
844 gpointer client_data;
846 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
848 if (xg_crazy_callback_abort)
849 return;
851 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
852 return;
854 /* For a group of radio buttons, GTK calls the selection callback first
855 for the item that was active before the selection and then for the one that
856 is active after the selection. For C-h k this means we get the help on
857 the deselected item and then the selected item is executed. Prevent that
858 by ignoring the non-active item. */
859 if (GTK_IS_RADIO_MENU_ITEM (widget)
860 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
861 return;
863 /* When a menu is popped down, X generates a focus event (i.e. focus
864 goes back to the frame below the menu). Since GTK buffers events,
865 we force it out here before the menu selection event. Otherwise
866 sit-for will exit at once if the focus event follows the menu selection
867 event. */
869 BLOCK_INPUT;
870 while (gtk_events_pending ())
871 gtk_main_iteration ();
872 UNBLOCK_INPUT;
874 find_and_call_menu_selection (cb_data->cl_data->f,
875 cb_data->cl_data->menu_bar_items_used,
876 cb_data->cl_data->menu_bar_vector,
877 cb_data->call_data);
880 #else /* not USE_GTK */
882 /* This callback is called from the menu bar pulldown menu
883 when the user makes a selection.
884 Figure out what the user chose
885 and put the appropriate events into the keyboard buffer. */
886 static void
887 menubar_selection_callback (widget, id, client_data)
888 Widget widget;
889 LWLIB_ID id;
890 XtPointer client_data;
892 FRAME_PTR f;
894 f = menubar_id_to_frame (id);
895 if (!f)
896 return;
897 find_and_call_menu_selection (f, f->menu_bar_items_used,
898 f->menu_bar_vector, client_data);
900 #endif /* not USE_GTK */
902 /* Recompute all the widgets of frame F, when the menu bar has been
903 changed. Value is non-zero if widgets were updated. */
905 static int
906 update_frame_menubar (f)
907 FRAME_PTR f;
909 #ifdef USE_GTK
910 return xg_update_frame_menubar (f);
911 #else
912 struct x_output *x;
913 int columns, rows;
915 if (! FRAME_X_P (f))
916 abort ();
918 x = f->output_data.x;
920 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
921 return 0;
923 BLOCK_INPUT;
924 /* Save the size of the frame because the pane widget doesn't accept
925 to resize itself. So force it. */
926 columns = FRAME_COLS (f);
927 rows = FRAME_LINES (f);
929 /* Do the voodoo which means "I'm changing lots of things, don't try
930 to refigure sizes until I'm done." */
931 lw_refigure_widget (x->column_widget, False);
933 /* The order in which children are managed is the top to bottom
934 order in which they are displayed in the paned window. First,
935 remove the text-area widget. */
936 XtUnmanageChild (x->edit_widget);
938 /* Remove the menubar that is there now, and put up the menubar that
939 should be there. */
940 XtManageChild (x->menubar_widget);
941 XtMapWidget (x->menubar_widget);
942 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
944 /* Re-manage the text-area widget, and then thrash the sizes. */
945 XtManageChild (x->edit_widget);
946 lw_refigure_widget (x->column_widget, True);
948 /* Force the pane widget to resize itself with the right values. */
949 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
950 UNBLOCK_INPUT;
951 #endif
952 return 1;
955 #ifdef USE_LUCID
956 static void
957 apply_systemfont_to_dialog (w)
958 Widget w;
960 const char *fn = xsettings_get_system_normal_font ();
961 if (fn)
963 XrmDatabase db = XtDatabase (XtDisplay (w));
964 if (db)
965 XrmPutStringResource (&db, "*dialog.faceName", fn);
969 static void
970 apply_systemfont_to_menu (w)
971 Widget w;
973 const char *fn = xsettings_get_system_normal_font ();
974 int defflt;
976 if (!fn) return;
978 if (XtIsShell (w)) /* popup menu */
980 Widget *childs = NULL;
982 XtVaGetValues (w, XtNchildren, &childs, NULL);
983 if (*childs) w = *childs;
986 /* Only use system font if the default is used for the menu. */
987 XtVaGetValues (w, XtNdefaultFace, &defflt, NULL);
988 if (defflt)
989 XtVaSetValues (w, XtNfaceName, fn, NULL);
991 #endif
993 /* Set the contents of the menubar widgets of frame F.
994 The argument FIRST_TIME is currently ignored;
995 it is set the first time this is called, from initialize_frame_menubar. */
997 void
998 set_frame_menubar (f, first_time, deep_p)
999 FRAME_PTR f;
1000 int first_time;
1001 int deep_p;
1003 xt_or_gtk_widget menubar_widget;
1004 #ifdef USE_X_TOOLKIT
1005 LWLIB_ID id;
1006 #endif
1007 Lisp_Object items;
1008 widget_value *wv, *first_wv, *prev_wv = 0;
1009 int i, last_i = 0;
1010 int *submenu_start, *submenu_end;
1011 int *submenu_top_level_items, *submenu_n_panes;
1013 if (! FRAME_X_P (f))
1014 abort ();
1016 menubar_widget = f->output_data.x->menubar_widget;
1018 XSETFRAME (Vmenu_updating_frame, f);
1020 #ifdef USE_X_TOOLKIT
1021 if (f->output_data.x->id == 0)
1022 f->output_data.x->id = next_menubar_widget_id++;
1023 id = f->output_data.x->id;
1024 #endif
1026 if (! menubar_widget)
1027 deep_p = 1;
1028 else if (pending_menu_activation && !deep_p)
1029 deep_p = 1;
1030 /* Make the first call for any given frame always go deep. */
1031 else if (!f->output_data.x->saved_menu_event && !deep_p)
1033 deep_p = 1;
1034 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
1035 f->output_data.x->saved_menu_event->type = 0;
1038 #ifdef USE_GTK
1039 /* If we have detached menus, we must update deep so detached menus
1040 also gets updated. */
1041 deep_p = deep_p || xg_have_tear_offs ();
1042 #endif
1044 if (deep_p)
1046 /* Make a widget-value tree representing the entire menu trees. */
1048 struct buffer *prev = current_buffer;
1049 Lisp_Object buffer;
1050 int specpdl_count = SPECPDL_INDEX ();
1051 int previous_menu_items_used = f->menu_bar_items_used;
1052 Lisp_Object *previous_items
1053 = (Lisp_Object *) alloca (previous_menu_items_used
1054 * sizeof (Lisp_Object));
1056 /* If we are making a new widget, its contents are empty,
1057 do always reinitialize them. */
1058 if (! menubar_widget)
1059 previous_menu_items_used = 0;
1061 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1062 specbind (Qinhibit_quit, Qt);
1063 /* Don't let the debugger step into this code
1064 because it is not reentrant. */
1065 specbind (Qdebug_on_next_call, Qnil);
1067 record_unwind_save_match_data ();
1068 if (NILP (Voverriding_local_map_menu_flag))
1070 specbind (Qoverriding_terminal_local_map, Qnil);
1071 specbind (Qoverriding_local_map, Qnil);
1074 set_buffer_internal_1 (XBUFFER (buffer));
1076 /* Run the Lucid hook. */
1077 safe_run_hooks (Qactivate_menubar_hook);
1079 /* If it has changed current-menubar from previous value,
1080 really recompute the menubar from the value. */
1081 if (! NILP (Vlucid_menu_bar_dirty_flag))
1082 call0 (Qrecompute_lucid_menubar);
1083 safe_run_hooks (Qmenu_bar_update_hook);
1084 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1086 items = FRAME_MENU_BAR_ITEMS (f);
1088 /* Save the frame's previous menu bar contents data. */
1089 if (previous_menu_items_used)
1090 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1091 previous_menu_items_used * sizeof (Lisp_Object));
1093 /* Fill in menu_items with the current menu bar contents.
1094 This can evaluate Lisp code. */
1095 save_menu_items ();
1097 menu_items = f->menu_bar_vector;
1098 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1099 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1100 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1101 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1102 submenu_top_level_items
1103 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1104 init_menu_items ();
1105 for (i = 0; i < XVECTOR (items)->size; i += 4)
1107 Lisp_Object key, string, maps;
1109 last_i = i;
1111 key = XVECTOR (items)->contents[i];
1112 string = XVECTOR (items)->contents[i + 1];
1113 maps = XVECTOR (items)->contents[i + 2];
1114 if (NILP (string))
1115 break;
1117 submenu_start[i] = menu_items_used;
1119 menu_items_n_panes = 0;
1120 submenu_top_level_items[i]
1121 = parse_single_submenu (key, string, maps);
1122 submenu_n_panes[i] = menu_items_n_panes;
1124 submenu_end[i] = menu_items_used;
1127 finish_menu_items ();
1129 /* Convert menu_items into widget_value trees
1130 to display the menu. This cannot evaluate Lisp code. */
1132 wv = xmalloc_widget_value ();
1133 wv->name = "menubar";
1134 wv->value = 0;
1135 wv->enabled = 1;
1136 wv->button_type = BUTTON_TYPE_NONE;
1137 wv->help = Qnil;
1138 first_wv = wv;
1140 for (i = 0; i < last_i; i += 4)
1142 menu_items_n_panes = submenu_n_panes[i];
1143 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1144 submenu_top_level_items[i]);
1145 if (prev_wv)
1146 prev_wv->next = wv;
1147 else
1148 first_wv->contents = wv;
1149 /* Don't set wv->name here; GC during the loop might relocate it. */
1150 wv->enabled = 1;
1151 wv->button_type = BUTTON_TYPE_NONE;
1152 prev_wv = wv;
1155 set_buffer_internal_1 (prev);
1157 /* If there has been no change in the Lisp-level contents
1158 of the menu bar, skip redisplaying it. Just exit. */
1160 /* Compare the new menu items with the ones computed last time. */
1161 for (i = 0; i < previous_menu_items_used; i++)
1162 if (menu_items_used == i
1163 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1164 break;
1165 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1167 /* The menu items have not changed. Don't bother updating
1168 the menus in any form, since it would be a no-op. */
1169 free_menubar_widget_value_tree (first_wv);
1170 discard_menu_items ();
1171 unbind_to (specpdl_count, Qnil);
1172 return;
1175 /* The menu items are different, so store them in the frame. */
1176 f->menu_bar_vector = menu_items;
1177 f->menu_bar_items_used = menu_items_used;
1179 /* This undoes save_menu_items. */
1180 unbind_to (specpdl_count, Qnil);
1182 /* Now GC cannot happen during the lifetime of the widget_value,
1183 so it's safe to store data from a Lisp_String. */
1184 wv = first_wv->contents;
1185 for (i = 0; i < XVECTOR (items)->size; i += 4)
1187 Lisp_Object string;
1188 string = XVECTOR (items)->contents[i + 1];
1189 if (NILP (string))
1190 break;
1191 wv->name = (char *) SDATA (string);
1192 update_submenu_strings (wv->contents);
1193 wv = wv->next;
1197 else
1199 /* Make a widget-value tree containing
1200 just the top level menu bar strings. */
1202 wv = xmalloc_widget_value ();
1203 wv->name = "menubar";
1204 wv->value = 0;
1205 wv->enabled = 1;
1206 wv->button_type = BUTTON_TYPE_NONE;
1207 wv->help = Qnil;
1208 first_wv = wv;
1210 items = FRAME_MENU_BAR_ITEMS (f);
1211 for (i = 0; i < XVECTOR (items)->size; i += 4)
1213 Lisp_Object string;
1215 string = XVECTOR (items)->contents[i + 1];
1216 if (NILP (string))
1217 break;
1219 wv = xmalloc_widget_value ();
1220 wv->name = (char *) SDATA (string);
1221 wv->value = 0;
1222 wv->enabled = 1;
1223 wv->button_type = BUTTON_TYPE_NONE;
1224 wv->help = Qnil;
1225 /* This prevents lwlib from assuming this
1226 menu item is really supposed to be empty. */
1227 /* The EMACS_INT cast avoids a warning.
1228 This value just has to be different from small integers. */
1229 wv->call_data = (void *) (EMACS_INT) (-1);
1231 if (prev_wv)
1232 prev_wv->next = wv;
1233 else
1234 first_wv->contents = wv;
1235 prev_wv = wv;
1238 /* Forget what we thought we knew about what is in the
1239 detailed contents of the menu bar menus.
1240 Changing the top level always destroys the contents. */
1241 f->menu_bar_items_used = 0;
1244 /* Create or update the menu bar widget. */
1246 BLOCK_INPUT;
1248 #ifdef USE_GTK
1249 xg_crazy_callback_abort = 1;
1250 if (menubar_widget)
1252 /* The fourth arg is DEEP_P, which says to consider the entire
1253 menu trees we supply, rather than just the menu bar item names. */
1254 xg_modify_menubar_widgets (menubar_widget,
1256 first_wv,
1257 deep_p,
1258 G_CALLBACK (menubar_selection_callback),
1259 G_CALLBACK (popup_deactivate_callback),
1260 G_CALLBACK (menu_highlight_callback));
1262 else
1264 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1266 menubar_widget
1267 = xg_create_widget ("menubar", "menubar", f, first_wv,
1268 G_CALLBACK (menubar_selection_callback),
1269 G_CALLBACK (popup_deactivate_callback),
1270 G_CALLBACK (menu_highlight_callback));
1272 f->output_data.x->menubar_widget = menubar_widget;
1276 #else /* not USE_GTK */
1277 if (menubar_widget)
1279 /* Disable resizing (done for Motif!) */
1280 lw_allow_resizing (f->output_data.x->widget, False);
1282 /* The third arg is DEEP_P, which says to consider the entire
1283 menu trees we supply, rather than just the menu bar item names. */
1284 lw_modify_all_widgets (id, first_wv, deep_p);
1286 /* Re-enable the edit widget to resize. */
1287 lw_allow_resizing (f->output_data.x->widget, True);
1289 else
1291 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1292 XtTranslations override = XtParseTranslationTable (menuOverride);
1294 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1295 f->output_data.x->column_widget,
1297 popup_activate_callback,
1298 menubar_selection_callback,
1299 popup_deactivate_callback,
1300 menu_highlight_callback);
1301 f->output_data.x->menubar_widget = menubar_widget;
1303 /* Make menu pop down on C-g. */
1304 XtOverrideTranslations (menubar_widget, override);
1305 apply_systemfont_to_menu (menubar_widget);
1309 int menubar_size
1310 = (f->output_data.x->menubar_widget
1311 ? (f->output_data.x->menubar_widget->core.height
1312 + f->output_data.x->menubar_widget->core.border_width)
1313 : 0);
1315 #if 1 /* Experimentally, we now get the right results
1316 for -geometry -0-0 without this. 24 Aug 96, rms.
1317 Maybe so, but the menu bar size is missing the pixels so the
1318 WM size hints are off by theses pixel. Jan D, oct 2009. */
1319 #ifdef USE_LUCID
1320 if (FRAME_EXTERNAL_MENU_BAR (f))
1322 Dimension ibw = 0;
1323 XtVaGetValues (f->output_data.x->column_widget,
1324 XtNinternalBorderWidth, &ibw, NULL);
1325 menubar_size += ibw;
1327 #endif /* USE_LUCID */
1328 #endif /* 1 */
1330 f->output_data.x->menubar_height = menubar_size;
1332 #endif /* not USE_GTK */
1334 free_menubar_widget_value_tree (first_wv);
1335 update_frame_menubar (f);
1337 #ifdef USE_GTK
1338 xg_crazy_callback_abort = 0;
1339 #endif
1341 UNBLOCK_INPUT;
1344 /* Called from Fx_create_frame to create the initial menubar of a frame
1345 before it is mapped, so that the window is mapped with the menubar already
1346 there instead of us tacking it on later and thrashing the window after it
1347 is visible. */
1349 void
1350 initialize_frame_menubar (f)
1351 FRAME_PTR f;
1353 /* This function is called before the first chance to redisplay
1354 the frame. It has to be, so the frame will have the right size. */
1355 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1356 set_frame_menubar (f, 1, 1);
1360 /* Get rid of the menu bar of frame F, and free its storage.
1361 This is used when deleting a frame, and when turning off the menu bar.
1362 For GTK this function is in gtkutil.c. */
1364 #ifndef USE_GTK
1365 void
1366 free_frame_menubar (f)
1367 FRAME_PTR f;
1369 Widget menubar_widget;
1371 if (! FRAME_X_P (f))
1372 abort ();
1374 menubar_widget = f->output_data.x->menubar_widget;
1376 f->output_data.x->menubar_height = 0;
1378 if (menubar_widget)
1380 #ifdef USE_MOTIF
1381 /* Removing the menu bar magically changes the shell widget's x
1382 and y position of (0, 0) which, when the menu bar is turned
1383 on again, leads to pull-down menuss appearing in strange
1384 positions near the upper-left corner of the display. This
1385 happens only with some window managers like twm and ctwm,
1386 but not with other like Motif's mwm or kwm, because the
1387 latter generate ConfigureNotify events when the menu bar
1388 is switched off, which fixes the shell position. */
1389 Position x0, y0, x1, y1;
1390 #endif
1392 BLOCK_INPUT;
1394 #ifdef USE_MOTIF
1395 if (f->output_data.x->widget)
1396 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1397 #endif
1399 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1400 f->output_data.x->menubar_widget = NULL;
1402 #ifdef USE_MOTIF
1403 if (f->output_data.x->widget)
1405 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1406 if (x1 == 0 && y1 == 0)
1407 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1409 #endif
1411 UNBLOCK_INPUT;
1414 #endif /* not USE_GTK */
1416 #endif /* USE_X_TOOLKIT || USE_GTK */
1418 /* xmenu_show actually displays a menu using the panes and items in menu_items
1419 and returns the value selected from it.
1420 There are two versions of xmenu_show, one for Xt and one for Xlib.
1421 Both assume input is blocked by the caller. */
1423 /* F is the frame the menu is for.
1424 X and Y are the frame-relative specified position,
1425 relative to the inside upper left corner of the frame F.
1426 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1427 KEYMAPS is 1 if this menu was specified with keymaps;
1428 in that case, we return a list containing the chosen item's value
1429 and perhaps also the pane's prefix.
1430 TITLE is the specified menu title.
1431 ERROR is a place to store an error message string in case of failure.
1432 (We return nil on failure, but the value doesn't actually matter.) */
1434 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1436 /* The item selected in the popup menu. */
1437 static Lisp_Object *volatile menu_item_selection;
1439 #ifdef USE_GTK
1441 /* Used when position a popup menu. See menu_position_func and
1442 create_and_show_popup_menu below. */
1443 struct next_popup_x_y
1445 FRAME_PTR f;
1446 int x;
1447 int y;
1450 /* The menu position function to use if we are not putting a popup
1451 menu where the pointer is.
1452 MENU is the menu to pop up.
1453 X and Y shall on exit contain x/y where the menu shall pop up.
1454 PUSH_IN is not documented in the GTK manual.
1455 USER_DATA is any data passed in when calling gtk_menu_popup.
1456 Here it points to a struct next_popup_x_y where the coordinates
1457 to store in *X and *Y are as well as the frame for the popup.
1459 Here only X and Y are used. */
1460 static void
1461 menu_position_func (menu, x, y, push_in, user_data)
1462 GtkMenu *menu;
1463 gint *x;
1464 gint *y;
1465 gboolean *push_in;
1466 gpointer user_data;
1468 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1469 GtkRequisition req;
1470 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1471 int disp_width = x_display_pixel_width (dpyinfo);
1472 int disp_height = x_display_pixel_height (dpyinfo);
1474 *x = data->x;
1475 *y = data->y;
1477 /* Check if there is room for the menu. If not, adjust x/y so that
1478 the menu is fully visible. */
1479 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1480 if (data->x + req.width > disp_width)
1481 *x -= data->x + req.width - disp_width;
1482 if (data->y + req.height > disp_height)
1483 *y -= data->y + req.height - disp_height;
1486 static void
1487 popup_selection_callback (widget, client_data)
1488 GtkWidget *widget;
1489 gpointer client_data;
1491 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1493 if (xg_crazy_callback_abort) return;
1494 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1497 static Lisp_Object
1498 pop_down_menu (arg)
1499 Lisp_Object arg;
1501 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1503 popup_activated_flag = 0;
1504 BLOCK_INPUT;
1505 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1506 UNBLOCK_INPUT;
1507 return Qnil;
1510 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1511 menu pops down.
1512 menu_item_selection will be set to the selection. */
1513 static void
1514 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1515 FRAME_PTR f;
1516 widget_value *first_wv;
1517 int x;
1518 int y;
1519 int for_click;
1520 EMACS_UINT timestamp;
1522 int i;
1523 GtkWidget *menu;
1524 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1525 struct next_popup_x_y popup_x_y;
1526 int specpdl_count = SPECPDL_INDEX ();
1528 if (! FRAME_X_P (f))
1529 abort ();
1531 xg_crazy_callback_abort = 1;
1532 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1533 G_CALLBACK (popup_selection_callback),
1534 G_CALLBACK (popup_deactivate_callback),
1535 G_CALLBACK (menu_highlight_callback));
1536 xg_crazy_callback_abort = 0;
1538 if (! for_click)
1540 /* Not invoked by a click. pop up at x/y. */
1541 pos_func = menu_position_func;
1543 /* Adjust coordinates to be root-window-relative. */
1544 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1545 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1547 popup_x_y.x = x;
1548 popup_x_y.y = y;
1549 popup_x_y.f = f;
1551 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1553 else
1555 for (i = 0; i < 5; i++)
1556 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1557 break;
1560 /* Display the menu. */
1561 gtk_widget_show_all (menu);
1563 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1564 timestamp > 0 ? timestamp : gtk_get_current_event_time());
1566 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1568 if (GTK_WIDGET_MAPPED (menu))
1570 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1571 two. show_help_echo uses this to detect popup menus. */
1572 popup_activated_flag = 1;
1573 /* Process events that apply to the menu. */
1574 popup_widget_loop (1, menu);
1577 unbind_to (specpdl_count, Qnil);
1579 /* Must reset this manually because the button release event is not passed
1580 to Emacs event loop. */
1581 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1584 #else /* not USE_GTK */
1586 /* We need a unique id for each widget handled by the Lucid Widget
1587 library.
1589 For the main windows, and popup menus, we use this counter,
1590 which we increment each time after use. This starts from 1<<16.
1592 For menu bars, we use numbers starting at 0, counted in
1593 next_menubar_widget_id. */
1594 LWLIB_ID widget_id_tick;
1596 static void
1597 popup_selection_callback (widget, id, client_data)
1598 Widget widget;
1599 LWLIB_ID id;
1600 XtPointer client_data;
1602 menu_item_selection = (Lisp_Object *) client_data;
1605 /* ARG is the LWLIB ID of the dialog box, represented
1606 as a Lisp object as (HIGHPART . LOWPART). */
1608 static Lisp_Object
1609 pop_down_menu (arg)
1610 Lisp_Object arg;
1612 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1613 | XINT (XCDR (arg)));
1615 BLOCK_INPUT;
1616 lw_destroy_all_widgets (id);
1617 UNBLOCK_INPUT;
1618 popup_activated_flag = 0;
1620 return Qnil;
1623 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1624 menu pops down.
1625 menu_item_selection will be set to the selection. */
1626 static void
1627 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1628 FRAME_PTR f;
1629 widget_value *first_wv;
1630 int x;
1631 int y;
1632 int for_click;
1633 EMACS_UINT timestamp;
1635 int i;
1636 Arg av[2];
1637 int ac = 0;
1638 XButtonPressedEvent dummy;
1639 LWLIB_ID menu_id;
1640 Widget menu;
1642 if (! FRAME_X_P (f))
1643 abort ();
1645 menu_id = widget_id_tick++;
1646 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1647 f->output_data.x->widget, 1, 0,
1648 popup_selection_callback,
1649 popup_deactivate_callback,
1650 menu_highlight_callback);
1652 apply_systemfont_to_menu (menu);
1654 dummy.type = ButtonPress;
1655 dummy.serial = 0;
1656 dummy.send_event = 0;
1657 dummy.display = FRAME_X_DISPLAY (f);
1658 dummy.time = CurrentTime;
1659 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1660 dummy.window = dummy.root;
1661 dummy.subwindow = dummy.root;
1662 dummy.x = x;
1663 dummy.y = y;
1665 /* Adjust coordinates to be root-window-relative. */
1666 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1667 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1669 dummy.x_root = x;
1670 dummy.y_root = y;
1672 dummy.state = 0;
1673 dummy.button = 0;
1674 for (i = 0; i < 5; i++)
1675 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1676 dummy.button = i;
1678 /* Don't allow any geometry request from the user. */
1679 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1680 XtSetValues (menu, av, ac);
1682 /* Display the menu. */
1683 lw_popup_menu (menu, (XEvent *) &dummy);
1684 popup_activated_flag = 1;
1685 x_activate_timeout_atimer ();
1688 int fact = 4 * sizeof (LWLIB_ID);
1689 int specpdl_count = SPECPDL_INDEX ();
1690 record_unwind_protect (pop_down_menu,
1691 Fcons (make_number (menu_id >> (fact)),
1692 make_number (menu_id & ~(-1 << (fact)))));
1694 /* Process events that apply to the menu. */
1695 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1697 unbind_to (specpdl_count, Qnil);
1701 #endif /* not USE_GTK */
1703 Lisp_Object
1704 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
1705 Lisp_Object title, char **error, EMACS_UINT timestamp)
1707 int i;
1708 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1709 widget_value **submenu_stack
1710 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1711 Lisp_Object *subprefix_stack
1712 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1713 int submenu_depth = 0;
1715 int first_pane;
1717 if (! FRAME_X_P (f))
1718 abort ();
1720 *error = NULL;
1722 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1724 *error = "Empty menu";
1725 return Qnil;
1728 /* Create a tree of widget_value objects
1729 representing the panes and their items. */
1730 wv = xmalloc_widget_value ();
1731 wv->name = "menu";
1732 wv->value = 0;
1733 wv->enabled = 1;
1734 wv->button_type = BUTTON_TYPE_NONE;
1735 wv->help =Qnil;
1736 first_wv = wv;
1737 first_pane = 1;
1739 /* Loop over all panes and items, filling in the tree. */
1740 i = 0;
1741 while (i < menu_items_used)
1743 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1745 submenu_stack[submenu_depth++] = save_wv;
1746 save_wv = prev_wv;
1747 prev_wv = 0;
1748 first_pane = 1;
1749 i++;
1751 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1753 prev_wv = save_wv;
1754 save_wv = submenu_stack[--submenu_depth];
1755 first_pane = 0;
1756 i++;
1758 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1759 && submenu_depth != 0)
1760 i += MENU_ITEMS_PANE_LENGTH;
1761 /* Ignore a nil in the item list.
1762 It's meaningful only for dialog boxes. */
1763 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1764 i += 1;
1765 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1767 /* Create a new pane. */
1768 Lisp_Object pane_name, prefix;
1769 char *pane_string;
1771 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1772 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1774 #ifndef HAVE_MULTILINGUAL_MENU
1775 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1777 pane_name = ENCODE_MENU_STRING (pane_name);
1778 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1780 #endif
1781 pane_string = (NILP (pane_name)
1782 ? "" : (char *) SDATA (pane_name));
1783 /* If there is just one top-level pane, put all its items directly
1784 under the top-level menu. */
1785 if (menu_items_n_panes == 1)
1786 pane_string = "";
1788 /* If the pane has a meaningful name,
1789 make the pane a top-level menu item
1790 with its items as a submenu beneath it. */
1791 if (!keymaps && strcmp (pane_string, ""))
1793 wv = xmalloc_widget_value ();
1794 if (save_wv)
1795 save_wv->next = wv;
1796 else
1797 first_wv->contents = wv;
1798 wv->name = pane_string;
1799 if (keymaps && !NILP (prefix))
1800 wv->name++;
1801 wv->value = 0;
1802 wv->enabled = 1;
1803 wv->button_type = BUTTON_TYPE_NONE;
1804 wv->help = Qnil;
1805 save_wv = wv;
1806 prev_wv = 0;
1808 else if (first_pane)
1810 save_wv = wv;
1811 prev_wv = 0;
1813 first_pane = 0;
1814 i += MENU_ITEMS_PANE_LENGTH;
1816 else
1818 /* Create a new item within current pane. */
1819 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1820 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1821 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1822 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1823 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1824 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1825 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1826 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1828 #ifndef HAVE_MULTILINGUAL_MENU
1829 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1831 item_name = ENCODE_MENU_STRING (item_name);
1832 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1835 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1837 descrip = ENCODE_MENU_STRING (descrip);
1838 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1840 #endif /* not HAVE_MULTILINGUAL_MENU */
1842 wv = xmalloc_widget_value ();
1843 if (prev_wv)
1844 prev_wv->next = wv;
1845 else
1846 save_wv->contents = wv;
1847 wv->name = (char *) SDATA (item_name);
1848 if (!NILP (descrip))
1849 wv->key = (char *) SDATA (descrip);
1850 wv->value = 0;
1851 /* If this item has a null value,
1852 make the call_data null so that it won't display a box
1853 when the mouse is on it. */
1854 wv->call_data
1855 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
1856 wv->enabled = !NILP (enable);
1858 if (NILP (type))
1859 wv->button_type = BUTTON_TYPE_NONE;
1860 else if (EQ (type, QCtoggle))
1861 wv->button_type = BUTTON_TYPE_TOGGLE;
1862 else if (EQ (type, QCradio))
1863 wv->button_type = BUTTON_TYPE_RADIO;
1864 else
1865 abort ();
1867 wv->selected = !NILP (selected);
1869 if (! STRINGP (help))
1870 help = Qnil;
1872 wv->help = help;
1874 prev_wv = wv;
1876 i += MENU_ITEMS_ITEM_LENGTH;
1880 /* Deal with the title, if it is non-nil. */
1881 if (!NILP (title))
1883 widget_value *wv_title = xmalloc_widget_value ();
1884 widget_value *wv_sep1 = xmalloc_widget_value ();
1885 widget_value *wv_sep2 = xmalloc_widget_value ();
1887 wv_sep2->name = "--";
1888 wv_sep2->next = first_wv->contents;
1889 wv_sep2->help = Qnil;
1891 wv_sep1->name = "--";
1892 wv_sep1->next = wv_sep2;
1893 wv_sep1->help = Qnil;
1895 #ifndef HAVE_MULTILINGUAL_MENU
1896 if (STRING_MULTIBYTE (title))
1897 title = ENCODE_MENU_STRING (title);
1898 #endif
1900 wv_title->name = (char *) SDATA (title);
1901 wv_title->enabled = TRUE;
1902 wv_title->button_type = BUTTON_TYPE_NONE;
1903 wv_title->help = Qnil;
1904 wv_title->next = wv_sep1;
1905 first_wv->contents = wv_title;
1908 /* No selection has been chosen yet. */
1909 menu_item_selection = 0;
1911 /* Actually create and show the menu until popped down. */
1912 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
1914 /* Free the widget_value objects we used to specify the contents. */
1915 free_menubar_widget_value_tree (first_wv);
1917 /* Find the selected item, and its pane, to return
1918 the proper value. */
1919 if (menu_item_selection != 0)
1921 Lisp_Object prefix, entry;
1923 prefix = entry = Qnil;
1924 i = 0;
1925 while (i < menu_items_used)
1927 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1929 subprefix_stack[submenu_depth++] = prefix;
1930 prefix = entry;
1931 i++;
1933 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1935 prefix = subprefix_stack[--submenu_depth];
1936 i++;
1938 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1940 prefix
1941 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1942 i += MENU_ITEMS_PANE_LENGTH;
1944 /* Ignore a nil in the item list.
1945 It's meaningful only for dialog boxes. */
1946 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1947 i += 1;
1948 else
1950 entry
1951 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1952 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1954 if (keymaps != 0)
1956 int j;
1958 entry = Fcons (entry, Qnil);
1959 if (!NILP (prefix))
1960 entry = Fcons (prefix, entry);
1961 for (j = submenu_depth - 1; j >= 0; j--)
1962 if (!NILP (subprefix_stack[j]))
1963 entry = Fcons (subprefix_stack[j], entry);
1965 return entry;
1967 i += MENU_ITEMS_ITEM_LENGTH;
1971 else if (!for_click)
1972 /* Make "Cancel" equivalent to C-g. */
1973 Fsignal (Qquit, Qnil);
1975 return Qnil;
1978 #ifdef USE_GTK
1979 static void
1980 dialog_selection_callback (widget, client_data)
1981 GtkWidget *widget;
1982 gpointer client_data;
1984 /* The EMACS_INT cast avoids a warning. There's no problem
1985 as long as pointers have enough bits to hold small integers. */
1986 if ((int) (EMACS_INT) client_data != -1)
1987 menu_item_selection = (Lisp_Object *) client_data;
1989 popup_activated_flag = 0;
1992 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1993 dialog pops down.
1994 menu_item_selection will be set to the selection. */
1995 static void
1996 create_and_show_dialog (f, first_wv)
1997 FRAME_PTR f;
1998 widget_value *first_wv;
2000 GtkWidget *menu;
2002 if (! FRAME_X_P (f))
2003 abort ();
2005 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2006 G_CALLBACK (dialog_selection_callback),
2007 G_CALLBACK (popup_deactivate_callback),
2010 if (menu)
2012 int specpdl_count = SPECPDL_INDEX ();
2013 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
2015 /* Display the menu. */
2016 gtk_widget_show_all (menu);
2018 /* Process events that apply to the menu. */
2019 popup_widget_loop (1, menu);
2021 unbind_to (specpdl_count, Qnil);
2025 #else /* not USE_GTK */
2026 static void
2027 dialog_selection_callback (widget, id, client_data)
2028 Widget widget;
2029 LWLIB_ID id;
2030 XtPointer client_data;
2032 /* The EMACS_INT cast avoids a warning. There's no problem
2033 as long as pointers have enough bits to hold small integers. */
2034 if ((int) (EMACS_INT) client_data != -1)
2035 menu_item_selection = (Lisp_Object *) client_data;
2037 BLOCK_INPUT;
2038 lw_destroy_all_widgets (id);
2039 UNBLOCK_INPUT;
2040 popup_activated_flag = 0;
2044 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2045 dialog pops down.
2046 menu_item_selection will be set to the selection. */
2047 static void
2048 create_and_show_dialog (f, first_wv)
2049 FRAME_PTR f;
2050 widget_value *first_wv;
2052 LWLIB_ID dialog_id;
2054 if (!FRAME_X_P (f))
2055 abort();
2057 dialog_id = widget_id_tick++;
2058 #ifdef HAVE_XFT
2059 apply_systemfont_to_dialog (f->output_data.x->widget);
2060 #endif
2061 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2062 f->output_data.x->widget, 1, 0,
2063 dialog_selection_callback, 0, 0);
2064 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2065 /* Display the dialog box. */
2066 lw_pop_up_all_widgets (dialog_id);
2067 popup_activated_flag = 1;
2068 x_activate_timeout_atimer ();
2070 /* Process events that apply to the dialog box.
2071 Also handle timers. */
2073 int count = SPECPDL_INDEX ();
2074 int fact = 4 * sizeof (LWLIB_ID);
2076 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2077 record_unwind_protect (pop_down_menu,
2078 Fcons (make_number (dialog_id >> (fact)),
2079 make_number (dialog_id & ~(-1 << (fact)))));
2081 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2082 dialog_id, 1);
2084 unbind_to (count, Qnil);
2088 #endif /* not USE_GTK */
2090 static char * button_names [] = {
2091 "button1", "button2", "button3", "button4", "button5",
2092 "button6", "button7", "button8", "button9", "button10" };
2094 static Lisp_Object
2095 xdialog_show (f, keymaps, title, header, error_name)
2096 FRAME_PTR f;
2097 int keymaps;
2098 Lisp_Object title, header;
2099 char **error_name;
2101 int i, nb_buttons=0;
2102 char dialog_name[6];
2104 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2106 /* Number of elements seen so far, before boundary. */
2107 int left_count = 0;
2108 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2109 int boundary_seen = 0;
2111 if (! FRAME_X_P (f))
2112 abort ();
2114 *error_name = NULL;
2116 if (menu_items_n_panes > 1)
2118 *error_name = "Multiple panes in dialog box";
2119 return Qnil;
2122 /* Create a tree of widget_value objects
2123 representing the text label and buttons. */
2125 Lisp_Object pane_name, prefix;
2126 char *pane_string;
2127 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2128 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2129 pane_string = (NILP (pane_name)
2130 ? "" : (char *) SDATA (pane_name));
2131 prev_wv = xmalloc_widget_value ();
2132 prev_wv->value = pane_string;
2133 if (keymaps && !NILP (prefix))
2134 prev_wv->name++;
2135 prev_wv->enabled = 1;
2136 prev_wv->name = "message";
2137 prev_wv->help = Qnil;
2138 first_wv = prev_wv;
2140 /* Loop over all panes and items, filling in the tree. */
2141 i = MENU_ITEMS_PANE_LENGTH;
2142 while (i < menu_items_used)
2145 /* Create a new item within current pane. */
2146 Lisp_Object item_name, enable, descrip;
2147 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2148 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2149 descrip
2150 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2152 if (NILP (item_name))
2154 free_menubar_widget_value_tree (first_wv);
2155 *error_name = "Submenu in dialog items";
2156 return Qnil;
2158 if (EQ (item_name, Qquote))
2160 /* This is the boundary between left-side elts
2161 and right-side elts. Stop incrementing right_count. */
2162 boundary_seen = 1;
2163 i++;
2164 continue;
2166 if (nb_buttons >= 9)
2168 free_menubar_widget_value_tree (first_wv);
2169 *error_name = "Too many dialog items";
2170 return Qnil;
2173 wv = xmalloc_widget_value ();
2174 prev_wv->next = wv;
2175 wv->name = (char *) button_names[nb_buttons];
2176 if (!NILP (descrip))
2177 wv->key = (char *) SDATA (descrip);
2178 wv->value = (char *) SDATA (item_name);
2179 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2180 wv->enabled = !NILP (enable);
2181 wv->help = Qnil;
2182 prev_wv = wv;
2184 if (! boundary_seen)
2185 left_count++;
2187 nb_buttons++;
2188 i += MENU_ITEMS_ITEM_LENGTH;
2191 /* If the boundary was not specified,
2192 by default put half on the left and half on the right. */
2193 if (! boundary_seen)
2194 left_count = nb_buttons - nb_buttons / 2;
2196 wv = xmalloc_widget_value ();
2197 wv->name = dialog_name;
2198 wv->help = Qnil;
2200 /* Frame title: 'Q' = Question, 'I' = Information.
2201 Can also have 'E' = Error if, one day, we want
2202 a popup for errors. */
2203 if (NILP(header))
2204 dialog_name[0] = 'Q';
2205 else
2206 dialog_name[0] = 'I';
2208 /* Dialog boxes use a really stupid name encoding
2209 which specifies how many buttons to use
2210 and how many buttons are on the right. */
2211 dialog_name[1] = '0' + nb_buttons;
2212 dialog_name[2] = 'B';
2213 dialog_name[3] = 'R';
2214 /* Number of buttons to put on the right. */
2215 dialog_name[4] = '0' + nb_buttons - left_count;
2216 dialog_name[5] = 0;
2217 wv->contents = first_wv;
2218 first_wv = wv;
2221 /* No selection has been chosen yet. */
2222 menu_item_selection = 0;
2224 /* Actually create and show the dialog. */
2225 create_and_show_dialog (f, first_wv);
2227 /* Free the widget_value objects we used to specify the contents. */
2228 free_menubar_widget_value_tree (first_wv);
2230 /* Find the selected item, and its pane, to return
2231 the proper value. */
2232 if (menu_item_selection != 0)
2234 Lisp_Object prefix;
2236 prefix = Qnil;
2237 i = 0;
2238 while (i < menu_items_used)
2240 Lisp_Object entry;
2242 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2244 prefix
2245 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2246 i += MENU_ITEMS_PANE_LENGTH;
2248 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2250 /* This is the boundary between left-side elts and
2251 right-side elts. */
2252 ++i;
2254 else
2256 entry
2257 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2258 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2260 if (keymaps != 0)
2262 entry = Fcons (entry, Qnil);
2263 if (!NILP (prefix))
2264 entry = Fcons (prefix, entry);
2266 return entry;
2268 i += MENU_ITEMS_ITEM_LENGTH;
2272 else
2273 /* Make "Cancel" equivalent to C-g. */
2274 Fsignal (Qquit, Qnil);
2276 return Qnil;
2279 #else /* not USE_X_TOOLKIT && not USE_GTK */
2281 /* The frame of the last activated non-toolkit menu bar.
2282 Used to generate menu help events. */
2284 static struct frame *menu_help_frame;
2287 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2289 PANE is the pane number, and ITEM is the menu item number in
2290 the menu (currently not used).
2292 This cannot be done with generating a HELP_EVENT because
2293 XMenuActivate contains a loop that doesn't let Emacs process
2294 keyboard events. */
2296 static void
2297 menu_help_callback (help_string, pane, item)
2298 char *help_string;
2299 int pane, item;
2301 extern Lisp_Object Qmenu_item;
2302 Lisp_Object *first_item;
2303 Lisp_Object pane_name;
2304 Lisp_Object menu_object;
2306 first_item = XVECTOR (menu_items)->contents;
2307 if (EQ (first_item[0], Qt))
2308 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2309 else if (EQ (first_item[0], Qquote))
2310 /* This shouldn't happen, see xmenu_show. */
2311 pane_name = empty_unibyte_string;
2312 else
2313 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2315 /* (menu-item MENU-NAME PANE-NUMBER) */
2316 menu_object = Fcons (Qmenu_item,
2317 Fcons (pane_name,
2318 Fcons (make_number (pane), Qnil)));
2319 show_help_echo (help_string ? build_string (help_string) : Qnil,
2320 Qnil, menu_object, make_number (item), 1);
2323 static Lisp_Object
2324 pop_down_menu (arg)
2325 Lisp_Object arg;
2327 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2328 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2330 FRAME_PTR f = p1->pointer;
2331 XMenu *menu = p2->pointer;
2333 BLOCK_INPUT;
2334 #ifndef MSDOS
2335 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2336 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2337 #endif
2338 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2340 #ifdef HAVE_X_WINDOWS
2341 /* Assume the mouse has moved out of the X window.
2342 If it has actually moved in, we will get an EnterNotify. */
2343 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2345 /* State that no mouse buttons are now held.
2346 (The oldXMenu code doesn't track this info for us.)
2347 That is not necessarily true, but the fiction leads to reasonable
2348 results, and it is a pain to ask which are actually held now. */
2349 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2351 #endif /* HAVE_X_WINDOWS */
2353 UNBLOCK_INPUT;
2355 return Qnil;
2359 Lisp_Object
2360 xmenu_show (f, x, y, for_click, keymaps, title, error, timestamp)
2361 FRAME_PTR f;
2362 int x, y;
2363 int for_click;
2364 int keymaps;
2365 Lisp_Object title;
2366 char **error;
2367 EMACS_UINT timestamp;
2369 Window root;
2370 XMenu *menu;
2371 int pane, selidx, lpane, status;
2372 Lisp_Object entry, pane_prefix;
2373 char *datap;
2374 int ulx, uly, width, height;
2375 int dispwidth, dispheight;
2376 int i, j, lines, maxlines;
2377 int maxwidth;
2378 int dummy_int;
2379 unsigned int dummy_uint;
2380 int specpdl_count = SPECPDL_INDEX ();
2382 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2383 abort ();
2385 *error = 0;
2386 if (menu_items_n_panes == 0)
2387 return Qnil;
2389 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2391 *error = "Empty menu";
2392 return Qnil;
2395 /* Figure out which root window F is on. */
2396 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2397 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2398 &dummy_uint, &dummy_uint);
2400 /* Make the menu on that window. */
2401 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2402 if (menu == NULL)
2404 *error = "Can't create menu";
2405 return Qnil;
2408 /* Don't GC while we prepare and show the menu,
2409 because we give the oldxmenu library pointers to the
2410 contents of strings. */
2411 inhibit_garbage_collection ();
2413 #ifdef HAVE_X_WINDOWS
2414 /* Adjust coordinates to relative to the outer (window manager) window. */
2415 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2416 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2417 #endif /* HAVE_X_WINDOWS */
2419 /* Adjust coordinates to be root-window-relative. */
2420 x += f->left_pos;
2421 y += f->top_pos;
2423 /* Create all the necessary panes and their items. */
2424 maxlines = lines = i = 0;
2425 while (i < menu_items_used)
2427 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2429 /* Create a new pane. */
2430 Lisp_Object pane_name, prefix;
2431 char *pane_string;
2433 maxlines = max (maxlines, lines);
2434 lines = 0;
2435 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2436 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2437 pane_string = (NILP (pane_name)
2438 ? "" : (char *) SDATA (pane_name));
2439 if (keymaps && !NILP (prefix))
2440 pane_string++;
2442 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2443 if (lpane == XM_FAILURE)
2445 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2446 *error = "Can't create pane";
2447 return Qnil;
2449 i += MENU_ITEMS_PANE_LENGTH;
2451 /* Find the width of the widest item in this pane. */
2452 maxwidth = 0;
2453 j = i;
2454 while (j < menu_items_used)
2456 Lisp_Object item;
2457 item = XVECTOR (menu_items)->contents[j];
2458 if (EQ (item, Qt))
2459 break;
2460 if (NILP (item))
2462 j++;
2463 continue;
2465 width = SBYTES (item);
2466 if (width > maxwidth)
2467 maxwidth = width;
2469 j += MENU_ITEMS_ITEM_LENGTH;
2472 /* Ignore a nil in the item list.
2473 It's meaningful only for dialog boxes. */
2474 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2475 i += 1;
2476 else
2478 /* Create a new item within current pane. */
2479 Lisp_Object item_name, enable, descrip, help;
2480 unsigned char *item_data;
2481 char *help_string;
2483 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2484 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2485 descrip
2486 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2487 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2488 help_string = STRINGP (help) ? SDATA (help) : NULL;
2490 if (!NILP (descrip))
2492 int gap = maxwidth - SBYTES (item_name);
2493 /* if alloca is fast, use that to make the space,
2494 to reduce gc needs. */
2495 item_data
2496 = (unsigned char *) alloca (maxwidth
2497 + SBYTES (descrip) + 1);
2498 bcopy (SDATA (item_name), item_data,
2499 SBYTES (item_name));
2500 for (j = SCHARS (item_name); j < maxwidth; j++)
2501 item_data[j] = ' ';
2502 bcopy (SDATA (descrip), item_data + j,
2503 SBYTES (descrip));
2504 item_data[j + SBYTES (descrip)] = 0;
2506 else
2507 item_data = SDATA (item_name);
2509 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2510 menu, lpane, 0, item_data,
2511 !NILP (enable), help_string)
2512 == XM_FAILURE)
2514 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2515 *error = "Can't add selection to menu";
2516 return Qnil;
2518 i += MENU_ITEMS_ITEM_LENGTH;
2519 lines++;
2523 maxlines = max (maxlines, lines);
2525 /* All set and ready to fly. */
2526 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2527 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2528 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2529 x = min (x, dispwidth);
2530 y = min (y, dispheight);
2531 x = max (x, 1);
2532 y = max (y, 1);
2533 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2534 &ulx, &uly, &width, &height);
2535 if (ulx+width > dispwidth)
2537 x -= (ulx + width) - dispwidth;
2538 ulx = dispwidth - width;
2540 if (uly+height > dispheight)
2542 y -= (uly + height) - dispheight;
2543 uly = dispheight - height;
2545 #ifndef HAVE_X_WINDOWS
2546 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2548 /* Move the menu away of the echo area, to avoid overwriting the
2549 menu with help echo messages or vice versa. */
2550 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2552 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2553 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2555 else
2557 y--;
2558 uly--;
2561 #endif
2562 if (ulx < 0) x -= ulx;
2563 if (uly < 0) y -= uly;
2565 if (! for_click)
2567 /* If position was not given by a mouse click, adjust so upper left
2568 corner of the menu as a whole ends up at given coordinates. This
2569 is what x-popup-menu says in its documentation. */
2570 x += width/2;
2571 y += 1.5*height/(maxlines+2);
2574 XMenuSetAEQ (menu, TRUE);
2575 XMenuSetFreeze (menu, TRUE);
2576 pane = selidx = 0;
2578 #ifndef MSDOS
2579 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2580 #endif
2582 record_unwind_protect (pop_down_menu,
2583 Fcons (make_save_value (f, 0),
2584 make_save_value (menu, 0)));
2586 /* Help display under X won't work because XMenuActivate contains
2587 a loop that doesn't give Emacs a chance to process it. */
2588 menu_help_frame = f;
2589 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2590 x, y, ButtonReleaseMask, &datap,
2591 menu_help_callback);
2593 switch (status)
2595 case XM_SUCCESS:
2596 #ifdef XDEBUG
2597 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2598 #endif
2600 /* Find the item number SELIDX in pane number PANE. */
2601 i = 0;
2602 while (i < menu_items_used)
2604 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2606 if (pane == 0)
2607 pane_prefix
2608 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2609 pane--;
2610 i += MENU_ITEMS_PANE_LENGTH;
2612 else
2614 if (pane == -1)
2616 if (selidx == 0)
2618 entry
2619 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2620 if (keymaps != 0)
2622 entry = Fcons (entry, Qnil);
2623 if (!NILP (pane_prefix))
2624 entry = Fcons (pane_prefix, entry);
2626 break;
2628 selidx--;
2630 i += MENU_ITEMS_ITEM_LENGTH;
2633 break;
2635 case XM_FAILURE:
2636 *error = "Can't activate menu";
2637 case XM_IA_SELECT:
2638 entry = Qnil;
2639 break;
2640 case XM_NO_SELECT:
2641 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2642 the menu was invoked with a mouse event as POSITION). */
2643 if (! for_click)
2644 Fsignal (Qquit, Qnil);
2645 entry = Qnil;
2646 break;
2649 unbind_to (specpdl_count, Qnil);
2651 return entry;
2654 #endif /* not USE_X_TOOLKIT */
2656 #endif /* HAVE_MENUS */
2658 /* Detect if a dialog or menu has been posted. */
2661 popup_activated ()
2663 return popup_activated_flag;
2666 /* The following is used by delayed window autoselection. */
2668 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2669 doc: /* Return t if a menu or popup dialog is active. */)
2672 #ifdef HAVE_MENUS
2673 return (popup_activated ()) ? Qt : Qnil;
2674 #else
2675 return Qnil;
2676 #endif /* HAVE_MENUS */
2679 void
2680 syms_of_xmenu ()
2682 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
2683 staticpro (&Qdebug_on_next_call);
2685 #ifdef USE_X_TOOLKIT
2686 widget_id_tick = (1<<16);
2687 next_menubar_widget_id = 1;
2688 #endif
2690 defsubr (&Smenu_or_popup_active_p);
2692 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2693 defsubr (&Sx_menu_bar_open_internal);
2694 Ffset (intern_c_string ("accelerate-menu"),
2695 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2696 #endif
2698 #ifdef HAVE_MENUS
2699 defsubr (&Sx_popup_dialog);
2700 #endif
2703 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2704 (do not change this comment) */