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