Merge changes from emacs-23 branch.
[bpt/emacs.git] / src / xmenu.c
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.
4
5 This file is part of GNU Emacs.
6
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.
11
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.
16
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/>. */
19
20 /* X pop-up deck-of-cards menu facility for GNU Emacs.
21 *
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
24 *
25 */
26
27 /* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
29
30 /* Rewritten for clarity and GC protection by rms in Feb 94. */
31
32 #include <config.h>
33
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
38
39 #include <stdio.h>
40 #include <setjmp.h>
41
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"
53
54 #ifdef MSDOS
55 #include "msdos.h"
56 #endif
57
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
63
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
69
70 #include "dispextern.h"
71
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 */
99
100 #ifdef USE_GTK
101 #include "gtkutil.h"
102 #endif
103
104 #include "menu.h"
105
106 #ifndef TRUE
107 #define TRUE 1
108 #define FALSE 0
109 #endif /* no TRUE */
110
111 Lisp_Object Qdebug_on_next_call;
112
113 extern Lisp_Object Qmenu_bar;
114
115 extern Lisp_Object QCtoggle, QCradio;
116
117 extern Lisp_Object Voverriding_local_map;
118 extern Lisp_Object Voverriding_local_map_menu_flag;
119
120 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
121
122 extern Lisp_Object Qmenu_bar_update_hook;
123
124 #ifdef USE_X_TOOLKIT
125 extern void set_frame_menubar (FRAME_PTR, int, int);
126 extern XtAppContext Xt_app_con;
127
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 */
133
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
139
140 static int update_frame_menubar (struct frame *);
141 \f
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;
145
146 static int next_menubar_widget_id;
147
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
153
154 /* This is set nonzero after the user activates the menu bar, and set
155 to zero again after the menu bars are redisplayed by prepare_menu_bar.
156 While it is nonzero, all calls to set_frame_menubar go deep.
157
158 I don't understand why this is needed, but it does seem to be
159 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
160
161 int pending_menu_activation;
162 \f
163 #ifdef USE_X_TOOLKIT
164
165 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
166
167 static struct frame *
168 menubar_id_to_frame (id)
169 LWLIB_ID id;
170 {
171 Lisp_Object tail, frame;
172 FRAME_PTR f;
173
174 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
175 {
176 frame = XCAR (tail);
177 if (!FRAMEP (frame))
178 continue;
179 f = XFRAME (frame);
180 if (!FRAME_WINDOW_P (f))
181 continue;
182 if (f->output_data.x->id == id)
183 return f;
184 }
185 return 0;
186 }
187
188 #endif
189 \f
190 #ifdef HAVE_X_WINDOWS
191 /* Return the mouse position in *X and *Y. The coordinates are window
192 relative for the edit window in frame F.
193 This is for Fx_popup_menu. The mouse_position_hook can not
194 be used for X, as it returns window relative coordinates
195 for the window where the mouse is in. This could be the menu bar,
196 the scroll bar or the edit window. Fx_popup_menu needs to be
197 sure it is the edit window. */
198 void
199 mouse_position_for_popup (FRAME_PTR f, int *x, int *y)
200 {
201 Window root, dummy_window;
202 int dummy;
203
204 if (! FRAME_X_P (f))
205 abort ();
206
207 BLOCK_INPUT;
208
209 XQueryPointer (FRAME_X_DISPLAY (f),
210 DefaultRootWindow (FRAME_X_DISPLAY (f)),
211
212 /* The root window which contains the pointer. */
213 &root,
214
215 /* Window pointer is on, not used */
216 &dummy_window,
217
218 /* The position on that root window. */
219 x, y,
220
221 /* x/y in dummy_window coordinates, not used. */
222 &dummy, &dummy,
223
224 /* Modifier keys and pointer buttons, about which
225 we don't care. */
226 (unsigned int *) &dummy);
227
228 UNBLOCK_INPUT;
229
230 /* xmenu_show expects window coordinates, not root window
231 coordinates. Translate. */
232 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
233 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
234 }
235
236 #endif /* HAVE_X_WINDOWS */
237
238 #ifdef HAVE_MENUS
239
240 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
241 doc: /* Pop up a dialog box and return user's selection.
242 POSITION specifies which frame to use.
243 This is normally a mouse button event or a window or frame.
244 If POSITION is t, it means to use the frame the mouse is on.
245 The dialog box appears in the middle of the specified frame.
246
247 CONTENTS specifies the alternatives to display in the dialog box.
248 It is a list of the form (DIALOG ITEM1 ITEM2...).
249 Each ITEM is a cons cell (STRING . VALUE).
250 The return value is VALUE from the chosen item.
251
252 An ITEM may also be just a string--that makes a nonselectable item.
253 An ITEM may also be nil--that means to put all preceding items
254 on the left of the dialog box and all following items on the right.
255 \(By default, approximately half appear on each side.)
256
257 If HEADER is non-nil, the frame title for the box is "Information",
258 otherwise it is "Question".
259
260 If the user gets rid of the dialog box without making a valid choice,
261 for instance using the window manager, then this produces a quit and
262 `x-popup-dialog' does not return. */)
263 (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
264 {
265 FRAME_PTR f = NULL;
266 Lisp_Object window;
267
268 check_x ();
269
270 /* Decode the first argument: find the window or frame to use. */
271 if (EQ (position, Qt)
272 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
273 || EQ (XCAR (position), Qtool_bar))))
274 {
275 #if 0 /* Using the frame the mouse is on may not be right. */
276 /* Use the mouse's current position. */
277 FRAME_PTR new_f = SELECTED_FRAME ();
278 Lisp_Object bar_window;
279 enum scroll_bar_part part;
280 unsigned long time;
281 Lisp_Object x, y;
282
283 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
284
285 if (new_f != 0)
286 XSETFRAME (window, new_f);
287 else
288 window = selected_window;
289 #endif
290 window = selected_window;
291 }
292 else if (CONSP (position))
293 {
294 Lisp_Object tem;
295 tem = Fcar (position);
296 if (CONSP (tem))
297 window = Fcar (Fcdr (position));
298 else
299 {
300 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
301 window = Fcar (tem); /* POSN_WINDOW (tem) */
302 }
303 }
304 else if (WINDOWP (position) || FRAMEP (position))
305 window = position;
306 else
307 window = Qnil;
308
309 /* Decode where to put the menu. */
310
311 if (FRAMEP (window))
312 f = XFRAME (window);
313 else if (WINDOWP (window))
314 {
315 CHECK_LIVE_WINDOW (window);
316 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
317 }
318 else
319 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
320 but I don't want to make one now. */
321 CHECK_WINDOW (window);
322
323 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
324 error ("Can not put X dialog on this terminal");
325
326 /* Force a redisplay before showing the dialog. If a frame is created
327 just before showing the dialog, its contents may not have been fully
328 drawn, as this depends on timing of events from the X server. Redisplay
329 is not done when a dialog is shown. If redisplay could be done in the
330 X event loop (i.e. the X event loop does not run in a signal handler)
331 this would not be needed.
332
333 Do this before creating the widget value that points to Lisp
334 string contents, because Fredisplay may GC and relocate them. */
335 Fredisplay (Qt);
336
337 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
338 /* Display a menu with these alternatives
339 in the middle of frame F. */
340 {
341 Lisp_Object x, y, frame, newpos;
342 XSETFRAME (frame, f);
343 XSETINT (x, x_pixel_width (f) / 2);
344 XSETINT (y, x_pixel_height (f) / 2);
345 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
346
347 return Fx_popup_menu (newpos,
348 Fcons (Fcar (contents), Fcons (contents, Qnil)));
349 }
350 #else
351 {
352 Lisp_Object title;
353 char *error_name;
354 Lisp_Object selection;
355 int specpdl_count = SPECPDL_INDEX ();
356
357 /* Decode the dialog items from what was specified. */
358 title = Fcar (contents);
359 CHECK_STRING (title);
360 record_unwind_protect (unuse_menu_items, Qnil);
361
362 if (NILP (Fcar (Fcdr (contents))))
363 /* No buttons specified, add an "Ok" button so users can pop down
364 the dialog. Also, the lesstif/motif version crashes if there are
365 no buttons. */
366 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil));
367
368 list_of_panes (Fcons (contents, Qnil));
369
370 /* Display them in a dialog box. */
371 BLOCK_INPUT;
372 selection = xdialog_show (f, 0, title, header, &error_name);
373 UNBLOCK_INPUT;
374
375 unbind_to (specpdl_count, Qnil);
376 discard_menu_items ();
377
378 if (error_name) error (error_name);
379 return selection;
380 }
381 #endif
382 }
383
384
385 #ifndef MSDOS
386
387 /* Set menu_items_inuse so no other popup menu or dialog is created. */
388
389 void
390 x_menu_set_in_use (int in_use)
391 {
392 menu_items_inuse = in_use ? Qt : Qnil;
393 popup_activated_flag = in_use;
394 #ifdef USE_X_TOOLKIT
395 if (popup_activated_flag)
396 x_activate_timeout_atimer ();
397 #endif
398 }
399
400 /* Wait for an X event to arrive or for a timer to expire. */
401
402 void
403 x_menu_wait_for_event (void *data)
404 {
405 /* Another way to do this is to register a timer callback, that can be
406 done in GTK and Xt. But we have to do it like this when using only X
407 anyway, and with callbacks we would have three variants for timer handling
408 instead of the small ifdefs below. */
409
410 while (
411 #ifdef USE_X_TOOLKIT
412 ! XtAppPending (Xt_app_con)
413 #elif defined USE_GTK
414 ! gtk_events_pending ()
415 #else
416 ! XPending ((Display*) data)
417 #endif
418 )
419 {
420 EMACS_TIME next_time = timer_check (1), *ntp;
421 long secs = EMACS_SECS (next_time);
422 long usecs = EMACS_USECS (next_time);
423 SELECT_TYPE read_fds;
424 struct x_display_info *dpyinfo;
425 int n = 0;
426
427 FD_ZERO (&read_fds);
428 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
429 {
430 int fd = ConnectionNumber (dpyinfo->display);
431 FD_SET (fd, &read_fds);
432 if (fd > n) n = fd;
433 XFlush (dpyinfo->display);
434 }
435
436 if (secs < 0 && usecs < 0)
437 ntp = 0;
438 else
439 ntp = &next_time;
440
441 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp);
442 }
443 }
444 #endif /* ! MSDOS */
445
446 \f
447 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
448
449 #ifdef USE_X_TOOLKIT
450
451 /* Loop in Xt until the menu pulldown or dialog popup has been
452 popped down (deactivated). This is used for x-popup-menu
453 and x-popup-dialog; it is not used for the menu bar.
454
455 NOTE: All calls to popup_get_selection should be protected
456 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
457
458 static void
459 popup_get_selection (initial_event, dpyinfo, id, do_timers)
460 XEvent *initial_event;
461 struct x_display_info *dpyinfo;
462 LWLIB_ID id;
463 int do_timers;
464 {
465 XEvent event;
466
467 while (popup_activated_flag)
468 {
469 if (initial_event)
470 {
471 event = *initial_event;
472 initial_event = 0;
473 }
474 else
475 {
476 if (do_timers) x_menu_wait_for_event (0);
477 XtAppNextEvent (Xt_app_con, &event);
478 }
479
480 /* Make sure we don't consider buttons grabbed after menu goes.
481 And make sure to deactivate for any ButtonRelease,
482 even if XtDispatchEvent doesn't do that. */
483 if (event.type == ButtonRelease
484 && dpyinfo->display == event.xbutton.display)
485 {
486 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
487 #ifdef USE_MOTIF /* Pretending that the event came from a
488 Btn1Down seems the only way to convince Motif to
489 activate its callbacks; setting the XmNmenuPost
490 isn't working. --marcus@sysc.pdx.edu. */
491 event.xbutton.button = 1;
492 /* Motif only pops down menus when no Ctrl, Alt or Mod
493 key is pressed and the button is released. So reset key state
494 so Motif thinks this is the case. */
495 event.xbutton.state = 0;
496 #endif
497 }
498 /* Pop down on C-g and Escape. */
499 else if (event.type == KeyPress
500 && dpyinfo->display == event.xbutton.display)
501 {
502 KeySym keysym = XLookupKeysym (&event.xkey, 0);
503
504 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
505 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
506 popup_activated_flag = 0;
507 }
508
509 x_dispatch_event (&event, event.xany.display);
510 }
511 }
512
513 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
514 doc: /* Start key navigation of the menu bar in FRAME.
515 This initially opens the first menu bar item and you can then navigate with the
516 arrow keys, select a menu entry with the return key or cancel with the
517 escape key. If FRAME has no menu bar this function does nothing.
518
519 If FRAME is nil or not given, use the selected frame. */)
520 (Lisp_Object frame)
521 {
522 XEvent ev;
523 FRAME_PTR f = check_x_frame (frame);
524 Widget menubar;
525 BLOCK_INPUT;
526
527 if (FRAME_EXTERNAL_MENU_BAR (f))
528 set_frame_menubar (f, 0, 1);
529
530 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
531 if (menubar)
532 {
533 Window child;
534 int error_p = 0;
535
536 x_catch_errors (FRAME_X_DISPLAY (f));
537 memset (&ev, 0, sizeof ev);
538 ev.xbutton.display = FRAME_X_DISPLAY (f);
539 ev.xbutton.window = XtWindow (menubar);
540 ev.xbutton.root = FRAME_X_DISPLAY_INFO (f)->root_window;
541 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
542 ev.xbutton.button = Button1;
543 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
544 ev.xbutton.same_screen = True;
545
546 #ifdef USE_MOTIF
547 {
548 Arg al[2];
549 WidgetList list;
550 Cardinal nr;
551 XtSetArg (al[0], XtNchildren, &list);
552 XtSetArg (al[1], XtNnumChildren, &nr);
553 XtGetValues (menubar, al, 2);
554 ev.xbutton.window = XtWindow (list[0]);
555 }
556 #endif
557
558 XTranslateCoordinates (FRAME_X_DISPLAY (f),
559 /* From-window, to-window. */
560 ev.xbutton.window, ev.xbutton.root,
561
562 /* From-position, to-position. */
563 ev.xbutton.x, ev.xbutton.y,
564 &ev.xbutton.x_root, &ev.xbutton.y_root,
565
566 /* Child of win. */
567 &child);
568 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
569 x_uncatch_errors ();
570
571 if (! error_p)
572 {
573 ev.type = ButtonPress;
574 ev.xbutton.state = 0;
575
576 XtDispatchEvent (&ev);
577 ev.xbutton.type = ButtonRelease;
578 ev.xbutton.state = Button1Mask;
579 XtDispatchEvent (&ev);
580 }
581 }
582
583 UNBLOCK_INPUT;
584
585 return Qnil;
586 }
587 #endif /* USE_X_TOOLKIT */
588
589
590 #ifdef USE_GTK
591 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
592 doc: /* Start key navigation of the menu bar in FRAME.
593 This initially opens the first menu bar item and you can then navigate with the
594 arrow keys, select a menu entry with the return key or cancel with the
595 escape key. If FRAME has no menu bar this function does nothing.
596
597 If FRAME is nil or not given, use the selected frame. */)
598 (Lisp_Object frame)
599 {
600 GtkWidget *menubar;
601 FRAME_PTR f;
602
603 /* gcc 2.95 doesn't accept the FRAME_PTR declaration after
604 BLOCK_INPUT. */
605
606 BLOCK_INPUT;
607 f = check_x_frame (frame);
608
609 if (FRAME_EXTERNAL_MENU_BAR (f))
610 set_frame_menubar (f, 0, 1);
611
612 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
613 if (menubar)
614 {
615 /* Activate the first menu. */
616 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
617
618 if (children)
619 {
620 g_signal_emit_by_name (children->data, "activate_item");
621 popup_activated_flag = 1;
622 g_list_free (children);
623 }
624 }
625 UNBLOCK_INPUT;
626
627 return Qnil;
628 }
629
630 /* Loop util popup_activated_flag is set to zero in a callback.
631 Used for popup menus and dialogs. */
632
633 static void
634 popup_widget_loop (int do_timers, GtkWidget *widget)
635 {
636 ++popup_activated_flag;
637
638 /* Process events in the Gtk event loop until done. */
639 while (popup_activated_flag)
640 {
641 if (do_timers) x_menu_wait_for_event (0);
642 gtk_main_iteration ();
643 }
644 }
645 #endif
646
647 /* Activate the menu bar of frame F.
648 This is called from keyboard.c when it gets the
649 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
650
651 To activate the menu bar, we use the X button-press event
652 that was saved in saved_menu_event.
653 That makes the toolkit do its thing.
654
655 But first we recompute the menu bar contents (the whole tree).
656
657 The reason for saving the button event until here, instead of
658 passing it to the toolkit right away, is that we can safely
659 execute Lisp code. */
660
661 void
662 x_activate_menubar (FRAME_PTR f)
663 {
664 if (! FRAME_X_P (f))
665 abort ();
666
667 if (!f->output_data.x->saved_menu_event->type)
668 return;
669
670 #ifdef USE_GTK
671 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
672 f->output_data.x->saved_menu_event->xany.window))
673 return;
674 #endif
675
676 set_frame_menubar (f, 0, 1);
677 BLOCK_INPUT;
678 #ifdef USE_GTK
679 /* If we click outside any menu item, the menu bar still grabs.
680 So we send Press and the Release. If outside, grab is released.
681 If on a menu item, it is popped up normally.
682 PutBack is like a stack, so we put back in reverse order. */
683 f->output_data.x->saved_menu_event->type = ButtonRelease;
684 XPutBackEvent (f->output_data.x->display_info->display,
685 f->output_data.x->saved_menu_event);
686 f->output_data.x->saved_menu_event->type = ButtonPress;
687 XPutBackEvent (f->output_data.x->display_info->display,
688 f->output_data.x->saved_menu_event);
689 popup_activated_flag = 1;
690 #else
691 XtDispatchEvent (f->output_data.x->saved_menu_event);
692 #endif
693 UNBLOCK_INPUT;
694 #ifdef USE_MOTIF
695 if (f->output_data.x->saved_menu_event->type == ButtonRelease)
696 pending_menu_activation = 1;
697 #endif
698
699 /* Ignore this if we get it a second time. */
700 f->output_data.x->saved_menu_event->type = 0;
701 }
702
703 /* This callback is invoked when the user selects a menubar cascade
704 pushbutton, but before the pulldown menu is posted. */
705
706 #ifndef USE_GTK
707 static void
708 popup_activate_callback (widget, id, client_data)
709 Widget widget;
710 LWLIB_ID id;
711 XtPointer client_data;
712 {
713 popup_activated_flag = 1;
714 #ifdef USE_X_TOOLKIT
715 x_activate_timeout_atimer ();
716 #endif
717 }
718 #endif
719
720 /* This callback is invoked when a dialog or menu is finished being
721 used and has been unposted. */
722
723 #ifdef USE_GTK
724 static void
725 popup_deactivate_callback (GtkWidget *widget, gpointer client_data)
726 {
727 popup_activated_flag = 0;
728 }
729 #else
730 static void
731 popup_deactivate_callback (widget, id, client_data)
732 Widget widget;
733 LWLIB_ID id;
734 XtPointer client_data;
735 {
736 popup_activated_flag = 0;
737 }
738 #endif
739
740
741 /* Function that finds the frame for WIDGET and shows the HELP text
742 for that widget.
743 F is the frame if known, or NULL if not known. */
744 static void
745 show_help_event (FRAME_PTR f, xt_or_gtk_widget widget, Lisp_Object help)
746 {
747 Lisp_Object frame;
748
749 if (f)
750 {
751 XSETFRAME (frame, f);
752 kbd_buffer_store_help_event (frame, help);
753 }
754 else
755 {
756 #if 0 /* This code doesn't do anything useful. ++kfs */
757 /* WIDGET is the popup menu. It's parent is the frame's
758 widget. See which frame that is. */
759 xt_or_gtk_widget frame_widget = XtParent (widget);
760 Lisp_Object tail;
761
762 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
763 {
764 frame = XCAR (tail);
765 if (FRAMEP (frame)
766 && (f = XFRAME (frame),
767 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
768 break;
769 }
770 #endif
771 show_help_echo (help, Qnil, Qnil, Qnil, 1);
772 }
773 }
774
775 /* Callback called when menu items are highlighted/unhighlighted
776 while moving the mouse over them. WIDGET is the menu bar or menu
777 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
778 the data structure for the menu item, or null in case of
779 unhighlighting. */
780
781 #ifdef USE_GTK
782 void
783 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
784 {
785 xg_menu_item_cb_data *cb_data;
786 Lisp_Object help;
787
788 cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget),
789 XG_ITEM_DATA);
790 if (! cb_data) return;
791
792 help = call_data ? cb_data->help : Qnil;
793
794 /* If popup_activated_flag is greater than 1 we are in a popup menu.
795 Don't show help for them, they won't appear before the
796 popup is popped down. */
797 if (popup_activated_flag <= 1)
798 show_help_event (cb_data->cl_data->f, widget, help);
799 }
800 #else
801 void
802 menu_highlight_callback (widget, id, call_data)
803 Widget widget;
804 LWLIB_ID id;
805 void *call_data;
806 {
807 struct frame *f;
808 Lisp_Object help;
809
810 widget_value *wv = (widget_value *) call_data;
811
812 help = wv ? wv->help : Qnil;
813
814 /* Determine the frame for the help event. */
815 f = menubar_id_to_frame (id);
816
817 show_help_event (f, widget, help);
818 }
819 #endif
820
821 #ifdef USE_GTK
822 /* Gtk calls callbacks just because we tell it what item should be
823 selected in a radio group. If this variable is set to a non-zero
824 value, we are creating menus and don't want callbacks right now.
825 */
826 static int xg_crazy_callback_abort;
827
828 /* This callback is called from the menu bar pulldown menu
829 when the user makes a selection.
830 Figure out what the user chose
831 and put the appropriate events into the keyboard buffer. */
832 static void
833 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
834 {
835 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
836
837 if (xg_crazy_callback_abort)
838 return;
839
840 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
841 return;
842
843 /* For a group of radio buttons, GTK calls the selection callback first
844 for the item that was active before the selection and then for the one that
845 is active after the selection. For C-h k this means we get the help on
846 the deselected item and then the selected item is executed. Prevent that
847 by ignoring the non-active item. */
848 if (GTK_IS_RADIO_MENU_ITEM (widget)
849 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
850 return;
851
852 /* When a menu is popped down, X generates a focus event (i.e. focus
853 goes back to the frame below the menu). Since GTK buffers events,
854 we force it out here before the menu selection event. Otherwise
855 sit-for will exit at once if the focus event follows the menu selection
856 event. */
857
858 BLOCK_INPUT;
859 while (gtk_events_pending ())
860 gtk_main_iteration ();
861 UNBLOCK_INPUT;
862
863 find_and_call_menu_selection (cb_data->cl_data->f,
864 cb_data->cl_data->menu_bar_items_used,
865 cb_data->cl_data->menu_bar_vector,
866 cb_data->call_data);
867 }
868
869 #else /* not USE_GTK */
870
871 /* This callback is called from the menu bar pulldown menu
872 when the user makes a selection.
873 Figure out what the user chose
874 and put the appropriate events into the keyboard buffer. */
875 static void
876 menubar_selection_callback (widget, id, client_data)
877 Widget widget;
878 LWLIB_ID id;
879 XtPointer client_data;
880 {
881 FRAME_PTR f;
882
883 f = menubar_id_to_frame (id);
884 if (!f)
885 return;
886 find_and_call_menu_selection (f, f->menu_bar_items_used,
887 f->menu_bar_vector, client_data);
888 }
889 #endif /* not USE_GTK */
890 \f
891 /* Recompute all the widgets of frame F, when the menu bar has been
892 changed. Value is non-zero if widgets were updated. */
893
894 static int
895 update_frame_menubar (FRAME_PTR f)
896 {
897 #ifdef USE_GTK
898 return xg_update_frame_menubar (f);
899 #else
900 struct x_output *x;
901 int columns, rows;
902
903 if (! FRAME_X_P (f))
904 abort ();
905
906 x = f->output_data.x;
907
908 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
909 return 0;
910
911 BLOCK_INPUT;
912 /* Save the size of the frame because the pane widget doesn't accept
913 to resize itself. So force it. */
914 columns = FRAME_COLS (f);
915 rows = FRAME_LINES (f);
916
917 /* Do the voodoo which means "I'm changing lots of things, don't try
918 to refigure sizes until I'm done." */
919 lw_refigure_widget (x->column_widget, False);
920
921 /* The order in which children are managed is the top to bottom
922 order in which they are displayed in the paned window. First,
923 remove the text-area widget. */
924 XtUnmanageChild (x->edit_widget);
925
926 /* Remove the menubar that is there now, and put up the menubar that
927 should be there. */
928 XtManageChild (x->menubar_widget);
929 XtMapWidget (x->menubar_widget);
930 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
931
932 /* Re-manage the text-area widget, and then thrash the sizes. */
933 XtManageChild (x->edit_widget);
934 lw_refigure_widget (x->column_widget, True);
935
936 /* Force the pane widget to resize itself with the right values. */
937 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
938 UNBLOCK_INPUT;
939 #endif
940 return 1;
941 }
942
943 #ifdef USE_LUCID
944 static void
945 apply_systemfont_to_dialog (w)
946 Widget w;
947 {
948 const char *fn = xsettings_get_system_normal_font ();
949 if (fn)
950 {
951 XrmDatabase db = XtDatabase (XtDisplay (w));
952 if (db)
953 XrmPutStringResource (&db, "*dialog.faceName", fn);
954 }
955 }
956
957 static void
958 apply_systemfont_to_menu (w)
959 Widget w;
960 {
961 const char *fn = xsettings_get_system_normal_font ();
962 int defflt;
963
964 if (!fn) return;
965
966 if (XtIsShell (w)) /* popup menu */
967 {
968 Widget *childs = NULL;
969
970 XtVaGetValues (w, XtNchildren, &childs, NULL);
971 if (*childs) w = *childs;
972 }
973
974 /* Only use system font if the default is used for the menu. */
975 XtVaGetValues (w, XtNdefaultFace, &defflt, NULL);
976 if (defflt)
977 XtVaSetValues (w, XtNfaceName, fn, NULL);
978 }
979 #endif
980
981 /* Set the contents of the menubar widgets of frame F.
982 The argument FIRST_TIME is currently ignored;
983 it is set the first time this is called, from initialize_frame_menubar. */
984
985 void
986 set_frame_menubar (FRAME_PTR f, int first_time, int deep_p)
987 {
988 xt_or_gtk_widget menubar_widget;
989 #ifdef USE_X_TOOLKIT
990 LWLIB_ID id;
991 #endif
992 Lisp_Object items;
993 widget_value *wv, *first_wv, *prev_wv = 0;
994 int i, last_i = 0;
995 int *submenu_start, *submenu_end;
996 int *submenu_top_level_items, *submenu_n_panes;
997
998 if (! FRAME_X_P (f))
999 abort ();
1000
1001 menubar_widget = f->output_data.x->menubar_widget;
1002
1003 XSETFRAME (Vmenu_updating_frame, f);
1004
1005 #ifdef USE_X_TOOLKIT
1006 if (f->output_data.x->id == 0)
1007 f->output_data.x->id = next_menubar_widget_id++;
1008 id = f->output_data.x->id;
1009 #endif
1010
1011 if (! menubar_widget)
1012 deep_p = 1;
1013 else if (pending_menu_activation && !deep_p)
1014 deep_p = 1;
1015 /* Make the first call for any given frame always go deep. */
1016 else if (!f->output_data.x->saved_menu_event && !deep_p)
1017 {
1018 deep_p = 1;
1019 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
1020 f->output_data.x->saved_menu_event->type = 0;
1021 }
1022
1023 #ifdef USE_GTK
1024 /* If we have detached menus, we must update deep so detached menus
1025 also gets updated. */
1026 deep_p = deep_p || xg_have_tear_offs ();
1027 #endif
1028
1029 if (deep_p)
1030 {
1031 /* Make a widget-value tree representing the entire menu trees. */
1032
1033 struct buffer *prev = current_buffer;
1034 Lisp_Object buffer;
1035 int specpdl_count = SPECPDL_INDEX ();
1036 int previous_menu_items_used = f->menu_bar_items_used;
1037 Lisp_Object *previous_items
1038 = (Lisp_Object *) alloca (previous_menu_items_used
1039 * sizeof (Lisp_Object));
1040
1041 /* If we are making a new widget, its contents are empty,
1042 do always reinitialize them. */
1043 if (! menubar_widget)
1044 previous_menu_items_used = 0;
1045
1046 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1047 specbind (Qinhibit_quit, Qt);
1048 /* Don't let the debugger step into this code
1049 because it is not reentrant. */
1050 specbind (Qdebug_on_next_call, Qnil);
1051
1052 record_unwind_save_match_data ();
1053 if (NILP (Voverriding_local_map_menu_flag))
1054 {
1055 specbind (Qoverriding_terminal_local_map, Qnil);
1056 specbind (Qoverriding_local_map, Qnil);
1057 }
1058
1059 set_buffer_internal_1 (XBUFFER (buffer));
1060
1061 /* Run the Lucid hook. */
1062 safe_run_hooks (Qactivate_menubar_hook);
1063
1064 /* If it has changed current-menubar from previous value,
1065 really recompute the menubar from the value. */
1066 if (! NILP (Vlucid_menu_bar_dirty_flag))
1067 call0 (Qrecompute_lucid_menubar);
1068 safe_run_hooks (Qmenu_bar_update_hook);
1069 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1070
1071 items = FRAME_MENU_BAR_ITEMS (f);
1072
1073 /* Save the frame's previous menu bar contents data. */
1074 if (previous_menu_items_used)
1075 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
1076 previous_menu_items_used * sizeof (Lisp_Object));
1077
1078 /* Fill in menu_items with the current menu bar contents.
1079 This can evaluate Lisp code. */
1080 save_menu_items ();
1081
1082 menu_items = f->menu_bar_vector;
1083 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1084 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1085 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1086 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1087 submenu_top_level_items
1088 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1089 init_menu_items ();
1090 for (i = 0; i < XVECTOR (items)->size; i += 4)
1091 {
1092 Lisp_Object key, string, maps;
1093
1094 last_i = i;
1095
1096 key = XVECTOR (items)->contents[i];
1097 string = XVECTOR (items)->contents[i + 1];
1098 maps = XVECTOR (items)->contents[i + 2];
1099 if (NILP (string))
1100 break;
1101
1102 submenu_start[i] = menu_items_used;
1103
1104 menu_items_n_panes = 0;
1105 submenu_top_level_items[i]
1106 = parse_single_submenu (key, string, maps);
1107 submenu_n_panes[i] = menu_items_n_panes;
1108
1109 submenu_end[i] = menu_items_used;
1110 }
1111
1112 finish_menu_items ();
1113
1114 /* Convert menu_items into widget_value trees
1115 to display the menu. This cannot evaluate Lisp code. */
1116
1117 wv = xmalloc_widget_value ();
1118 wv->name = "menubar";
1119 wv->value = 0;
1120 wv->enabled = 1;
1121 wv->button_type = BUTTON_TYPE_NONE;
1122 wv->help = Qnil;
1123 first_wv = wv;
1124
1125 for (i = 0; i < last_i; i += 4)
1126 {
1127 menu_items_n_panes = submenu_n_panes[i];
1128 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1129 submenu_top_level_items[i]);
1130 if (prev_wv)
1131 prev_wv->next = wv;
1132 else
1133 first_wv->contents = wv;
1134 /* Don't set wv->name here; GC during the loop might relocate it. */
1135 wv->enabled = 1;
1136 wv->button_type = BUTTON_TYPE_NONE;
1137 prev_wv = wv;
1138 }
1139
1140 set_buffer_internal_1 (prev);
1141
1142 /* If there has been no change in the Lisp-level contents
1143 of the menu bar, skip redisplaying it. Just exit. */
1144
1145 /* Compare the new menu items with the ones computed last time. */
1146 for (i = 0; i < previous_menu_items_used; i++)
1147 if (menu_items_used == i
1148 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1149 break;
1150 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1151 {
1152 /* The menu items have not changed. Don't bother updating
1153 the menus in any form, since it would be a no-op. */
1154 free_menubar_widget_value_tree (first_wv);
1155 discard_menu_items ();
1156 unbind_to (specpdl_count, Qnil);
1157 return;
1158 }
1159
1160 /* The menu items are different, so store them in the frame. */
1161 f->menu_bar_vector = menu_items;
1162 f->menu_bar_items_used = menu_items_used;
1163
1164 /* This undoes save_menu_items. */
1165 unbind_to (specpdl_count, Qnil);
1166
1167 /* Now GC cannot happen during the lifetime of the widget_value,
1168 so it's safe to store data from a Lisp_String. */
1169 wv = first_wv->contents;
1170 for (i = 0; i < XVECTOR (items)->size; i += 4)
1171 {
1172 Lisp_Object string;
1173 string = XVECTOR (items)->contents[i + 1];
1174 if (NILP (string))
1175 break;
1176 wv->name = (char *) SDATA (string);
1177 update_submenu_strings (wv->contents);
1178 wv = wv->next;
1179 }
1180
1181 }
1182 else
1183 {
1184 /* Make a widget-value tree containing
1185 just the top level menu bar strings. */
1186
1187 wv = xmalloc_widget_value ();
1188 wv->name = "menubar";
1189 wv->value = 0;
1190 wv->enabled = 1;
1191 wv->button_type = BUTTON_TYPE_NONE;
1192 wv->help = Qnil;
1193 first_wv = wv;
1194
1195 items = FRAME_MENU_BAR_ITEMS (f);
1196 for (i = 0; i < XVECTOR (items)->size; i += 4)
1197 {
1198 Lisp_Object string;
1199
1200 string = XVECTOR (items)->contents[i + 1];
1201 if (NILP (string))
1202 break;
1203
1204 wv = xmalloc_widget_value ();
1205 wv->name = (char *) SDATA (string);
1206 wv->value = 0;
1207 wv->enabled = 1;
1208 wv->button_type = BUTTON_TYPE_NONE;
1209 wv->help = Qnil;
1210 /* This prevents lwlib from assuming this
1211 menu item is really supposed to be empty. */
1212 /* The EMACS_INT cast avoids a warning.
1213 This value just has to be different from small integers. */
1214 wv->call_data = (void *) (EMACS_INT) (-1);
1215
1216 if (prev_wv)
1217 prev_wv->next = wv;
1218 else
1219 first_wv->contents = wv;
1220 prev_wv = wv;
1221 }
1222
1223 /* Forget what we thought we knew about what is in the
1224 detailed contents of the menu bar menus.
1225 Changing the top level always destroys the contents. */
1226 f->menu_bar_items_used = 0;
1227 }
1228
1229 /* Create or update the menu bar widget. */
1230
1231 BLOCK_INPUT;
1232
1233 #ifdef USE_GTK
1234 xg_crazy_callback_abort = 1;
1235 if (menubar_widget)
1236 {
1237 /* The fourth arg is DEEP_P, which says to consider the entire
1238 menu trees we supply, rather than just the menu bar item names. */
1239 xg_modify_menubar_widgets (menubar_widget,
1240 f,
1241 first_wv,
1242 deep_p,
1243 G_CALLBACK (menubar_selection_callback),
1244 G_CALLBACK (popup_deactivate_callback),
1245 G_CALLBACK (menu_highlight_callback));
1246 }
1247 else
1248 {
1249 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1250
1251 menubar_widget
1252 = xg_create_widget ("menubar", "menubar", f, first_wv,
1253 G_CALLBACK (menubar_selection_callback),
1254 G_CALLBACK (popup_deactivate_callback),
1255 G_CALLBACK (menu_highlight_callback));
1256
1257 f->output_data.x->menubar_widget = menubar_widget;
1258 }
1259
1260
1261 #else /* not USE_GTK */
1262 if (menubar_widget)
1263 {
1264 /* Disable resizing (done for Motif!) */
1265 lw_allow_resizing (f->output_data.x->widget, False);
1266
1267 /* The third arg is DEEP_P, which says to consider the entire
1268 menu trees we supply, rather than just the menu bar item names. */
1269 lw_modify_all_widgets (id, first_wv, deep_p);
1270
1271 /* Re-enable the edit widget to resize. */
1272 lw_allow_resizing (f->output_data.x->widget, True);
1273 }
1274 else
1275 {
1276 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1277 XtTranslations override = XtParseTranslationTable (menuOverride);
1278
1279 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1280 f->output_data.x->column_widget,
1281 0,
1282 popup_activate_callback,
1283 menubar_selection_callback,
1284 popup_deactivate_callback,
1285 menu_highlight_callback);
1286 f->output_data.x->menubar_widget = menubar_widget;
1287
1288 /* Make menu pop down on C-g. */
1289 XtOverrideTranslations (menubar_widget, override);
1290 #ifdef USE_LUCID
1291 apply_systemfont_to_menu (menubar_widget);
1292 #endif
1293 }
1294
1295 {
1296 if (f->output_data.x->menubar_widget)
1297 XtRealizeWidget (f->output_data.x->menubar_widget);
1298
1299 int menubar_size
1300 = (f->output_data.x->menubar_widget
1301 ? (f->output_data.x->menubar_widget->core.height
1302 + f->output_data.x->menubar_widget->core.border_width)
1303 : 0);
1304
1305 #if 1 /* Experimentally, we now get the right results
1306 for -geometry -0-0 without this. 24 Aug 96, rms.
1307 Maybe so, but the menu bar size is missing the pixels so the
1308 WM size hints are off by theses pixel. Jan D, oct 2009. */
1309 #ifdef USE_LUCID
1310 if (FRAME_EXTERNAL_MENU_BAR (f))
1311 {
1312 Dimension ibw = 0;
1313 XtVaGetValues (f->output_data.x->column_widget,
1314 XtNinternalBorderWidth, &ibw, NULL);
1315 menubar_size += ibw;
1316 }
1317 #endif /* USE_LUCID */
1318 #endif /* 1 */
1319
1320 f->output_data.x->menubar_height = menubar_size;
1321 }
1322 #endif /* not USE_GTK */
1323
1324 free_menubar_widget_value_tree (first_wv);
1325 update_frame_menubar (f);
1326
1327 #ifdef USE_GTK
1328 xg_crazy_callback_abort = 0;
1329 #endif
1330
1331 UNBLOCK_INPUT;
1332 }
1333
1334 /* Called from Fx_create_frame to create the initial menubar of a frame
1335 before it is mapped, so that the window is mapped with the menubar already
1336 there instead of us tacking it on later and thrashing the window after it
1337 is visible. */
1338
1339 void
1340 initialize_frame_menubar (FRAME_PTR f)
1341 {
1342 /* This function is called before the first chance to redisplay
1343 the frame. It has to be, so the frame will have the right size. */
1344 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1345 set_frame_menubar (f, 1, 1);
1346 }
1347
1348
1349 /* Get rid of the menu bar of frame F, and free its storage.
1350 This is used when deleting a frame, and when turning off the menu bar.
1351 For GTK this function is in gtkutil.c. */
1352
1353 #ifndef USE_GTK
1354 void
1355 free_frame_menubar (f)
1356 FRAME_PTR f;
1357 {
1358 Widget menubar_widget;
1359
1360 if (! FRAME_X_P (f))
1361 abort ();
1362
1363 menubar_widget = f->output_data.x->menubar_widget;
1364
1365 f->output_data.x->menubar_height = 0;
1366
1367 if (menubar_widget)
1368 {
1369 #ifdef USE_MOTIF
1370 /* Removing the menu bar magically changes the shell widget's x
1371 and y position of (0, 0) which, when the menu bar is turned
1372 on again, leads to pull-down menuss appearing in strange
1373 positions near the upper-left corner of the display. This
1374 happens only with some window managers like twm and ctwm,
1375 but not with other like Motif's mwm or kwm, because the
1376 latter generate ConfigureNotify events when the menu bar
1377 is switched off, which fixes the shell position. */
1378 Position x0, y0, x1, y1;
1379 #endif
1380
1381 BLOCK_INPUT;
1382
1383 #ifdef USE_MOTIF
1384 if (f->output_data.x->widget)
1385 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1386 #endif
1387
1388 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1389 f->output_data.x->menubar_widget = NULL;
1390
1391 #ifdef USE_MOTIF
1392 if (f->output_data.x->widget)
1393 {
1394 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1395 if (x1 == 0 && y1 == 0)
1396 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1397 }
1398 #endif
1399 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1400 UNBLOCK_INPUT;
1401 }
1402 }
1403 #endif /* not USE_GTK */
1404
1405 #endif /* USE_X_TOOLKIT || USE_GTK */
1406 \f
1407 /* xmenu_show actually displays a menu using the panes and items in menu_items
1408 and returns the value selected from it.
1409 There are two versions of xmenu_show, one for Xt and one for Xlib.
1410 Both assume input is blocked by the caller. */
1411
1412 /* F is the frame the menu is for.
1413 X and Y are the frame-relative specified position,
1414 relative to the inside upper left corner of the frame F.
1415 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1416 KEYMAPS is 1 if this menu was specified with keymaps;
1417 in that case, we return a list containing the chosen item's value
1418 and perhaps also the pane's prefix.
1419 TITLE is the specified menu title.
1420 ERROR is a place to store an error message string in case of failure.
1421 (We return nil on failure, but the value doesn't actually matter.) */
1422
1423 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1424
1425 /* The item selected in the popup menu. */
1426 static Lisp_Object *volatile menu_item_selection;
1427
1428 #ifdef USE_GTK
1429
1430 /* Used when position a popup menu. See menu_position_func and
1431 create_and_show_popup_menu below. */
1432 struct next_popup_x_y
1433 {
1434 FRAME_PTR f;
1435 int x;
1436 int y;
1437 };
1438
1439 /* The menu position function to use if we are not putting a popup
1440 menu where the pointer is.
1441 MENU is the menu to pop up.
1442 X and Y shall on exit contain x/y where the menu shall pop up.
1443 PUSH_IN is not documented in the GTK manual.
1444 USER_DATA is any data passed in when calling gtk_menu_popup.
1445 Here it points to a struct next_popup_x_y where the coordinates
1446 to store in *X and *Y are as well as the frame for the popup.
1447
1448 Here only X and Y are used. */
1449 static void
1450 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1451 {
1452 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1453 GtkRequisition req;
1454 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1455 int disp_width = x_display_pixel_width (dpyinfo);
1456 int disp_height = x_display_pixel_height (dpyinfo);
1457
1458 *x = data->x;
1459 *y = data->y;
1460
1461 /* Check if there is room for the menu. If not, adjust x/y so that
1462 the menu is fully visible. */
1463 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1464 if (data->x + req.width > disp_width)
1465 *x -= data->x + req.width - disp_width;
1466 if (data->y + req.height > disp_height)
1467 *y -= data->y + req.height - disp_height;
1468 }
1469
1470 static void
1471 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1472 {
1473 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1474
1475 if (xg_crazy_callback_abort) return;
1476 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1477 }
1478
1479 static Lisp_Object
1480 pop_down_menu (Lisp_Object arg)
1481 {
1482 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1483
1484 popup_activated_flag = 0;
1485 BLOCK_INPUT;
1486 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1487 UNBLOCK_INPUT;
1488 return Qnil;
1489 }
1490
1491 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1492 menu pops down.
1493 menu_item_selection will be set to the selection. */
1494 static void
1495 create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, int for_click, EMACS_UINT timestamp)
1496 {
1497 int i;
1498 GtkWidget *menu;
1499 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1500 struct next_popup_x_y popup_x_y;
1501 int specpdl_count = SPECPDL_INDEX ();
1502
1503 if (! FRAME_X_P (f))
1504 abort ();
1505
1506 xg_crazy_callback_abort = 1;
1507 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1508 G_CALLBACK (popup_selection_callback),
1509 G_CALLBACK (popup_deactivate_callback),
1510 G_CALLBACK (menu_highlight_callback));
1511 xg_crazy_callback_abort = 0;
1512
1513 if (! for_click)
1514 {
1515 /* Not invoked by a click. pop up at x/y. */
1516 pos_func = menu_position_func;
1517
1518 /* Adjust coordinates to be root-window-relative. */
1519 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1520 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1521
1522 popup_x_y.x = x;
1523 popup_x_y.y = y;
1524 popup_x_y.f = f;
1525
1526 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1527 }
1528 else
1529 {
1530 for (i = 0; i < 5; i++)
1531 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1532 break;
1533 }
1534
1535 /* Display the menu. */
1536 gtk_widget_show_all (menu);
1537
1538 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1539 timestamp > 0 ? timestamp : gtk_get_current_event_time());
1540
1541 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1542
1543 if (gtk_widget_get_mapped (menu))
1544 {
1545 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1546 two. show_help_echo uses this to detect popup menus. */
1547 popup_activated_flag = 1;
1548 /* Process events that apply to the menu. */
1549 popup_widget_loop (1, menu);
1550 }
1551
1552 unbind_to (specpdl_count, Qnil);
1553
1554 /* Must reset this manually because the button release event is not passed
1555 to Emacs event loop. */
1556 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1557 }
1558
1559 #else /* not USE_GTK */
1560
1561 /* We need a unique id for each widget handled by the Lucid Widget
1562 library.
1563
1564 For the main windows, and popup menus, we use this counter,
1565 which we increment each time after use. This starts from 1<<16.
1566
1567 For menu bars, we use numbers starting at 0, counted in
1568 next_menubar_widget_id. */
1569 LWLIB_ID widget_id_tick;
1570
1571 static void
1572 popup_selection_callback (widget, id, client_data)
1573 Widget widget;
1574 LWLIB_ID id;
1575 XtPointer client_data;
1576 {
1577 menu_item_selection = (Lisp_Object *) client_data;
1578 }
1579
1580 /* ARG is the LWLIB ID of the dialog box, represented
1581 as a Lisp object as (HIGHPART . LOWPART). */
1582
1583 static Lisp_Object
1584 pop_down_menu (arg)
1585 Lisp_Object arg;
1586 {
1587 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1588 | XINT (XCDR (arg)));
1589
1590 BLOCK_INPUT;
1591 lw_destroy_all_widgets (id);
1592 UNBLOCK_INPUT;
1593 popup_activated_flag = 0;
1594
1595 return Qnil;
1596 }
1597
1598 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1599 menu pops down.
1600 menu_item_selection will be set to the selection. */
1601 static void
1602 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1603 FRAME_PTR f;
1604 widget_value *first_wv;
1605 int x;
1606 int y;
1607 int for_click;
1608 EMACS_UINT timestamp;
1609 {
1610 int i;
1611 Arg av[2];
1612 int ac = 0;
1613 XButtonPressedEvent dummy;
1614 LWLIB_ID menu_id;
1615 Widget menu;
1616
1617 if (! FRAME_X_P (f))
1618 abort ();
1619
1620 menu_id = widget_id_tick++;
1621 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1622 f->output_data.x->widget, 1, 0,
1623 popup_selection_callback,
1624 popup_deactivate_callback,
1625 menu_highlight_callback);
1626
1627 #ifdef USE_LUCID
1628 apply_systemfont_to_menu (menu);
1629 #endif
1630
1631 dummy.type = ButtonPress;
1632 dummy.serial = 0;
1633 dummy.send_event = 0;
1634 dummy.display = FRAME_X_DISPLAY (f);
1635 dummy.time = CurrentTime;
1636 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1637 dummy.window = dummy.root;
1638 dummy.subwindow = dummy.root;
1639 dummy.x = x;
1640 dummy.y = y;
1641
1642 /* Adjust coordinates to be root-window-relative. */
1643 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1644 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1645
1646 dummy.x_root = x;
1647 dummy.y_root = y;
1648
1649 dummy.state = 0;
1650 dummy.button = 0;
1651 for (i = 0; i < 5; i++)
1652 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1653 dummy.button = i;
1654
1655 /* Don't allow any geometry request from the user. */
1656 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1657 XtSetValues (menu, av, ac);
1658
1659 /* Display the menu. */
1660 lw_popup_menu (menu, (XEvent *) &dummy);
1661 popup_activated_flag = 1;
1662 x_activate_timeout_atimer ();
1663
1664 {
1665 int fact = 4 * sizeof (LWLIB_ID);
1666 int specpdl_count = SPECPDL_INDEX ();
1667 record_unwind_protect (pop_down_menu,
1668 Fcons (make_number (menu_id >> (fact)),
1669 make_number (menu_id & ~(-1 << (fact)))));
1670
1671 /* Process events that apply to the menu. */
1672 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1673
1674 unbind_to (specpdl_count, Qnil);
1675 }
1676 }
1677
1678 #endif /* not USE_GTK */
1679
1680 Lisp_Object
1681 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
1682 Lisp_Object title, char **error, EMACS_UINT timestamp)
1683 {
1684 int i;
1685 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1686 widget_value **submenu_stack
1687 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1688 Lisp_Object *subprefix_stack
1689 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1690 int submenu_depth = 0;
1691
1692 int first_pane;
1693
1694 if (! FRAME_X_P (f))
1695 abort ();
1696
1697 *error = NULL;
1698
1699 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1700 {
1701 *error = "Empty menu";
1702 return Qnil;
1703 }
1704
1705 /* Create a tree of widget_value objects
1706 representing the panes and their items. */
1707 wv = xmalloc_widget_value ();
1708 wv->name = "menu";
1709 wv->value = 0;
1710 wv->enabled = 1;
1711 wv->button_type = BUTTON_TYPE_NONE;
1712 wv->help =Qnil;
1713 first_wv = wv;
1714 first_pane = 1;
1715
1716 /* Loop over all panes and items, filling in the tree. */
1717 i = 0;
1718 while (i < menu_items_used)
1719 {
1720 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1721 {
1722 submenu_stack[submenu_depth++] = save_wv;
1723 save_wv = prev_wv;
1724 prev_wv = 0;
1725 first_pane = 1;
1726 i++;
1727 }
1728 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1729 {
1730 prev_wv = save_wv;
1731 save_wv = submenu_stack[--submenu_depth];
1732 first_pane = 0;
1733 i++;
1734 }
1735 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1736 && submenu_depth != 0)
1737 i += MENU_ITEMS_PANE_LENGTH;
1738 /* Ignore a nil in the item list.
1739 It's meaningful only for dialog boxes. */
1740 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1741 i += 1;
1742 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1743 {
1744 /* Create a new pane. */
1745 Lisp_Object pane_name, prefix;
1746 char *pane_string;
1747
1748 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1749 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1750
1751 #ifndef HAVE_MULTILINGUAL_MENU
1752 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1753 {
1754 pane_name = ENCODE_MENU_STRING (pane_name);
1755 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1756 }
1757 #endif
1758 pane_string = (NILP (pane_name)
1759 ? "" : (char *) SDATA (pane_name));
1760 /* If there is just one top-level pane, put all its items directly
1761 under the top-level menu. */
1762 if (menu_items_n_panes == 1)
1763 pane_string = "";
1764
1765 /* If the pane has a meaningful name,
1766 make the pane a top-level menu item
1767 with its items as a submenu beneath it. */
1768 if (!keymaps && strcmp (pane_string, ""))
1769 {
1770 wv = xmalloc_widget_value ();
1771 if (save_wv)
1772 save_wv->next = wv;
1773 else
1774 first_wv->contents = wv;
1775 wv->name = pane_string;
1776 if (keymaps && !NILP (prefix))
1777 wv->name++;
1778 wv->value = 0;
1779 wv->enabled = 1;
1780 wv->button_type = BUTTON_TYPE_NONE;
1781 wv->help = Qnil;
1782 save_wv = wv;
1783 prev_wv = 0;
1784 }
1785 else if (first_pane)
1786 {
1787 save_wv = wv;
1788 prev_wv = 0;
1789 }
1790 first_pane = 0;
1791 i += MENU_ITEMS_PANE_LENGTH;
1792 }
1793 else
1794 {
1795 /* Create a new item within current pane. */
1796 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1797 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1798 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1799 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1800 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1801 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1802 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1803 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1804
1805 #ifndef HAVE_MULTILINGUAL_MENU
1806 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1807 {
1808 item_name = ENCODE_MENU_STRING (item_name);
1809 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1810 }
1811
1812 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1813 {
1814 descrip = ENCODE_MENU_STRING (descrip);
1815 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1816 }
1817 #endif /* not HAVE_MULTILINGUAL_MENU */
1818
1819 wv = xmalloc_widget_value ();
1820 if (prev_wv)
1821 prev_wv->next = wv;
1822 else
1823 save_wv->contents = wv;
1824 wv->name = (char *) SDATA (item_name);
1825 if (!NILP (descrip))
1826 wv->key = (char *) SDATA (descrip);
1827 wv->value = 0;
1828 /* If this item has a null value,
1829 make the call_data null so that it won't display a box
1830 when the mouse is on it. */
1831 wv->call_data
1832 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
1833 wv->enabled = !NILP (enable);
1834
1835 if (NILP (type))
1836 wv->button_type = BUTTON_TYPE_NONE;
1837 else if (EQ (type, QCtoggle))
1838 wv->button_type = BUTTON_TYPE_TOGGLE;
1839 else if (EQ (type, QCradio))
1840 wv->button_type = BUTTON_TYPE_RADIO;
1841 else
1842 abort ();
1843
1844 wv->selected = !NILP (selected);
1845
1846 if (! STRINGP (help))
1847 help = Qnil;
1848
1849 wv->help = help;
1850
1851 prev_wv = wv;
1852
1853 i += MENU_ITEMS_ITEM_LENGTH;
1854 }
1855 }
1856
1857 /* Deal with the title, if it is non-nil. */
1858 if (!NILP (title))
1859 {
1860 widget_value *wv_title = xmalloc_widget_value ();
1861 widget_value *wv_sep1 = xmalloc_widget_value ();
1862 widget_value *wv_sep2 = xmalloc_widget_value ();
1863
1864 wv_sep2->name = "--";
1865 wv_sep2->next = first_wv->contents;
1866 wv_sep2->help = Qnil;
1867
1868 wv_sep1->name = "--";
1869 wv_sep1->next = wv_sep2;
1870 wv_sep1->help = Qnil;
1871
1872 #ifndef HAVE_MULTILINGUAL_MENU
1873 if (STRING_MULTIBYTE (title))
1874 title = ENCODE_MENU_STRING (title);
1875 #endif
1876
1877 wv_title->name = (char *) SDATA (title);
1878 wv_title->enabled = TRUE;
1879 wv_title->button_type = BUTTON_TYPE_NONE;
1880 wv_title->help = Qnil;
1881 wv_title->next = wv_sep1;
1882 first_wv->contents = wv_title;
1883 }
1884
1885 /* No selection has been chosen yet. */
1886 menu_item_selection = 0;
1887
1888 /* Actually create and show the menu until popped down. */
1889 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
1890
1891 /* Free the widget_value objects we used to specify the contents. */
1892 free_menubar_widget_value_tree (first_wv);
1893
1894 /* Find the selected item, and its pane, to return
1895 the proper value. */
1896 if (menu_item_selection != 0)
1897 {
1898 Lisp_Object prefix, entry;
1899
1900 prefix = entry = Qnil;
1901 i = 0;
1902 while (i < menu_items_used)
1903 {
1904 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1905 {
1906 subprefix_stack[submenu_depth++] = prefix;
1907 prefix = entry;
1908 i++;
1909 }
1910 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1911 {
1912 prefix = subprefix_stack[--submenu_depth];
1913 i++;
1914 }
1915 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1916 {
1917 prefix
1918 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1919 i += MENU_ITEMS_PANE_LENGTH;
1920 }
1921 /* Ignore a nil in the item list.
1922 It's meaningful only for dialog boxes. */
1923 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1924 i += 1;
1925 else
1926 {
1927 entry
1928 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1929 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1930 {
1931 if (keymaps != 0)
1932 {
1933 int j;
1934
1935 entry = Fcons (entry, Qnil);
1936 if (!NILP (prefix))
1937 entry = Fcons (prefix, entry);
1938 for (j = submenu_depth - 1; j >= 0; j--)
1939 if (!NILP (subprefix_stack[j]))
1940 entry = Fcons (subprefix_stack[j], entry);
1941 }
1942 return entry;
1943 }
1944 i += MENU_ITEMS_ITEM_LENGTH;
1945 }
1946 }
1947 }
1948 else if (!for_click)
1949 /* Make "Cancel" equivalent to C-g. */
1950 Fsignal (Qquit, Qnil);
1951
1952 return Qnil;
1953 }
1954 \f
1955 #ifdef USE_GTK
1956 static void
1957 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1958 {
1959 /* The EMACS_INT cast avoids a warning. There's no problem
1960 as long as pointers have enough bits to hold small integers. */
1961 if ((int) (EMACS_INT) client_data != -1)
1962 menu_item_selection = (Lisp_Object *) client_data;
1963
1964 popup_activated_flag = 0;
1965 }
1966
1967 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1968 dialog pops down.
1969 menu_item_selection will be set to the selection. */
1970 static void
1971 create_and_show_dialog (FRAME_PTR f, widget_value *first_wv)
1972 {
1973 GtkWidget *menu;
1974
1975 if (! FRAME_X_P (f))
1976 abort ();
1977
1978 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1979 G_CALLBACK (dialog_selection_callback),
1980 G_CALLBACK (popup_deactivate_callback),
1981 0);
1982
1983 if (menu)
1984 {
1985 int specpdl_count = SPECPDL_INDEX ();
1986 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1987
1988 /* Display the menu. */
1989 gtk_widget_show_all (menu);
1990
1991 /* Process events that apply to the menu. */
1992 popup_widget_loop (1, menu);
1993
1994 unbind_to (specpdl_count, Qnil);
1995 }
1996 }
1997
1998 #else /* not USE_GTK */
1999 static void
2000 dialog_selection_callback (widget, id, client_data)
2001 Widget widget;
2002 LWLIB_ID id;
2003 XtPointer client_data;
2004 {
2005 /* The EMACS_INT cast avoids a warning. There's no problem
2006 as long as pointers have enough bits to hold small integers. */
2007 if ((int) (EMACS_INT) client_data != -1)
2008 menu_item_selection = (Lisp_Object *) client_data;
2009
2010 BLOCK_INPUT;
2011 lw_destroy_all_widgets (id);
2012 UNBLOCK_INPUT;
2013 popup_activated_flag = 0;
2014 }
2015
2016
2017 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2018 dialog pops down.
2019 menu_item_selection will be set to the selection. */
2020 static void
2021 create_and_show_dialog (f, first_wv)
2022 FRAME_PTR f;
2023 widget_value *first_wv;
2024 {
2025 LWLIB_ID dialog_id;
2026
2027 if (!FRAME_X_P (f))
2028 abort();
2029
2030 dialog_id = widget_id_tick++;
2031 #ifdef USE_LUCID
2032 apply_systemfont_to_dialog (f->output_data.x->widget);
2033 #endif
2034 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2035 f->output_data.x->widget, 1, 0,
2036 dialog_selection_callback, 0, 0);
2037 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2038 /* Display the dialog box. */
2039 lw_pop_up_all_widgets (dialog_id);
2040 popup_activated_flag = 1;
2041 x_activate_timeout_atimer ();
2042
2043 /* Process events that apply to the dialog box.
2044 Also handle timers. */
2045 {
2046 int count = SPECPDL_INDEX ();
2047 int fact = 4 * sizeof (LWLIB_ID);
2048
2049 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2050 record_unwind_protect (pop_down_menu,
2051 Fcons (make_number (dialog_id >> (fact)),
2052 make_number (dialog_id & ~(-1 << (fact)))));
2053
2054 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2055 dialog_id, 1);
2056
2057 unbind_to (count, Qnil);
2058 }
2059 }
2060
2061 #endif /* not USE_GTK */
2062
2063 static char * button_names [] = {
2064 "button1", "button2", "button3", "button4", "button5",
2065 "button6", "button7", "button8", "button9", "button10" };
2066
2067 static Lisp_Object
2068 xdialog_show (FRAME_PTR f, int keymaps, Lisp_Object title, Lisp_Object header, char **error_name)
2069 {
2070 int i, nb_buttons=0;
2071 char dialog_name[6];
2072
2073 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2074
2075 /* Number of elements seen so far, before boundary. */
2076 int left_count = 0;
2077 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2078 int boundary_seen = 0;
2079
2080 if (! FRAME_X_P (f))
2081 abort ();
2082
2083 *error_name = NULL;
2084
2085 if (menu_items_n_panes > 1)
2086 {
2087 *error_name = "Multiple panes in dialog box";
2088 return Qnil;
2089 }
2090
2091 /* Create a tree of widget_value objects
2092 representing the text label and buttons. */
2093 {
2094 Lisp_Object pane_name, prefix;
2095 char *pane_string;
2096 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2097 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2098 pane_string = (NILP (pane_name)
2099 ? "" : (char *) SDATA (pane_name));
2100 prev_wv = xmalloc_widget_value ();
2101 prev_wv->value = pane_string;
2102 if (keymaps && !NILP (prefix))
2103 prev_wv->name++;
2104 prev_wv->enabled = 1;
2105 prev_wv->name = "message";
2106 prev_wv->help = Qnil;
2107 first_wv = prev_wv;
2108
2109 /* Loop over all panes and items, filling in the tree. */
2110 i = MENU_ITEMS_PANE_LENGTH;
2111 while (i < menu_items_used)
2112 {
2113
2114 /* Create a new item within current pane. */
2115 Lisp_Object item_name, enable, descrip;
2116 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2117 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2118 descrip
2119 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2120
2121 if (NILP (item_name))
2122 {
2123 free_menubar_widget_value_tree (first_wv);
2124 *error_name = "Submenu in dialog items";
2125 return Qnil;
2126 }
2127 if (EQ (item_name, Qquote))
2128 {
2129 /* This is the boundary between left-side elts
2130 and right-side elts. Stop incrementing right_count. */
2131 boundary_seen = 1;
2132 i++;
2133 continue;
2134 }
2135 if (nb_buttons >= 9)
2136 {
2137 free_menubar_widget_value_tree (first_wv);
2138 *error_name = "Too many dialog items";
2139 return Qnil;
2140 }
2141
2142 wv = xmalloc_widget_value ();
2143 prev_wv->next = wv;
2144 wv->name = (char *) button_names[nb_buttons];
2145 if (!NILP (descrip))
2146 wv->key = (char *) SDATA (descrip);
2147 wv->value = (char *) SDATA (item_name);
2148 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2149 wv->enabled = !NILP (enable);
2150 wv->help = Qnil;
2151 prev_wv = wv;
2152
2153 if (! boundary_seen)
2154 left_count++;
2155
2156 nb_buttons++;
2157 i += MENU_ITEMS_ITEM_LENGTH;
2158 }
2159
2160 /* If the boundary was not specified,
2161 by default put half on the left and half on the right. */
2162 if (! boundary_seen)
2163 left_count = nb_buttons - nb_buttons / 2;
2164
2165 wv = xmalloc_widget_value ();
2166 wv->name = dialog_name;
2167 wv->help = Qnil;
2168
2169 /* Frame title: 'Q' = Question, 'I' = Information.
2170 Can also have 'E' = Error if, one day, we want
2171 a popup for errors. */
2172 if (NILP(header))
2173 dialog_name[0] = 'Q';
2174 else
2175 dialog_name[0] = 'I';
2176
2177 /* Dialog boxes use a really stupid name encoding
2178 which specifies how many buttons to use
2179 and how many buttons are on the right. */
2180 dialog_name[1] = '0' + nb_buttons;
2181 dialog_name[2] = 'B';
2182 dialog_name[3] = 'R';
2183 /* Number of buttons to put on the right. */
2184 dialog_name[4] = '0' + nb_buttons - left_count;
2185 dialog_name[5] = 0;
2186 wv->contents = first_wv;
2187 first_wv = wv;
2188 }
2189
2190 /* No selection has been chosen yet. */
2191 menu_item_selection = 0;
2192
2193 /* Actually create and show the dialog. */
2194 create_and_show_dialog (f, first_wv);
2195
2196 /* Free the widget_value objects we used to specify the contents. */
2197 free_menubar_widget_value_tree (first_wv);
2198
2199 /* Find the selected item, and its pane, to return
2200 the proper value. */
2201 if (menu_item_selection != 0)
2202 {
2203 Lisp_Object prefix;
2204
2205 prefix = Qnil;
2206 i = 0;
2207 while (i < menu_items_used)
2208 {
2209 Lisp_Object entry;
2210
2211 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2212 {
2213 prefix
2214 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2215 i += MENU_ITEMS_PANE_LENGTH;
2216 }
2217 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2218 {
2219 /* This is the boundary between left-side elts and
2220 right-side elts. */
2221 ++i;
2222 }
2223 else
2224 {
2225 entry
2226 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2227 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2228 {
2229 if (keymaps != 0)
2230 {
2231 entry = Fcons (entry, Qnil);
2232 if (!NILP (prefix))
2233 entry = Fcons (prefix, entry);
2234 }
2235 return entry;
2236 }
2237 i += MENU_ITEMS_ITEM_LENGTH;
2238 }
2239 }
2240 }
2241 else
2242 /* Make "Cancel" equivalent to C-g. */
2243 Fsignal (Qquit, Qnil);
2244
2245 return Qnil;
2246 }
2247
2248 #else /* not USE_X_TOOLKIT && not USE_GTK */
2249
2250 /* The frame of the last activated non-toolkit menu bar.
2251 Used to generate menu help events. */
2252
2253 static struct frame *menu_help_frame;
2254
2255
2256 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2257
2258 PANE is the pane number, and ITEM is the menu item number in
2259 the menu (currently not used).
2260
2261 This cannot be done with generating a HELP_EVENT because
2262 XMenuActivate contains a loop that doesn't let Emacs process
2263 keyboard events. */
2264
2265 static void
2266 menu_help_callback (help_string, pane, item)
2267 char *help_string;
2268 int pane, item;
2269 {
2270 extern Lisp_Object Qmenu_item;
2271 Lisp_Object *first_item;
2272 Lisp_Object pane_name;
2273 Lisp_Object menu_object;
2274
2275 first_item = XVECTOR (menu_items)->contents;
2276 if (EQ (first_item[0], Qt))
2277 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2278 else if (EQ (first_item[0], Qquote))
2279 /* This shouldn't happen, see xmenu_show. */
2280 pane_name = empty_unibyte_string;
2281 else
2282 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2283
2284 /* (menu-item MENU-NAME PANE-NUMBER) */
2285 menu_object = Fcons (Qmenu_item,
2286 Fcons (pane_name,
2287 Fcons (make_number (pane), Qnil)));
2288 show_help_echo (help_string ? build_string (help_string) : Qnil,
2289 Qnil, menu_object, make_number (item), 1);
2290 }
2291
2292 static Lisp_Object
2293 pop_down_menu (arg)
2294 Lisp_Object arg;
2295 {
2296 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2297 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2298
2299 FRAME_PTR f = p1->pointer;
2300 XMenu *menu = p2->pointer;
2301
2302 BLOCK_INPUT;
2303 #ifndef MSDOS
2304 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2305 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2306 #endif
2307 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2308
2309 #ifdef HAVE_X_WINDOWS
2310 /* Assume the mouse has moved out of the X window.
2311 If it has actually moved in, we will get an EnterNotify. */
2312 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2313
2314 /* State that no mouse buttons are now held.
2315 (The oldXMenu code doesn't track this info for us.)
2316 That is not necessarily true, but the fiction leads to reasonable
2317 results, and it is a pain to ask which are actually held now. */
2318 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2319
2320 #endif /* HAVE_X_WINDOWS */
2321
2322 UNBLOCK_INPUT;
2323
2324 return Qnil;
2325 }
2326
2327
2328 Lisp_Object
2329 xmenu_show (f, x, y, for_click, keymaps, title, error, timestamp)
2330 FRAME_PTR f;
2331 int x, y;
2332 int for_click;
2333 int keymaps;
2334 Lisp_Object title;
2335 char **error;
2336 EMACS_UINT timestamp;
2337 {
2338 Window root;
2339 XMenu *menu;
2340 int pane, selidx, lpane, status;
2341 Lisp_Object entry, pane_prefix;
2342 char *datap;
2343 int ulx, uly, width, height;
2344 int dispwidth, dispheight;
2345 int i, j, lines, maxlines;
2346 int maxwidth;
2347 int dummy_int;
2348 unsigned int dummy_uint;
2349 int specpdl_count = SPECPDL_INDEX ();
2350
2351 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2352 abort ();
2353
2354 *error = 0;
2355 if (menu_items_n_panes == 0)
2356 return Qnil;
2357
2358 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2359 {
2360 *error = "Empty menu";
2361 return Qnil;
2362 }
2363
2364 /* Figure out which root window F is on. */
2365 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2366 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2367 &dummy_uint, &dummy_uint);
2368
2369 /* Make the menu on that window. */
2370 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2371 if (menu == NULL)
2372 {
2373 *error = "Can't create menu";
2374 return Qnil;
2375 }
2376
2377 /* Don't GC while we prepare and show the menu,
2378 because we give the oldxmenu library pointers to the
2379 contents of strings. */
2380 inhibit_garbage_collection ();
2381
2382 #ifdef HAVE_X_WINDOWS
2383 /* Adjust coordinates to relative to the outer (window manager) window. */
2384 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2385 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2386 #endif /* HAVE_X_WINDOWS */
2387
2388 /* Adjust coordinates to be root-window-relative. */
2389 x += f->left_pos;
2390 y += f->top_pos;
2391
2392 /* Create all the necessary panes and their items. */
2393 maxlines = lines = i = 0;
2394 while (i < menu_items_used)
2395 {
2396 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2397 {
2398 /* Create a new pane. */
2399 Lisp_Object pane_name, prefix;
2400 char *pane_string;
2401
2402 maxlines = max (maxlines, lines);
2403 lines = 0;
2404 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2405 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2406 pane_string = (NILP (pane_name)
2407 ? "" : (char *) SDATA (pane_name));
2408 if (keymaps && !NILP (prefix))
2409 pane_string++;
2410
2411 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2412 if (lpane == XM_FAILURE)
2413 {
2414 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2415 *error = "Can't create pane";
2416 return Qnil;
2417 }
2418 i += MENU_ITEMS_PANE_LENGTH;
2419
2420 /* Find the width of the widest item in this pane. */
2421 maxwidth = 0;
2422 j = i;
2423 while (j < menu_items_used)
2424 {
2425 Lisp_Object item;
2426 item = XVECTOR (menu_items)->contents[j];
2427 if (EQ (item, Qt))
2428 break;
2429 if (NILP (item))
2430 {
2431 j++;
2432 continue;
2433 }
2434 width = SBYTES (item);
2435 if (width > maxwidth)
2436 maxwidth = width;
2437
2438 j += MENU_ITEMS_ITEM_LENGTH;
2439 }
2440 }
2441 /* Ignore a nil in the item list.
2442 It's meaningful only for dialog boxes. */
2443 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2444 i += 1;
2445 else
2446 {
2447 /* Create a new item within current pane. */
2448 Lisp_Object item_name, enable, descrip, help;
2449 unsigned char *item_data;
2450 char *help_string;
2451
2452 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2453 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2454 descrip
2455 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2456 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2457 help_string = STRINGP (help) ? SDATA (help) : NULL;
2458
2459 if (!NILP (descrip))
2460 {
2461 int gap = maxwidth - SBYTES (item_name);
2462 /* if alloca is fast, use that to make the space,
2463 to reduce gc needs. */
2464 item_data
2465 = (unsigned char *) alloca (maxwidth
2466 + SBYTES (descrip) + 1);
2467 memcpy (item_data, SDATA (item_name), SBYTES (item_name));
2468 for (j = SCHARS (item_name); j < maxwidth; j++)
2469 item_data[j] = ' ';
2470 memcpy (item_data + j, SDATA (descrip), SBYTES (descrip));
2471 item_data[j + SBYTES (descrip)] = 0;
2472 }
2473 else
2474 item_data = SDATA (item_name);
2475
2476 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2477 menu, lpane, 0, item_data,
2478 !NILP (enable), help_string)
2479 == XM_FAILURE)
2480 {
2481 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2482 *error = "Can't add selection to menu";
2483 return Qnil;
2484 }
2485 i += MENU_ITEMS_ITEM_LENGTH;
2486 lines++;
2487 }
2488 }
2489
2490 maxlines = max (maxlines, lines);
2491
2492 /* All set and ready to fly. */
2493 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2494 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2495 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2496 x = min (x, dispwidth);
2497 y = min (y, dispheight);
2498 x = max (x, 1);
2499 y = max (y, 1);
2500 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2501 &ulx, &uly, &width, &height);
2502 if (ulx+width > dispwidth)
2503 {
2504 x -= (ulx + width) - dispwidth;
2505 ulx = dispwidth - width;
2506 }
2507 if (uly+height > dispheight)
2508 {
2509 y -= (uly + height) - dispheight;
2510 uly = dispheight - height;
2511 }
2512 #ifndef HAVE_X_WINDOWS
2513 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2514 {
2515 /* Move the menu away of the echo area, to avoid overwriting the
2516 menu with help echo messages or vice versa. */
2517 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2518 {
2519 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2520 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2521 }
2522 else
2523 {
2524 y--;
2525 uly--;
2526 }
2527 }
2528 #endif
2529 if (ulx < 0) x -= ulx;
2530 if (uly < 0) y -= uly;
2531
2532 if (! for_click)
2533 {
2534 /* If position was not given by a mouse click, adjust so upper left
2535 corner of the menu as a whole ends up at given coordinates. This
2536 is what x-popup-menu says in its documentation. */
2537 x += width/2;
2538 y += 1.5*height/(maxlines+2);
2539 }
2540
2541 XMenuSetAEQ (menu, TRUE);
2542 XMenuSetFreeze (menu, TRUE);
2543 pane = selidx = 0;
2544
2545 #ifndef MSDOS
2546 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2547 #endif
2548
2549 record_unwind_protect (pop_down_menu,
2550 Fcons (make_save_value (f, 0),
2551 make_save_value (menu, 0)));
2552
2553 /* Help display under X won't work because XMenuActivate contains
2554 a loop that doesn't give Emacs a chance to process it. */
2555 menu_help_frame = f;
2556 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2557 x, y, ButtonReleaseMask, &datap,
2558 menu_help_callback);
2559
2560 switch (status)
2561 {
2562 case XM_SUCCESS:
2563 #ifdef XDEBUG
2564 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2565 #endif
2566
2567 /* Find the item number SELIDX in pane number PANE. */
2568 i = 0;
2569 while (i < menu_items_used)
2570 {
2571 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2572 {
2573 if (pane == 0)
2574 pane_prefix
2575 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2576 pane--;
2577 i += MENU_ITEMS_PANE_LENGTH;
2578 }
2579 else
2580 {
2581 if (pane == -1)
2582 {
2583 if (selidx == 0)
2584 {
2585 entry
2586 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2587 if (keymaps != 0)
2588 {
2589 entry = Fcons (entry, Qnil);
2590 if (!NILP (pane_prefix))
2591 entry = Fcons (pane_prefix, entry);
2592 }
2593 break;
2594 }
2595 selidx--;
2596 }
2597 i += MENU_ITEMS_ITEM_LENGTH;
2598 }
2599 }
2600 break;
2601
2602 case XM_FAILURE:
2603 *error = "Can't activate menu";
2604 case XM_IA_SELECT:
2605 entry = Qnil;
2606 break;
2607 case XM_NO_SELECT:
2608 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2609 the menu was invoked with a mouse event as POSITION). */
2610 if (! for_click)
2611 Fsignal (Qquit, Qnil);
2612 entry = Qnil;
2613 break;
2614 }
2615
2616 unbind_to (specpdl_count, Qnil);
2617
2618 return entry;
2619 }
2620
2621 #endif /* not USE_X_TOOLKIT */
2622
2623 #endif /* HAVE_MENUS */
2624
2625 /* Detect if a dialog or menu has been posted. */
2626
2627 int
2628 popup_activated (void)
2629 {
2630 return popup_activated_flag;
2631 }
2632
2633 /* The following is used by delayed window autoselection. */
2634
2635 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2636 doc: /* Return t if a menu or popup dialog is active. */)
2637 (void)
2638 {
2639 #ifdef HAVE_MENUS
2640 return (popup_activated ()) ? Qt : Qnil;
2641 #else
2642 return Qnil;
2643 #endif /* HAVE_MENUS */
2644 }
2645 \f
2646 void
2647 syms_of_xmenu (void)
2648 {
2649 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
2650 staticpro (&Qdebug_on_next_call);
2651
2652 #ifdef USE_X_TOOLKIT
2653 widget_id_tick = (1<<16);
2654 next_menubar_widget_id = 1;
2655 #endif
2656
2657 defsubr (&Smenu_or_popup_active_p);
2658
2659 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2660 defsubr (&Sx_menu_bar_open_internal);
2661 Ffset (intern_c_string ("accelerate-menu"),
2662 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2663 #endif
2664
2665 #ifdef HAVE_MENUS
2666 defsubr (&Sx_popup_dialog);
2667 #endif
2668 }
2669
2670 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2671 (do not change this comment) */