* vm-limit.c (check_memory_limits): Fix previous change; accidentally reverted an...
[emacs.git] / src / xmenu.c
blob2fb39339b9858409f67d78112e6268601afad7fb
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 (FRAME_PTR, int, int);
126 extern XtAppContext Xt_app_con;
128 static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
129 char **);
130 static void popup_get_selection (XEvent *, struct x_display_info *,
131 LWLIB_ID, int);
132 #endif /* USE_X_TOOLKIT */
134 #ifdef USE_GTK
135 extern void set_frame_menubar (FRAME_PTR, int, int);
136 static Lisp_Object xdialog_show (FRAME_PTR, int, Lisp_Object, Lisp_Object,
137 char **);
138 #endif
140 static int update_frame_menubar (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 (void);
151 extern widget_value *digest_single_submenu (int, int, int);
152 #endif
155 #ifdef USE_X_TOOLKIT
157 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
159 static struct frame *
160 menubar_id_to_frame (LWLIB_ID id)
162 Lisp_Object tail, frame;
163 FRAME_PTR f;
165 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
167 frame = XCAR (tail);
168 if (!FRAMEP (frame))
169 continue;
170 f = XFRAME (frame);
171 if (!FRAME_WINDOW_P (f))
172 continue;
173 if (f->output_data.x->id == id)
174 return f;
176 return 0;
179 #endif
181 #ifdef HAVE_X_WINDOWS
182 /* Return the mouse position in *X and *Y. The coordinates are window
183 relative for the edit window in frame F.
184 This is for Fx_popup_menu. The mouse_position_hook can not
185 be used for X, as it returns window relative coordinates
186 for the window where the mouse is in. This could be the menu bar,
187 the scroll bar or the edit window. Fx_popup_menu needs to be
188 sure it is the edit window. */
189 void
190 mouse_position_for_popup (FRAME_PTR f, int *x, int *y)
192 Window root, dummy_window;
193 int dummy;
195 if (! FRAME_X_P (f))
196 abort ();
198 BLOCK_INPUT;
200 XQueryPointer (FRAME_X_DISPLAY (f),
201 DefaultRootWindow (FRAME_X_DISPLAY (f)),
203 /* The root window which contains the pointer. */
204 &root,
206 /* Window pointer is on, not used */
207 &dummy_window,
209 /* The position on that root window. */
210 x, y,
212 /* x/y in dummy_window coordinates, not used. */
213 &dummy, &dummy,
215 /* Modifier keys and pointer buttons, about which
216 we don't care. */
217 (unsigned int *) &dummy);
219 UNBLOCK_INPUT;
221 /* xmenu_show expects window coordinates, not root window
222 coordinates. Translate. */
223 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
224 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
227 #endif /* HAVE_X_WINDOWS */
229 #ifdef HAVE_MENUS
231 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
232 doc: /* Pop up a dialog box and return user's selection.
233 POSITION specifies which frame to use.
234 This is normally a mouse button event or a window or frame.
235 If POSITION is t, it means to use the frame the mouse is on.
236 The dialog box appears in the middle of the specified frame.
238 CONTENTS specifies the alternatives to display in the dialog box.
239 It is a list of the form (DIALOG ITEM1 ITEM2...).
240 Each ITEM is a cons cell (STRING . VALUE).
241 The return value is VALUE from the chosen item.
243 An ITEM may also be just a string--that makes a nonselectable item.
244 An ITEM may also be nil--that means to put all preceding items
245 on the left of the dialog box and all following items on the right.
246 \(By default, approximately half appear on each side.)
248 If HEADER is non-nil, the frame title for the box is "Information",
249 otherwise it is "Question".
251 If the user gets rid of the dialog box without making a valid choice,
252 for instance using the window manager, then this produces a quit and
253 `x-popup-dialog' does not return. */)
254 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
256 FRAME_PTR f = NULL;
257 Lisp_Object window;
259 check_x ();
261 /* Decode the first argument: find the window or frame to use. */
262 if (EQ (position, Qt)
263 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
264 || EQ (XCAR (position), Qtool_bar))))
266 #if 0 /* Using the frame the mouse is on may not be right. */
267 /* Use the mouse's current position. */
268 FRAME_PTR new_f = SELECTED_FRAME ();
269 Lisp_Object bar_window;
270 enum scroll_bar_part part;
271 unsigned long time;
272 Lisp_Object x, y;
274 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
276 if (new_f != 0)
277 XSETFRAME (window, new_f);
278 else
279 window = selected_window;
280 #endif
281 window = selected_window;
283 else if (CONSP (position))
285 Lisp_Object tem;
286 tem = Fcar (position);
287 if (CONSP (tem))
288 window = Fcar (Fcdr (position));
289 else
291 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
292 window = Fcar (tem); /* POSN_WINDOW (tem) */
295 else if (WINDOWP (position) || FRAMEP (position))
296 window = position;
297 else
298 window = Qnil;
300 /* Decode where to put the menu. */
302 if (FRAMEP (window))
303 f = XFRAME (window);
304 else if (WINDOWP (window))
306 CHECK_LIVE_WINDOW (window);
307 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
309 else
310 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
311 but I don't want to make one now. */
312 CHECK_WINDOW (window);
314 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
315 error ("Can not put X dialog on this terminal");
317 /* Force a redisplay before showing the dialog. If a frame is created
318 just before showing the dialog, its contents may not have been fully
319 drawn, as this depends on timing of events from the X server. Redisplay
320 is not done when a dialog is shown. If redisplay could be done in the
321 X event loop (i.e. the X event loop does not run in a signal handler)
322 this would not be needed.
324 Do this before creating the widget value that points to Lisp
325 string contents, because Fredisplay may GC and relocate them. */
326 Fredisplay (Qt);
328 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
329 /* Display a menu with these alternatives
330 in the middle of frame F. */
332 Lisp_Object x, y, frame, newpos;
333 XSETFRAME (frame, f);
334 XSETINT (x, x_pixel_width (f) / 2);
335 XSETINT (y, x_pixel_height (f) / 2);
336 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
338 return Fx_popup_menu (newpos,
339 Fcons (Fcar (contents), Fcons (contents, Qnil)));
341 #else
343 Lisp_Object title;
344 char *error_name;
345 Lisp_Object selection;
346 int specpdl_count = SPECPDL_INDEX ();
348 /* Decode the dialog items from what was specified. */
349 title = Fcar (contents);
350 CHECK_STRING (title);
351 record_unwind_protect (unuse_menu_items, Qnil);
353 if (NILP (Fcar (Fcdr (contents))))
354 /* No buttons specified, add an "Ok" button so users can pop down
355 the dialog. Also, the lesstif/motif version crashes if there are
356 no buttons. */
357 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
359 list_of_panes (Fcons (contents, Qnil));
361 /* Display them in a dialog box. */
362 BLOCK_INPUT;
363 selection = xdialog_show (f, 0, title, header, &error_name);
364 UNBLOCK_INPUT;
366 unbind_to (specpdl_count, Qnil);
367 discard_menu_items ();
369 if (error_name) error (error_name);
370 return selection;
372 #endif
376 #ifndef MSDOS
378 /* Set menu_items_inuse so no other popup menu or dialog is created. */
380 void
381 x_menu_set_in_use (int in_use)
383 menu_items_inuse = in_use ? Qt : Qnil;
384 popup_activated_flag = in_use;
385 #ifdef USE_X_TOOLKIT
386 if (popup_activated_flag)
387 x_activate_timeout_atimer ();
388 #endif
391 /* Wait for an X event to arrive or for a timer to expire. */
393 void
394 x_menu_wait_for_event (void *data)
396 /* Another way to do this is to register a timer callback, that can be
397 done in GTK and Xt. But we have to do it like this when using only X
398 anyway, and with callbacks we would have three variants for timer handling
399 instead of the small ifdefs below. */
401 while (
402 #ifdef USE_X_TOOLKIT
403 ! XtAppPending (Xt_app_con)
404 #elif defined USE_GTK
405 ! gtk_events_pending ()
406 #else
407 ! XPending ((Display*) data)
408 #endif
411 EMACS_TIME next_time = timer_check (1), *ntp;
412 long secs = EMACS_SECS (next_time);
413 long usecs = EMACS_USECS (next_time);
414 SELECT_TYPE read_fds;
415 struct x_display_info *dpyinfo;
416 int n = 0;
418 FD_ZERO (&read_fds);
419 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
421 int fd = ConnectionNumber (dpyinfo->display);
422 FD_SET (fd, &read_fds);
423 if (fd > n) n = fd;
424 XFlush (dpyinfo->display);
427 if (secs < 0 && usecs < 0)
428 ntp = 0;
429 else
430 ntp = &next_time;
432 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
435 #endif /* ! MSDOS */
438 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
440 #ifdef USE_X_TOOLKIT
442 /* Loop in Xt until the menu pulldown or dialog popup has been
443 popped down (deactivated). This is used for x-popup-menu
444 and x-popup-dialog; it is not used for the menu bar.
446 NOTE: All calls to popup_get_selection should be protected
447 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
449 static void
450 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo, LWLIB_ID id, int do_timers)
452 XEvent event;
454 while (popup_activated_flag)
456 if (initial_event)
458 event = *initial_event;
459 initial_event = 0;
461 else
463 if (do_timers) x_menu_wait_for_event (0);
464 XtAppNextEvent (Xt_app_con, &event);
467 /* Make sure we don't consider buttons grabbed after menu goes.
468 And make sure to deactivate for any ButtonRelease,
469 even if XtDispatchEvent doesn't do that. */
470 if (event.type == ButtonRelease
471 && dpyinfo->display == event.xbutton.display)
473 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
474 #ifdef USE_MOTIF /* Pretending that the event came from a
475 Btn1Down seems the only way to convince Motif to
476 activate its callbacks; setting the XmNmenuPost
477 isn't working. --marcus@sysc.pdx.edu. */
478 event.xbutton.button = 1;
479 /* Motif only pops down menus when no Ctrl, Alt or Mod
480 key is pressed and the button is released. So reset key state
481 so Motif thinks this is the case. */
482 event.xbutton.state = 0;
483 #endif
485 /* Pop down on C-g and Escape. */
486 else if (event.type == KeyPress
487 && dpyinfo->display == event.xbutton.display)
489 KeySym keysym = XLookupKeysym (&event.xkey, 0);
491 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
492 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
493 popup_activated_flag = 0;
496 x_dispatch_event (&event, event.xany.display);
500 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
501 doc: /* Start key navigation of the menu bar in FRAME.
502 This initially opens the first menu bar item and you can then navigate with the
503 arrow keys, select a menu entry with the return key or cancel with the
504 escape key. If FRAME has no menu bar this function does nothing.
506 If FRAME is nil or not given, use the selected frame. */)
507 (Lisp_Object frame)
509 XEvent ev;
510 FRAME_PTR f = check_x_frame (frame);
511 Widget menubar;
512 BLOCK_INPUT;
514 if (FRAME_EXTERNAL_MENU_BAR (f))
515 set_frame_menubar (f, 0, 1);
517 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
518 if (menubar)
520 Window child;
521 int error_p = 0;
523 x_catch_errors (FRAME_X_DISPLAY (f));
524 memset (&ev, 0, sizeof ev);
525 ev.xbutton.display = FRAME_X_DISPLAY (f);
526 ev.xbutton.window = XtWindow (menubar);
527 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
528 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
529 ev.xbutton.button = Button1;
530 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
531 ev.xbutton.same_screen = True;
533 #ifdef USE_MOTIF
535 Arg al[2];
536 WidgetList list;
537 Cardinal nr;
538 XtSetArg (al[0], XtNchildren, &list);
539 XtSetArg (al[1], XtNnumChildren, &nr);
540 XtGetValues (menubar, al, 2);
541 ev.xbutton.window = XtWindow (list[0]);
543 #endif
545 XTranslateCoordinates (FRAME_X_DISPLAY (f),
546 /* From-window, to-window. */
547 ev.xbutton.window, ev.xbutton.root,
549 /* From-position, to-position. */
550 ev.xbutton.x, ev.xbutton.y,
551 &ev.xbutton.x_root, &ev.xbutton.y_root,
553 /* Child of win. */
554 &child);
555 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
556 x_uncatch_errors ();
558 if (! error_p)
560 ev.type = ButtonPress;
561 ev.xbutton.state = 0;
563 XtDispatchEvent (&ev);
564 ev.xbutton.type = ButtonRelease;
565 ev.xbutton.state = Button1Mask;
566 XtDispatchEvent (&ev);
570 UNBLOCK_INPUT;
572 return Qnil;
574 #endif /* USE_X_TOOLKIT */
577 #ifdef USE_GTK
578 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
579 doc: /* Start key navigation of the menu bar in FRAME.
580 This initially opens the first menu bar item and you can then navigate with the
581 arrow keys, select a menu entry with the return key or cancel with the
582 escape key. If FRAME has no menu bar this function does nothing.
584 If FRAME is nil or not given, use the selected frame. */)
585 (Lisp_Object frame)
587 GtkWidget *menubar;
588 FRAME_PTR f;
590 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
591 BLOCK_INPUT. */
593 BLOCK_INPUT;
594 f = check_x_frame (frame);
596 if (FRAME_EXTERNAL_MENU_BAR (f))
597 set_frame_menubar (f, 0, 1);
599 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
600 if (menubar)
602 /* Activate the first menu. */
603 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
605 if (children)
607 g_signal_emit_by_name (children->data, "activate_item");
608 popup_activated_flag = 1;
609 g_list_free (children);
612 UNBLOCK_INPUT;
614 return Qnil;
617 /* Loop util popup_activated_flag is set to zero in a callback.
618 Used for popup menus and dialogs. */
620 static void
621 popup_widget_loop (int do_timers, GtkWidget *widget)
623 ++popup_activated_flag;
625 /* Process events in the Gtk event loop until done. */
626 while (popup_activated_flag)
628 if (do_timers) x_menu_wait_for_event (0);
629 gtk_main_iteration ();
632 #endif
634 /* Activate the menu bar of frame F.
635 This is called from keyboard.c when it gets the
636 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
638 To activate the menu bar, we use the X button-press event
639 that was saved in saved_menu_event.
640 That makes the toolkit do its thing.
642 But first we recompute the menu bar contents (the whole tree).
644 The reason for saving the button event until here, instead of
645 passing it to the toolkit right away, is that we can safely
646 execute Lisp code. */
648 void
649 x_activate_menubar (FRAME_PTR f)
651 if (! FRAME_X_P (f))
652 abort ();
654 if (!f->output_data.x->saved_menu_event->type)
655 return;
657 #ifdef USE_GTK
658 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
659 f->output_data.x->saved_menu_event->xany.window))
660 return;
661 #endif
663 set_frame_menubar (f, 0, 1);
664 BLOCK_INPUT;
665 popup_activated_flag = 1;
666 #ifdef USE_GTK
667 XPutBackEvent (f->output_data.x->display_info->display,
668 f->output_data.x->saved_menu_event);
669 #else
670 XtDispatchEvent (f->output_data.x->saved_menu_event);
671 #endif
672 UNBLOCK_INPUT;
674 /* Ignore this if we get it a second time. */
675 f->output_data.x->saved_menu_event->type = 0;
678 /* This callback is invoked when the user selects a menubar cascade
679 pushbutton, but before the pulldown menu is posted. */
681 #ifndef USE_GTK
682 static void
683 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
685 popup_activated_flag = 1;
686 #ifdef USE_X_TOOLKIT
687 x_activate_timeout_atimer ();
688 #endif
690 #endif
692 /* This callback is invoked when a dialog or menu is finished being
693 used and has been unposted. */
695 #ifdef USE_GTK
696 static void
697 popup_deactivate_callback (GtkWidget *widget, gpointer client_data)
699 popup_activated_flag = 0;
701 #else
702 static void
703 popup_deactivate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
705 popup_activated_flag = 0;
707 #endif
710 /* Function that finds the frame for WIDGET and shows the HELP text
711 for that widget.
712 F is the frame if known, or NULL if not known. */
713 static void
714 show_help_event (FRAME_PTR f, xt_or_gtk_widget widget, Lisp_Object help)
716 Lisp_Object frame;
718 if (f)
720 XSETFRAME (frame, f);
721 kbd_buffer_store_help_event (frame, help);
723 else
725 #if 0 /* This code doesn't do anything useful. ++kfs */
726 /* WIDGET is the popup menu. It's parent is the frame's
727 widget. See which frame that is. */
728 xt_or_gtk_widget frame_widget = XtParent (widget);
729 Lisp_Object tail;
731 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
733 frame = XCAR (tail);
734 if (FRAMEP (frame)
735 && (f = XFRAME (frame),
736 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
737 break;
739 #endif
740 show_help_echo (help, Qnil, Qnil, Qnil, 1);
744 /* Callback called when menu items are highlighted/unhighlighted
745 while moving the mouse over them. WIDGET is the menu bar or menu
746 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
747 the data structure for the menu item, or null in case of
748 unhighlighting. */
750 #ifdef USE_GTK
751 void
752 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
754 xg_menu_item_cb_data *cb_data;
755 Lisp_Object help;
757 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
758 XG_ITEM_DATA);
759 if (! cb_data) return;
761 help = call_data ? cb_data->help : Qnil;
763 /* If popup_activated_flag is greater than 1 we are in a popup menu.
764 Don't show help for them, they won't appear before the
765 popup is popped down. */
766 if (popup_activated_flag <= 1)
767 show_help_event (cb_data->cl_data->f, widget, help);
769 #else
770 void
771 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
773 struct frame *f;
774 Lisp_Object help;
776 widget_value *wv = (widget_value *) call_data;
778 help = wv ? wv->help : Qnil;
780 /* Determine the frame for the help event. */
781 f = menubar_id_to_frame (id);
783 show_help_event (f, widget, help);
785 #endif
787 #ifdef USE_GTK
788 /* Gtk calls callbacks just because we tell it what item should be
789 selected in a radio group. If this variable is set to a non-zero
790 value, we are creating menus and don't want callbacks right now.
792 static int xg_crazy_callback_abort;
794 /* This callback is called from the menu bar pulldown menu
795 when the user makes a selection.
796 Figure out what the user chose
797 and put the appropriate events into the keyboard buffer. */
798 static void
799 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
801 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
803 if (xg_crazy_callback_abort)
804 return;
806 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
807 return;
809 /* For a group of radio buttons, GTK calls the selection callback first
810 for the item that was active before the selection and then for the one that
811 is active after the selection. For C-h k this means we get the help on
812 the deselected item and then the selected item is executed. Prevent that
813 by ignoring the non-active item. */
814 if (GTK_IS_RADIO_MENU_ITEM (widget)
815 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
816 return;
818 /* When a menu is popped down, X generates a focus event (i.e. focus
819 goes back to the frame below the menu). Since GTK buffers events,
820 we force it out here before the menu selection event. Otherwise
821 sit-for will exit at once if the focus event follows the menu selection
822 event. */
824 BLOCK_INPUT;
825 while (gtk_events_pending ())
826 gtk_main_iteration ();
827 UNBLOCK_INPUT;
829 find_and_call_menu_selection (cb_data->cl_data->f,
830 cb_data->cl_data->menu_bar_items_used,
831 cb_data->cl_data->menu_bar_vector,
832 cb_data->call_data);
835 #else /* not USE_GTK */
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 widget, LWLIB_ID id, XtPointer client_data)
844 FRAME_PTR f;
846 f = menubar_id_to_frame (id);
847 if (!f)
848 return;
849 find_and_call_menu_selection (f, f->menu_bar_items_used,
850 f->menu_bar_vector, client_data);
852 #endif /* not USE_GTK */
854 /* Recompute all the widgets of frame F, when the menu bar has been
855 changed. Value is non-zero if widgets were updated. */
857 static int
858 update_frame_menubar (FRAME_PTR f)
860 #ifdef USE_GTK
861 return xg_update_frame_menubar (f);
862 #else
863 struct x_output *x;
864 int columns, rows;
866 if (! FRAME_X_P (f))
867 abort ();
869 x = f->output_data.x;
871 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
872 return 0;
874 BLOCK_INPUT;
875 /* Save the size of the frame because the pane widget doesn't accept
876 to resize itself. So force it. */
877 columns = FRAME_COLS (f);
878 rows = FRAME_LINES (f);
880 /* Do the voodoo which means "I'm changing lots of things, don't try
881 to refigure sizes until I'm done." */
882 lw_refigure_widget (x->column_widget, False);
884 /* The order in which children are managed is the top to bottom
885 order in which they are displayed in the paned window. First,
886 remove the text-area widget. */
887 XtUnmanageChild (x->edit_widget);
889 /* Remove the menubar that is there now, and put up the menubar that
890 should be there. */
891 XtManageChild (x->menubar_widget);
892 XtMapWidget (x->menubar_widget);
893 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
895 /* Re-manage the text-area widget, and then thrash the sizes. */
896 XtManageChild (x->edit_widget);
897 lw_refigure_widget (x->column_widget, True);
899 /* Force the pane widget to resize itself with the right values. */
900 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
901 UNBLOCK_INPUT;
902 #endif
903 return 1;
906 #ifdef USE_LUCID
907 static void
908 apply_systemfont_to_dialog (Widget w)
910 const char *fn = xsettings_get_system_normal_font ();
911 if (fn)
913 XrmDatabase db = XtDatabase (XtDisplay (w));
914 if (db)
915 XrmPutStringResource (&db, "*dialog.faceName", fn);
919 static void
920 apply_systemfont_to_menu (Widget w)
922 const char *fn = xsettings_get_system_normal_font ();
923 int defflt;
925 if (!fn) return;
927 if (XtIsShell (w)) /* popup menu */
929 Widget *childs = NULL;
931 XtVaGetValues (w, XtNchildren, &childs, NULL);
932 if (*childs) w = *childs;
935 /* Only use system font if the default is used for the menu. */
936 XtVaGetValues (w, XtNdefaultFace, &defflt, NULL);
937 if (defflt)
938 XtVaSetValues (w, XtNfaceName, fn, NULL);
940 #endif
942 /* Set the contents of the menubar widgets of frame F.
943 The argument FIRST_TIME is currently ignored;
944 it is set the first time this is called, from initialize_frame_menubar. */
946 void
947 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
949 xt_or_gtk_widget menubar_widget;
950 #ifdef USE_X_TOOLKIT
951 LWLIB_ID id;
952 #endif
953 Lisp_Object items;
954 widget_value *wv, *first_wv, *prev_wv = 0;
955 int i, last_i = 0;
956 int *submenu_start, *submenu_end;
957 int *submenu_top_level_items, *submenu_n_panes;
959 if (! FRAME_X_P (f))
960 abort ();
962 menubar_widget = f->output_data.x->menubar_widget;
964 XSETFRAME (Vmenu_updating_frame, f);
966 #ifdef USE_X_TOOLKIT
967 if (f->output_data.x->id == 0)
968 f->output_data.x->id = next_menubar_widget_id++;
969 id = f->output_data.x->id;
970 #endif
972 if (! menubar_widget)
973 deep_p = 1;
974 /* Make the first call for any given frame always go deep. */
975 else if (!f->output_data.x->saved_menu_event && !deep_p)
977 deep_p = 1;
978 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
979 f->output_data.x->saved_menu_event->type = 0;
982 #ifdef USE_GTK
983 /* If we have detached menus, we must update deep so detached menus
984 also gets updated. */
985 deep_p = deep_p || xg_have_tear_offs ();
986 #endif
988 if (deep_p)
990 /* Make a widget-value tree representing the entire menu trees. */
992 struct buffer *prev = current_buffer;
993 Lisp_Object buffer;
994 int specpdl_count = SPECPDL_INDEX ();
995 int previous_menu_items_used = f->menu_bar_items_used;
996 Lisp_Object *previous_items
997 = (Lisp_Object *) alloca (previous_menu_items_used
998 * sizeof (Lisp_Object));
1000 /* If we are making a new widget, its contents are empty,
1001 do always reinitialize them. */
1002 if (! menubar_widget)
1003 previous_menu_items_used = 0;
1005 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1006 specbind (Qinhibit_quit, Qt);
1007 /* Don't let the debugger step into this code
1008 because it is not reentrant. */
1009 specbind (Qdebug_on_next_call, Qnil);
1011 record_unwind_save_match_data ();
1012 if (NILP (Voverriding_local_map_menu_flag))
1014 specbind (Qoverriding_terminal_local_map, Qnil);
1015 specbind (Qoverriding_local_map, Qnil);
1018 set_buffer_internal_1 (XBUFFER (buffer));
1020 /* Run the Lucid hook. */
1021 safe_run_hooks (Qactivate_menubar_hook);
1023 /* If it has changed current-menubar from previous value,
1024 really recompute the menubar from the value. */
1025 if (! NILP (Vlucid_menu_bar_dirty_flag))
1026 call0 (Qrecompute_lucid_menubar);
1027 safe_run_hooks (Qmenu_bar_update_hook);
1028 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1030 items = FRAME_MENU_BAR_ITEMS (f);
1032 /* Save the frame's previous menu bar contents data. */
1033 if (previous_menu_items_used)
1034 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
1035 previous_menu_items_used * sizeof (Lisp_Object));
1037 /* Fill in menu_items with the current menu bar contents.
1038 This can evaluate Lisp code. */
1039 save_menu_items ();
1041 menu_items = f->menu_bar_vector;
1042 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1043 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1044 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1045 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1046 submenu_top_level_items
1047 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1048 init_menu_items ();
1049 for (i = 0; i < XVECTOR (items)->size; i += 4)
1051 Lisp_Object key, string, maps;
1053 last_i = i;
1055 key = XVECTOR (items)->contents[i];
1056 string = XVECTOR (items)->contents[i + 1];
1057 maps = XVECTOR (items)->contents[i + 2];
1058 if (NILP (string))
1059 break;
1061 submenu_start[i] = menu_items_used;
1063 menu_items_n_panes = 0;
1064 submenu_top_level_items[i]
1065 = parse_single_submenu (key, string, maps);
1066 submenu_n_panes[i] = menu_items_n_panes;
1068 submenu_end[i] = menu_items_used;
1071 finish_menu_items ();
1073 /* Convert menu_items into widget_value trees
1074 to display the menu. This cannot evaluate Lisp code. */
1076 wv = xmalloc_widget_value ();
1077 wv->name = "menubar";
1078 wv->value = 0;
1079 wv->enabled = 1;
1080 wv->button_type = BUTTON_TYPE_NONE;
1081 wv->help = Qnil;
1082 first_wv = wv;
1084 for (i = 0; i < last_i; i += 4)
1086 menu_items_n_panes = submenu_n_panes[i];
1087 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1088 submenu_top_level_items[i]);
1089 if (prev_wv)
1090 prev_wv->next = wv;
1091 else
1092 first_wv->contents = wv;
1093 /* Don't set wv->name here; GC during the loop might relocate it. */
1094 wv->enabled = 1;
1095 wv->button_type = BUTTON_TYPE_NONE;
1096 prev_wv = wv;
1099 set_buffer_internal_1 (prev);
1101 /* If there has been no change in the Lisp-level contents
1102 of the menu bar, skip redisplaying it. Just exit. */
1104 /* Compare the new menu items with the ones computed last time. */
1105 for (i = 0; i < previous_menu_items_used; i++)
1106 if (menu_items_used == i
1107 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1108 break;
1109 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1111 /* The menu items have not changed. Don't bother updating
1112 the menus in any form, since it would be a no-op. */
1113 free_menubar_widget_value_tree (first_wv);
1114 discard_menu_items ();
1115 unbind_to (specpdl_count, Qnil);
1116 return;
1119 /* The menu items are different, so store them in the frame. */
1120 f->menu_bar_vector = menu_items;
1121 f->menu_bar_items_used = menu_items_used;
1123 /* This undoes save_menu_items. */
1124 unbind_to (specpdl_count, Qnil);
1126 /* Now GC cannot happen during the lifetime of the widget_value,
1127 so it's safe to store data from a Lisp_String. */
1128 wv = first_wv->contents;
1129 for (i = 0; i < XVECTOR (items)->size; i += 4)
1131 Lisp_Object string;
1132 string = XVECTOR (items)->contents[i + 1];
1133 if (NILP (string))
1134 break;
1135 wv->name = (char *) SDATA (string);
1136 update_submenu_strings (wv->contents);
1137 wv = wv->next;
1141 else
1143 /* Make a widget-value tree containing
1144 just the top level menu bar strings. */
1146 wv = xmalloc_widget_value ();
1147 wv->name = "menubar";
1148 wv->value = 0;
1149 wv->enabled = 1;
1150 wv->button_type = BUTTON_TYPE_NONE;
1151 wv->help = Qnil;
1152 first_wv = wv;
1154 items = FRAME_MENU_BAR_ITEMS (f);
1155 for (i = 0; i < XVECTOR (items)->size; i += 4)
1157 Lisp_Object string;
1159 string = XVECTOR (items)->contents[i + 1];
1160 if (NILP (string))
1161 break;
1163 wv = xmalloc_widget_value ();
1164 wv->name = (char *) SDATA (string);
1165 wv->value = 0;
1166 wv->enabled = 1;
1167 wv->button_type = BUTTON_TYPE_NONE;
1168 wv->help = Qnil;
1169 /* This prevents lwlib from assuming this
1170 menu item is really supposed to be empty. */
1171 /* The EMACS_INT cast avoids a warning.
1172 This value just has to be different from small integers. */
1173 wv->call_data = (void *) (EMACS_INT) (-1);
1175 if (prev_wv)
1176 prev_wv->next = wv;
1177 else
1178 first_wv->contents = wv;
1179 prev_wv = wv;
1182 /* Forget what we thought we knew about what is in the
1183 detailed contents of the menu bar menus.
1184 Changing the top level always destroys the contents. */
1185 f->menu_bar_items_used = 0;
1188 /* Create or update the menu bar widget. */
1190 BLOCK_INPUT;
1192 #ifdef USE_GTK
1193 xg_crazy_callback_abort = 1;
1194 if (menubar_widget)
1196 /* The fourth arg is DEEP_P, which says to consider the entire
1197 menu trees we supply, rather than just the menu bar item names. */
1198 xg_modify_menubar_widgets (menubar_widget,
1200 first_wv,
1201 deep_p,
1202 G_CALLBACK (menubar_selection_callback),
1203 G_CALLBACK (popup_deactivate_callback),
1204 G_CALLBACK (menu_highlight_callback));
1206 else
1208 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1210 menubar_widget
1211 = xg_create_widget ("menubar", "menubar", f, first_wv,
1212 G_CALLBACK (menubar_selection_callback),
1213 G_CALLBACK (popup_deactivate_callback),
1214 G_CALLBACK (menu_highlight_callback));
1216 f->output_data.x->menubar_widget = menubar_widget;
1220 #else /* not USE_GTK */
1221 if (menubar_widget)
1223 /* Disable resizing (done for Motif!) */
1224 lw_allow_resizing (f->output_data.x->widget, False);
1226 /* The third arg is DEEP_P, which says to consider the entire
1227 menu trees we supply, rather than just the menu bar item names. */
1228 lw_modify_all_widgets (id, first_wv, deep_p);
1230 /* Re-enable the edit widget to resize. */
1231 lw_allow_resizing (f->output_data.x->widget, True);
1233 else
1235 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1236 XtTranslations override = XtParseTranslationTable (menuOverride);
1238 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1239 f->output_data.x->column_widget,
1241 popup_activate_callback,
1242 menubar_selection_callback,
1243 popup_deactivate_callback,
1244 menu_highlight_callback);
1245 f->output_data.x->menubar_widget = menubar_widget;
1247 /* Make menu pop down on C-g. */
1248 XtOverrideTranslations (menubar_widget, override);
1249 #ifdef USE_LUCID
1250 apply_systemfont_to_menu (menubar_widget);
1251 #endif
1255 int menubar_size;
1256 if (f->output_data.x->menubar_widget)
1257 XtRealizeWidget (f->output_data.x->menubar_widget);
1259 menubar_size
1260 = (f->output_data.x->menubar_widget
1261 ? (f->output_data.x->menubar_widget->core.height
1262 + f->output_data.x->menubar_widget->core.border_width)
1263 : 0);
1265 #if 1 /* Experimentally, we now get the right results
1266 for -geometry -0-0 without this. 24 Aug 96, rms.
1267 Maybe so, but the menu bar size is missing the pixels so the
1268 WM size hints are off by these pixels. Jan D, oct 2009. */
1269 #ifdef USE_LUCID
1270 if (FRAME_EXTERNAL_MENU_BAR (f))
1272 Dimension ibw = 0;
1273 XtVaGetValues (f->output_data.x->column_widget,
1274 XtNinternalBorderWidth, &ibw, NULL);
1275 menubar_size += ibw;
1277 #endif /* USE_LUCID */
1278 #endif /* 1 */
1280 f->output_data.x->menubar_height = menubar_size;
1282 #endif /* not USE_GTK */
1284 free_menubar_widget_value_tree (first_wv);
1285 update_frame_menubar (f);
1287 #ifdef USE_GTK
1288 xg_crazy_callback_abort = 0;
1289 #endif
1291 UNBLOCK_INPUT;
1294 /* Called from Fx_create_frame to create the initial menubar of a frame
1295 before it is mapped, so that the window is mapped with the menubar already
1296 there instead of us tacking it on later and thrashing the window after it
1297 is visible. */
1299 void
1300 initialize_frame_menubar (FRAME_PTR f)
1302 /* This function is called before the first chance to redisplay
1303 the frame. It has to be, so the frame will have the right size. */
1304 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1305 set_frame_menubar (f, 1, 1);
1309 /* Get rid of the menu bar of frame F, and free its storage.
1310 This is used when deleting a frame, and when turning off the menu bar.
1311 For GTK this function is in gtkutil.c. */
1313 #ifndef USE_GTK
1314 void
1315 free_frame_menubar (FRAME_PTR f)
1317 Widget menubar_widget;
1319 if (! FRAME_X_P (f))
1320 abort ();
1322 menubar_widget = f->output_data.x->menubar_widget;
1324 f->output_data.x->menubar_height = 0;
1326 if (menubar_widget)
1328 #ifdef USE_MOTIF
1329 /* Removing the menu bar magically changes the shell widget's x
1330 and y position of (0, 0) which, when the menu bar is turned
1331 on again, leads to pull-down menuss appearing in strange
1332 positions near the upper-left corner of the display. This
1333 happens only with some window managers like twm and ctwm,
1334 but not with other like Motif's mwm or kwm, because the
1335 latter generate ConfigureNotify events when the menu bar
1336 is switched off, which fixes the shell position. */
1337 Position x0, y0, x1, y1;
1338 #endif
1340 BLOCK_INPUT;
1342 #ifdef USE_MOTIF
1343 if (f->output_data.x->widget)
1344 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1345 #endif
1347 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1348 f->output_data.x->menubar_widget = NULL;
1350 if (f->output_data.x->widget)
1352 #ifdef USE_MOTIF
1353 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1354 if (x1 == 0 && y1 == 0)
1355 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1356 #endif
1357 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1359 UNBLOCK_INPUT;
1362 #endif /* not USE_GTK */
1364 #endif /* USE_X_TOOLKIT || USE_GTK */
1366 /* xmenu_show actually displays a menu using the panes and items in menu_items
1367 and returns the value selected from it.
1368 There are two versions of xmenu_show, one for Xt and one for Xlib.
1369 Both assume input is blocked by the caller. */
1371 /* F is the frame the menu is for.
1372 X and Y are the frame-relative specified position,
1373 relative to the inside upper left corner of the frame F.
1374 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1375 KEYMAPS is 1 if this menu was specified with keymaps;
1376 in that case, we return a list containing the chosen item's value
1377 and perhaps also the pane's prefix.
1378 TITLE is the specified menu title.
1379 ERROR is a place to store an error message string in case of failure.
1380 (We return nil on failure, but the value doesn't actually matter.) */
1382 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1384 /* The item selected in the popup menu. */
1385 static Lisp_Object *volatile menu_item_selection;
1387 #ifdef USE_GTK
1389 /* Used when position a popup menu. See menu_position_func and
1390 create_and_show_popup_menu below. */
1391 struct next_popup_x_y
1393 FRAME_PTR f;
1394 int x;
1395 int y;
1398 /* The menu position function to use if we are not putting a popup
1399 menu where the pointer is.
1400 MENU is the menu to pop up.
1401 X and Y shall on exit contain x/y where the menu shall pop up.
1402 PUSH_IN is not documented in the GTK manual.
1403 USER_DATA is any data passed in when calling gtk_menu_popup.
1404 Here it points to a struct next_popup_x_y where the coordinates
1405 to store in *X and *Y are as well as the frame for the popup.
1407 Here only X and Y are used. */
1408 static void
1409 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1411 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1412 GtkRequisition req;
1413 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1414 int disp_width = x_display_pixel_width (dpyinfo);
1415 int disp_height = x_display_pixel_height (dpyinfo);
1417 *x = data->x;
1418 *y = data->y;
1420 /* Check if there is room for the menu. If not, adjust x/y so that
1421 the menu is fully visible. */
1422 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1423 if (data->x + req.width > disp_width)
1424 *x -= data->x + req.width - disp_width;
1425 if (data->y + req.height > disp_height)
1426 *y -= data->y + req.height - disp_height;
1429 static void
1430 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1432 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1434 if (xg_crazy_callback_abort) return;
1435 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1438 static Lisp_Object
1439 pop_down_menu (Lisp_Object arg)
1441 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1443 popup_activated_flag = 0;
1444 BLOCK_INPUT;
1445 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1446 UNBLOCK_INPUT;
1447 return Qnil;
1450 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1451 menu pops down.
1452 menu_item_selection will be set to the selection. */
1453 static void
1454 create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, int for_click, EMACS_UINT timestamp)
1456 int i;
1457 GtkWidget *menu;
1458 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1459 struct next_popup_x_y popup_x_y;
1460 int specpdl_count = SPECPDL_INDEX ();
1462 if (! FRAME_X_P (f))
1463 abort ();
1465 xg_crazy_callback_abort = 1;
1466 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1467 G_CALLBACK (popup_selection_callback),
1468 G_CALLBACK (popup_deactivate_callback),
1469 G_CALLBACK (menu_highlight_callback));
1470 xg_crazy_callback_abort = 0;
1472 if (! for_click)
1474 /* Not invoked by a click. pop up at x/y. */
1475 pos_func = menu_position_func;
1477 /* Adjust coordinates to be root-window-relative. */
1478 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1479 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1481 popup_x_y.x = x;
1482 popup_x_y.y = y;
1483 popup_x_y.f = f;
1485 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1487 else
1489 for (i = 0; i < 5; i++)
1490 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1491 break;
1494 /* Display the menu. */
1495 gtk_widget_show_all (menu);
1497 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1498 timestamp > 0 ? timestamp : gtk_get_current_event_time());
1500 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1502 if (gtk_widget_get_mapped (menu))
1504 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1505 two. show_help_echo uses this to detect popup menus. */
1506 popup_activated_flag = 1;
1507 /* Process events that apply to the menu. */
1508 popup_widget_loop (1, menu);
1511 unbind_to (specpdl_count, Qnil);
1513 /* Must reset this manually because the button release event is not passed
1514 to Emacs event loop. */
1515 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1518 #else /* not USE_GTK */
1520 /* We need a unique id for each widget handled by the Lucid Widget
1521 library.
1523 For the main windows, and popup menus, we use this counter,
1524 which we increment each time after use. This starts from 1<<16.
1526 For menu bars, we use numbers starting at 0, counted in
1527 next_menubar_widget_id. */
1528 LWLIB_ID widget_id_tick;
1530 static void
1531 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1533 menu_item_selection = (Lisp_Object *) client_data;
1536 /* ARG is the LWLIB ID of the dialog box, represented
1537 as a Lisp object as (HIGHPART . LOWPART). */
1539 static Lisp_Object
1540 pop_down_menu (Lisp_Object arg)
1542 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1543 | XINT (XCDR (arg)));
1545 BLOCK_INPUT;
1546 lw_destroy_all_widgets (id);
1547 UNBLOCK_INPUT;
1548 popup_activated_flag = 0;
1550 return Qnil;
1553 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1554 menu pops down.
1555 menu_item_selection will be set to the selection. */
1556 static void
1557 create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv,
1558 int x, int y, int for_click, EMACS_UINT timestamp)
1560 int i;
1561 Arg av[2];
1562 int ac = 0;
1563 XButtonPressedEvent dummy;
1564 LWLIB_ID menu_id;
1565 Widget menu;
1567 if (! FRAME_X_P (f))
1568 abort ();
1570 menu_id = widget_id_tick++;
1571 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1572 f->output_data.x->widget, 1, 0,
1573 popup_selection_callback,
1574 popup_deactivate_callback,
1575 menu_highlight_callback);
1577 #ifdef USE_LUCID
1578 apply_systemfont_to_menu (menu);
1579 #endif
1581 dummy.type = ButtonPress;
1582 dummy.serial = 0;
1583 dummy.send_event = 0;
1584 dummy.display = FRAME_X_DISPLAY (f);
1585 dummy.time = CurrentTime;
1586 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1587 dummy.window = dummy.root;
1588 dummy.subwindow = dummy.root;
1589 dummy.x = x;
1590 dummy.y = y;
1592 /* Adjust coordinates to be root-window-relative. */
1593 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1594 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1596 dummy.x_root = x;
1597 dummy.y_root = y;
1599 dummy.state = 0;
1600 dummy.button = 0;
1601 for (i = 0; i < 5; i++)
1602 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1603 dummy.button = i;
1605 /* Don't allow any geometry request from the user. */
1606 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1607 XtSetValues (menu, av, ac);
1609 /* Display the menu. */
1610 lw_popup_menu (menu, (XEvent *) &dummy);
1611 popup_activated_flag = 1;
1612 x_activate_timeout_atimer ();
1615 int fact = 4 * sizeof (LWLIB_ID);
1616 int specpdl_count = SPECPDL_INDEX ();
1617 record_unwind_protect (pop_down_menu,
1618 Fcons (make_number (menu_id >> (fact)),
1619 make_number (menu_id & ~(-1 << (fact)))));
1621 /* Process events that apply to the menu. */
1622 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1624 unbind_to (specpdl_count, Qnil);
1628 #endif /* not USE_GTK */
1630 Lisp_Object
1631 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
1632 Lisp_Object title, char **error, EMACS_UINT timestamp)
1634 int i;
1635 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1636 widget_value **submenu_stack
1637 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1638 Lisp_Object *subprefix_stack
1639 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1640 int submenu_depth = 0;
1642 int first_pane;
1644 if (! FRAME_X_P (f))
1645 abort ();
1647 *error = NULL;
1649 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1651 *error = "Empty menu";
1652 return Qnil;
1655 /* Create a tree of widget_value objects
1656 representing the panes and their items. */
1657 wv = xmalloc_widget_value ();
1658 wv->name = "menu";
1659 wv->value = 0;
1660 wv->enabled = 1;
1661 wv->button_type = BUTTON_TYPE_NONE;
1662 wv->help =Qnil;
1663 first_wv = wv;
1664 first_pane = 1;
1666 /* Loop over all panes and items, filling in the tree. */
1667 i = 0;
1668 while (i < menu_items_used)
1670 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1672 submenu_stack[submenu_depth++] = save_wv;
1673 save_wv = prev_wv;
1674 prev_wv = 0;
1675 first_pane = 1;
1676 i++;
1678 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1680 prev_wv = save_wv;
1681 save_wv = submenu_stack[--submenu_depth];
1682 first_pane = 0;
1683 i++;
1685 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1686 && submenu_depth != 0)
1687 i += MENU_ITEMS_PANE_LENGTH;
1688 /* Ignore a nil in the item list.
1689 It's meaningful only for dialog boxes. */
1690 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1691 i += 1;
1692 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1694 /* Create a new pane. */
1695 Lisp_Object pane_name, prefix;
1696 char *pane_string;
1698 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1699 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1701 #ifndef HAVE_MULTILINGUAL_MENU
1702 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1704 pane_name = ENCODE_MENU_STRING (pane_name);
1705 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1707 #endif
1708 pane_string = (NILP (pane_name)
1709 ? "" : (char *) SDATA (pane_name));
1710 /* If there is just one top-level pane, put all its items directly
1711 under the top-level menu. */
1712 if (menu_items_n_panes == 1)
1713 pane_string = "";
1715 /* If the pane has a meaningful name,
1716 make the pane a top-level menu item
1717 with its items as a submenu beneath it. */
1718 if (!keymaps && strcmp (pane_string, ""))
1720 wv = xmalloc_widget_value ();
1721 if (save_wv)
1722 save_wv->next = wv;
1723 else
1724 first_wv->contents = wv;
1725 wv->name = pane_string;
1726 if (keymaps && !NILP (prefix))
1727 wv->name++;
1728 wv->value = 0;
1729 wv->enabled = 1;
1730 wv->button_type = BUTTON_TYPE_NONE;
1731 wv->help = Qnil;
1732 save_wv = wv;
1733 prev_wv = 0;
1735 else if (first_pane)
1737 save_wv = wv;
1738 prev_wv = 0;
1740 first_pane = 0;
1741 i += MENU_ITEMS_PANE_LENGTH;
1743 else
1745 /* Create a new item within current pane. */
1746 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1747 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1748 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1749 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1750 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1751 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1752 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1753 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1755 #ifndef HAVE_MULTILINGUAL_MENU
1756 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1758 item_name = ENCODE_MENU_STRING (item_name);
1759 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1762 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1764 descrip = ENCODE_MENU_STRING (descrip);
1765 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1767 #endif /* not HAVE_MULTILINGUAL_MENU */
1769 wv = xmalloc_widget_value ();
1770 if (prev_wv)
1771 prev_wv->next = wv;
1772 else
1773 save_wv->contents = wv;
1774 wv->name = (char *) SDATA (item_name);
1775 if (!NILP (descrip))
1776 wv->key = (char *) SDATA (descrip);
1777 wv->value = 0;
1778 /* If this item has a null value,
1779 make the call_data null so that it won't display a box
1780 when the mouse is on it. */
1781 wv->call_data
1782 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
1783 wv->enabled = !NILP (enable);
1785 if (NILP (type))
1786 wv->button_type = BUTTON_TYPE_NONE;
1787 else if (EQ (type, QCtoggle))
1788 wv->button_type = BUTTON_TYPE_TOGGLE;
1789 else if (EQ (type, QCradio))
1790 wv->button_type = BUTTON_TYPE_RADIO;
1791 else
1792 abort ();
1794 wv->selected = !NILP (selected);
1796 if (! STRINGP (help))
1797 help = Qnil;
1799 wv->help = help;
1801 prev_wv = wv;
1803 i += MENU_ITEMS_ITEM_LENGTH;
1807 /* Deal with the title, if it is non-nil. */
1808 if (!NILP (title))
1810 widget_value *wv_title = xmalloc_widget_value ();
1811 widget_value *wv_sep1 = xmalloc_widget_value ();
1812 widget_value *wv_sep2 = xmalloc_widget_value ();
1814 wv_sep2->name = "--";
1815 wv_sep2->next = first_wv->contents;
1816 wv_sep2->help = Qnil;
1818 wv_sep1->name = "--";
1819 wv_sep1->next = wv_sep2;
1820 wv_sep1->help = Qnil;
1822 #ifndef HAVE_MULTILINGUAL_MENU
1823 if (STRING_MULTIBYTE (title))
1824 title = ENCODE_MENU_STRING (title);
1825 #endif
1827 wv_title->name = (char *) SDATA (title);
1828 wv_title->enabled = TRUE;
1829 wv_title->button_type = BUTTON_TYPE_NONE;
1830 wv_title->help = Qnil;
1831 wv_title->next = wv_sep1;
1832 first_wv->contents = wv_title;
1835 /* No selection has been chosen yet. */
1836 menu_item_selection = 0;
1838 /* Actually create and show the menu until popped down. */
1839 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
1841 /* Free the widget_value objects we used to specify the contents. */
1842 free_menubar_widget_value_tree (first_wv);
1844 /* Find the selected item, and its pane, to return
1845 the proper value. */
1846 if (menu_item_selection != 0)
1848 Lisp_Object prefix, entry;
1850 prefix = entry = Qnil;
1851 i = 0;
1852 while (i < menu_items_used)
1854 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1856 subprefix_stack[submenu_depth++] = prefix;
1857 prefix = entry;
1858 i++;
1860 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1862 prefix = subprefix_stack[--submenu_depth];
1863 i++;
1865 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1867 prefix
1868 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1869 i += MENU_ITEMS_PANE_LENGTH;
1871 /* Ignore a nil in the item list.
1872 It's meaningful only for dialog boxes. */
1873 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1874 i += 1;
1875 else
1877 entry
1878 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1879 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1881 if (keymaps != 0)
1883 int j;
1885 entry = Fcons (entry, Qnil);
1886 if (!NILP (prefix))
1887 entry = Fcons (prefix, entry);
1888 for (j = submenu_depth - 1; j >= 0; j--)
1889 if (!NILP (subprefix_stack[j]))
1890 entry = Fcons (subprefix_stack[j], entry);
1892 return entry;
1894 i += MENU_ITEMS_ITEM_LENGTH;
1898 else if (!for_click)
1899 /* Make "Cancel" equivalent to C-g. */
1900 Fsignal (Qquit, Qnil);
1902 return Qnil;
1905 #ifdef USE_GTK
1906 static void
1907 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1909 /* The EMACS_INT cast avoids a warning. There's no problem
1910 as long as pointers have enough bits to hold small integers. */
1911 if ((int) (EMACS_INT) client_data != -1)
1912 menu_item_selection = (Lisp_Object *) client_data;
1914 popup_activated_flag = 0;
1917 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1918 dialog pops down.
1919 menu_item_selection will be set to the selection. */
1920 static void
1921 create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
1923 GtkWidget *menu;
1925 if (! FRAME_X_P (f))
1926 abort ();
1928 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1929 G_CALLBACK (dialog_selection_callback),
1930 G_CALLBACK (popup_deactivate_callback),
1933 if (menu)
1935 int specpdl_count = SPECPDL_INDEX ();
1936 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1938 /* Display the menu. */
1939 gtk_widget_show_all (menu);
1941 /* Process events that apply to the menu. */
1942 popup_widget_loop (1, menu);
1944 unbind_to (specpdl_count, Qnil);
1948 #else /* not USE_GTK */
1949 static void
1950 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1952 /* The EMACS_INT cast avoids a warning. There's no problem
1953 as long as pointers have enough bits to hold small integers. */
1954 if ((int) (EMACS_INT) client_data != -1)
1955 menu_item_selection = (Lisp_Object *) client_data;
1957 BLOCK_INPUT;
1958 lw_destroy_all_widgets (id);
1959 UNBLOCK_INPUT;
1960 popup_activated_flag = 0;
1964 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1965 dialog pops down.
1966 menu_item_selection will be set to the selection. */
1967 static void
1968 create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
1970 LWLIB_ID dialog_id;
1972 if (!FRAME_X_P (f))
1973 abort();
1975 dialog_id = widget_id_tick++;
1976 #ifdef USE_LUCID
1977 apply_systemfont_to_dialog (f->output_data.x->widget);
1978 #endif
1979 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1980 f->output_data.x->widget, 1, 0,
1981 dialog_selection_callback, 0, 0);
1982 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1983 /* Display the dialog box. */
1984 lw_pop_up_all_widgets (dialog_id);
1985 popup_activated_flag = 1;
1986 x_activate_timeout_atimer ();
1988 /* Process events that apply to the dialog box.
1989 Also handle timers. */
1991 int count = SPECPDL_INDEX ();
1992 int fact = 4 * sizeof (LWLIB_ID);
1994 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1995 record_unwind_protect (pop_down_menu,
1996 Fcons (make_number (dialog_id >> (fact)),
1997 make_number (dialog_id & ~(-1 << (fact)))));
1999 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2000 dialog_id, 1);
2002 unbind_to (count, Qnil);
2006 #endif /* not USE_GTK */
2008 static char * button_names [] = {
2009 "button1", "button2", "button3", "button4", "button5",
2010 "button6", "button7", "button8", "button9", "button10" };
2012 static Lisp_Object
2013 xdialog_show (FRAME_PTR f, int keymaps, Lisp_Object title, Lisp_Object header, char **error_name)
2015 int i, nb_buttons=0;
2016 char dialog_name[6];
2018 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2020 /* Number of elements seen so far, before boundary. */
2021 int left_count = 0;
2022 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2023 int boundary_seen = 0;
2025 if (! FRAME_X_P (f))
2026 abort ();
2028 *error_name = NULL;
2030 if (menu_items_n_panes > 1)
2032 *error_name = "Multiple panes in dialog box";
2033 return Qnil;
2036 /* Create a tree of widget_value objects
2037 representing the text label and buttons. */
2039 Lisp_Object pane_name, prefix;
2040 char *pane_string;
2041 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2042 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2043 pane_string = (NILP (pane_name)
2044 ? "" : (char *) SDATA (pane_name));
2045 prev_wv = xmalloc_widget_value ();
2046 prev_wv->value = pane_string;
2047 if (keymaps && !NILP (prefix))
2048 prev_wv->name++;
2049 prev_wv->enabled = 1;
2050 prev_wv->name = "message";
2051 prev_wv->help = Qnil;
2052 first_wv = prev_wv;
2054 /* Loop over all panes and items, filling in the tree. */
2055 i = MENU_ITEMS_PANE_LENGTH;
2056 while (i < menu_items_used)
2059 /* Create a new item within current pane. */
2060 Lisp_Object item_name, enable, descrip;
2061 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2062 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2063 descrip
2064 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2066 if (NILP (item_name))
2068 free_menubar_widget_value_tree (first_wv);
2069 *error_name = "Submenu in dialog items";
2070 return Qnil;
2072 if (EQ (item_name, Qquote))
2074 /* This is the boundary between left-side elts
2075 and right-side elts. Stop incrementing right_count. */
2076 boundary_seen = 1;
2077 i++;
2078 continue;
2080 if (nb_buttons >= 9)
2082 free_menubar_widget_value_tree (first_wv);
2083 *error_name = "Too many dialog items";
2084 return Qnil;
2087 wv = xmalloc_widget_value ();
2088 prev_wv->next = wv;
2089 wv->name = (char *) button_names[nb_buttons];
2090 if (!NILP (descrip))
2091 wv->key = (char *) SDATA (descrip);
2092 wv->value = (char *) SDATA (item_name);
2093 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2094 wv->enabled = !NILP (enable);
2095 wv->help = Qnil;
2096 prev_wv = wv;
2098 if (! boundary_seen)
2099 left_count++;
2101 nb_buttons++;
2102 i += MENU_ITEMS_ITEM_LENGTH;
2105 /* If the boundary was not specified,
2106 by default put half on the left and half on the right. */
2107 if (! boundary_seen)
2108 left_count = nb_buttons - nb_buttons / 2;
2110 wv = xmalloc_widget_value ();
2111 wv->name = dialog_name;
2112 wv->help = Qnil;
2114 /* Frame title: 'Q' = Question, 'I' = Information.
2115 Can also have 'E' = Error if, one day, we want
2116 a popup for errors. */
2117 if (NILP(header))
2118 dialog_name[0] = 'Q';
2119 else
2120 dialog_name[0] = 'I';
2122 /* Dialog boxes use a really stupid name encoding
2123 which specifies how many buttons to use
2124 and how many buttons are on the right. */
2125 dialog_name[1] = '0' + nb_buttons;
2126 dialog_name[2] = 'B';
2127 dialog_name[3] = 'R';
2128 /* Number of buttons to put on the right. */
2129 dialog_name[4] = '0' + nb_buttons - left_count;
2130 dialog_name[5] = 0;
2131 wv->contents = first_wv;
2132 first_wv = wv;
2135 /* No selection has been chosen yet. */
2136 menu_item_selection = 0;
2138 /* Actually create and show the dialog. */
2139 create_and_show_dialog (f, first_wv);
2141 /* Free the widget_value objects we used to specify the contents. */
2142 free_menubar_widget_value_tree (first_wv);
2144 /* Find the selected item, and its pane, to return
2145 the proper value. */
2146 if (menu_item_selection != 0)
2148 Lisp_Object prefix;
2150 prefix = Qnil;
2151 i = 0;
2152 while (i < menu_items_used)
2154 Lisp_Object entry;
2156 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2158 prefix
2159 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2160 i += MENU_ITEMS_PANE_LENGTH;
2162 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2164 /* This is the boundary between left-side elts and
2165 right-side elts. */
2166 ++i;
2168 else
2170 entry
2171 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2172 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2174 if (keymaps != 0)
2176 entry = Fcons (entry, Qnil);
2177 if (!NILP (prefix))
2178 entry = Fcons (prefix, entry);
2180 return entry;
2182 i += MENU_ITEMS_ITEM_LENGTH;
2186 else
2187 /* Make "Cancel" equivalent to C-g. */
2188 Fsignal (Qquit, Qnil);
2190 return Qnil;
2193 #else /* not USE_X_TOOLKIT && not USE_GTK */
2195 /* The frame of the last activated non-toolkit menu bar.
2196 Used to generate menu help events. */
2198 static struct frame *menu_help_frame;
2201 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2203 PANE is the pane number, and ITEM is the menu item number in
2204 the menu (currently not used).
2206 This cannot be done with generating a HELP_EVENT because
2207 XMenuActivate contains a loop that doesn't let Emacs process
2208 keyboard events. */
2210 static void
2211 menu_help_callback (char *help_string, int pane, int item)
2213 extern Lisp_Object Qmenu_item;
2214 Lisp_Object *first_item;
2215 Lisp_Object pane_name;
2216 Lisp_Object menu_object;
2218 first_item = XVECTOR (menu_items)->contents;
2219 if (EQ (first_item[0], Qt))
2220 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2221 else if (EQ (first_item[0], Qquote))
2222 /* This shouldn't happen, see xmenu_show. */
2223 pane_name = empty_unibyte_string;
2224 else
2225 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2227 /* (menu-item MENU-NAME PANE-NUMBER) */
2228 menu_object = Fcons (Qmenu_item,
2229 Fcons (pane_name,
2230 Fcons (make_number (pane), Qnil)));
2231 show_help_echo (help_string ? build_string (help_string) : Qnil,
2232 Qnil, menu_object, make_number (item), 1);
2235 static Lisp_Object
2236 pop_down_menu (Lisp_Object arg)
2238 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2239 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2241 FRAME_PTR f = p1->pointer;
2242 XMenu *menu = p2->pointer;
2244 BLOCK_INPUT;
2245 #ifndef MSDOS
2246 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2247 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2248 #endif
2249 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2251 #ifdef HAVE_X_WINDOWS
2252 /* Assume the mouse has moved out of the X window.
2253 If it has actually moved in, we will get an EnterNotify. */
2254 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2256 /* State that no mouse buttons are now held.
2257 (The oldXMenu code doesn't track this info for us.)
2258 That is not necessarily true, but the fiction leads to reasonable
2259 results, and it is a pain to ask which are actually held now. */
2260 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2262 #endif /* HAVE_X_WINDOWS */
2264 UNBLOCK_INPUT;
2266 return Qnil;
2270 Lisp_Object
2271 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
2272 Lisp_Object title, char **error, EMACS_UINT timestamp)
2274 Window root;
2275 XMenu *menu;
2276 int pane, selidx, lpane, status;
2277 Lisp_Object entry, pane_prefix;
2278 char *datap;
2279 int ulx, uly, width, height;
2280 int dispwidth, dispheight;
2281 int i, j, lines, maxlines;
2282 int maxwidth;
2283 int dummy_int;
2284 unsigned int dummy_uint;
2285 int specpdl_count = SPECPDL_INDEX ();
2287 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2288 abort ();
2290 *error = 0;
2291 if (menu_items_n_panes == 0)
2292 return Qnil;
2294 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2296 *error = "Empty menu";
2297 return Qnil;
2300 /* Figure out which root window F is on. */
2301 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2302 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2303 &dummy_uint, &dummy_uint);
2305 /* Make the menu on that window. */
2306 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2307 if (menu == NULL)
2309 *error = "Can't create menu";
2310 return Qnil;
2313 /* Don't GC while we prepare and show the menu,
2314 because we give the oldxmenu library pointers to the
2315 contents of strings. */
2316 inhibit_garbage_collection ();
2318 #ifdef HAVE_X_WINDOWS
2319 /* Adjust coordinates to relative to the outer (window manager) window. */
2320 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2321 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2322 #endif /* HAVE_X_WINDOWS */
2324 /* Adjust coordinates to be root-window-relative. */
2325 x += f->left_pos;
2326 y += f->top_pos;
2328 /* Create all the necessary panes and their items. */
2329 maxlines = lines = i = 0;
2330 while (i < menu_items_used)
2332 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2334 /* Create a new pane. */
2335 Lisp_Object pane_name, prefix;
2336 char *pane_string;
2338 maxlines = max (maxlines, lines);
2339 lines = 0;
2340 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2341 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2342 pane_string = (NILP (pane_name)
2343 ? "" : (char *) SDATA (pane_name));
2344 if (keymaps && !NILP (prefix))
2345 pane_string++;
2347 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2348 if (lpane == XM_FAILURE)
2350 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2351 *error = "Can't create pane";
2352 return Qnil;
2354 i += MENU_ITEMS_PANE_LENGTH;
2356 /* Find the width of the widest item in this pane. */
2357 maxwidth = 0;
2358 j = i;
2359 while (j < menu_items_used)
2361 Lisp_Object item;
2362 item = XVECTOR (menu_items)->contents[j];
2363 if (EQ (item, Qt))
2364 break;
2365 if (NILP (item))
2367 j++;
2368 continue;
2370 width = SBYTES (item);
2371 if (width > maxwidth)
2372 maxwidth = width;
2374 j += MENU_ITEMS_ITEM_LENGTH;
2377 /* Ignore a nil in the item list.
2378 It's meaningful only for dialog boxes. */
2379 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2380 i += 1;
2381 else
2383 /* Create a new item within current pane. */
2384 Lisp_Object item_name, enable, descrip, help;
2385 unsigned char *item_data;
2386 char *help_string;
2388 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2389 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2390 descrip
2391 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2392 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2393 help_string = STRINGP (help) ? SDATA (help) : NULL;
2395 if (!NILP (descrip))
2397 int gap = maxwidth - SBYTES (item_name);
2398 /* if alloca is fast, use that to make the space,
2399 to reduce gc needs. */
2400 item_data
2401 = (unsigned char *) alloca (maxwidth
2402 + SBYTES (descrip) + 1);
2403 memcpy (item_data, SDATA (item_name), SBYTES (item_name));
2404 for (j = SCHARS (item_name); j < maxwidth; j++)
2405 item_data[j] = ' ';
2406 memcpy (item_data + j, SDATA (descrip), SBYTES (descrip));
2407 item_data[j + SBYTES (descrip)] = 0;
2409 else
2410 item_data = SDATA (item_name);
2412 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2413 menu, lpane, 0, item_data,
2414 !NILP (enable), help_string)
2415 == XM_FAILURE)
2417 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2418 *error = "Can't add selection to menu";
2419 return Qnil;
2421 i += MENU_ITEMS_ITEM_LENGTH;
2422 lines++;
2426 maxlines = max (maxlines, lines);
2428 /* All set and ready to fly. */
2429 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2430 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2431 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2432 x = min (x, dispwidth);
2433 y = min (y, dispheight);
2434 x = max (x, 1);
2435 y = max (y, 1);
2436 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2437 &ulx, &uly, &width, &height);
2438 if (ulx+width > dispwidth)
2440 x -= (ulx + width) - dispwidth;
2441 ulx = dispwidth - width;
2443 if (uly+height > dispheight)
2445 y -= (uly + height) - dispheight;
2446 uly = dispheight - height;
2448 #ifndef HAVE_X_WINDOWS
2449 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2451 /* Move the menu away of the echo area, to avoid overwriting the
2452 menu with help echo messages or vice versa. */
2453 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2455 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2456 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2458 else
2460 y--;
2461 uly--;
2464 #endif
2465 if (ulx < 0) x -= ulx;
2466 if (uly < 0) y -= uly;
2468 if (! for_click)
2470 /* If position was not given by a mouse click, adjust so upper left
2471 corner of the menu as a whole ends up at given coordinates. This
2472 is what x-popup-menu says in its documentation. */
2473 x += width/2;
2474 y += 1.5*height/(maxlines+2);
2477 XMenuSetAEQ (menu, TRUE);
2478 XMenuSetFreeze (menu, TRUE);
2479 pane = selidx = 0;
2481 #ifndef MSDOS
2482 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2483 #endif
2485 record_unwind_protect (pop_down_menu,
2486 Fcons (make_save_value (f, 0),
2487 make_save_value (menu, 0)));
2489 /* Help display under X won't work because XMenuActivate contains
2490 a loop that doesn't give Emacs a chance to process it. */
2491 menu_help_frame = f;
2492 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2493 x, y, ButtonReleaseMask, &datap,
2494 menu_help_callback);
2496 switch (status)
2498 case XM_SUCCESS:
2499 #ifdef XDEBUG
2500 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2501 #endif
2503 /* Find the item number SELIDX in pane number PANE. */
2504 i = 0;
2505 while (i < menu_items_used)
2507 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2509 if (pane == 0)
2510 pane_prefix
2511 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2512 pane--;
2513 i += MENU_ITEMS_PANE_LENGTH;
2515 else
2517 if (pane == -1)
2519 if (selidx == 0)
2521 entry
2522 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2523 if (keymaps != 0)
2525 entry = Fcons (entry, Qnil);
2526 if (!NILP (pane_prefix))
2527 entry = Fcons (pane_prefix, entry);
2529 break;
2531 selidx--;
2533 i += MENU_ITEMS_ITEM_LENGTH;
2536 break;
2538 case XM_FAILURE:
2539 *error = "Can't activate menu";
2540 case XM_IA_SELECT:
2541 entry = Qnil;
2542 break;
2543 case XM_NO_SELECT:
2544 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2545 the menu was invoked with a mouse event as POSITION). */
2546 if (! for_click)
2547 Fsignal (Qquit, Qnil);
2548 entry = Qnil;
2549 break;
2552 unbind_to (specpdl_count, Qnil);
2554 return entry;
2557 #endif /* not USE_X_TOOLKIT */
2559 #endif /* HAVE_MENUS */
2561 /* Detect if a dialog or menu has been posted. */
2564 popup_activated (void)
2566 return popup_activated_flag;
2569 /* The following is used by delayed window autoselection. */
2571 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2572 doc: /* Return t if a menu or popup dialog is active. */)
2573 (void)
2575 #ifdef HAVE_MENUS
2576 return (popup_activated ()) ? Qt : Qnil;
2577 #else
2578 return Qnil;
2579 #endif /* HAVE_MENUS */
2582 void
2583 syms_of_xmenu (void)
2585 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
2586 staticpro (&Qdebug_on_next_call);
2588 #ifdef USE_X_TOOLKIT
2589 widget_id_tick = (1<<16);
2590 next_menubar_widget_id = 1;
2591 #endif
2593 defsubr (&Smenu_or_popup_active_p);
2595 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2596 defsubr (&Sx_menu_bar_open_internal);
2597 Ffset (intern_c_string ("accelerate-menu"),
2598 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2599 #endif
2601 #ifdef HAVE_MENUS
2602 defsubr (&Sx_popup_dialog);
2603 #endif
2606 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2607 (do not change this comment) */