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