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