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