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