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