Merge from trunk.
[emacs.git] / src / xmenu.c
bloba04eb2502b375f4435ffbc635b7cdeb92f5c9b22
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 #else /* not USE_X_TOOLKIT */
93 #ifndef USE_GTK
94 #include "../oldXMenu/XMenu.h"
95 #endif
96 #endif /* not USE_X_TOOLKIT */
97 #endif /* HAVE_X_WINDOWS */
99 #ifdef USE_GTK
100 #include "gtkutil.h"
101 #endif
103 #include "menu.h"
105 #ifndef TRUE
106 #define TRUE 1
107 #define FALSE 0
108 #endif /* no TRUE */
110 Lisp_Object Qdebug_on_next_call;
112 extern Lisp_Object Qmenu_bar;
114 extern Lisp_Object QCtoggle, QCradio;
116 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
118 extern Lisp_Object Qmenu_bar_update_hook;
120 #ifdef USE_X_TOOLKIT
121 extern void set_frame_menubar (FRAME_PTR, int, int);
122 extern XtAppContext Xt_app_con;
124 static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
125 char **);
126 static void popup_get_selection (XEvent *, struct x_display_info *,
127 LWLIB_ID, int);
128 #endif /* USE_X_TOOLKIT */
130 #ifdef USE_GTK
131 extern void set_frame_menubar (FRAME_PTR, int, int);
132 static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
133 char **);
134 #endif
136 static int update_frame_menubar (struct frame *);
138 /* Flag which when set indicates a dialog or menu has been posted by
139 Xt on behalf of one of the widget sets. */
140 static int popup_activated_flag;
142 static int next_menubar_widget_id;
144 /* For NS and NTGUI, these prototypes are defined in keyboard.h. */
145 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
146 extern widget_value *xmalloc_widget_value (void);
147 extern widget_value *digest_single_submenu (int, int, int);
148 #endif
151 #ifdef USE_X_TOOLKIT
153 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
155 static struct frame *
156 menubar_id_to_frame (LWLIB_ID id)
158 Lisp_Object tail, frame;
159 FRAME_PTR f;
161 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
163 frame = XCAR (tail);
164 if (!FRAMEP (frame))
165 continue;
166 f = XFRAME (frame);
167 if (!FRAME_WINDOW_P (f))
168 continue;
169 if (f->output_data.x->id == id)
170 return f;
172 return 0;
175 #endif
177 #ifdef HAVE_X_WINDOWS
178 /* Return the mouse position in *X and *Y. The coordinates are window
179 relative for the edit window in frame F.
180 This is for Fx_popup_menu. The mouse_position_hook can not
181 be used for X, as it returns window relative coordinates
182 for the window where the mouse is in. This could be the menu bar,
183 the scroll bar or the edit window. Fx_popup_menu needs to be
184 sure it is the edit window. */
185 void
186 mouse_position_for_popup (FRAME_PTR f, int *x, int *y)
188 Window root, dummy_window;
189 int dummy;
191 if (! FRAME_X_P (f))
192 abort ();
194 BLOCK_INPUT;
196 XQueryPointer (FRAME_X_DISPLAY (f),
197 DefaultRootWindow (FRAME_X_DISPLAY (f)),
199 /* The root window which contains the pointer. */
200 &root,
202 /* Window pointer is on, not used */
203 &dummy_window,
205 /* The position on that root window. */
206 x, y,
208 /* x/y in dummy_window coordinates, not used. */
209 &dummy, &dummy,
211 /* Modifier keys and pointer buttons, about which
212 we don't care. */
213 (unsigned int *) &dummy);
215 UNBLOCK_INPUT;
217 /* xmenu_show expects window coordinates, not root window
218 coordinates. Translate. */
219 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
220 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
223 #endif /* HAVE_X_WINDOWS */
225 #ifdef HAVE_MENUS
227 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
228 doc: /* Pop up a dialog box and return user's selection.
229 POSITION specifies which frame to use.
230 This is normally a mouse button event or a window or frame.
231 If POSITION is t, it means to use the frame the mouse is on.
232 The dialog box appears in the middle of the specified frame.
234 CONTENTS specifies the alternatives to display in the dialog box.
235 It is a list of the form (DIALOG ITEM1 ITEM2...).
236 Each ITEM is a cons cell (STRING . VALUE).
237 The return value is VALUE from the chosen item.
239 An ITEM may also be just a string--that makes a nonselectable item.
240 An ITEM may also be nil--that means to put all preceding items
241 on the left of the dialog box and all following items on the right.
242 \(By default, approximately half appear on each side.)
244 If HEADER is non-nil, the frame title for the box is "Information",
245 otherwise it is "Question".
247 If the user gets rid of the dialog box without making a valid choice,
248 for instance using the window manager, then this produces a quit and
249 `x-popup-dialog' does not return. */)
250 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
252 FRAME_PTR f = NULL;
253 Lisp_Object window;
255 check_x ();
257 /* Decode the first argument: find the window or frame to use. */
258 if (EQ (position, Qt)
259 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
260 || EQ (XCAR (position), Qtool_bar))))
262 #if 0 /* Using the frame the mouse is on may not be right. */
263 /* Use the mouse's current position. */
264 FRAME_PTR new_f = SELECTED_FRAME ();
265 Lisp_Object bar_window;
266 enum scroll_bar_part part;
267 unsigned long time;
268 Lisp_Object x, y;
270 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
272 if (new_f != 0)
273 XSETFRAME (window, new_f);
274 else
275 window = selected_window;
276 #endif
277 window = selected_window;
279 else if (CONSP (position))
281 Lisp_Object tem;
282 tem = Fcar (position);
283 if (CONSP (tem))
284 window = Fcar (Fcdr (position));
285 else
287 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
288 window = Fcar (tem); /* POSN_WINDOW (tem) */
291 else if (WINDOWP (position) || FRAMEP (position))
292 window = position;
293 else
294 window = Qnil;
296 /* Decode where to put the menu. */
298 if (FRAMEP (window))
299 f = XFRAME (window);
300 else if (WINDOWP (window))
302 CHECK_LIVE_WINDOW (window);
303 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
305 else
306 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
307 but I don't want to make one now. */
308 CHECK_WINDOW (window);
310 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
311 error ("Can not put X dialog on this terminal");
313 /* Force a redisplay before showing the dialog. If a frame is created
314 just before showing the dialog, its contents may not have been fully
315 drawn, as this depends on timing of events from the X server. Redisplay
316 is not done when a dialog is shown. If redisplay could be done in the
317 X event loop (i.e. the X event loop does not run in a signal handler)
318 this would not be needed.
320 Do this before creating the widget value that points to Lisp
321 string contents, because Fredisplay may GC and relocate them. */
322 Fredisplay (Qt);
324 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
325 /* Display a menu with these alternatives
326 in the middle of frame F. */
328 Lisp_Object x, y, frame, newpos;
329 XSETFRAME (frame, f);
330 XSETINT (x, x_pixel_width (f) / 2);
331 XSETINT (y, x_pixel_height (f) / 2);
332 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
334 return Fx_popup_menu (newpos,
335 Fcons (Fcar (contents), Fcons (contents, Qnil)));
337 #else
339 Lisp_Object title;
340 char *error_name;
341 Lisp_Object selection;
342 int specpdl_count = SPECPDL_INDEX ();
344 /* Decode the dialog items from what was specified. */
345 title = Fcar (contents);
346 CHECK_STRING (title);
347 record_unwind_protect (unuse_menu_items, Qnil);
349 if (NILP (Fcar (Fcdr (contents))))
350 /* No buttons specified, add an "Ok" button so users can pop down
351 the dialog. Also, the lesstif/motif version crashes if there are
352 no buttons. */
353 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
355 list_of_panes (Fcons (contents, Qnil));
357 /* Display them in a dialog box. */
358 BLOCK_INPUT;
359 selection = xdialog_show (f, 0, title, header, &error_name);
360 UNBLOCK_INPUT;
362 unbind_to (specpdl_count, Qnil);
363 discard_menu_items ();
365 if (error_name) error (error_name);
366 return selection;
368 #endif
372 #ifndef MSDOS
374 /* Set menu_items_inuse so no other popup menu or dialog is created. */
376 void
377 x_menu_set_in_use (int in_use)
379 menu_items_inuse = in_use ? Qt : Qnil;
380 popup_activated_flag = in_use;
381 #ifdef USE_X_TOOLKIT
382 if (popup_activated_flag)
383 x_activate_timeout_atimer ();
384 #endif
387 /* Wait for an X event to arrive or for a timer to expire. */
389 void
390 x_menu_wait_for_event (void *data)
392 /* Another way to do this is to register a timer callback, that can be
393 done in GTK and Xt. But we have to do it like this when using only X
394 anyway, and with callbacks we would have three variants for timer handling
395 instead of the small ifdefs below. */
397 while (
398 #ifdef USE_X_TOOLKIT
399 ! XtAppPending (Xt_app_con)
400 #elif defined USE_GTK
401 ! gtk_events_pending ()
402 #else
403 ! XPending ((Display*) data)
404 #endif
407 EMACS_TIME next_time = timer_check (1), *ntp;
408 long secs = EMACS_SECS (next_time);
409 long usecs = EMACS_USECS (next_time);
410 SELECT_TYPE read_fds;
411 struct x_display_info *dpyinfo;
412 int n = 0;
414 FD_ZERO (&read_fds);
415 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
417 int fd = ConnectionNumber (dpyinfo->display);
418 FD_SET (fd, &read_fds);
419 if (fd > n) n = fd;
420 XFlush (dpyinfo->display);
423 if (secs < 0 && usecs < 0)
424 ntp = 0;
425 else
426 ntp = &next_time;
428 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
431 #endif /* ! MSDOS */
434 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
436 #ifdef USE_X_TOOLKIT
438 /* Loop in Xt until the menu pulldown or dialog popup has been
439 popped down (deactivated). This is used for x-popup-menu
440 and x-popup-dialog; it is not used for the menu bar.
442 NOTE: All calls to popup_get_selection should be protected
443 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
445 static void
446 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo, LWLIB_ID id, int do_timers)
448 XEvent event;
450 while (popup_activated_flag)
452 if (initial_event)
454 event = *initial_event;
455 initial_event = 0;
457 else
459 if (do_timers) x_menu_wait_for_event (0);
460 XtAppNextEvent (Xt_app_con, &event);
463 /* Make sure we don't consider buttons grabbed after menu goes.
464 And make sure to deactivate for any ButtonRelease,
465 even if XtDispatchEvent doesn't do that. */
466 if (event.type == ButtonRelease
467 && dpyinfo->display == event.xbutton.display)
469 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
470 #ifdef USE_MOTIF /* Pretending that the event came from a
471 Btn1Down seems the only way to convince Motif to
472 activate its callbacks; setting the XmNmenuPost
473 isn't working. --marcus@sysc.pdx.edu. */
474 event.xbutton.button = 1;
475 /* Motif only pops down menus when no Ctrl, Alt or Mod
476 key is pressed and the button is released. So reset key state
477 so Motif thinks this is the case. */
478 event.xbutton.state = 0;
479 #endif
481 /* Pop down on C-g and Escape. */
482 else if (event.type == KeyPress
483 && dpyinfo->display == event.xbutton.display)
485 KeySym keysym = XLookupKeysym (&event.xkey, 0);
487 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
488 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
489 popup_activated_flag = 0;
492 x_dispatch_event (&event, event.xany.display);
496 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
497 doc: /* Start key navigation of the menu bar in FRAME.
498 This initially opens the first menu bar item and you can then navigate with the
499 arrow keys, select a menu entry with the return key or cancel with the
500 escape key. If FRAME has no menu bar this function does nothing.
502 If FRAME is nil or not given, use the selected frame. */)
503 (Lisp_Object frame)
505 XEvent ev;
506 FRAME_PTR f = check_x_frame (frame);
507 Widget menubar;
508 BLOCK_INPUT;
510 if (FRAME_EXTERNAL_MENU_BAR (f))
511 set_frame_menubar (f, 0, 1);
513 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
514 if (menubar)
516 Window child;
517 int error_p = 0;
519 x_catch_errors (FRAME_X_DISPLAY (f));
520 memset (&ev, 0, sizeof ev);
521 ev.xbutton.display = FRAME_X_DISPLAY (f);
522 ev.xbutton.window = XtWindow (menubar);
523 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
524 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
525 ev.xbutton.button = Button1;
526 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
527 ev.xbutton.same_screen = True;
529 #ifdef USE_MOTIF
531 Arg al[2];
532 WidgetList list;
533 Cardinal nr;
534 XtSetArg (al[0], XtNchildren, &list);
535 XtSetArg (al[1], XtNnumChildren, &nr);
536 XtGetValues (menubar, al, 2);
537 ev.xbutton.window = XtWindow (list[0]);
539 #endif
541 XTranslateCoordinates (FRAME_X_DISPLAY (f),
542 /* From-window, to-window. */
543 ev.xbutton.window, ev.xbutton.root,
545 /* From-position, to-position. */
546 ev.xbutton.x, ev.xbutton.y,
547 &ev.xbutton.x_root, &ev.xbutton.y_root,
549 /* Child of win. */
550 &child);
551 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
552 x_uncatch_errors ();
554 if (! error_p)
556 ev.type = ButtonPress;
557 ev.xbutton.state = 0;
559 XtDispatchEvent (&ev);
560 ev.xbutton.type = ButtonRelease;
561 ev.xbutton.state = Button1Mask;
562 XtDispatchEvent (&ev);
566 UNBLOCK_INPUT;
568 return Qnil;
570 #endif /* USE_X_TOOLKIT */
573 #ifdef USE_GTK
574 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
575 doc: /* Start key navigation of the menu bar in FRAME.
576 This initially opens the first menu bar item and you can then navigate with the
577 arrow keys, select a menu entry with the return key or cancel with the
578 escape key. If FRAME has no menu bar this function does nothing.
580 If FRAME is nil or not given, use the selected frame. */)
581 (Lisp_Object frame)
583 GtkWidget *menubar;
584 FRAME_PTR f;
586 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
587 BLOCK_INPUT. */
589 BLOCK_INPUT;
590 f = check_x_frame (frame);
592 if (FRAME_EXTERNAL_MENU_BAR (f))
593 set_frame_menubar (f, 0, 1);
595 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
596 if (menubar)
598 /* Activate the first menu. */
599 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
601 if (children)
603 g_signal_emit_by_name (children->data, "activate_item");
604 popup_activated_flag = 1;
605 g_list_free (children);
608 UNBLOCK_INPUT;
610 return Qnil;
613 /* Loop util popup_activated_flag is set to zero in a callback.
614 Used for popup menus and dialogs. */
616 static void
617 popup_widget_loop (int do_timers, GtkWidget *widget)
619 ++popup_activated_flag;
621 /* Process events in the Gtk event loop until done. */
622 while (popup_activated_flag)
624 if (do_timers) x_menu_wait_for_event (0);
625 gtk_main_iteration ();
628 #endif
630 /* Activate the menu bar of frame F.
631 This is called from keyboard.c when it gets the
632 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
634 To activate the menu bar, we use the X button-press event
635 that was saved in saved_menu_event.
636 That makes the toolkit do its thing.
638 But first we recompute the menu bar contents (the whole tree).
640 The reason for saving the button event until here, instead of
641 passing it to the toolkit right away, is that we can safely
642 execute Lisp code. */
644 void
645 x_activate_menubar (FRAME_PTR f)
647 if (! FRAME_X_P (f))
648 abort ();
650 if (!f->output_data.x->saved_menu_event->type)
651 return;
653 #ifdef USE_GTK
654 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
655 f->output_data.x->saved_menu_event->xany.window))
656 return;
657 #endif
659 set_frame_menubar (f, 0, 1);
660 BLOCK_INPUT;
661 popup_activated_flag = 1;
662 #ifdef USE_GTK
663 XPutBackEvent (f->output_data.x->display_info->display,
664 f->output_data.x->saved_menu_event);
665 #else
666 XtDispatchEvent (f->output_data.x->saved_menu_event);
667 #endif
668 UNBLOCK_INPUT;
670 /* Ignore this if we get it a second time. */
671 f->output_data.x->saved_menu_event->type = 0;
674 /* This callback is invoked when the user selects a menubar cascade
675 pushbutton, but before the pulldown menu is posted. */
677 #ifndef USE_GTK
678 static void
679 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
681 popup_activated_flag = 1;
682 #ifdef USE_X_TOOLKIT
683 x_activate_timeout_atimer ();
684 #endif
686 #endif
688 /* This callback is invoked when a dialog or menu is finished being
689 used and has been unposted. */
691 #ifdef USE_GTK
692 static void
693 popup_deactivate_callback (GtkWidget *widget, gpointer client_data)
695 popup_activated_flag = 0;
697 #else
698 static void
699 popup_deactivate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
701 popup_activated_flag = 0;
703 #endif
706 /* Function that finds the frame for WIDGET and shows the HELP text
707 for that widget.
708 F is the frame if known, or NULL if not known. */
709 static void
710 show_help_event (FRAME_PTR f, xt_or_gtk_widget widget, Lisp_Object help)
712 Lisp_Object frame;
714 if (f)
716 XSETFRAME (frame, f);
717 kbd_buffer_store_help_event (frame, help);
719 else
721 #if 0 /* This code doesn't do anything useful. ++kfs */
722 /* WIDGET is the popup menu. It's parent is the frame's
723 widget. See which frame that is. */
724 xt_or_gtk_widget frame_widget = XtParent (widget);
725 Lisp_Object tail;
727 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
729 frame = XCAR (tail);
730 if (FRAMEP (frame)
731 && (f = XFRAME (frame),
732 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
733 break;
735 #endif
736 show_help_echo (help, Qnil, Qnil, Qnil, 1);
740 /* Callback called when menu items are highlighted/unhighlighted
741 while moving the mouse over them. WIDGET is the menu bar or menu
742 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
743 the data structure for the menu item, or null in case of
744 unhighlighting. */
746 #ifdef USE_GTK
747 void
748 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
750 xg_menu_item_cb_data *cb_data;
751 Lisp_Object help;
753 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
754 XG_ITEM_DATA);
755 if (! cb_data) return;
757 help = call_data ? cb_data->help : Qnil;
759 /* If popup_activated_flag is greater than 1 we are in a popup menu.
760 Don't show help for them, they won't appear before the
761 popup is popped down. */
762 if (popup_activated_flag <= 1)
763 show_help_event (cb_data->cl_data->f, widget, help);
765 #else
766 void
767 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
769 struct frame *f;
770 Lisp_Object help;
772 widget_value *wv = (widget_value *) call_data;
774 help = wv ? wv->help : Qnil;
776 /* Determine the frame for the help event. */
777 f = menubar_id_to_frame (id);
779 show_help_event (f, widget, help);
781 #endif
783 #ifdef USE_GTK
784 /* Gtk calls callbacks just because we tell it what item should be
785 selected in a radio group. If this variable is set to a non-zero
786 value, we are creating menus and don't want callbacks right now.
788 static int xg_crazy_callback_abort;
790 /* This callback is called from the menu bar pulldown menu
791 when the user makes a selection.
792 Figure out what the user chose
793 and put the appropriate events into the keyboard buffer. */
794 static void
795 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
797 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
799 if (xg_crazy_callback_abort)
800 return;
802 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
803 return;
805 /* For a group of radio buttons, GTK calls the selection callback first
806 for the item that was active before the selection and then for the one that
807 is active after the selection. For C-h k this means we get the help on
808 the deselected item and then the selected item is executed. Prevent that
809 by ignoring the non-active item. */
810 if (GTK_IS_RADIO_MENU_ITEM (widget)
811 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
812 return;
814 /* When a menu is popped down, X generates a focus event (i.e. focus
815 goes back to the frame below the menu). Since GTK buffers events,
816 we force it out here before the menu selection event. Otherwise
817 sit-for will exit at once if the focus event follows the menu selection
818 event. */
820 BLOCK_INPUT;
821 while (gtk_events_pending ())
822 gtk_main_iteration ();
823 UNBLOCK_INPUT;
825 find_and_call_menu_selection (cb_data->cl_data->f,
826 cb_data->cl_data->menu_bar_items_used,
827 cb_data->cl_data->menu_bar_vector,
828 cb_data->call_data);
831 #else /* not USE_GTK */
833 /* This callback is called from the menu bar pulldown menu
834 when the user makes a selection.
835 Figure out what the user chose
836 and put the appropriate events into the keyboard buffer. */
837 static void
838 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
840 FRAME_PTR f;
842 f = menubar_id_to_frame (id);
843 if (!f)
844 return;
845 find_and_call_menu_selection (f, f->menu_bar_items_used,
846 f->menu_bar_vector, client_data);
848 #endif /* not USE_GTK */
850 /* Recompute all the widgets of frame F, when the menu bar has been
851 changed. Value is non-zero if widgets were updated. */
853 static int
854 update_frame_menubar (FRAME_PTR f)
856 #ifdef USE_GTK
857 return xg_update_frame_menubar (f);
858 #else
859 struct x_output *x;
860 int columns, rows;
862 if (! FRAME_X_P (f))
863 abort ();
865 x = f->output_data.x;
867 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
868 return 0;
870 BLOCK_INPUT;
871 /* Save the size of the frame because the pane widget doesn't accept
872 to resize itself. So force it. */
873 columns = FRAME_COLS (f);
874 rows = FRAME_LINES (f);
876 /* Do the voodoo which means "I'm changing lots of things, don't try
877 to refigure sizes until I'm done." */
878 lw_refigure_widget (x->column_widget, False);
880 /* The order in which children are managed is the top to bottom
881 order in which they are displayed in the paned window. First,
882 remove the text-area widget. */
883 XtUnmanageChild (x->edit_widget);
885 /* Remove the menubar that is there now, and put up the menubar that
886 should be there. */
887 XtManageChild (x->menubar_widget);
888 XtMapWidget (x->menubar_widget);
889 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
891 /* Re-manage the text-area widget, and then thrash the sizes. */
892 XtManageChild (x->edit_widget);
893 lw_refigure_widget (x->column_widget, True);
895 /* Force the pane widget to resize itself with the right values. */
896 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
897 UNBLOCK_INPUT;
898 #endif
899 return 1;
902 #ifdef USE_LUCID
903 static void
904 apply_systemfont_to_dialog (Widget w)
906 const char *fn = xsettings_get_system_normal_font ();
907 if (fn)
909 XrmDatabase db = XtDatabase (XtDisplay (w));
910 if (db)
911 XrmPutStringResource (&db, "*dialog.faceName", fn);
915 static void
916 apply_systemfont_to_menu (Widget w)
918 const char *fn = xsettings_get_system_normal_font ();
919 int defflt;
921 if (!fn) return;
923 if (XtIsShell (w)) /* popup menu */
925 Widget *childs = NULL;
927 XtVaGetValues (w, XtNchildren, &childs, NULL);
928 if (*childs) w = *childs;
931 /* Only use system font if the default is used for the menu. */
932 XtVaGetValues (w, XtNdefaultFace, &defflt, NULL);
933 if (defflt)
934 XtVaSetValues (w, XtNfaceName, fn, NULL);
936 #endif
938 /* Set the contents of the menubar widgets of frame F.
939 The argument FIRST_TIME is currently ignored;
940 it is set the first time this is called, from initialize_frame_menubar. */
942 void
943 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
945 xt_or_gtk_widget menubar_widget;
946 #ifdef USE_X_TOOLKIT
947 LWLIB_ID id;
948 #endif
949 Lisp_Object items;
950 widget_value *wv, *first_wv, *prev_wv = 0;
951 int i, last_i = 0;
952 int *submenu_start, *submenu_end;
953 int *submenu_top_level_items, *submenu_n_panes;
955 if (! FRAME_X_P (f))
956 abort ();
958 menubar_widget = f->output_data.x->menubar_widget;
960 XSETFRAME (Vmenu_updating_frame, f);
962 #ifdef USE_X_TOOLKIT
963 if (f->output_data.x->id == 0)
964 f->output_data.x->id = next_menubar_widget_id++;
965 id = f->output_data.x->id;
966 #endif
968 if (! menubar_widget)
969 deep_p = 1;
970 /* Make the first call for any given frame always go deep. */
971 else if (!f->output_data.x->saved_menu_event && !deep_p)
973 deep_p = 1;
974 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
975 f->output_data.x->saved_menu_event->type = 0;
978 #ifdef USE_GTK
979 /* If we have detached menus, we must update deep so detached menus
980 also gets updated. */
981 deep_p = deep_p || xg_have_tear_offs ();
982 #endif
984 if (deep_p)
986 /* Make a widget-value tree representing the entire menu trees. */
988 struct buffer *prev = current_buffer;
989 Lisp_Object buffer;
990 int specpdl_count = SPECPDL_INDEX ();
991 int previous_menu_items_used = f->menu_bar_items_used;
992 Lisp_Object *previous_items
993 = (Lisp_Object *) alloca (previous_menu_items_used
994 * sizeof (Lisp_Object));
996 /* If we are making a new widget, its contents are empty,
997 do always reinitialize them. */
998 if (! menubar_widget)
999 previous_menu_items_used = 0;
1001 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1002 specbind (Qinhibit_quit, Qt);
1003 /* Don't let the debugger step into this code
1004 because it is not reentrant. */
1005 specbind (Qdebug_on_next_call, Qnil);
1007 record_unwind_save_match_data ();
1008 if (NILP (Voverriding_local_map_menu_flag))
1010 specbind (Qoverriding_terminal_local_map, Qnil);
1011 specbind (Qoverriding_local_map, Qnil);
1014 set_buffer_internal_1 (XBUFFER (buffer));
1016 /* Run the Lucid hook. */
1017 safe_run_hooks (Qactivate_menubar_hook);
1019 /* If it has changed current-menubar from previous value,
1020 really recompute the menubar from the value. */
1021 if (! NILP (Vlucid_menu_bar_dirty_flag))
1022 call0 (Qrecompute_lucid_menubar);
1023 safe_run_hooks (Qmenu_bar_update_hook);
1024 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1026 items = FRAME_MENU_BAR_ITEMS (f);
1028 /* Save the frame's previous menu bar contents data. */
1029 if (previous_menu_items_used)
1030 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
1031 previous_menu_items_used * sizeof (Lisp_Object));
1033 /* Fill in menu_items with the current menu bar contents.
1034 This can evaluate Lisp code. */
1035 save_menu_items ();
1037 menu_items = f->menu_bar_vector;
1038 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1039 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1040 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1041 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1042 submenu_top_level_items
1043 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1044 init_menu_items ();
1045 for (i = 0; i < XVECTOR (items)->size; i += 4)
1047 Lisp_Object key, string, maps;
1049 last_i = i;
1051 key = XVECTOR (items)->contents[i];
1052 string = XVECTOR (items)->contents[i + 1];
1053 maps = XVECTOR (items)->contents[i + 2];
1054 if (NILP (string))
1055 break;
1057 submenu_start[i] = menu_items_used;
1059 menu_items_n_panes = 0;
1060 submenu_top_level_items[i]
1061 = parse_single_submenu (key, string, maps);
1062 submenu_n_panes[i] = menu_items_n_panes;
1064 submenu_end[i] = menu_items_used;
1067 finish_menu_items ();
1069 /* Convert menu_items into widget_value trees
1070 to display the menu. This cannot evaluate Lisp code. */
1072 wv = xmalloc_widget_value ();
1073 wv->name = "menubar";
1074 wv->value = 0;
1075 wv->enabled = 1;
1076 wv->button_type = BUTTON_TYPE_NONE;
1077 wv->help = Qnil;
1078 first_wv = wv;
1080 for (i = 0; i < last_i; i += 4)
1082 menu_items_n_panes = submenu_n_panes[i];
1083 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1084 submenu_top_level_items[i]);
1085 if (prev_wv)
1086 prev_wv->next = wv;
1087 else
1088 first_wv->contents = wv;
1089 /* Don't set wv->name here; GC during the loop might relocate it. */
1090 wv->enabled = 1;
1091 wv->button_type = BUTTON_TYPE_NONE;
1092 prev_wv = wv;
1095 set_buffer_internal_1 (prev);
1097 /* If there has been no change in the Lisp-level contents
1098 of the menu bar, skip redisplaying it. Just exit. */
1100 /* Compare the new menu items with the ones computed last time. */
1101 for (i = 0; i < previous_menu_items_used; i++)
1102 if (menu_items_used == i
1103 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1104 break;
1105 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1107 /* The menu items have not changed. Don't bother updating
1108 the menus in any form, since it would be a no-op. */
1109 free_menubar_widget_value_tree (first_wv);
1110 discard_menu_items ();
1111 unbind_to (specpdl_count, Qnil);
1112 return;
1115 /* The menu items are different, so store them in the frame. */
1116 f->menu_bar_vector = menu_items;
1117 f->menu_bar_items_used = menu_items_used;
1119 /* This undoes save_menu_items. */
1120 unbind_to (specpdl_count, Qnil);
1122 /* Now GC cannot happen during the lifetime of the widget_value,
1123 so it's safe to store data from a Lisp_String. */
1124 wv = first_wv->contents;
1125 for (i = 0; i < XVECTOR (items)->size; i += 4)
1127 Lisp_Object string;
1128 string = XVECTOR (items)->contents[i + 1];
1129 if (NILP (string))
1130 break;
1131 wv->name = (char *) SDATA (string);
1132 update_submenu_strings (wv->contents);
1133 wv = wv->next;
1137 else
1139 /* Make a widget-value tree containing
1140 just the top level menu bar strings. */
1142 wv = xmalloc_widget_value ();
1143 wv->name = "menubar";
1144 wv->value = 0;
1145 wv->enabled = 1;
1146 wv->button_type = BUTTON_TYPE_NONE;
1147 wv->help = Qnil;
1148 first_wv = wv;
1150 items = FRAME_MENU_BAR_ITEMS (f);
1151 for (i = 0; i < XVECTOR (items)->size; i += 4)
1153 Lisp_Object string;
1155 string = XVECTOR (items)->contents[i + 1];
1156 if (NILP (string))
1157 break;
1159 wv = xmalloc_widget_value ();
1160 wv->name = (char *) SDATA (string);
1161 wv->value = 0;
1162 wv->enabled = 1;
1163 wv->button_type = BUTTON_TYPE_NONE;
1164 wv->help = Qnil;
1165 /* This prevents lwlib from assuming this
1166 menu item is really supposed to be empty. */
1167 /* The EMACS_INT cast avoids a warning.
1168 This value just has to be different from small integers. */
1169 wv->call_data = (void *) (EMACS_INT) (-1);
1171 if (prev_wv)
1172 prev_wv->next = wv;
1173 else
1174 first_wv->contents = wv;
1175 prev_wv = wv;
1178 /* Forget what we thought we knew about what is in the
1179 detailed contents of the menu bar menus.
1180 Changing the top level always destroys the contents. */
1181 f->menu_bar_items_used = 0;
1184 /* Create or update the menu bar widget. */
1186 BLOCK_INPUT;
1188 #ifdef USE_GTK
1189 xg_crazy_callback_abort = 1;
1190 if (menubar_widget)
1192 /* The fourth arg is DEEP_P, which says to consider the entire
1193 menu trees we supply, rather than just the menu bar item names. */
1194 xg_modify_menubar_widgets (menubar_widget,
1196 first_wv,
1197 deep_p,
1198 G_CALLBACK (menubar_selection_callback),
1199 G_CALLBACK (popup_deactivate_callback),
1200 G_CALLBACK (menu_highlight_callback));
1202 else
1204 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1206 menubar_widget
1207 = xg_create_widget ("menubar", "menubar", f, first_wv,
1208 G_CALLBACK (menubar_selection_callback),
1209 G_CALLBACK (popup_deactivate_callback),
1210 G_CALLBACK (menu_highlight_callback));
1212 f->output_data.x->menubar_widget = menubar_widget;
1216 #else /* not USE_GTK */
1217 if (menubar_widget)
1219 /* Disable resizing (done for Motif!) */
1220 lw_allow_resizing (f->output_data.x->widget, False);
1222 /* The third arg is DEEP_P, which says to consider the entire
1223 menu trees we supply, rather than just the menu bar item names. */
1224 lw_modify_all_widgets (id, first_wv, deep_p);
1226 /* Re-enable the edit widget to resize. */
1227 lw_allow_resizing (f->output_data.x->widget, True);
1229 else
1231 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1232 XtTranslations override = XtParseTranslationTable (menuOverride);
1234 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1235 f->output_data.x->column_widget,
1237 popup_activate_callback,
1238 menubar_selection_callback,
1239 popup_deactivate_callback,
1240 menu_highlight_callback);
1241 f->output_data.x->menubar_widget = menubar_widget;
1243 /* Make menu pop down on C-g. */
1244 XtOverrideTranslations (menubar_widget, override);
1245 #ifdef USE_LUCID
1246 apply_systemfont_to_menu (menubar_widget);
1247 #endif
1251 int menubar_size;
1252 if (f->output_data.x->menubar_widget)
1253 XtRealizeWidget (f->output_data.x->menubar_widget);
1255 menubar_size
1256 = (f->output_data.x->menubar_widget
1257 ? (f->output_data.x->menubar_widget->core.height
1258 + f->output_data.x->menubar_widget->core.border_width)
1259 : 0);
1261 #if 1 /* Experimentally, we now get the right results
1262 for -geometry -0-0 without this. 24 Aug 96, rms.
1263 Maybe so, but the menu bar size is missing the pixels so the
1264 WM size hints are off by these pixels. Jan D, oct 2009. */
1265 #ifdef USE_LUCID
1266 if (FRAME_EXTERNAL_MENU_BAR (f))
1268 Dimension ibw = 0;
1269 XtVaGetValues (f->output_data.x->column_widget,
1270 XtNinternalBorderWidth, &ibw, NULL);
1271 menubar_size += ibw;
1273 #endif /* USE_LUCID */
1274 #endif /* 1 */
1276 f->output_data.x->menubar_height = menubar_size;
1278 #endif /* not USE_GTK */
1280 free_menubar_widget_value_tree (first_wv);
1281 update_frame_menubar (f);
1283 #ifdef USE_GTK
1284 xg_crazy_callback_abort = 0;
1285 #endif
1287 UNBLOCK_INPUT;
1290 /* Called from Fx_create_frame to create the initial menubar of a frame
1291 before it is mapped, so that the window is mapped with the menubar already
1292 there instead of us tacking it on later and thrashing the window after it
1293 is visible. */
1295 void
1296 initialize_frame_menubar (FRAME_PTR f)
1298 /* This function is called before the first chance to redisplay
1299 the frame. It has to be, so the frame will have the right size. */
1300 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1301 set_frame_menubar (f, 1, 1);
1305 /* Get rid of the menu bar of frame F, and free its storage.
1306 This is used when deleting a frame, and when turning off the menu bar.
1307 For GTK this function is in gtkutil.c. */
1309 #ifndef USE_GTK
1310 void
1311 free_frame_menubar (FRAME_PTR f)
1313 Widget menubar_widget;
1315 if (! FRAME_X_P (f))
1316 abort ();
1318 menubar_widget = f->output_data.x->menubar_widget;
1320 f->output_data.x->menubar_height = 0;
1322 if (menubar_widget)
1324 #ifdef USE_MOTIF
1325 /* Removing the menu bar magically changes the shell widget's x
1326 and y position of (0, 0) which, when the menu bar is turned
1327 on again, leads to pull-down menuss appearing in strange
1328 positions near the upper-left corner of the display. This
1329 happens only with some window managers like twm and ctwm,
1330 but not with other like Motif's mwm or kwm, because the
1331 latter generate ConfigureNotify events when the menu bar
1332 is switched off, which fixes the shell position. */
1333 Position x0, y0, x1, y1;
1334 #endif
1336 BLOCK_INPUT;
1338 #ifdef USE_MOTIF
1339 if (f->output_data.x->widget)
1340 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1341 #endif
1343 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1344 f->output_data.x->menubar_widget = NULL;
1346 if (f->output_data.x->widget)
1348 #ifdef USE_MOTIF
1349 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1350 if (x1 == 0 && y1 == 0)
1351 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1352 #endif
1353 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1355 UNBLOCK_INPUT;
1358 #endif /* not USE_GTK */
1360 #endif /* USE_X_TOOLKIT || USE_GTK */
1362 /* xmenu_show actually displays a menu using the panes and items in menu_items
1363 and returns the value selected from it.
1364 There are two versions of xmenu_show, one for Xt and one for Xlib.
1365 Both assume input is blocked by the caller. */
1367 /* F is the frame the menu is for.
1368 X and Y are the frame-relative specified position,
1369 relative to the inside upper left corner of the frame F.
1370 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1371 KEYMAPS is 1 if this menu was specified with keymaps;
1372 in that case, we return a list containing the chosen item's value
1373 and perhaps also the pane's prefix.
1374 TITLE is the specified menu title.
1375 ERROR is a place to store an error message string in case of failure.
1376 (We return nil on failure, but the value doesn't actually matter.) */
1378 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1380 /* The item selected in the popup menu. */
1381 static Lisp_Object *volatile menu_item_selection;
1383 #ifdef USE_GTK
1385 /* Used when position a popup menu. See menu_position_func and
1386 create_and_show_popup_menu below. */
1387 struct next_popup_x_y
1389 FRAME_PTR f;
1390 int x;
1391 int y;
1394 /* The menu position function to use if we are not putting a popup
1395 menu where the pointer is.
1396 MENU is the menu to pop up.
1397 X and Y shall on exit contain x/y where the menu shall pop up.
1398 PUSH_IN is not documented in the GTK manual.
1399 USER_DATA is any data passed in when calling gtk_menu_popup.
1400 Here it points to a struct next_popup_x_y where the coordinates
1401 to store in *X and *Y are as well as the frame for the popup.
1403 Here only X and Y are used. */
1404 static void
1405 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1407 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1408 GtkRequisition req;
1409 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1410 int disp_width = x_display_pixel_width (dpyinfo);
1411 int disp_height = x_display_pixel_height (dpyinfo);
1413 *x = data->x;
1414 *y = data->y;
1416 /* Check if there is room for the menu. If not, adjust x/y so that
1417 the menu is fully visible. */
1418 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1419 if (data->x + req.width > disp_width)
1420 *x -= data->x + req.width - disp_width;
1421 if (data->y + req.height > disp_height)
1422 *y -= data->y + req.height - disp_height;
1425 static void
1426 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1428 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1430 if (xg_crazy_callback_abort) return;
1431 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1434 static Lisp_Object
1435 pop_down_menu (Lisp_Object arg)
1437 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1439 popup_activated_flag = 0;
1440 BLOCK_INPUT;
1441 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1442 UNBLOCK_INPUT;
1443 return Qnil;
1446 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1447 menu pops down.
1448 menu_item_selection will be set to the selection. */
1449 static void
1450 create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, int for_click, EMACS_UINT timestamp)
1452 int i;
1453 GtkWidget *menu;
1454 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1455 struct next_popup_x_y popup_x_y;
1456 int specpdl_count = SPECPDL_INDEX ();
1458 if (! FRAME_X_P (f))
1459 abort ();
1461 xg_crazy_callback_abort = 1;
1462 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1463 G_CALLBACK (popup_selection_callback),
1464 G_CALLBACK (popup_deactivate_callback),
1465 G_CALLBACK (menu_highlight_callback));
1466 xg_crazy_callback_abort = 0;
1468 if (! for_click)
1470 /* Not invoked by a click. pop up at x/y. */
1471 pos_func = menu_position_func;
1473 /* Adjust coordinates to be root-window-relative. */
1474 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1475 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1477 popup_x_y.x = x;
1478 popup_x_y.y = y;
1479 popup_x_y.f = f;
1481 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1483 else
1485 for (i = 0; i < 5; i++)
1486 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1487 break;
1490 /* Display the menu. */
1491 gtk_widget_show_all (menu);
1493 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1494 timestamp > 0 ? timestamp : gtk_get_current_event_time());
1496 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1498 if (gtk_widget_get_mapped (menu))
1500 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1501 two. show_help_echo uses this to detect popup menus. */
1502 popup_activated_flag = 1;
1503 /* Process events that apply to the menu. */
1504 popup_widget_loop (1, menu);
1507 unbind_to (specpdl_count, Qnil);
1509 /* Must reset this manually because the button release event is not passed
1510 to Emacs event loop. */
1511 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1514 #else /* not USE_GTK */
1516 /* We need a unique id for each widget handled by the Lucid Widget
1517 library.
1519 For the main windows, and popup menus, we use this counter,
1520 which we increment each time after use. This starts from 1<<16.
1522 For menu bars, we use numbers starting at 0, counted in
1523 next_menubar_widget_id. */
1524 LWLIB_ID widget_id_tick;
1526 static void
1527 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1529 menu_item_selection = (Lisp_Object *) client_data;
1532 /* ARG is the LWLIB ID of the dialog box, represented
1533 as a Lisp object as (HIGHPART . LOWPART). */
1535 static Lisp_Object
1536 pop_down_menu (Lisp_Object arg)
1538 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1539 | XINT (XCDR (arg)));
1541 BLOCK_INPUT;
1542 lw_destroy_all_widgets (id);
1543 UNBLOCK_INPUT;
1544 popup_activated_flag = 0;
1546 return Qnil;
1549 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1550 menu pops down.
1551 menu_item_selection will be set to the selection. */
1552 static void
1553 create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv,
1554 int x, int y, int for_click, EMACS_UINT timestamp)
1556 int i;
1557 Arg av[2];
1558 int ac = 0;
1559 XButtonPressedEvent dummy;
1560 LWLIB_ID menu_id;
1561 Widget menu;
1563 if (! FRAME_X_P (f))
1564 abort ();
1566 menu_id = widget_id_tick++;
1567 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1568 f->output_data.x->widget, 1, 0,
1569 popup_selection_callback,
1570 popup_deactivate_callback,
1571 menu_highlight_callback);
1573 #ifdef USE_LUCID
1574 apply_systemfont_to_menu (menu);
1575 #endif
1577 dummy.type = ButtonPress;
1578 dummy.serial = 0;
1579 dummy.send_event = 0;
1580 dummy.display = FRAME_X_DISPLAY (f);
1581 dummy.time = CurrentTime;
1582 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1583 dummy.window = dummy.root;
1584 dummy.subwindow = dummy.root;
1585 dummy.x = x;
1586 dummy.y = y;
1588 /* Adjust coordinates to be root-window-relative. */
1589 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1590 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1592 dummy.x_root = x;
1593 dummy.y_root = y;
1595 dummy.state = 0;
1596 dummy.button = 0;
1597 for (i = 0; i < 5; i++)
1598 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1599 dummy.button = i;
1601 /* Don't allow any geometry request from the user. */
1602 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1603 XtSetValues (menu, av, ac);
1605 /* Display the menu. */
1606 lw_popup_menu (menu, (XEvent *) &dummy);
1607 popup_activated_flag = 1;
1608 x_activate_timeout_atimer ();
1611 int fact = 4 * sizeof (LWLIB_ID);
1612 int specpdl_count = SPECPDL_INDEX ();
1613 record_unwind_protect (pop_down_menu,
1614 Fcons (make_number (menu_id >> (fact)),
1615 make_number (menu_id & ~(-1 << (fact)))));
1617 /* Process events that apply to the menu. */
1618 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1620 unbind_to (specpdl_count, Qnil);
1624 #endif /* not USE_GTK */
1626 Lisp_Object
1627 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
1628 Lisp_Object title, char **error, EMACS_UINT timestamp)
1630 int i;
1631 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1632 widget_value **submenu_stack
1633 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1634 Lisp_Object *subprefix_stack
1635 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1636 int submenu_depth = 0;
1638 int first_pane;
1640 if (! FRAME_X_P (f))
1641 abort ();
1643 *error = NULL;
1645 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1647 *error = "Empty menu";
1648 return Qnil;
1651 /* Create a tree of widget_value objects
1652 representing the panes and their items. */
1653 wv = xmalloc_widget_value ();
1654 wv->name = "menu";
1655 wv->value = 0;
1656 wv->enabled = 1;
1657 wv->button_type = BUTTON_TYPE_NONE;
1658 wv->help =Qnil;
1659 first_wv = wv;
1660 first_pane = 1;
1662 /* Loop over all panes and items, filling in the tree. */
1663 i = 0;
1664 while (i < menu_items_used)
1666 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1668 submenu_stack[submenu_depth++] = save_wv;
1669 save_wv = prev_wv;
1670 prev_wv = 0;
1671 first_pane = 1;
1672 i++;
1674 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1676 prev_wv = save_wv;
1677 save_wv = submenu_stack[--submenu_depth];
1678 first_pane = 0;
1679 i++;
1681 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1682 && submenu_depth != 0)
1683 i += MENU_ITEMS_PANE_LENGTH;
1684 /* Ignore a nil in the item list.
1685 It's meaningful only for dialog boxes. */
1686 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1687 i += 1;
1688 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1690 /* Create a new pane. */
1691 Lisp_Object pane_name, prefix;
1692 char *pane_string;
1694 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1695 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1697 #ifndef HAVE_MULTILINGUAL_MENU
1698 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1700 pane_name = ENCODE_MENU_STRING (pane_name);
1701 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1703 #endif
1704 pane_string = (NILP (pane_name)
1705 ? "" : (char *) SDATA (pane_name));
1706 /* If there is just one top-level pane, put all its items directly
1707 under the top-level menu. */
1708 if (menu_items_n_panes == 1)
1709 pane_string = "";
1711 /* If the pane has a meaningful name,
1712 make the pane a top-level menu item
1713 with its items as a submenu beneath it. */
1714 if (!keymaps && strcmp (pane_string, ""))
1716 wv = xmalloc_widget_value ();
1717 if (save_wv)
1718 save_wv->next = wv;
1719 else
1720 first_wv->contents = wv;
1721 wv->name = pane_string;
1722 if (keymaps && !NILP (prefix))
1723 wv->name++;
1724 wv->value = 0;
1725 wv->enabled = 1;
1726 wv->button_type = BUTTON_TYPE_NONE;
1727 wv->help = Qnil;
1728 save_wv = wv;
1729 prev_wv = 0;
1731 else if (first_pane)
1733 save_wv = wv;
1734 prev_wv = 0;
1736 first_pane = 0;
1737 i += MENU_ITEMS_PANE_LENGTH;
1739 else
1741 /* Create a new item within current pane. */
1742 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1743 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1744 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1745 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1746 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1747 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1748 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1749 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1751 #ifndef HAVE_MULTILINGUAL_MENU
1752 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1754 item_name = ENCODE_MENU_STRING (item_name);
1755 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1758 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1760 descrip = ENCODE_MENU_STRING (descrip);
1761 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1763 #endif /* not HAVE_MULTILINGUAL_MENU */
1765 wv = xmalloc_widget_value ();
1766 if (prev_wv)
1767 prev_wv->next = wv;
1768 else
1769 save_wv->contents = wv;
1770 wv->name = (char *) SDATA (item_name);
1771 if (!NILP (descrip))
1772 wv->key = (char *) SDATA (descrip);
1773 wv->value = 0;
1774 /* If this item has a null value,
1775 make the call_data null so that it won't display a box
1776 when the mouse is on it. */
1777 wv->call_data
1778 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
1779 wv->enabled = !NILP (enable);
1781 if (NILP (type))
1782 wv->button_type = BUTTON_TYPE_NONE;
1783 else if (EQ (type, QCtoggle))
1784 wv->button_type = BUTTON_TYPE_TOGGLE;
1785 else if (EQ (type, QCradio))
1786 wv->button_type = BUTTON_TYPE_RADIO;
1787 else
1788 abort ();
1790 wv->selected = !NILP (selected);
1792 if (! STRINGP (help))
1793 help = Qnil;
1795 wv->help = help;
1797 prev_wv = wv;
1799 i += MENU_ITEMS_ITEM_LENGTH;
1803 /* Deal with the title, if it is non-nil. */
1804 if (!NILP (title))
1806 widget_value *wv_title = xmalloc_widget_value ();
1807 widget_value *wv_sep1 = xmalloc_widget_value ();
1808 widget_value *wv_sep2 = xmalloc_widget_value ();
1810 wv_sep2->name = "--";
1811 wv_sep2->next = first_wv->contents;
1812 wv_sep2->help = Qnil;
1814 wv_sep1->name = "--";
1815 wv_sep1->next = wv_sep2;
1816 wv_sep1->help = Qnil;
1818 #ifndef HAVE_MULTILINGUAL_MENU
1819 if (STRING_MULTIBYTE (title))
1820 title = ENCODE_MENU_STRING (title);
1821 #endif
1823 wv_title->name = (char *) SDATA (title);
1824 wv_title->enabled = TRUE;
1825 wv_title->button_type = BUTTON_TYPE_NONE;
1826 wv_title->help = Qnil;
1827 wv_title->next = wv_sep1;
1828 first_wv->contents = wv_title;
1831 /* No selection has been chosen yet. */
1832 menu_item_selection = 0;
1834 /* Actually create and show the menu until popped down. */
1835 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
1837 /* Free the widget_value objects we used to specify the contents. */
1838 free_menubar_widget_value_tree (first_wv);
1840 /* Find the selected item, and its pane, to return
1841 the proper value. */
1842 if (menu_item_selection != 0)
1844 Lisp_Object prefix, entry;
1846 prefix = entry = Qnil;
1847 i = 0;
1848 while (i < menu_items_used)
1850 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1852 subprefix_stack[submenu_depth++] = prefix;
1853 prefix = entry;
1854 i++;
1856 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1858 prefix = subprefix_stack[--submenu_depth];
1859 i++;
1861 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1863 prefix
1864 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1865 i += MENU_ITEMS_PANE_LENGTH;
1867 /* Ignore a nil in the item list.
1868 It's meaningful only for dialog boxes. */
1869 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1870 i += 1;
1871 else
1873 entry
1874 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1875 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1877 if (keymaps != 0)
1879 int j;
1881 entry = Fcons (entry, Qnil);
1882 if (!NILP (prefix))
1883 entry = Fcons (prefix, entry);
1884 for (j = submenu_depth - 1; j >= 0; j--)
1885 if (!NILP (subprefix_stack[j]))
1886 entry = Fcons (subprefix_stack[j], entry);
1888 return entry;
1890 i += MENU_ITEMS_ITEM_LENGTH;
1894 else if (!for_click)
1895 /* Make "Cancel" equivalent to C-g. */
1896 Fsignal (Qquit, Qnil);
1898 return Qnil;
1901 #ifdef USE_GTK
1902 static void
1903 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1905 /* The EMACS_INT cast avoids a warning. There's no problem
1906 as long as pointers have enough bits to hold small integers. */
1907 if ((int) (EMACS_INT) client_data != -1)
1908 menu_item_selection = (Lisp_Object *) client_data;
1910 popup_activated_flag = 0;
1913 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1914 dialog pops down.
1915 menu_item_selection will be set to the selection. */
1916 static void
1917 create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
1919 GtkWidget *menu;
1921 if (! FRAME_X_P (f))
1922 abort ();
1924 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1925 G_CALLBACK (dialog_selection_callback),
1926 G_CALLBACK (popup_deactivate_callback),
1929 if (menu)
1931 int specpdl_count = SPECPDL_INDEX ();
1932 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1934 /* Display the menu. */
1935 gtk_widget_show_all (menu);
1937 /* Process events that apply to the menu. */
1938 popup_widget_loop (1, menu);
1940 unbind_to (specpdl_count, Qnil);
1944 #else /* not USE_GTK */
1945 static void
1946 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1948 /* The EMACS_INT cast avoids a warning. There's no problem
1949 as long as pointers have enough bits to hold small integers. */
1950 if ((int) (EMACS_INT) client_data != -1)
1951 menu_item_selection = (Lisp_Object *) client_data;
1953 BLOCK_INPUT;
1954 lw_destroy_all_widgets (id);
1955 UNBLOCK_INPUT;
1956 popup_activated_flag = 0;
1960 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1961 dialog pops down.
1962 menu_item_selection will be set to the selection. */
1963 static void
1964 create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
1966 LWLIB_ID dialog_id;
1968 if (!FRAME_X_P (f))
1969 abort();
1971 dialog_id = widget_id_tick++;
1972 #ifdef USE_LUCID
1973 apply_systemfont_to_dialog (f->output_data.x->widget);
1974 #endif
1975 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1976 f->output_data.x->widget, 1, 0,
1977 dialog_selection_callback, 0, 0);
1978 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1979 /* Display the dialog box. */
1980 lw_pop_up_all_widgets (dialog_id);
1981 popup_activated_flag = 1;
1982 x_activate_timeout_atimer ();
1984 /* Process events that apply to the dialog box.
1985 Also handle timers. */
1987 int count = SPECPDL_INDEX ();
1988 int fact = 4 * sizeof (LWLIB_ID);
1990 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1991 record_unwind_protect (pop_down_menu,
1992 Fcons (make_number (dialog_id >> (fact)),
1993 make_number (dialog_id & ~(-1 << (fact)))));
1995 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
1996 dialog_id, 1);
1998 unbind_to (count, Qnil);
2002 #endif /* not USE_GTK */
2004 static char * button_names [] = {
2005 "button1", "button2", "button3", "button4", "button5",
2006 "button6", "button7", "button8", "button9", "button10" };
2008 static Lisp_Object
2009 xdialog_show (FRAME_PTR f, int keymaps, Lisp_Object title, Lisp_Object header, char **error_name)
2011 int i, nb_buttons=0;
2012 char dialog_name[6];
2014 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2016 /* Number of elements seen so far, before boundary. */
2017 int left_count = 0;
2018 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2019 int boundary_seen = 0;
2021 if (! FRAME_X_P (f))
2022 abort ();
2024 *error_name = NULL;
2026 if (menu_items_n_panes > 1)
2028 *error_name = "Multiple panes in dialog box";
2029 return Qnil;
2032 /* Create a tree of widget_value objects
2033 representing the text label and buttons. */
2035 Lisp_Object pane_name, prefix;
2036 char *pane_string;
2037 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2038 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2039 pane_string = (NILP (pane_name)
2040 ? "" : (char *) SDATA (pane_name));
2041 prev_wv = xmalloc_widget_value ();
2042 prev_wv->value = pane_string;
2043 if (keymaps && !NILP (prefix))
2044 prev_wv->name++;
2045 prev_wv->enabled = 1;
2046 prev_wv->name = "message";
2047 prev_wv->help = Qnil;
2048 first_wv = prev_wv;
2050 /* Loop over all panes and items, filling in the tree. */
2051 i = MENU_ITEMS_PANE_LENGTH;
2052 while (i < menu_items_used)
2055 /* Create a new item within current pane. */
2056 Lisp_Object item_name, enable, descrip;
2057 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2058 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2059 descrip
2060 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2062 if (NILP (item_name))
2064 free_menubar_widget_value_tree (first_wv);
2065 *error_name = "Submenu in dialog items";
2066 return Qnil;
2068 if (EQ (item_name, Qquote))
2070 /* This is the boundary between left-side elts
2071 and right-side elts. Stop incrementing right_count. */
2072 boundary_seen = 1;
2073 i++;
2074 continue;
2076 if (nb_buttons >= 9)
2078 free_menubar_widget_value_tree (first_wv);
2079 *error_name = "Too many dialog items";
2080 return Qnil;
2083 wv = xmalloc_widget_value ();
2084 prev_wv->next = wv;
2085 wv->name = (char *) button_names[nb_buttons];
2086 if (!NILP (descrip))
2087 wv->key = (char *) SDATA (descrip);
2088 wv->value = (char *) SDATA (item_name);
2089 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2090 wv->enabled = !NILP (enable);
2091 wv->help = Qnil;
2092 prev_wv = wv;
2094 if (! boundary_seen)
2095 left_count++;
2097 nb_buttons++;
2098 i += MENU_ITEMS_ITEM_LENGTH;
2101 /* If the boundary was not specified,
2102 by default put half on the left and half on the right. */
2103 if (! boundary_seen)
2104 left_count = nb_buttons - nb_buttons / 2;
2106 wv = xmalloc_widget_value ();
2107 wv->name = dialog_name;
2108 wv->help = Qnil;
2110 /* Frame title: 'Q' = Question, 'I' = Information.
2111 Can also have 'E' = Error if, one day, we want
2112 a popup for errors. */
2113 if (NILP(header))
2114 dialog_name[0] = 'Q';
2115 else
2116 dialog_name[0] = 'I';
2118 /* Dialog boxes use a really stupid name encoding
2119 which specifies how many buttons to use
2120 and how many buttons are on the right. */
2121 dialog_name[1] = '0' + nb_buttons;
2122 dialog_name[2] = 'B';
2123 dialog_name[3] = 'R';
2124 /* Number of buttons to put on the right. */
2125 dialog_name[4] = '0' + nb_buttons - left_count;
2126 dialog_name[5] = 0;
2127 wv->contents = first_wv;
2128 first_wv = wv;
2131 /* No selection has been chosen yet. */
2132 menu_item_selection = 0;
2134 /* Actually create and show the dialog. */
2135 create_and_show_dialog (f, first_wv);
2137 /* Free the widget_value objects we used to specify the contents. */
2138 free_menubar_widget_value_tree (first_wv);
2140 /* Find the selected item, and its pane, to return
2141 the proper value. */
2142 if (menu_item_selection != 0)
2144 Lisp_Object prefix;
2146 prefix = Qnil;
2147 i = 0;
2148 while (i < menu_items_used)
2150 Lisp_Object entry;
2152 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2154 prefix
2155 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2156 i += MENU_ITEMS_PANE_LENGTH;
2158 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2160 /* This is the boundary between left-side elts and
2161 right-side elts. */
2162 ++i;
2164 else
2166 entry
2167 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2168 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2170 if (keymaps != 0)
2172 entry = Fcons (entry, Qnil);
2173 if (!NILP (prefix))
2174 entry = Fcons (prefix, entry);
2176 return entry;
2178 i += MENU_ITEMS_ITEM_LENGTH;
2182 else
2183 /* Make "Cancel" equivalent to C-g. */
2184 Fsignal (Qquit, Qnil);
2186 return Qnil;
2189 #else /* not USE_X_TOOLKIT && not USE_GTK */
2191 /* The frame of the last activated non-toolkit menu bar.
2192 Used to generate menu help events. */
2194 static struct frame *menu_help_frame;
2197 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2199 PANE is the pane number, and ITEM is the menu item number in
2200 the menu (currently not used).
2202 This cannot be done with generating a HELP_EVENT because
2203 XMenuActivate contains a loop that doesn't let Emacs process
2204 keyboard events. */
2206 static void
2207 menu_help_callback (char *help_string, int pane, int item)
2209 Lisp_Object *first_item;
2210 Lisp_Object pane_name;
2211 Lisp_Object menu_object;
2213 first_item = XVECTOR (menu_items)->contents;
2214 if (EQ (first_item[0], Qt))
2215 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2216 else if (EQ (first_item[0], Qquote))
2217 /* This shouldn't happen, see xmenu_show. */
2218 pane_name = empty_unibyte_string;
2219 else
2220 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2222 /* (menu-item MENU-NAME PANE-NUMBER) */
2223 menu_object = Fcons (Qmenu_item,
2224 Fcons (pane_name,
2225 Fcons (make_number (pane), Qnil)));
2226 show_help_echo (help_string ? build_string (help_string) : Qnil,
2227 Qnil, menu_object, make_number (item), 1);
2230 static Lisp_Object
2231 pop_down_menu (Lisp_Object arg)
2233 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2234 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2236 FRAME_PTR f = p1->pointer;
2237 XMenu *menu = p2->pointer;
2239 BLOCK_INPUT;
2240 #ifndef MSDOS
2241 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2242 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2243 #endif
2244 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2246 #ifdef HAVE_X_WINDOWS
2247 /* Assume the mouse has moved out of the X window.
2248 If it has actually moved in, we will get an EnterNotify. */
2249 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2251 /* State that no mouse buttons are now held.
2252 (The oldXMenu code doesn't track this info for us.)
2253 That is not necessarily true, but the fiction leads to reasonable
2254 results, and it is a pain to ask which are actually held now. */
2255 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2257 #endif /* HAVE_X_WINDOWS */
2259 UNBLOCK_INPUT;
2261 return Qnil;
2265 Lisp_Object
2266 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
2267 Lisp_Object title, char **error, EMACS_UINT timestamp)
2269 Window root;
2270 XMenu *menu;
2271 int pane, selidx, lpane, status;
2272 Lisp_Object entry, pane_prefix;
2273 char *datap;
2274 int ulx, uly, width, height;
2275 int dispwidth, dispheight;
2276 int i, j, lines, maxlines;
2277 int maxwidth;
2278 int dummy_int;
2279 unsigned int dummy_uint;
2280 int specpdl_count = SPECPDL_INDEX ();
2282 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2283 abort ();
2285 *error = 0;
2286 if (menu_items_n_panes == 0)
2287 return Qnil;
2289 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2291 *error = "Empty menu";
2292 return Qnil;
2295 /* Figure out which root window F is on. */
2296 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2297 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2298 &dummy_uint, &dummy_uint);
2300 /* Make the menu on that window. */
2301 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2302 if (menu == NULL)
2304 *error = "Can't create menu";
2305 return Qnil;
2308 /* Don't GC while we prepare and show the menu,
2309 because we give the oldxmenu library pointers to the
2310 contents of strings. */
2311 inhibit_garbage_collection ();
2313 #ifdef HAVE_X_WINDOWS
2314 /* Adjust coordinates to relative to the outer (window manager) window. */
2315 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2316 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2317 #endif /* HAVE_X_WINDOWS */
2319 /* Adjust coordinates to be root-window-relative. */
2320 x += f->left_pos;
2321 y += f->top_pos;
2323 /* Create all the necessary panes and their items. */
2324 maxlines = lines = i = 0;
2325 while (i < menu_items_used)
2327 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2329 /* Create a new pane. */
2330 Lisp_Object pane_name, prefix;
2331 char *pane_string;
2333 maxlines = max (maxlines, lines);
2334 lines = 0;
2335 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2336 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2337 pane_string = (NILP (pane_name)
2338 ? "" : (char *) SDATA (pane_name));
2339 if (keymaps && !NILP (prefix))
2340 pane_string++;
2342 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2343 if (lpane == XM_FAILURE)
2345 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2346 *error = "Can't create pane";
2347 return Qnil;
2349 i += MENU_ITEMS_PANE_LENGTH;
2351 /* Find the width of the widest item in this pane. */
2352 maxwidth = 0;
2353 j = i;
2354 while (j < menu_items_used)
2356 Lisp_Object item;
2357 item = XVECTOR (menu_items)->contents[j];
2358 if (EQ (item, Qt))
2359 break;
2360 if (NILP (item))
2362 j++;
2363 continue;
2365 width = SBYTES (item);
2366 if (width > maxwidth)
2367 maxwidth = width;
2369 j += MENU_ITEMS_ITEM_LENGTH;
2372 /* Ignore a nil in the item list.
2373 It's meaningful only for dialog boxes. */
2374 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2375 i += 1;
2376 else
2378 /* Create a new item within current pane. */
2379 Lisp_Object item_name, enable, descrip, help;
2380 unsigned char *item_data;
2381 char *help_string;
2383 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2384 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2385 descrip
2386 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2387 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2388 help_string = STRINGP (help) ? SDATA (help) : NULL;
2390 if (!NILP (descrip))
2392 int gap = maxwidth - SBYTES (item_name);
2393 /* if alloca is fast, use that to make the space,
2394 to reduce gc needs. */
2395 item_data
2396 = (unsigned char *) alloca (maxwidth
2397 + SBYTES (descrip) + 1);
2398 memcpy (item_data, SDATA (item_name), SBYTES (item_name));
2399 for (j = SCHARS (item_name); j < maxwidth; j++)
2400 item_data[j] = ' ';
2401 memcpy (item_data + j, SDATA (descrip), SBYTES (descrip));
2402 item_data[j + SBYTES (descrip)] = 0;
2404 else
2405 item_data = SDATA (item_name);
2407 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2408 menu, lpane, 0, item_data,
2409 !NILP (enable), help_string)
2410 == XM_FAILURE)
2412 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2413 *error = "Can't add selection to menu";
2414 return Qnil;
2416 i += MENU_ITEMS_ITEM_LENGTH;
2417 lines++;
2421 maxlines = max (maxlines, lines);
2423 /* All set and ready to fly. */
2424 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2425 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2426 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2427 x = min (x, dispwidth);
2428 y = min (y, dispheight);
2429 x = max (x, 1);
2430 y = max (y, 1);
2431 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2432 &ulx, &uly, &width, &height);
2433 if (ulx+width > dispwidth)
2435 x -= (ulx + width) - dispwidth;
2436 ulx = dispwidth - width;
2438 if (uly+height > dispheight)
2440 y -= (uly + height) - dispheight;
2441 uly = dispheight - height;
2443 #ifndef HAVE_X_WINDOWS
2444 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2446 /* Move the menu away of the echo area, to avoid overwriting the
2447 menu with help echo messages or vice versa. */
2448 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2450 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2451 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2453 else
2455 y--;
2456 uly--;
2459 #endif
2460 if (ulx < 0) x -= ulx;
2461 if (uly < 0) y -= uly;
2463 if (! for_click)
2465 /* If position was not given by a mouse click, adjust so upper left
2466 corner of the menu as a whole ends up at given coordinates. This
2467 is what x-popup-menu says in its documentation. */
2468 x += width/2;
2469 y += 1.5*height/(maxlines+2);
2472 XMenuSetAEQ (menu, TRUE);
2473 XMenuSetFreeze (menu, TRUE);
2474 pane = selidx = 0;
2476 #ifndef MSDOS
2477 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2478 #endif
2480 record_unwind_protect (pop_down_menu,
2481 Fcons (make_save_value (f, 0),
2482 make_save_value (menu, 0)));
2484 /* Help display under X won't work because XMenuActivate contains
2485 a loop that doesn't give Emacs a chance to process it. */
2486 menu_help_frame = f;
2487 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2488 x, y, ButtonReleaseMask, &datap,
2489 menu_help_callback);
2491 switch (status)
2493 case XM_SUCCESS:
2494 #ifdef XDEBUG
2495 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2496 #endif
2498 /* Find the item number SELIDX in pane number PANE. */
2499 i = 0;
2500 while (i < menu_items_used)
2502 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2504 if (pane == 0)
2505 pane_prefix
2506 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2507 pane--;
2508 i += MENU_ITEMS_PANE_LENGTH;
2510 else
2512 if (pane == -1)
2514 if (selidx == 0)
2516 entry
2517 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2518 if (keymaps != 0)
2520 entry = Fcons (entry, Qnil);
2521 if (!NILP (pane_prefix))
2522 entry = Fcons (pane_prefix, entry);
2524 break;
2526 selidx--;
2528 i += MENU_ITEMS_ITEM_LENGTH;
2531 break;
2533 case XM_FAILURE:
2534 *error = "Can't activate menu";
2535 case XM_IA_SELECT:
2536 entry = Qnil;
2537 break;
2538 case XM_NO_SELECT:
2539 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2540 the menu was invoked with a mouse event as POSITION). */
2541 if (! for_click)
2542 Fsignal (Qquit, Qnil);
2543 entry = Qnil;
2544 break;
2547 unbind_to (specpdl_count, Qnil);
2549 return entry;
2552 #endif /* not USE_X_TOOLKIT */
2554 #endif /* HAVE_MENUS */
2556 /* Detect if a dialog or menu has been posted. */
2559 popup_activated (void)
2561 return popup_activated_flag;
2564 /* The following is used by delayed window autoselection. */
2566 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2567 doc: /* Return t if a menu or popup dialog is active. */)
2568 (void)
2570 #ifdef HAVE_MENUS
2571 return (popup_activated ()) ? Qt : Qnil;
2572 #else
2573 return Qnil;
2574 #endif /* HAVE_MENUS */
2577 void
2578 syms_of_xmenu (void)
2580 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
2581 staticpro (&Qdebug_on_next_call);
2583 #ifdef USE_X_TOOLKIT
2584 widget_id_tick = (1<<16);
2585 next_menubar_widget_id = 1;
2586 #endif
2588 defsubr (&Smenu_or_popup_active_p);
2590 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2591 defsubr (&Sx_menu_bar_open_internal);
2592 Ffset (intern_c_string ("accelerate-menu"),
2593 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2594 #endif
2596 #ifdef HAVE_MENUS
2597 defsubr (&Sx_popup_dialog);
2598 #endif
2601 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2602 (do not change this comment) */