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