Lucid menus can now use Xft for fonts.
[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_menu (w)
958 Widget w;
959 {
960 const char *fn = xsettings_get_system_normal_font ();
961 int defflt;
962
963 if (!fn) return;
964
965 if (XtIsShell (w)) /* popup menu */
966 {
967 Widget *childs[1];
968 int num = 0;
969
970 XtVaGetValues (w, XtNnumChildren, &num, NULL);
971 if (num != 1) return; /* Should only be one. */
972
973 childs[0] = 0;
974 XtVaGetValues (w, XtNchildren, childs, NULL);
975 if (childs[0] && *childs[0]) w = *childs[0];
976 }
977
978 /* Only use system font if the default is used for the menu. */
979 XtVaGetValues (w, XtNdefaultFace, &defflt, NULL);
980 if (defflt)
981 XtVaSetValues (w, XtNfaceName, fn, NULL);
982 }
983 #endif
984
985 /* Set the contents of the menubar widgets of frame F.
986 The argument FIRST_TIME is currently ignored;
987 it is set the first time this is called, from initialize_frame_menubar. */
988
989 void
990 set_frame_menubar (f, first_time, deep_p)
991 FRAME_PTR f;
992 int first_time;
993 int deep_p;
994 {
995 xt_or_gtk_widget menubar_widget;
996 #ifdef USE_X_TOOLKIT
997 LWLIB_ID id;
998 #endif
999 Lisp_Object items;
1000 widget_value *wv, *first_wv, *prev_wv = 0;
1001 int i, last_i = 0;
1002 int *submenu_start, *submenu_end;
1003 int *submenu_top_level_items, *submenu_n_panes;
1004
1005 if (! FRAME_X_P (f))
1006 abort ();
1007
1008 menubar_widget = f->output_data.x->menubar_widget;
1009
1010 XSETFRAME (Vmenu_updating_frame, f);
1011
1012 #ifdef USE_X_TOOLKIT
1013 if (f->output_data.x->id == 0)
1014 f->output_data.x->id = next_menubar_widget_id++;
1015 id = f->output_data.x->id;
1016 #endif
1017
1018 if (! menubar_widget)
1019 deep_p = 1;
1020 else if (pending_menu_activation && !deep_p)
1021 deep_p = 1;
1022 /* Make the first call for any given frame always go deep. */
1023 else if (!f->output_data.x->saved_menu_event && !deep_p)
1024 {
1025 deep_p = 1;
1026 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent));
1027 f->output_data.x->saved_menu_event->type = 0;
1028 }
1029
1030 #ifdef USE_GTK
1031 /* If we have detached menus, we must update deep so detached menus
1032 also gets updated. */
1033 deep_p = deep_p || xg_have_tear_offs ();
1034 #endif
1035
1036 if (deep_p)
1037 {
1038 /* Make a widget-value tree representing the entire menu trees. */
1039
1040 struct buffer *prev = current_buffer;
1041 Lisp_Object buffer;
1042 int specpdl_count = SPECPDL_INDEX ();
1043 int previous_menu_items_used = f->menu_bar_items_used;
1044 Lisp_Object *previous_items
1045 = (Lisp_Object *) alloca (previous_menu_items_used
1046 * sizeof (Lisp_Object));
1047
1048 /* If we are making a new widget, its contents are empty,
1049 do always reinitialize them. */
1050 if (! menubar_widget)
1051 previous_menu_items_used = 0;
1052
1053 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1054 specbind (Qinhibit_quit, Qt);
1055 /* Don't let the debugger step into this code
1056 because it is not reentrant. */
1057 specbind (Qdebug_on_next_call, Qnil);
1058
1059 record_unwind_save_match_data ();
1060 if (NILP (Voverriding_local_map_menu_flag))
1061 {
1062 specbind (Qoverriding_terminal_local_map, Qnil);
1063 specbind (Qoverriding_local_map, Qnil);
1064 }
1065
1066 set_buffer_internal_1 (XBUFFER (buffer));
1067
1068 /* Run the Lucid hook. */
1069 safe_run_hooks (Qactivate_menubar_hook);
1070
1071 /* If it has changed current-menubar from previous value,
1072 really recompute the menubar from the value. */
1073 if (! NILP (Vlucid_menu_bar_dirty_flag))
1074 call0 (Qrecompute_lucid_menubar);
1075 safe_run_hooks (Qmenu_bar_update_hook);
1076 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1077
1078 items = FRAME_MENU_BAR_ITEMS (f);
1079
1080 /* Save the frame's previous menu bar contents data. */
1081 if (previous_menu_items_used)
1082 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1083 previous_menu_items_used * sizeof (Lisp_Object));
1084
1085 /* Fill in menu_items with the current menu bar contents.
1086 This can evaluate Lisp code. */
1087 save_menu_items ();
1088
1089 menu_items = f->menu_bar_vector;
1090 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
1091 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1092 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1093 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1094 submenu_top_level_items
1095 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1096 init_menu_items ();
1097 for (i = 0; i < XVECTOR (items)->size; i += 4)
1098 {
1099 Lisp_Object key, string, maps;
1100
1101 last_i = i;
1102
1103 key = XVECTOR (items)->contents[i];
1104 string = XVECTOR (items)->contents[i + 1];
1105 maps = XVECTOR (items)->contents[i + 2];
1106 if (NILP (string))
1107 break;
1108
1109 submenu_start[i] = menu_items_used;
1110
1111 menu_items_n_panes = 0;
1112 submenu_top_level_items[i]
1113 = parse_single_submenu (key, string, maps);
1114 submenu_n_panes[i] = menu_items_n_panes;
1115
1116 submenu_end[i] = menu_items_used;
1117 }
1118
1119 finish_menu_items ();
1120
1121 /* Convert menu_items into widget_value trees
1122 to display the menu. This cannot evaluate Lisp code. */
1123
1124 wv = xmalloc_widget_value ();
1125 wv->name = "menubar";
1126 wv->value = 0;
1127 wv->enabled = 1;
1128 wv->button_type = BUTTON_TYPE_NONE;
1129 wv->help = Qnil;
1130 first_wv = wv;
1131
1132 for (i = 0; i < last_i; i += 4)
1133 {
1134 menu_items_n_panes = submenu_n_panes[i];
1135 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1136 submenu_top_level_items[i]);
1137 if (prev_wv)
1138 prev_wv->next = wv;
1139 else
1140 first_wv->contents = wv;
1141 /* Don't set wv->name here; GC during the loop might relocate it. */
1142 wv->enabled = 1;
1143 wv->button_type = BUTTON_TYPE_NONE;
1144 prev_wv = wv;
1145 }
1146
1147 set_buffer_internal_1 (prev);
1148
1149 /* If there has been no change in the Lisp-level contents
1150 of the menu bar, skip redisplaying it. Just exit. */
1151
1152 /* Compare the new menu items with the ones computed last time. */
1153 for (i = 0; i < previous_menu_items_used; i++)
1154 if (menu_items_used == i
1155 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1156 break;
1157 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1158 {
1159 /* The menu items have not changed. Don't bother updating
1160 the menus in any form, since it would be a no-op. */
1161 free_menubar_widget_value_tree (first_wv);
1162 discard_menu_items ();
1163 unbind_to (specpdl_count, Qnil);
1164 return;
1165 }
1166
1167 /* The menu items are different, so store them in the frame. */
1168 f->menu_bar_vector = menu_items;
1169 f->menu_bar_items_used = menu_items_used;
1170
1171 /* This undoes save_menu_items. */
1172 unbind_to (specpdl_count, Qnil);
1173
1174 /* Now GC cannot happen during the lifetime of the widget_value,
1175 so it's safe to store data from a Lisp_String. */
1176 wv = first_wv->contents;
1177 for (i = 0; i < XVECTOR (items)->size; i += 4)
1178 {
1179 Lisp_Object string;
1180 string = XVECTOR (items)->contents[i + 1];
1181 if (NILP (string))
1182 break;
1183 wv->name = (char *) SDATA (string);
1184 update_submenu_strings (wv->contents);
1185 wv = wv->next;
1186 }
1187
1188 }
1189 else
1190 {
1191 /* Make a widget-value tree containing
1192 just the top level menu bar strings. */
1193
1194 wv = xmalloc_widget_value ();
1195 wv->name = "menubar";
1196 wv->value = 0;
1197 wv->enabled = 1;
1198 wv->button_type = BUTTON_TYPE_NONE;
1199 wv->help = Qnil;
1200 first_wv = wv;
1201
1202 items = FRAME_MENU_BAR_ITEMS (f);
1203 for (i = 0; i < XVECTOR (items)->size; i += 4)
1204 {
1205 Lisp_Object string;
1206
1207 string = XVECTOR (items)->contents[i + 1];
1208 if (NILP (string))
1209 break;
1210
1211 wv = xmalloc_widget_value ();
1212 wv->name = (char *) SDATA (string);
1213 wv->value = 0;
1214 wv->enabled = 1;
1215 wv->button_type = BUTTON_TYPE_NONE;
1216 wv->help = Qnil;
1217 /* This prevents lwlib from assuming this
1218 menu item is really supposed to be empty. */
1219 /* The EMACS_INT cast avoids a warning.
1220 This value just has to be different from small integers. */
1221 wv->call_data = (void *) (EMACS_INT) (-1);
1222
1223 if (prev_wv)
1224 prev_wv->next = wv;
1225 else
1226 first_wv->contents = wv;
1227 prev_wv = wv;
1228 }
1229
1230 /* Forget what we thought we knew about what is in the
1231 detailed contents of the menu bar menus.
1232 Changing the top level always destroys the contents. */
1233 f->menu_bar_items_used = 0;
1234 }
1235
1236 /* Create or update the menu bar widget. */
1237
1238 BLOCK_INPUT;
1239
1240 #ifdef USE_GTK
1241 xg_crazy_callback_abort = 1;
1242 if (menubar_widget)
1243 {
1244 /* The fourth arg is DEEP_P, which says to consider the entire
1245 menu trees we supply, rather than just the menu bar item names. */
1246 xg_modify_menubar_widgets (menubar_widget,
1247 f,
1248 first_wv,
1249 deep_p,
1250 G_CALLBACK (menubar_selection_callback),
1251 G_CALLBACK (popup_deactivate_callback),
1252 G_CALLBACK (menu_highlight_callback));
1253 }
1254 else
1255 {
1256 GtkWidget *wvbox = f->output_data.x->vbox_widget;
1257
1258 menubar_widget
1259 = xg_create_widget ("menubar", "menubar", f, first_wv,
1260 G_CALLBACK (menubar_selection_callback),
1261 G_CALLBACK (popup_deactivate_callback),
1262 G_CALLBACK (menu_highlight_callback));
1263
1264 f->output_data.x->menubar_widget = menubar_widget;
1265 }
1266
1267
1268 #else /* not USE_GTK */
1269 if (menubar_widget)
1270 {
1271 /* Disable resizing (done for Motif!) */
1272 lw_allow_resizing (f->output_data.x->widget, False);
1273
1274 /* The third arg is DEEP_P, which says to consider the entire
1275 menu trees we supply, rather than just the menu bar item names. */
1276 lw_modify_all_widgets (id, first_wv, deep_p);
1277
1278 /* Re-enable the edit widget to resize. */
1279 lw_allow_resizing (f->output_data.x->widget, True);
1280 }
1281 else
1282 {
1283 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
1284 XtTranslations override = XtParseTranslationTable (menuOverride);
1285
1286 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv,
1287 f->output_data.x->column_widget,
1288 0,
1289 popup_activate_callback,
1290 menubar_selection_callback,
1291 popup_deactivate_callback,
1292 menu_highlight_callback);
1293 f->output_data.x->menubar_widget = menubar_widget;
1294
1295 /* Make menu pop down on C-g. */
1296 XtOverrideTranslations (menubar_widget, override);
1297 apply_systemfont_to_menu (menubar_widget);
1298 }
1299
1300 {
1301 int menubar_size
1302 = (f->output_data.x->menubar_widget
1303 ? (f->output_data.x->menubar_widget->core.height
1304 + f->output_data.x->menubar_widget->core.border_width)
1305 : 0);
1306
1307 #if 1 /* Experimentally, we now get the right results
1308 for -geometry -0-0 without this. 24 Aug 96, rms.
1309 Maybe so, but the menu bar size is missing the pixels so the
1310 WM size hints are off by theses pixel. Jan D, oct 2009. */
1311 #ifdef USE_LUCID
1312 if (FRAME_EXTERNAL_MENU_BAR (f))
1313 {
1314 Dimension ibw = 0;
1315 XtVaGetValues (f->output_data.x->column_widget,
1316 XtNinternalBorderWidth, &ibw, NULL);
1317 menubar_size += ibw;
1318 }
1319 #endif /* USE_LUCID */
1320 #endif /* 1 */
1321
1322 f->output_data.x->menubar_height = menubar_size;
1323 }
1324 #endif /* not USE_GTK */
1325
1326 free_menubar_widget_value_tree (first_wv);
1327 update_frame_menubar (f);
1328
1329 #ifdef USE_GTK
1330 xg_crazy_callback_abort = 0;
1331 #endif
1332
1333 UNBLOCK_INPUT;
1334 }
1335
1336 /* Called from Fx_create_frame to create the initial menubar of a frame
1337 before it is mapped, so that the window is mapped with the menubar already
1338 there instead of us tacking it on later and thrashing the window after it
1339 is visible. */
1340
1341 void
1342 initialize_frame_menubar (f)
1343 FRAME_PTR f;
1344 {
1345 /* This function is called before the first chance to redisplay
1346 the frame. It has to be, so the frame will have the right size. */
1347 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1348 set_frame_menubar (f, 1, 1);
1349 }
1350
1351
1352 /* Get rid of the menu bar of frame F, and free its storage.
1353 This is used when deleting a frame, and when turning off the menu bar.
1354 For GTK this function is in gtkutil.c. */
1355
1356 #ifndef USE_GTK
1357 void
1358 free_frame_menubar (f)
1359 FRAME_PTR f;
1360 {
1361 Widget menubar_widget;
1362
1363 if (! FRAME_X_P (f))
1364 abort ();
1365
1366 menubar_widget = f->output_data.x->menubar_widget;
1367
1368 f->output_data.x->menubar_height = 0;
1369
1370 if (menubar_widget)
1371 {
1372 #ifdef USE_MOTIF
1373 /* Removing the menu bar magically changes the shell widget's x
1374 and y position of (0, 0) which, when the menu bar is turned
1375 on again, leads to pull-down menuss appearing in strange
1376 positions near the upper-left corner of the display. This
1377 happens only with some window managers like twm and ctwm,
1378 but not with other like Motif's mwm or kwm, because the
1379 latter generate ConfigureNotify events when the menu bar
1380 is switched off, which fixes the shell position. */
1381 Position x0, y0, x1, y1;
1382 #endif
1383
1384 BLOCK_INPUT;
1385
1386 #ifdef USE_MOTIF
1387 if (f->output_data.x->widget)
1388 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1389 #endif
1390
1391 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1392 f->output_data.x->menubar_widget = NULL;
1393
1394 #ifdef USE_MOTIF
1395 if (f->output_data.x->widget)
1396 {
1397 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1398 if (x1 == 0 && y1 == 0)
1399 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1400 }
1401 #endif
1402
1403 UNBLOCK_INPUT;
1404 }
1405 }
1406 #endif /* not USE_GTK */
1407
1408 #endif /* USE_X_TOOLKIT || USE_GTK */
1409 \f
1410 /* xmenu_show actually displays a menu using the panes and items in menu_items
1411 and returns the value selected from it.
1412 There are two versions of xmenu_show, one for Xt and one for Xlib.
1413 Both assume input is blocked by the caller. */
1414
1415 /* F is the frame the menu is for.
1416 X and Y are the frame-relative specified position,
1417 relative to the inside upper left corner of the frame F.
1418 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1419 KEYMAPS is 1 if this menu was specified with keymaps;
1420 in that case, we return a list containing the chosen item's value
1421 and perhaps also the pane's prefix.
1422 TITLE is the specified menu title.
1423 ERROR is a place to store an error message string in case of failure.
1424 (We return nil on failure, but the value doesn't actually matter.) */
1425
1426 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1427
1428 /* The item selected in the popup menu. */
1429 static Lisp_Object *volatile menu_item_selection;
1430
1431 #ifdef USE_GTK
1432
1433 /* Used when position a popup menu. See menu_position_func and
1434 create_and_show_popup_menu below. */
1435 struct next_popup_x_y
1436 {
1437 FRAME_PTR f;
1438 int x;
1439 int y;
1440 };
1441
1442 /* The menu position function to use if we are not putting a popup
1443 menu where the pointer is.
1444 MENU is the menu to pop up.
1445 X and Y shall on exit contain x/y where the menu shall pop up.
1446 PUSH_IN is not documented in the GTK manual.
1447 USER_DATA is any data passed in when calling gtk_menu_popup.
1448 Here it points to a struct next_popup_x_y where the coordinates
1449 to store in *X and *Y are as well as the frame for the popup.
1450
1451 Here only X and Y are used. */
1452 static void
1453 menu_position_func (menu, x, y, push_in, user_data)
1454 GtkMenu *menu;
1455 gint *x;
1456 gint *y;
1457 gboolean *push_in;
1458 gpointer user_data;
1459 {
1460 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1461 GtkRequisition req;
1462 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1463 int disp_width = x_display_pixel_width (dpyinfo);
1464 int disp_height = x_display_pixel_height (dpyinfo);
1465
1466 *x = data->x;
1467 *y = data->y;
1468
1469 /* Check if there is room for the menu. If not, adjust x/y so that
1470 the menu is fully visible. */
1471 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1472 if (data->x + req.width > disp_width)
1473 *x -= data->x + req.width - disp_width;
1474 if (data->y + req.height > disp_height)
1475 *y -= data->y + req.height - disp_height;
1476 }
1477
1478 static void
1479 popup_selection_callback (widget, client_data)
1480 GtkWidget *widget;
1481 gpointer client_data;
1482 {
1483 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1484
1485 if (xg_crazy_callback_abort) return;
1486 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1487 }
1488
1489 static Lisp_Object
1490 pop_down_menu (arg)
1491 Lisp_Object arg;
1492 {
1493 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1494
1495 popup_activated_flag = 0;
1496 BLOCK_INPUT;
1497 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1498 UNBLOCK_INPUT;
1499 return Qnil;
1500 }
1501
1502 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1503 menu pops down.
1504 menu_item_selection will be set to the selection. */
1505 static void
1506 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1507 FRAME_PTR f;
1508 widget_value *first_wv;
1509 int x;
1510 int y;
1511 int for_click;
1512 EMACS_UINT timestamp;
1513 {
1514 int i;
1515 GtkWidget *menu;
1516 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1517 struct next_popup_x_y popup_x_y;
1518 int specpdl_count = SPECPDL_INDEX ();
1519
1520 if (! FRAME_X_P (f))
1521 abort ();
1522
1523 xg_crazy_callback_abort = 1;
1524 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1525 G_CALLBACK (popup_selection_callback),
1526 G_CALLBACK (popup_deactivate_callback),
1527 G_CALLBACK (menu_highlight_callback));
1528 xg_crazy_callback_abort = 0;
1529
1530 if (! for_click)
1531 {
1532 /* Not invoked by a click. pop up at x/y. */
1533 pos_func = menu_position_func;
1534
1535 /* Adjust coordinates to be root-window-relative. */
1536 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1537 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1538
1539 popup_x_y.x = x;
1540 popup_x_y.y = y;
1541 popup_x_y.f = f;
1542
1543 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1544 }
1545 else
1546 {
1547 for (i = 0; i < 5; i++)
1548 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1549 break;
1550 }
1551
1552 /* Display the menu. */
1553 gtk_widget_show_all (menu);
1554
1555 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1556 timestamp > 0 ? timestamp : gtk_get_current_event_time());
1557
1558 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
1559
1560 if (GTK_WIDGET_MAPPED (menu))
1561 {
1562 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1563 two. show_help_echo uses this to detect popup menus. */
1564 popup_activated_flag = 1;
1565 /* Process events that apply to the menu. */
1566 popup_widget_loop (1, menu);
1567 }
1568
1569 unbind_to (specpdl_count, Qnil);
1570
1571 /* Must reset this manually because the button release event is not passed
1572 to Emacs event loop. */
1573 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1574 }
1575
1576 #else /* not USE_GTK */
1577
1578 /* We need a unique id for each widget handled by the Lucid Widget
1579 library.
1580
1581 For the main windows, and popup menus, we use this counter,
1582 which we increment each time after use. This starts from 1<<16.
1583
1584 For menu bars, we use numbers starting at 0, counted in
1585 next_menubar_widget_id. */
1586 LWLIB_ID widget_id_tick;
1587
1588 static void
1589 popup_selection_callback (widget, id, client_data)
1590 Widget widget;
1591 LWLIB_ID id;
1592 XtPointer client_data;
1593 {
1594 menu_item_selection = (Lisp_Object *) client_data;
1595 }
1596
1597 /* ARG is the LWLIB ID of the dialog box, represented
1598 as a Lisp object as (HIGHPART . LOWPART). */
1599
1600 static Lisp_Object
1601 pop_down_menu (arg)
1602 Lisp_Object arg;
1603 {
1604 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1605 | XINT (XCDR (arg)));
1606
1607 BLOCK_INPUT;
1608 lw_destroy_all_widgets (id);
1609 UNBLOCK_INPUT;
1610 popup_activated_flag = 0;
1611
1612 return Qnil;
1613 }
1614
1615 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1616 menu pops down.
1617 menu_item_selection will be set to the selection. */
1618 static void
1619 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp)
1620 FRAME_PTR f;
1621 widget_value *first_wv;
1622 int x;
1623 int y;
1624 int for_click;
1625 EMACS_UINT timestamp;
1626 {
1627 int i;
1628 Arg av[2];
1629 int ac = 0;
1630 XButtonPressedEvent dummy;
1631 LWLIB_ID menu_id;
1632 Widget menu;
1633
1634 if (! FRAME_X_P (f))
1635 abort ();
1636
1637 menu_id = widget_id_tick++;
1638 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1639 f->output_data.x->widget, 1, 0,
1640 popup_selection_callback,
1641 popup_deactivate_callback,
1642 menu_highlight_callback);
1643
1644 apply_systemfont_to_menu (menu);
1645
1646 dummy.type = ButtonPress;
1647 dummy.serial = 0;
1648 dummy.send_event = 0;
1649 dummy.display = FRAME_X_DISPLAY (f);
1650 dummy.time = CurrentTime;
1651 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1652 dummy.window = dummy.root;
1653 dummy.subwindow = dummy.root;
1654 dummy.x = x;
1655 dummy.y = y;
1656
1657 /* Adjust coordinates to be root-window-relative. */
1658 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1659 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1660
1661 dummy.x_root = x;
1662 dummy.y_root = y;
1663
1664 dummy.state = 0;
1665 dummy.button = 0;
1666 for (i = 0; i < 5; i++)
1667 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1668 dummy.button = i;
1669
1670 /* Don't allow any geometry request from the user. */
1671 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1672 XtSetValues (menu, av, ac);
1673
1674 /* Display the menu. */
1675 lw_popup_menu (menu, (XEvent *) &dummy);
1676 popup_activated_flag = 1;
1677 x_activate_timeout_atimer ();
1678
1679 {
1680 int fact = 4 * sizeof (LWLIB_ID);
1681 int specpdl_count = SPECPDL_INDEX ();
1682 record_unwind_protect (pop_down_menu,
1683 Fcons (make_number (menu_id >> (fact)),
1684 make_number (menu_id & ~(-1 << (fact)))));
1685
1686 /* Process events that apply to the menu. */
1687 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
1688
1689 unbind_to (specpdl_count, Qnil);
1690 }
1691 }
1692
1693 #endif /* not USE_GTK */
1694
1695 Lisp_Object
1696 xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps,
1697 Lisp_Object title, char **error, EMACS_UINT timestamp)
1698 {
1699 int i;
1700 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1701 widget_value **submenu_stack
1702 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1703 Lisp_Object *subprefix_stack
1704 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1705 int submenu_depth = 0;
1706
1707 int first_pane;
1708
1709 if (! FRAME_X_P (f))
1710 abort ();
1711
1712 *error = NULL;
1713
1714 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1715 {
1716 *error = "Empty menu";
1717 return Qnil;
1718 }
1719
1720 /* Create a tree of widget_value objects
1721 representing the panes and their items. */
1722 wv = xmalloc_widget_value ();
1723 wv->name = "menu";
1724 wv->value = 0;
1725 wv->enabled = 1;
1726 wv->button_type = BUTTON_TYPE_NONE;
1727 wv->help =Qnil;
1728 first_wv = wv;
1729 first_pane = 1;
1730
1731 /* Loop over all panes and items, filling in the tree. */
1732 i = 0;
1733 while (i < menu_items_used)
1734 {
1735 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1736 {
1737 submenu_stack[submenu_depth++] = save_wv;
1738 save_wv = prev_wv;
1739 prev_wv = 0;
1740 first_pane = 1;
1741 i++;
1742 }
1743 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1744 {
1745 prev_wv = save_wv;
1746 save_wv = submenu_stack[--submenu_depth];
1747 first_pane = 0;
1748 i++;
1749 }
1750 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1751 && submenu_depth != 0)
1752 i += MENU_ITEMS_PANE_LENGTH;
1753 /* Ignore a nil in the item list.
1754 It's meaningful only for dialog boxes. */
1755 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1756 i += 1;
1757 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1758 {
1759 /* Create a new pane. */
1760 Lisp_Object pane_name, prefix;
1761 char *pane_string;
1762
1763 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1764 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1765
1766 #ifndef HAVE_MULTILINGUAL_MENU
1767 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1768 {
1769 pane_name = ENCODE_MENU_STRING (pane_name);
1770 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1771 }
1772 #endif
1773 pane_string = (NILP (pane_name)
1774 ? "" : (char *) SDATA (pane_name));
1775 /* If there is just one top-level pane, put all its items directly
1776 under the top-level menu. */
1777 if (menu_items_n_panes == 1)
1778 pane_string = "";
1779
1780 /* If the pane has a meaningful name,
1781 make the pane a top-level menu item
1782 with its items as a submenu beneath it. */
1783 if (!keymaps && strcmp (pane_string, ""))
1784 {
1785 wv = xmalloc_widget_value ();
1786 if (save_wv)
1787 save_wv->next = wv;
1788 else
1789 first_wv->contents = wv;
1790 wv->name = pane_string;
1791 if (keymaps && !NILP (prefix))
1792 wv->name++;
1793 wv->value = 0;
1794 wv->enabled = 1;
1795 wv->button_type = BUTTON_TYPE_NONE;
1796 wv->help = Qnil;
1797 save_wv = wv;
1798 prev_wv = 0;
1799 }
1800 else if (first_pane)
1801 {
1802 save_wv = wv;
1803 prev_wv = 0;
1804 }
1805 first_pane = 0;
1806 i += MENU_ITEMS_PANE_LENGTH;
1807 }
1808 else
1809 {
1810 /* Create a new item within current pane. */
1811 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1812 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1813 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1814 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1815 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1816 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1817 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1818 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1819
1820 #ifndef HAVE_MULTILINGUAL_MENU
1821 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1822 {
1823 item_name = ENCODE_MENU_STRING (item_name);
1824 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1825 }
1826
1827 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1828 {
1829 descrip = ENCODE_MENU_STRING (descrip);
1830 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1831 }
1832 #endif /* not HAVE_MULTILINGUAL_MENU */
1833
1834 wv = xmalloc_widget_value ();
1835 if (prev_wv)
1836 prev_wv->next = wv;
1837 else
1838 save_wv->contents = wv;
1839 wv->name = (char *) SDATA (item_name);
1840 if (!NILP (descrip))
1841 wv->key = (char *) SDATA (descrip);
1842 wv->value = 0;
1843 /* If this item has a null value,
1844 make the call_data null so that it won't display a box
1845 when the mouse is on it. */
1846 wv->call_data
1847 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
1848 wv->enabled = !NILP (enable);
1849
1850 if (NILP (type))
1851 wv->button_type = BUTTON_TYPE_NONE;
1852 else if (EQ (type, QCtoggle))
1853 wv->button_type = BUTTON_TYPE_TOGGLE;
1854 else if (EQ (type, QCradio))
1855 wv->button_type = BUTTON_TYPE_RADIO;
1856 else
1857 abort ();
1858
1859 wv->selected = !NILP (selected);
1860
1861 if (! STRINGP (help))
1862 help = Qnil;
1863
1864 wv->help = help;
1865
1866 prev_wv = wv;
1867
1868 i += MENU_ITEMS_ITEM_LENGTH;
1869 }
1870 }
1871
1872 /* Deal with the title, if it is non-nil. */
1873 if (!NILP (title))
1874 {
1875 widget_value *wv_title = xmalloc_widget_value ();
1876 widget_value *wv_sep1 = xmalloc_widget_value ();
1877 widget_value *wv_sep2 = xmalloc_widget_value ();
1878
1879 wv_sep2->name = "--";
1880 wv_sep2->next = first_wv->contents;
1881 wv_sep2->help = Qnil;
1882
1883 wv_sep1->name = "--";
1884 wv_sep1->next = wv_sep2;
1885 wv_sep1->help = Qnil;
1886
1887 #ifndef HAVE_MULTILINGUAL_MENU
1888 if (STRING_MULTIBYTE (title))
1889 title = ENCODE_MENU_STRING (title);
1890 #endif
1891
1892 wv_title->name = (char *) SDATA (title);
1893 wv_title->enabled = TRUE;
1894 wv_title->button_type = BUTTON_TYPE_NONE;
1895 wv_title->help = Qnil;
1896 wv_title->next = wv_sep1;
1897 first_wv->contents = wv_title;
1898 }
1899
1900 /* No selection has been chosen yet. */
1901 menu_item_selection = 0;
1902
1903 /* Actually create and show the menu until popped down. */
1904 create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp);
1905
1906 /* Free the widget_value objects we used to specify the contents. */
1907 free_menubar_widget_value_tree (first_wv);
1908
1909 /* Find the selected item, and its pane, to return
1910 the proper value. */
1911 if (menu_item_selection != 0)
1912 {
1913 Lisp_Object prefix, entry;
1914
1915 prefix = entry = Qnil;
1916 i = 0;
1917 while (i < menu_items_used)
1918 {
1919 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1920 {
1921 subprefix_stack[submenu_depth++] = prefix;
1922 prefix = entry;
1923 i++;
1924 }
1925 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1926 {
1927 prefix = subprefix_stack[--submenu_depth];
1928 i++;
1929 }
1930 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1931 {
1932 prefix
1933 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1934 i += MENU_ITEMS_PANE_LENGTH;
1935 }
1936 /* Ignore a nil in the item list.
1937 It's meaningful only for dialog boxes. */
1938 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1939 i += 1;
1940 else
1941 {
1942 entry
1943 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1944 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1945 {
1946 if (keymaps != 0)
1947 {
1948 int j;
1949
1950 entry = Fcons (entry, Qnil);
1951 if (!NILP (prefix))
1952 entry = Fcons (prefix, entry);
1953 for (j = submenu_depth - 1; j >= 0; j--)
1954 if (!NILP (subprefix_stack[j]))
1955 entry = Fcons (subprefix_stack[j], entry);
1956 }
1957 return entry;
1958 }
1959 i += MENU_ITEMS_ITEM_LENGTH;
1960 }
1961 }
1962 }
1963 else if (!for_click)
1964 /* Make "Cancel" equivalent to C-g. */
1965 Fsignal (Qquit, Qnil);
1966
1967 return Qnil;
1968 }
1969 \f
1970 #ifdef USE_GTK
1971 static void
1972 dialog_selection_callback (widget, client_data)
1973 GtkWidget *widget;
1974 gpointer client_data;
1975 {
1976 /* The EMACS_INT cast avoids a warning. There's no problem
1977 as long as pointers have enough bits to hold small integers. */
1978 if ((int) (EMACS_INT) client_data != -1)
1979 menu_item_selection = (Lisp_Object *) client_data;
1980
1981 popup_activated_flag = 0;
1982 }
1983
1984 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1985 dialog pops down.
1986 menu_item_selection will be set to the selection. */
1987 static void
1988 create_and_show_dialog (f, first_wv)
1989 FRAME_PTR f;
1990 widget_value *first_wv;
1991 {
1992 GtkWidget *menu;
1993
1994 if (! FRAME_X_P (f))
1995 abort ();
1996
1997 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1998 G_CALLBACK (dialog_selection_callback),
1999 G_CALLBACK (popup_deactivate_callback),
2000 0);
2001
2002 if (menu)
2003 {
2004 int specpdl_count = SPECPDL_INDEX ();
2005 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
2006
2007 /* Display the menu. */
2008 gtk_widget_show_all (menu);
2009
2010 /* Process events that apply to the menu. */
2011 popup_widget_loop (1, menu);
2012
2013 unbind_to (specpdl_count, Qnil);
2014 }
2015 }
2016
2017 #else /* not USE_GTK */
2018 static void
2019 dialog_selection_callback (widget, id, client_data)
2020 Widget widget;
2021 LWLIB_ID id;
2022 XtPointer client_data;
2023 {
2024 /* The EMACS_INT cast avoids a warning. There's no problem
2025 as long as pointers have enough bits to hold small integers. */
2026 if ((int) (EMACS_INT) client_data != -1)
2027 menu_item_selection = (Lisp_Object *) client_data;
2028
2029 BLOCK_INPUT;
2030 lw_destroy_all_widgets (id);
2031 UNBLOCK_INPUT;
2032 popup_activated_flag = 0;
2033 }
2034
2035
2036 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2037 dialog pops down.
2038 menu_item_selection will be set to the selection. */
2039 static void
2040 create_and_show_dialog (f, first_wv)
2041 FRAME_PTR f;
2042 widget_value *first_wv;
2043 {
2044 LWLIB_ID dialog_id;
2045
2046 if (!FRAME_X_P (f))
2047 abort();
2048
2049 dialog_id = widget_id_tick++;
2050 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2051 f->output_data.x->widget, 1, 0,
2052 dialog_selection_callback, 0, 0);
2053 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2054
2055 /* Display the dialog box. */
2056 lw_pop_up_all_widgets (dialog_id);
2057 popup_activated_flag = 1;
2058 x_activate_timeout_atimer ();
2059
2060 /* Process events that apply to the dialog box.
2061 Also handle timers. */
2062 {
2063 int count = SPECPDL_INDEX ();
2064 int fact = 4 * sizeof (LWLIB_ID);
2065
2066 /* xdialog_show_unwind is responsible for popping the dialog box down. */
2067 record_unwind_protect (pop_down_menu,
2068 Fcons (make_number (dialog_id >> (fact)),
2069 make_number (dialog_id & ~(-1 << (fact)))));
2070
2071 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
2072 dialog_id, 1);
2073
2074 unbind_to (count, Qnil);
2075 }
2076 }
2077
2078 #endif /* not USE_GTK */
2079
2080 static char * button_names [] = {
2081 "button1", "button2", "button3", "button4", "button5",
2082 "button6", "button7", "button8", "button9", "button10" };
2083
2084 static Lisp_Object
2085 xdialog_show (f, keymaps, title, header, error_name)
2086 FRAME_PTR f;
2087 int keymaps;
2088 Lisp_Object title, header;
2089 char **error_name;
2090 {
2091 int i, nb_buttons=0;
2092 char dialog_name[6];
2093
2094 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2095
2096 /* Number of elements seen so far, before boundary. */
2097 int left_count = 0;
2098 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2099 int boundary_seen = 0;
2100
2101 if (! FRAME_X_P (f))
2102 abort ();
2103
2104 *error_name = NULL;
2105
2106 if (menu_items_n_panes > 1)
2107 {
2108 *error_name = "Multiple panes in dialog box";
2109 return Qnil;
2110 }
2111
2112 /* Create a tree of widget_value objects
2113 representing the text label and buttons. */
2114 {
2115 Lisp_Object pane_name, prefix;
2116 char *pane_string;
2117 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2118 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2119 pane_string = (NILP (pane_name)
2120 ? "" : (char *) SDATA (pane_name));
2121 prev_wv = xmalloc_widget_value ();
2122 prev_wv->value = pane_string;
2123 if (keymaps && !NILP (prefix))
2124 prev_wv->name++;
2125 prev_wv->enabled = 1;
2126 prev_wv->name = "message";
2127 prev_wv->help = Qnil;
2128 first_wv = prev_wv;
2129
2130 /* Loop over all panes and items, filling in the tree. */
2131 i = MENU_ITEMS_PANE_LENGTH;
2132 while (i < menu_items_used)
2133 {
2134
2135 /* Create a new item within current pane. */
2136 Lisp_Object item_name, enable, descrip;
2137 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2138 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2139 descrip
2140 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2141
2142 if (NILP (item_name))
2143 {
2144 free_menubar_widget_value_tree (first_wv);
2145 *error_name = "Submenu in dialog items";
2146 return Qnil;
2147 }
2148 if (EQ (item_name, Qquote))
2149 {
2150 /* This is the boundary between left-side elts
2151 and right-side elts. Stop incrementing right_count. */
2152 boundary_seen = 1;
2153 i++;
2154 continue;
2155 }
2156 if (nb_buttons >= 9)
2157 {
2158 free_menubar_widget_value_tree (first_wv);
2159 *error_name = "Too many dialog items";
2160 return Qnil;
2161 }
2162
2163 wv = xmalloc_widget_value ();
2164 prev_wv->next = wv;
2165 wv->name = (char *) button_names[nb_buttons];
2166 if (!NILP (descrip))
2167 wv->key = (char *) SDATA (descrip);
2168 wv->value = (char *) SDATA (item_name);
2169 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2170 wv->enabled = !NILP (enable);
2171 wv->help = Qnil;
2172 prev_wv = wv;
2173
2174 if (! boundary_seen)
2175 left_count++;
2176
2177 nb_buttons++;
2178 i += MENU_ITEMS_ITEM_LENGTH;
2179 }
2180
2181 /* If the boundary was not specified,
2182 by default put half on the left and half on the right. */
2183 if (! boundary_seen)
2184 left_count = nb_buttons - nb_buttons / 2;
2185
2186 wv = xmalloc_widget_value ();
2187 wv->name = dialog_name;
2188 wv->help = Qnil;
2189
2190 /* Frame title: 'Q' = Question, 'I' = Information.
2191 Can also have 'E' = Error if, one day, we want
2192 a popup for errors. */
2193 if (NILP(header))
2194 dialog_name[0] = 'Q';
2195 else
2196 dialog_name[0] = 'I';
2197
2198 /* Dialog boxes use a really stupid name encoding
2199 which specifies how many buttons to use
2200 and how many buttons are on the right. */
2201 dialog_name[1] = '0' + nb_buttons;
2202 dialog_name[2] = 'B';
2203 dialog_name[3] = 'R';
2204 /* Number of buttons to put on the right. */
2205 dialog_name[4] = '0' + nb_buttons - left_count;
2206 dialog_name[5] = 0;
2207 wv->contents = first_wv;
2208 first_wv = wv;
2209 }
2210
2211 /* No selection has been chosen yet. */
2212 menu_item_selection = 0;
2213
2214 /* Actually create and show the dialog. */
2215 create_and_show_dialog (f, first_wv);
2216
2217 /* Free the widget_value objects we used to specify the contents. */
2218 free_menubar_widget_value_tree (first_wv);
2219
2220 /* Find the selected item, and its pane, to return
2221 the proper value. */
2222 if (menu_item_selection != 0)
2223 {
2224 Lisp_Object prefix;
2225
2226 prefix = Qnil;
2227 i = 0;
2228 while (i < menu_items_used)
2229 {
2230 Lisp_Object entry;
2231
2232 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2233 {
2234 prefix
2235 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2236 i += MENU_ITEMS_PANE_LENGTH;
2237 }
2238 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2239 {
2240 /* This is the boundary between left-side elts and
2241 right-side elts. */
2242 ++i;
2243 }
2244 else
2245 {
2246 entry
2247 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2248 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2249 {
2250 if (keymaps != 0)
2251 {
2252 entry = Fcons (entry, Qnil);
2253 if (!NILP (prefix))
2254 entry = Fcons (prefix, entry);
2255 }
2256 return entry;
2257 }
2258 i += MENU_ITEMS_ITEM_LENGTH;
2259 }
2260 }
2261 }
2262 else
2263 /* Make "Cancel" equivalent to C-g. */
2264 Fsignal (Qquit, Qnil);
2265
2266 return Qnil;
2267 }
2268
2269 #else /* not USE_X_TOOLKIT && not USE_GTK */
2270
2271 /* The frame of the last activated non-toolkit menu bar.
2272 Used to generate menu help events. */
2273
2274 static struct frame *menu_help_frame;
2275
2276
2277 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2278
2279 PANE is the pane number, and ITEM is the menu item number in
2280 the menu (currently not used).
2281
2282 This cannot be done with generating a HELP_EVENT because
2283 XMenuActivate contains a loop that doesn't let Emacs process
2284 keyboard events. */
2285
2286 static void
2287 menu_help_callback (help_string, pane, item)
2288 char *help_string;
2289 int pane, item;
2290 {
2291 extern Lisp_Object Qmenu_item;
2292 Lisp_Object *first_item;
2293 Lisp_Object pane_name;
2294 Lisp_Object menu_object;
2295
2296 first_item = XVECTOR (menu_items)->contents;
2297 if (EQ (first_item[0], Qt))
2298 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2299 else if (EQ (first_item[0], Qquote))
2300 /* This shouldn't happen, see xmenu_show. */
2301 pane_name = empty_unibyte_string;
2302 else
2303 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2304
2305 /* (menu-item MENU-NAME PANE-NUMBER) */
2306 menu_object = Fcons (Qmenu_item,
2307 Fcons (pane_name,
2308 Fcons (make_number (pane), Qnil)));
2309 show_help_echo (help_string ? build_string (help_string) : Qnil,
2310 Qnil, menu_object, make_number (item), 1);
2311 }
2312
2313 static Lisp_Object
2314 pop_down_menu (arg)
2315 Lisp_Object arg;
2316 {
2317 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2318 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
2319
2320 FRAME_PTR f = p1->pointer;
2321 XMenu *menu = p2->pointer;
2322
2323 BLOCK_INPUT;
2324 #ifndef MSDOS
2325 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2326 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2327 #endif
2328 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2329
2330 #ifdef HAVE_X_WINDOWS
2331 /* Assume the mouse has moved out of the X window.
2332 If it has actually moved in, we will get an EnterNotify. */
2333 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2334
2335 /* State that no mouse buttons are now held.
2336 (The oldXMenu code doesn't track this info for us.)
2337 That is not necessarily true, but the fiction leads to reasonable
2338 results, and it is a pain to ask which are actually held now. */
2339 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2340
2341 #endif /* HAVE_X_WINDOWS */
2342
2343 UNBLOCK_INPUT;
2344
2345 return Qnil;
2346 }
2347
2348
2349 Lisp_Object
2350 xmenu_show (f, x, y, for_click, keymaps, title, error, timestamp)
2351 FRAME_PTR f;
2352 int x, y;
2353 int for_click;
2354 int keymaps;
2355 Lisp_Object title;
2356 char **error;
2357 EMACS_UINT timestamp;
2358 {
2359 Window root;
2360 XMenu *menu;
2361 int pane, selidx, lpane, status;
2362 Lisp_Object entry, pane_prefix;
2363 char *datap;
2364 int ulx, uly, width, height;
2365 int dispwidth, dispheight;
2366 int i, j, lines, maxlines;
2367 int maxwidth;
2368 int dummy_int;
2369 unsigned int dummy_uint;
2370 int specpdl_count = SPECPDL_INDEX ();
2371
2372 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
2373 abort ();
2374
2375 *error = 0;
2376 if (menu_items_n_panes == 0)
2377 return Qnil;
2378
2379 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2380 {
2381 *error = "Empty menu";
2382 return Qnil;
2383 }
2384
2385 /* Figure out which root window F is on. */
2386 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2387 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2388 &dummy_uint, &dummy_uint);
2389
2390 /* Make the menu on that window. */
2391 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2392 if (menu == NULL)
2393 {
2394 *error = "Can't create menu";
2395 return Qnil;
2396 }
2397
2398 /* Don't GC while we prepare and show the menu,
2399 because we give the oldxmenu library pointers to the
2400 contents of strings. */
2401 inhibit_garbage_collection ();
2402
2403 #ifdef HAVE_X_WINDOWS
2404 /* Adjust coordinates to relative to the outer (window manager) window. */
2405 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2406 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2407 #endif /* HAVE_X_WINDOWS */
2408
2409 /* Adjust coordinates to be root-window-relative. */
2410 x += f->left_pos;
2411 y += f->top_pos;
2412
2413 /* Create all the necessary panes and their items. */
2414 maxlines = lines = i = 0;
2415 while (i < menu_items_used)
2416 {
2417 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2418 {
2419 /* Create a new pane. */
2420 Lisp_Object pane_name, prefix;
2421 char *pane_string;
2422
2423 maxlines = max (maxlines, lines);
2424 lines = 0;
2425 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2426 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2427 pane_string = (NILP (pane_name)
2428 ? "" : (char *) SDATA (pane_name));
2429 if (keymaps && !NILP (prefix))
2430 pane_string++;
2431
2432 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2433 if (lpane == XM_FAILURE)
2434 {
2435 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2436 *error = "Can't create pane";
2437 return Qnil;
2438 }
2439 i += MENU_ITEMS_PANE_LENGTH;
2440
2441 /* Find the width of the widest item in this pane. */
2442 maxwidth = 0;
2443 j = i;
2444 while (j < menu_items_used)
2445 {
2446 Lisp_Object item;
2447 item = XVECTOR (menu_items)->contents[j];
2448 if (EQ (item, Qt))
2449 break;
2450 if (NILP (item))
2451 {
2452 j++;
2453 continue;
2454 }
2455 width = SBYTES (item);
2456 if (width > maxwidth)
2457 maxwidth = width;
2458
2459 j += MENU_ITEMS_ITEM_LENGTH;
2460 }
2461 }
2462 /* Ignore a nil in the item list.
2463 It's meaningful only for dialog boxes. */
2464 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2465 i += 1;
2466 else
2467 {
2468 /* Create a new item within current pane. */
2469 Lisp_Object item_name, enable, descrip, help;
2470 unsigned char *item_data;
2471 char *help_string;
2472
2473 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2474 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2475 descrip
2476 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2477 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
2478 help_string = STRINGP (help) ? SDATA (help) : NULL;
2479
2480 if (!NILP (descrip))
2481 {
2482 int gap = maxwidth - SBYTES (item_name);
2483 /* if alloca is fast, use that to make the space,
2484 to reduce gc needs. */
2485 item_data
2486 = (unsigned char *) alloca (maxwidth
2487 + SBYTES (descrip) + 1);
2488 bcopy (SDATA (item_name), item_data,
2489 SBYTES (item_name));
2490 for (j = SCHARS (item_name); j < maxwidth; j++)
2491 item_data[j] = ' ';
2492 bcopy (SDATA (descrip), item_data + j,
2493 SBYTES (descrip));
2494 item_data[j + SBYTES (descrip)] = 0;
2495 }
2496 else
2497 item_data = SDATA (item_name);
2498
2499 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2500 menu, lpane, 0, item_data,
2501 !NILP (enable), help_string)
2502 == XM_FAILURE)
2503 {
2504 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2505 *error = "Can't add selection to menu";
2506 return Qnil;
2507 }
2508 i += MENU_ITEMS_ITEM_LENGTH;
2509 lines++;
2510 }
2511 }
2512
2513 maxlines = max (maxlines, lines);
2514
2515 /* All set and ready to fly. */
2516 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2517 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2518 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2519 x = min (x, dispwidth);
2520 y = min (y, dispheight);
2521 x = max (x, 1);
2522 y = max (y, 1);
2523 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2524 &ulx, &uly, &width, &height);
2525 if (ulx+width > dispwidth)
2526 {
2527 x -= (ulx + width) - dispwidth;
2528 ulx = dispwidth - width;
2529 }
2530 if (uly+height > dispheight)
2531 {
2532 y -= (uly + height) - dispheight;
2533 uly = dispheight - height;
2534 }
2535 #ifndef HAVE_X_WINDOWS
2536 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2537 {
2538 /* Move the menu away of the echo area, to avoid overwriting the
2539 menu with help echo messages or vice versa. */
2540 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2541 {
2542 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2543 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2544 }
2545 else
2546 {
2547 y--;
2548 uly--;
2549 }
2550 }
2551 #endif
2552 if (ulx < 0) x -= ulx;
2553 if (uly < 0) y -= uly;
2554
2555 if (! for_click)
2556 {
2557 /* If position was not given by a mouse click, adjust so upper left
2558 corner of the menu as a whole ends up at given coordinates. This
2559 is what x-popup-menu says in its documentation. */
2560 x += width/2;
2561 y += 1.5*height/(maxlines+2);
2562 }
2563
2564 XMenuSetAEQ (menu, TRUE);
2565 XMenuSetFreeze (menu, TRUE);
2566 pane = selidx = 0;
2567
2568 #ifndef MSDOS
2569 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2570 #endif
2571
2572 record_unwind_protect (pop_down_menu,
2573 Fcons (make_save_value (f, 0),
2574 make_save_value (menu, 0)));
2575
2576 /* Help display under X won't work because XMenuActivate contains
2577 a loop that doesn't give Emacs a chance to process it. */
2578 menu_help_frame = f;
2579 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2580 x, y, ButtonReleaseMask, &datap,
2581 menu_help_callback);
2582
2583 switch (status)
2584 {
2585 case XM_SUCCESS:
2586 #ifdef XDEBUG
2587 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2588 #endif
2589
2590 /* Find the item number SELIDX in pane number PANE. */
2591 i = 0;
2592 while (i < menu_items_used)
2593 {
2594 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2595 {
2596 if (pane == 0)
2597 pane_prefix
2598 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2599 pane--;
2600 i += MENU_ITEMS_PANE_LENGTH;
2601 }
2602 else
2603 {
2604 if (pane == -1)
2605 {
2606 if (selidx == 0)
2607 {
2608 entry
2609 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2610 if (keymaps != 0)
2611 {
2612 entry = Fcons (entry, Qnil);
2613 if (!NILP (pane_prefix))
2614 entry = Fcons (pane_prefix, entry);
2615 }
2616 break;
2617 }
2618 selidx--;
2619 }
2620 i += MENU_ITEMS_ITEM_LENGTH;
2621 }
2622 }
2623 break;
2624
2625 case XM_FAILURE:
2626 *error = "Can't activate menu";
2627 case XM_IA_SELECT:
2628 entry = Qnil;
2629 break;
2630 case XM_NO_SELECT:
2631 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2632 the menu was invoked with a mouse event as POSITION). */
2633 if (! for_click)
2634 Fsignal (Qquit, Qnil);
2635 entry = Qnil;
2636 break;
2637 }
2638
2639 unbind_to (specpdl_count, Qnil);
2640
2641 return entry;
2642 }
2643
2644 #endif /* not USE_X_TOOLKIT */
2645
2646 #endif /* HAVE_MENUS */
2647
2648 /* Detect if a dialog or menu has been posted. */
2649
2650 int
2651 popup_activated ()
2652 {
2653 return popup_activated_flag;
2654 }
2655
2656 /* The following is used by delayed window autoselection. */
2657
2658 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2659 doc: /* Return t if a menu or popup dialog is active. */)
2660 ()
2661 {
2662 #ifdef HAVE_MENUS
2663 return (popup_activated ()) ? Qt : Qnil;
2664 #else
2665 return Qnil;
2666 #endif /* HAVE_MENUS */
2667 }
2668 \f
2669 void
2670 syms_of_xmenu ()
2671 {
2672 Qdebug_on_next_call = intern_c_string ("debug-on-next-call");
2673 staticpro (&Qdebug_on_next_call);
2674
2675 #ifdef USE_X_TOOLKIT
2676 widget_id_tick = (1<<16);
2677 next_menubar_widget_id = 1;
2678 #endif
2679
2680 defsubr (&Smenu_or_popup_active_p);
2681
2682 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2683 defsubr (&Sx_menu_bar_open_internal);
2684 Ffset (intern_c_string ("accelerate-menu"),
2685 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2686 #endif
2687
2688 #ifdef HAVE_MENUS
2689 defsubr (&Sx_popup_dialog);
2690 #endif
2691 }
2692
2693 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2694 (do not change this comment) */