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