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