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