comparison src/menubar-x.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children 080151679be2
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
1 /* Implements an elisp-programmable menubar -- X interface.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Synched up with: Not in FSF. */
23
24 /* created 16-dec-91 by jwz */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "console-x.h"
30 #include "EmacsFrame.h"
31 #include "gui-x.h"
32
33 #include "buffer.h"
34 #include "commands.h" /* zmacs_regions */
35 #include "gui.h"
36 #include "events.h"
37 #include "frame.h"
38 #include "opaque.h"
39 #include "window.h"
40
41 static int set_frame_menubar (struct frame *f,
42 int deep_p,
43 int first_time_p);
44
45 #define FRAME_MENUBAR_DATA(frame) ((frame)->menubar_data)
46 #define XFRAME_MENUBAR_DATA(frame) XPOPUP_DATA ((frame)->menubar_data)
47
48 #define MENUBAR_TYPE 0
49 #define SUBMENU_TYPE 1
50 #define POPUP_TYPE 2
51
52
53 /* Converting Lisp menu tree descriptions to lwlib's `widget_value' form.
54
55 menu_item_descriptor_to_widget_value() converts a lisp description of a
56 menubar into a tree of widget_value structures. It allocates widget_values
57 with malloc_widget_value() and allocates other storage only for the `key'
58 slot. All other slots are filled with pointers to Lisp_String data. We
59 allocate a widget_value description of the menu or menubar, and hand it to
60 lwlib, which then makes a copy of it, which it manages internally. We then
61 immediately free our widget_value tree; it will not be referenced again.
62
63 Incremental menu construction callbacks operate just a bit differently.
64 They allocate widget_values and call replace_widget_value_tree() to tell
65 lwlib to destructively modify the incremental stub (subtree) of its
66 separate widget_value tree.
67
68 This function is highly recursive (it follows the menu trees) and may call
69 eval. The reason we keep pointers to lisp string data instead of copying
70 it and freeing it later is to avoid the speed penalty that would entail
71 (since this needs to be fast, in the simple cases at least). (The reason
72 we malloc/free the keys slot is because there's not a lisp string around
73 for us to use in that case.)
74
75 Since we keep pointers to lisp strings, and we call eval, we could lose if
76 GC relocates (or frees) those strings. It's not easy to gc protect the
77 strings because of the recursive nature of this function, and the fact that
78 it returns a data structure that gets freed later. So... we do the
79 sleaziest thing possible and inhibit GC for the duration. This is probably
80 not a big deal...
81
82 We do not have to worry about the pointers to Lisp_String data after
83 this function successfully finishes. lwlib copies all such data with
84 strdup(). */
85
86 static widget_value *
87 menu_item_descriptor_to_widget_value_1 (Lisp_Object desc,
88 int menu_type, int deep_p,
89 int filter_p,
90 int depth)
91 {
92 /* This function cannot GC.
93 It is only called from menu_item_descriptor_to_widget_value, which
94 prohibits GC. */
95 /* !!#### This function has not been Mule-ized */
96 int menubar_root_p = (menu_type == MENUBAR_TYPE && depth == 0);
97 widget_value *wv;
98 Lisp_Object wv_closure;
99 int count = specpdl_depth ();
100 int partition_seen = 0;
101
102 wv = xmalloc_widget_value ();
103
104 wv_closure = make_opaque_ptr (wv);
105 record_unwind_protect (widget_value_unwind, wv_closure);
106
107 if (STRINGP (desc))
108 {
109 char *string_chars = (char *) XSTRING_DATA (desc);
110 wv->type = (separator_string_p (string_chars) ? SEPARATOR_TYPE :
111 TEXT_TYPE);
112 #if 1
113 /* #### - should internationalize with X resources instead.
114 Not so! --ben */
115 string_chars = GETTEXT (string_chars);
116 #endif
117 if (wv->type == SEPARATOR_TYPE)
118 {
119 wv->value = menu_separator_style (string_chars);
120 }
121 else
122 {
123 wv->name = string_chars;
124 wv->enabled = 1;
125 /* dverna Dec. 98: command_builder_operate_menu_accelerator will
126 manipulate the accel as a Lisp_Object if the widget has a name.
127 Since simple labels have a name, but no accel, we *must* set it
128 to nil */
129 wv->accel = LISP_TO_VOID (Qnil);
130 }
131 }
132 else if (VECTORP (desc))
133 {
134 Lisp_Object gui_item = gui_parse_item_keywords (desc);
135 if (!button_item_to_widget_value (gui_item, wv, 1,
136 (menu_type == MENUBAR_TYPE
137 && depth <= 1)))
138 {
139 /* :included form was nil */
140 wv = NULL;
141 goto menu_item_done;
142 }
143 }
144 else if (CONSP (desc))
145 {
146 Lisp_Object incremental_data = desc;
147 widget_value *prev = 0;
148
149 if (STRINGP (XCAR (desc)))
150 {
151 Lisp_Object key, val;
152 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil;
153 Lisp_Object active_p = Qt;
154 Lisp_Object accel;
155 int included_spec = 0;
156 int active_spec = 0;
157 wv->type = CASCADE_TYPE;
158 wv->enabled = 1;
159 wv->name = (char *) XSTRING_DATA (LISP_GETTEXT (XCAR (desc)));
160
161 accel = gui_name_accelerator (LISP_GETTEXT (XCAR (desc)));
162 wv->accel = LISP_TO_VOID (accel);
163
164 desc = Fcdr (desc);
165
166 while (key = Fcar (desc), KEYWORDP (key))
167 {
168 Lisp_Object cascade = desc;
169 desc = Fcdr (desc);
170 if (NILP (desc))
171 signal_simple_error ("Keyword in menu lacks a value",
172 cascade);
173 val = Fcar (desc);
174 desc = Fcdr (desc);
175 if (EQ (key, Q_included))
176 include_p = val, included_spec = 1;
177 else if (EQ (key, Q_config))
178 config_tag = val;
179 else if (EQ (key, Q_filter))
180 hook_fn = val;
181 else if (EQ (key, Q_active))
182 active_p = val, active_spec = 1;
183 else if (EQ (key, Q_accelerator))
184 {
185 if ( SYMBOLP (val)
186 || CHARP (val))
187 wv->accel = LISP_TO_VOID (val);
188 else
189 signal_simple_error ("bad keyboard accelerator", val);
190 }
191 else if (EQ (key, Q_label))
192 {
193 /* implement in 21.2 */
194 }
195 else
196 signal_simple_error ("Unknown menu cascade keyword", cascade);
197 }
198
199 if ((!NILP (config_tag)
200 && NILP (Fmemq (config_tag, Vmenubar_configuration)))
201 || (included_spec && NILP (Feval (include_p))))
202 {
203 wv = NULL;
204 goto menu_item_done;
205 }
206
207 if (active_spec)
208 active_p = Feval (active_p);
209
210 if (!NILP (hook_fn) && !NILP (active_p))
211 {
212 #if defined LWLIB_MENUBARS_LUCID || defined LWLIB_MENUBARS_MOTIF
213 if (filter_p || depth == 0)
214 {
215 #endif
216 desc = call1_trapping_errors ("Error in menubar filter",
217 hook_fn, desc);
218 if (UNBOUNDP (desc))
219 desc = Qnil;
220 #if defined LWLIB_MENUBARS_LUCID || defined LWLIB_MENUBARS_MOTIF
221 }
222 else
223 {
224 widget_value *incr_wv = xmalloc_widget_value ();
225 wv->contents = incr_wv;
226 incr_wv->type = INCREMENTAL_TYPE;
227 incr_wv->enabled = 1;
228 incr_wv->name = wv->name;
229 /* This is automatically GC protected through
230 the call to lw_map_widget_values(); no need
231 to worry. */
232 incr_wv->call_data = LISP_TO_VOID (incremental_data);
233 goto menu_item_done;
234 }
235 #endif /* LWLIB_MENUBARS_LUCID || LWLIB_MENUBARS_MOTIF */
236 }
237 if (menu_type == POPUP_TYPE && popup_menu_titles && depth == 0)
238 {
239 /* Simply prepend three more widget values to the contents of
240 the menu: a label, and two separators (to get a double
241 line). */
242 widget_value *title_wv = xmalloc_widget_value ();
243 widget_value *sep_wv = xmalloc_widget_value ();
244 title_wv->type = TEXT_TYPE;
245 title_wv->name = wv->name;
246 title_wv->enabled = 1;
247 title_wv->next = sep_wv;
248 sep_wv->type = SEPARATOR_TYPE;
249 sep_wv->value = menu_separator_style ("==");
250 sep_wv->next = 0;
251
252 wv->contents = title_wv;
253 prev = sep_wv;
254 }
255 wv->enabled = ! NILP (active_p);
256 if (deep_p && !wv->enabled && !NILP (desc))
257 {
258 widget_value *dummy;
259 /* Add a fake entry so the menus show up */
260 wv->contents = dummy = xmalloc_widget_value ();
261 dummy->name = "(inactive)";
262 dummy->accel = LISP_TO_VOID (Qnil);
263 dummy->enabled = 0;
264 dummy->selected = 0;
265 dummy->value = NULL;
266 dummy->type = BUTTON_TYPE;
267 dummy->call_data = NULL;
268 dummy->next = NULL;
269
270 goto menu_item_done;
271 }
272
273 }
274 else if (menubar_root_p)
275 {
276 wv->name = (char *) "menubar";
277 wv->type = CASCADE_TYPE; /* Well, nothing else seems to fit and
278 this is ignored anyway... */
279 }
280 else
281 {
282 signal_simple_error ("Menu name (first element) must be a string",
283 desc);
284 }
285
286 if (deep_p || menubar_root_p)
287 {
288 widget_value *next;
289 for (; !NILP (desc); desc = Fcdr (desc))
290 {
291 Lisp_Object child = Fcar (desc);
292 if (menubar_root_p && NILP (child)) /* the partition */
293 {
294 if (partition_seen)
295 error (
296 "More than one partition (nil) in menubar description");
297 partition_seen = 1;
298 next = xmalloc_widget_value ();
299 next->type = PUSHRIGHT_TYPE;
300 }
301 else
302 {
303 next = menu_item_descriptor_to_widget_value_1
304 (child, menu_type, deep_p, filter_p, depth + 1);
305 }
306 if (! next)
307 continue;
308 else if (prev)
309 prev->next = next;
310 else
311 wv->contents = next;
312 prev = next;
313 }
314 }
315 if (deep_p && !wv->contents)
316 wv = NULL;
317 }
318 else if (NILP (desc))
319 error ("nil may not appear in menu descriptions");
320 else
321 signal_simple_error ("Unrecognized menu descriptor", desc);
322
323 menu_item_done:
324
325 if (wv)
326 {
327 /* Completed normally. Clear out the object that widget_value_unwind()
328 will be called with to tell it not to free the wv (as we are
329 returning it.) */
330 set_opaque_ptr (wv_closure, 0);
331 }
332
333 unbind_to (count, Qnil);
334 return wv;
335 }
336
337 static widget_value *
338 menu_item_descriptor_to_widget_value (Lisp_Object desc,
339 int menu_type, /* if this is a menubar,
340 popup or sub menu */
341 int deep_p, /* */
342 int filter_p) /* if :filter forms
343 should run now */
344 {
345 widget_value *wv;
346 int count = specpdl_depth ();
347 record_unwind_protect (restore_gc_inhibit,
348 make_int (gc_currently_forbidden));
349 gc_currently_forbidden = 1;
350 /* Can't GC! */
351 wv = menu_item_descriptor_to_widget_value_1 (desc, menu_type, deep_p,
352 filter_p, 0);
353 unbind_to (count, Qnil);
354 return wv;
355 }
356
357
358 #if defined LWLIB_MENUBARS_LUCID || defined LWLIB_MENUBARS_MOTIF
359 int in_menu_callback;
360
361 static Lisp_Object
362 restore_in_menu_callback (Lisp_Object val)
363 {
364 in_menu_callback = XINT(val);
365 return Qnil;
366 }
367 #endif /* LWLIB_MENUBARS_LUCID || LWLIB_MENUBARS_MOTIF */
368
369 #if 0
370 /* #### Sort of a hack needed to process Vactivate_menubar_hook
371 correctly wrt buffer-local values. A correct solution would
372 involve adding a callback mechanism to run_hook(). This function
373 is currently unused. */
374 static int
375 my_run_hook (Lisp_Object hooksym, int allow_global_p)
376 {
377 /* This function can GC */
378 Lisp_Object tail;
379 Lisp_Object value = Fsymbol_value (hooksym);
380 int changes = 0;
381
382 if (!NILP (value) && (!CONSP (value) || EQ (XCAR (value), Qlambda)))
383 return !EQ (call0 (value), Qt);
384
385 EXTERNAL_LIST_LOOP (tail, value)
386 {
387 if (allow_global_p && EQ (XCAR (tail), Qt))
388 changes |= my_run_hook (Fdefault_value (hooksym), 0);
389 if (!EQ (call0 (XCAR (tail)), Qt))
390 changes = 1;
391 }
392 return changes;
393 }
394 #endif
395
396
397 /* The order in which callbacks are run is funny to say the least.
398 It's sometimes tricky to avoid running a callback twice, and to
399 avoid returning prematurely. So, this function returns true
400 if the menu's callbacks are no longer gc protected. So long
401 as we unprotect them before allowing other callbacks to run,
402 everything should be ok.
403
404 The pre_activate_callback() *IS* intentionally called multiple times.
405 If client_data == NULL, then it's being called before the menu is posted.
406 If client_data != NULL, then client_data is a (widget_value *) and
407 client_data->data is a Lisp_Object pointing to a lisp submenu description
408 that must be converted into widget_values. *client_data is destructively
409 modified.
410
411 #### Stig thinks that there may be a GC problem here due to the
412 fact that pre_activate_callback() is called multiple times, but I
413 think he's wrong.
414
415 */
416
417 static void
418 pre_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
419 {
420 /* This function can GC */
421 struct device *d = get_device_from_display (XtDisplay (widget));
422 struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
423 Lisp_Object frame;
424 int count;
425
426 /* set in lwlib to the time stamp associated with the most recent menu
427 operation */
428 extern Time x_focus_timestamp_really_sucks_fix_me_better;
429
430 if (!f)
431 f = x_any_window_to_frame (d, XtWindow (XtParent (widget)));
432 if (!f)
433 return;
434
435 /* make sure f is the selected frame */
436 XSETFRAME (frame, f);
437 Fselect_frame (frame);
438
439 if (client_data)
440 {
441 /* this is an incremental menu construction callback */
442 widget_value *hack_wv = (widget_value *) client_data;
443 Lisp_Object submenu_desc;
444 widget_value *wv;
445
446 assert (hack_wv->type == INCREMENTAL_TYPE);
447 VOID_TO_LISP (submenu_desc, hack_wv->call_data);
448
449 /*
450 * #### Fix the menu code so this isn't necessary.
451 *
452 * Protect against reentering the menu code otherwise we will
453 * crash later when the code gets confused at the state
454 * changes.
455 */
456 count = specpdl_depth ();
457 record_unwind_protect (restore_in_menu_callback,
458 make_int (in_menu_callback));
459 in_menu_callback = 1;
460 wv = menu_item_descriptor_to_widget_value (submenu_desc, SUBMENU_TYPE,
461 1, 0);
462 unbind_to (count, Qnil);
463
464 if (!wv)
465 {
466 wv = xmalloc_widget_value ();
467 wv->type = CASCADE_TYPE;
468 wv->next = NULL;
469 wv->accel = LISP_TO_VOID (Qnil);
470 wv->contents = xmalloc_widget_value ();
471 wv->contents->type = TEXT_TYPE;
472 wv->contents->name = (char *) "No menu";
473 wv->contents->next = NULL;
474 wv->contents->accel = LISP_TO_VOID (Qnil);
475 }
476 assert (wv && wv->type == CASCADE_TYPE && wv->contents);
477 replace_widget_value_tree (hack_wv, wv->contents);
478 free_popup_widget_value_tree (wv);
479 }
480 else if (!POPUP_DATAP (FRAME_MENUBAR_DATA (f)))
481 return;
482 else
483 {
484 #if 0 /* Unused, see comment below. */
485 int any_changes;
486
487 /* #### - this menubar update mechanism is expensively anti-social and
488 the activate-menubar-hook is now mostly obsolete. */
489 any_changes = my_run_hook (Qactivate_menubar_hook, 1);
490
491 /* #### - It is necessary to *ALWAYS* call set_frame_menubar() now that
492 incremental menus are implemented. If a subtree of a menu has been
493 updated incrementally (a destructive operation), then that subtree
494 must somehow be wiped.
495
496 It is difficult to undo the destructive operation in lwlib because
497 a pointer back to lisp data needs to be hidden away somewhere. So
498 that an INCREMENTAL_TYPE widget_value can be recreated... Hmmmmm. */
499 if (any_changes ||
500 !XFRAME_MENUBAR_DATA (f)->menubar_contents_up_to_date)
501 set_frame_menubar (f, 1, 0);
502 #else
503 run_hook (Qactivate_menubar_hook);
504 set_frame_menubar (f, 1, 0);
505 #endif
506 DEVICE_X_MOUSE_TIMESTAMP (XDEVICE (FRAME_DEVICE (f))) =
507 DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (XDEVICE (FRAME_DEVICE (f))) =
508 x_focus_timestamp_really_sucks_fix_me_better;
509 }
510 }
511
512 static widget_value *
513 compute_menubar_data (struct frame *f, Lisp_Object menubar, int deep_p)
514 {
515 widget_value *data;
516
517 if (NILP (menubar))
518 data = 0;
519 else
520 {
521 Lisp_Object old_buffer;
522 int count = specpdl_depth ();
523
524 old_buffer = Fcurrent_buffer ();
525 record_unwind_protect (Fset_buffer, old_buffer);
526 Fset_buffer ( XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer);
527 data = menu_item_descriptor_to_widget_value (menubar, MENUBAR_TYPE,
528 deep_p, 0);
529 Fset_buffer (old_buffer);
530 unbind_to (count, Qnil);
531 }
532 return data;
533 }
534
535 static int
536 set_frame_menubar (struct frame *f, int deep_p, int first_time_p)
537 {
538 widget_value *data;
539 Lisp_Object menubar;
540 int menubar_visible;
541 long id;
542 /* As for the toolbar, the minibuffer does not have its own menubar. */
543 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
544
545 if (! FRAME_X_P (f))
546 return 0;
547
548 /***** first compute the contents of the menubar *****/
549
550 if (! first_time_p)
551 {
552 /* evaluate `current-menubar' in the buffer of the selected window
553 of the frame in question. */
554 menubar = symbol_value_in_buffer (Qcurrent_menubar, w->buffer);
555 }
556 else
557 {
558 /* That's a little tricky the first time since the frame isn't
559 fully initialized yet. */
560 menubar = Fsymbol_value (Qcurrent_menubar);
561 }
562
563 if (NILP (menubar))
564 {
565 menubar = Vblank_menubar;
566 menubar_visible = 0;
567 }
568 else
569 menubar_visible = !NILP (w->menubar_visible_p);
570
571 data = compute_menubar_data (f, menubar, deep_p);
572 if (!data || (!data->next && !data->contents))
573 abort ();
574
575 if (NILP (FRAME_MENUBAR_DATA (f)))
576 {
577 struct popup_data *mdata =
578 alloc_lcrecord_type (struct popup_data, &lrecord_popup_data);
579
580 mdata->id = new_lwlib_id ();
581 mdata->last_menubar_buffer = Qnil;
582 mdata->menubar_contents_up_to_date = 0;
583 XSETPOPUP_DATA (FRAME_MENUBAR_DATA (f), mdata);
584 }
585
586 /***** now store into the menubar widget, creating it if necessary *****/
587
588 id = XFRAME_MENUBAR_DATA (f)->id;
589 if (!FRAME_X_MENUBAR_WIDGET (f))
590 {
591 Widget parent = FRAME_X_CONTAINER_WIDGET (f);
592
593 assert (first_time_p);
594
595 /* It's the first time we've mapped the menubar so compute its
596 contents completely once. This makes sure that the menubar
597 components are created with the right type. */
598 if (!deep_p)
599 {
600 free_popup_widget_value_tree (data);
601 data = compute_menubar_data (f, menubar, 1);
602 }
603
604
605 FRAME_X_MENUBAR_WIDGET (f) =
606 lw_create_widget ("menubar", "menubar", id, data, parent,
607 0, pre_activate_callback,
608 popup_selection_callback, 0);
609
610 }
611 else
612 {
613 lw_modify_all_widgets (id, data, deep_p ? True : False);
614 }
615 free_popup_widget_value_tree (data);
616
617 XFRAME_MENUBAR_DATA (f)->menubar_contents_up_to_date = deep_p;
618 XFRAME_MENUBAR_DATA (f)->last_menubar_buffer =
619 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer;
620 return menubar_visible;
621 }
622
623
624 /* Called from x_create_widgets() to create the initial menubar of a frame
625 before it is mapped, so that the window is mapped with the menubar already
626 there instead of us tacking it on later and thrashing the window after it
627 is visible. */
628 int
629 x_initialize_frame_menubar (struct frame *f)
630 {
631 return set_frame_menubar (f, 1, 1);
632 }
633
634
635 static LWLIB_ID last_popup_menu_selection_callback_id;
636
637 static void
638 popup_menu_selection_callback (Widget widget, LWLIB_ID id,
639 XtPointer client_data)
640 {
641 last_popup_menu_selection_callback_id = id;
642 popup_selection_callback (widget, id, client_data);
643 /* lw_destroy_all_widgets() will be called from popup_down_callback() */
644 }
645
646 static void
647 popup_menu_down_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
648 {
649 if (popup_handled_p (id))
650 return;
651 assert (popup_up_p != 0);
652 ungcpro_popup_callbacks (id);
653 popup_up_p--;
654 /* if this isn't called immediately after the selection callback, then
655 there wasn't a menu selection. */
656 if (id != last_popup_menu_selection_callback_id)
657 popup_selection_callback (widget, id, (XtPointer) -1);
658 lw_destroy_all_widgets (id);
659 }
660
661
662 static void
663 make_dummy_xbutton_event (XEvent *dummy,
664 Widget daddy,
665 struct Lisp_Event *eev)
666 /* NULL for eev means query pointer */
667 {
668 XButtonPressedEvent *btn = (XButtonPressedEvent *) dummy;
669
670 btn->type = ButtonPress;
671 btn->serial = 0;
672 btn->send_event = 0;
673 btn->display = XtDisplay (daddy);
674 btn->window = XtWindow (daddy);
675 if (eev)
676 {
677 Position shellx, shelly, framex, framey;
678 Arg al [2];
679 btn->time = eev->timestamp;
680 btn->button = eev->event.button.button;
681 btn->root = RootWindowOfScreen (XtScreen (daddy));
682 btn->subwindow = (Window) NULL;
683 btn->x = eev->event.button.x;
684 btn->y = eev->event.button.y;
685 shellx = shelly = 0;
686 #ifndef HAVE_WMCOMMAND
687 {
688 Widget shell = XtParent (daddy);
689
690 XtSetArg (al [0], XtNx, &shellx);
691 XtSetArg (al [1], XtNy, &shelly);
692 XtGetValues (shell, al, 2);
693 }
694 #endif
695 XtSetArg (al [0], XtNx, &framex);
696 XtSetArg (al [1], XtNy, &framey);
697 XtGetValues (daddy, al, 2);
698 btn->x_root = shellx + framex + btn->x;
699 btn->y_root = shelly + framey + btn->y;
700 btn->state = ButtonPressMask; /* all buttons pressed */
701 }
702 else
703 {
704 /* CurrentTime is just ZERO, so it's worthless for
705 determining relative click times. */
706 struct device *d = get_device_from_display (XtDisplay (daddy));
707 btn->time = DEVICE_X_MOUSE_TIMESTAMP (d); /* event-Xt maintains this */
708 btn->button = 0;
709 XQueryPointer (btn->display, btn->window, &btn->root,
710 &btn->subwindow, &btn->x_root, &btn->y_root,
711 &btn->x, &btn->y, &btn->state);
712 }
713 }
714
715
716
717 static void
718 x_update_frame_menubar_internal (struct frame *f)
719 {
720 /* We assume the menubar contents has changed if the global flag is set,
721 or if the current buffer has changed, or if the menubar has never
722 been updated before.
723 */
724 int menubar_contents_changed =
725 (f->menubar_changed
726 || NILP (FRAME_MENUBAR_DATA (f))
727 || (!EQ (XFRAME_MENUBAR_DATA (f)->last_menubar_buffer,
728 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer)));
729
730 Boolean menubar_was_visible = XtIsManaged (FRAME_X_MENUBAR_WIDGET (f));
731 Boolean menubar_will_be_visible = menubar_was_visible;
732 Boolean menubar_visibility_changed;
733
734 if (menubar_contents_changed)
735 menubar_will_be_visible = set_frame_menubar (f, 0, 0);
736
737 menubar_visibility_changed = menubar_was_visible != menubar_will_be_visible;
738
739 if (!menubar_visibility_changed)
740 return;
741
742 /* Set menubar visibility */
743 (menubar_will_be_visible ? XtManageChild : XtUnmanageChild)
744 (FRAME_X_MENUBAR_WIDGET (f));
745
746 MARK_FRAME_SIZE_SLIPPED (f);
747 }
748
749 static void
750 x_update_frame_menubars (struct frame *f)
751 {
752 assert (FRAME_X_P (f));
753
754 x_update_frame_menubar_internal (f);
755
756 /* #### This isn't going to work right now that this function works on
757 a per-frame, not per-device basis. Guess what? I don't care. */
758 }
759
760 static void
761 x_free_frame_menubars (struct frame *f)
762 {
763 Widget menubar_widget;
764
765 assert (FRAME_X_P (f));
766
767 menubar_widget = FRAME_X_MENUBAR_WIDGET (f);
768 if (menubar_widget)
769 {
770 LWLIB_ID id = XFRAME_MENUBAR_DATA (f)->id;
771 lw_destroy_all_widgets (id);
772 XFRAME_MENUBAR_DATA (f)->id = 0;
773 }
774 }
775
776 static void
777 x_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
778 {
779 int menu_id;
780 struct frame *f = selected_frame ();
781 widget_value *data;
782 Widget parent;
783 Widget menu;
784 struct Lisp_Event *eev = NULL;
785 XEvent xev;
786 Lisp_Object frame;
787
788 XSETFRAME (frame, f);
789 CHECK_X_FRAME (frame);
790 parent = FRAME_X_SHELL_WIDGET (f);
791
792 if (!NILP (event))
793 {
794 CHECK_LIVE_EVENT (event);
795 eev= XEVENT (event);
796 if (eev->event_type != button_press_event
797 && eev->event_type != button_release_event)
798 wrong_type_argument (Qmouse_event_p, event);
799 }
800 else if (!NILP (Vthis_command_keys))
801 {
802 /* if an event wasn't passed, use the last event of the event sequence
803 currently being executed, if that event is a mouse event */
804 eev = XEVENT (Vthis_command_keys); /* last event first */
805 if (eev->event_type != button_press_event
806 && eev->event_type != button_release_event)
807 eev = NULL;
808 }
809 make_dummy_xbutton_event (&xev, parent, eev);
810
811 if (SYMBOLP (menu_desc))
812 menu_desc = Fsymbol_value (menu_desc);
813 CHECK_CONS (menu_desc);
814 CHECK_STRING (XCAR (menu_desc));
815 data = menu_item_descriptor_to_widget_value (menu_desc, POPUP_TYPE, 1, 1);
816
817 if (! data) error ("no menu");
818
819 menu_id = new_lwlib_id ();
820 menu = lw_create_widget ("popup", "popup" /* data->name */, menu_id, data,
821 parent, 1, 0,
822 popup_menu_selection_callback,
823 popup_menu_down_callback);
824 free_popup_widget_value_tree (data);
825
826 gcpro_popup_callbacks (menu_id);
827
828 /* Setting zmacs-region-stays is necessary here because executing a command
829 from a menu is really a two-command process: the first command (bound to
830 the button-click) simply pops up the menu, and returns. This causes a
831 sequence of magic-events (destined for the popup-menu widget) to begin.
832 Eventually, a menu item is selected, and a menu-event blip is pushed onto
833 the end of the input stream, which is then executed by the event loop.
834
835 So there are two command-events, with a bunch of magic-events between
836 them. We don't want the *first* command event to alter the state of the
837 region, so that the region can be available as an argument for the second
838 command.
839 */
840 if (zmacs_regions)
841 zmacs_region_stays = 1;
842
843 popup_up_p++;
844 lw_popup_menu (menu, &xev);
845 /* this speeds up display of pop-up menus */
846 XFlush (XtDisplay (parent));
847 }
848
849
850 void
851 syms_of_menubar_x (void)
852 {
853 }
854
855 void
856 console_type_create_menubar_x (void)
857 {
858 CONSOLE_HAS_METHOD (x, update_frame_menubars);
859 CONSOLE_HAS_METHOD (x, free_frame_menubars);
860 CONSOLE_HAS_METHOD (x, popup_menu);
861 }
862
863 void
864 reinit_vars_of_menubar_x (void)
865 {
866 last_popup_menu_selection_callback_id = (LWLIB_ID) -1;
867 }
868
869 void
870 vars_of_menubar_x (void)
871 {
872 reinit_vars_of_menubar_x ();
873
874 #if defined (LWLIB_MENUBARS_LUCID)
875 Fprovide (intern ("lucid-menubars"));
876 #elif defined (LWLIB_MENUBARS_MOTIF)
877 Fprovide (intern ("motif-menubars"));
878 #elif defined (LWLIB_MENUBARS_ATHENA)
879 Fprovide (intern ("athena-menubars"));
880 #endif
881 }