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