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