comparison src/menubar-x.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
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 "EmacsManager.h"
31 #include "EmacsFrame.h"
32 #include "EmacsShell.h"
33 #include "gui-x.h"
34
35 #include "buffer.h"
36 #include "commands.h" /* zmacs_regions */
37 #include "events.h"
38 #include "frame.h"
39 #include "opaque.h"
40 #include "window.h"
41
42 static int set_frame_menubar (struct frame *f,
43 int deep_p,
44 int first_time_p);
45
46 #define FRAME_MENUBAR_DATA(frame) ((frame)->menubar_data)
47 #define XFRAME_MENUBAR_DATA(frame) XPOPUP_DATA ((frame)->menubar_data)
48
49 #define MENUBAR_TYPE 0
50 #define SUBMENU_TYPE 1
51 #define POPUP_TYPE 2
52
53
54 /* Converting Lisp menu tree descriptions to lwlib's `widget_value' form.
55
56 menu_item_descriptor_to_widget_value() converts a lisp description of a
57 menubar into a tree of widget_value structures. It allocates widget_values
58 with malloc_widget_value() and allocates other storage only for the `key'
59 slot. All other slots are filled with pointers to Lisp_String data. We
60 allocate a widget_value description of the menu or menubar, and hand it to
61 lwlib, which then makes a copy of it, which it manages internally. We then
62 immediately free our widget_value tree; it will not be referenced again.
63
64 Incremental menu construction callbacks operate just a bit differently.
65 They allocate widget_values and call replace_widget_value_tree() to tell
66 lwlib to destructively modify the incremental stub (subtree) of its
67 separate widget_value tree.
68
69 This function is highly recursive (it follows the menu trees) and may call
70 eval. The reason we keep pointers to lisp string data instead of copying
71 it and freeing it later is to avoid the speed penalty that would entail
72 (since this needs to be fast, in the simple cases at least). (The reason
73 we malloc/free the keys slot is because there's not a lisp string around
74 for us to use in that case.)
75
76 Since we keep pointers to lisp strings, and we call eval, we could lose if
77 GC relocates (or frees) those strings. It's not easy to gc protect the
78 strings because of the recursive nature of this function, and the fact that
79 it returns a data structure that gets freed later. So... we do the
80 sleaziest thing possible and inhibit GC for the duration. This is probably
81 not a big deal...
82
83 We do not have to worry about the pointers to Lisp_String data after
84 this function successfully finishes. lwlib copies all such data with
85 strdup().
86
87 */
88
89 static widget_value *
90 menu_item_descriptor_to_widget_value_1 (Lisp_Object desc,
91 int menu_type, int deep_p,
92 int filter_p,
93 int depth)
94 {
95 /* This function cannot GC.
96 It is only called from menu_item_descriptor_to_widget_value, which
97 prohibits GC. */
98 /* !!#### This function has not been Mule-ized */
99 int menubar_root_p = (menu_type == MENUBAR_TYPE && depth == 0);
100 widget_value *wv;
101 Lisp_Object wv_closure;
102 int count = specpdl_depth ();
103 int partition_seen = 0;
104
105 wv = xmalloc_widget_value ();
106
107 wv_closure = make_opaque_ptr (wv);
108 record_unwind_protect (widget_value_unwind, wv_closure);
109
110 if (STRINGP (desc))
111 {
112 char *string_chars = (char *) string_data (XSTRING (desc));
113 wv->type = (separator_string_p (string_chars) ? SEPARATOR_TYPE :
114 TEXT_TYPE);
115 #if 1
116 /* #### - should internationalize with X resources instead.
117 Not so! --ben */
118 string_chars = GETTEXT (string_chars);
119 #endif
120 if (wv->type == SEPARATOR_TYPE)
121 {
122 wv->value = menu_separator_style (string_chars);
123 }
124 else
125 {
126 wv->name = string_chars;
127 wv->enabled = 1;
128 }
129 }
130 else if (VECTORP (desc))
131 {
132 if (!button_item_to_widget_value (desc, wv, 1,
133 (menu_type == MENUBAR_TYPE
134 && depth <= 1)))
135 {
136 /* :included form was nil */
137 wv = NULL;
138 goto menu_item_done;
139 }
140 }
141 else if (CONSP (desc))
142 {
143 Lisp_Object incremental_data = desc;
144 widget_value *prev = 0;
145
146 if (STRINGP (XCAR (desc)))
147 {
148 Lisp_Object key, val;
149 Lisp_Object include_p, hook_fn = Qnil, config_tag = Qnil;
150 int included_spec = 0;
151 wv->type = CASCADE_TYPE;
152 wv->enabled = 1;
153 wv->name =
154 (char *) string_data (XSTRING (LISP_GETTEXT (XCAR (desc))));
155 desc = Fcdr (desc);
156
157 while (key = Fcar (desc), KEYWORDP (key))
158 {
159 Lisp_Object cascade = desc;
160 desc = Fcdr (desc);
161 if (NILP (desc))
162 signal_simple_error ("keyword in menu lacks a value",
163 cascade);
164 val = Fcar (desc);
165 desc = Fcdr (desc);
166 if (EQ (key, Q_included))
167 include_p = val, included_spec = 1;
168 else if (EQ (key, Q_config))
169 config_tag = val;
170 else if (EQ (key, Q_filter))
171 hook_fn = val;
172 else
173 signal_simple_error ("unknown menu cascade keyword", cascade);
174 }
175
176 if ((!NILP (config_tag)
177 && NILP (Fmemq (config_tag, Vmenubar_configuration)))
178 || (included_spec && NILP (Feval (include_p))))
179 {
180 wv = NULL;
181 goto menu_item_done;
182 }
183 if (!NILP (hook_fn))
184 {
185 #ifdef LWLIB_MENUBARS_LUCID
186 if (filter_p || depth == 0)
187 {
188 #endif
189 desc = call1_trapping_errors ("Error in menubar filter",
190 hook_fn, desc);
191 if (UNBOUNDP (desc))
192 desc = Qnil;
193 #ifdef LWLIB_MENUBARS_LUCID
194 }
195 else
196 {
197 widget_value *incr_wv = xmalloc_widget_value ();
198 wv->contents = incr_wv;
199 incr_wv->type = INCREMENTAL_TYPE;
200 incr_wv->enabled = 1;
201 incr_wv->name = wv->name;
202 /* This is automatically GC protected through
203 the call to lw_map_widget_values(); no need
204 to worry. */
205 incr_wv->call_data = LISP_TO_VOID (incremental_data);
206 goto menu_item_done;
207 }
208 #endif
209 }
210 if (menu_type == POPUP_TYPE && popup_menu_titles && depth == 0)
211 {
212 /* Simply prepend three more widget values to the contents of
213 the menu: a label, and two separators (to get a double
214 line). */
215 widget_value *title_wv = xmalloc_widget_value ();
216 widget_value *sep_wv = xmalloc_widget_value ();
217 title_wv->type = TEXT_TYPE;
218 title_wv->name = wv->name;
219 title_wv->enabled = 1;
220 title_wv->next = sep_wv;
221 sep_wv->type = SEPARATOR_TYPE;
222 sep_wv->value = menu_separator_style ("==");
223 sep_wv->next = 0;
224
225 wv->contents = title_wv;
226 prev = sep_wv;
227 }
228 }
229 else if (menubar_root_p)
230 {
231 wv->name = "menubar";
232 wv->type = CASCADE_TYPE; /* Well, nothing else seems to fit and
233 this is ignored anyway... */
234 }
235 else
236 {
237 signal_simple_error ("menu name (first element) must be a string",
238 desc);
239 }
240
241 wv->enabled = 1;
242 if (deep_p || menubar_root_p)
243 {
244 widget_value *next;
245 for (; !NILP (desc); desc = Fcdr (desc))
246 {
247 Lisp_Object child = Fcar (desc);
248 if (menubar_root_p && NILP (child)) /* the partition */
249 {
250 if (partition_seen)
251 error (
252 "more than one partition (nil) in menubar description");
253 partition_seen = 1;
254 next = xmalloc_widget_value ();
255 next->type = PUSHRIGHT_TYPE;
256 }
257 else
258 {
259 next = menu_item_descriptor_to_widget_value_1 (child,
260 menu_type,
261 deep_p,
262 filter_p,
263 depth + 1);
264 }
265 if (! next)
266 continue;
267 else if (prev)
268 prev->next = next;
269 else
270 wv->contents = next;
271 prev = next;
272 }
273 }
274 if (deep_p && !wv->contents)
275 wv = NULL;
276 }
277 else if (NILP (desc))
278 error ("nil may not appear in menu descriptions");
279 else
280 signal_simple_error ("unrecognized menu descriptor", desc);
281
282 menu_item_done:
283
284 if (wv)
285 {
286 /* Completed normally. Clear out the object that widget_value_unwind()
287 will be called with to tell it not to free the wv (as we are
288 returning it.) */
289 set_opaque_ptr (wv_closure, 0);
290 }
291
292 unbind_to (count, Qnil);
293 return wv;
294 }
295
296 static widget_value *
297 menu_item_descriptor_to_widget_value (Lisp_Object desc,
298 int menu_type, /* if this is a menubar,
299 popup or sub menu */
300 int deep_p, /* */
301 int filter_p) /* if :filter forms
302 should run now */
303 {
304 widget_value *wv;
305 int count = specpdl_depth ();
306 record_unwind_protect (restore_gc_inhibit,
307 make_int (gc_currently_forbidden));
308 gc_currently_forbidden = 1;
309 /* Can't GC! */
310 wv = menu_item_descriptor_to_widget_value_1 (desc, menu_type, deep_p,
311 filter_p, 0);
312 unbind_to (count, Qnil);
313 return wv;
314 }
315
316
317 /* The order in which callbacks are run is funny to say the least.
318 It's sometimes tricky to avoid running a callback twice, and to
319 avoid returning prematurely. So, this function returns true
320 if the menu's callbacks are no longer gc protected. So long
321 as we unprotect them before allowing other callbacks to run,
322 everything should be ok.
323
324 The pre_activate_callback() *IS* intentionally called multiple times.
325 If client_data == NULL, then it's being called before the menu is posted.
326 If client_data != NULL, then client_data is a (widget_value *) and
327 client_data->data is a Lisp_Object pointing to a lisp submenu description
328 that must be converted into widget_values. *client_data is destructively
329 modified.
330
331 #### Stig thinks that there may be a GC problem here due to the
332 fact that pre_activate_callback() is called multiple times, but I
333 think he's wrong.
334
335 */
336
337 static void
338 pre_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
339 {
340 /* This function can GC */
341 struct gcpro gcpro1;
342 struct device *d = get_device_from_display (XtDisplay (widget));
343 struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
344 Lisp_Object rest = Qnil;
345 int any_changes = 0;
346
347 if (!f)
348 f = x_any_window_to_frame (d, XtWindow (XtParent (widget)));
349 if (!f)
350 return;
351
352 if (client_data)
353 {
354 /* this is an incremental menu construction callback */
355 widget_value *hack_wv = (widget_value *) client_data;
356 Lisp_Object submenu_desc;
357 widget_value *wv;
358
359 assert (hack_wv->type == INCREMENTAL_TYPE);
360 VOID_TO_LISP (submenu_desc, hack_wv->call_data);
361 wv = menu_item_descriptor_to_widget_value (submenu_desc, SUBMENU_TYPE,
362 1, 1);
363 if (!wv)
364 {
365 wv = xmalloc_widget_value ();
366 wv->type = CASCADE_TYPE;
367 wv->next = NULL;
368 wv->contents = xmalloc_widget_value ();
369 wv->contents->type = TEXT_TYPE;
370 wv->contents->name = "No menu";
371 wv->contents->next = NULL;
372 }
373 assert (wv && wv->type == CASCADE_TYPE && wv->contents);
374 replace_widget_value_tree (hack_wv, wv->contents);
375 free_popup_widget_value_tree (wv);
376 }
377 else
378 {
379 if (!POPUP_DATAP (FRAME_MENUBAR_DATA (f)))
380 return;
381 /* #### - this menubar update mechanism is expensively anti-social and
382 the activate-menubar-hook is now mostly obsolete. */
383 /* make the activate-menubar-hook be a list of functions, not a single
384 function, just to simplify things. */
385 if (!NILP (Vactivate_menubar_hook) &&
386 (!CONSP (Vactivate_menubar_hook) ||
387 EQ (XCAR (Vactivate_menubar_hook), Qlambda)))
388 Vactivate_menubar_hook = Fcons (Vactivate_menubar_hook, Qnil);
389
390 GCPRO1 (rest);
391 for (rest = Vactivate_menubar_hook; !NILP (rest); rest = Fcdr (rest))
392 if (!EQ (call0 (XCAR (rest)), Qt))
393 any_changes = 1;
394 #if 0
395 /* #### - It is necessary to *ALWAYS* call set_frame_menubar() now that
396 incremental menus are implemented. If a subtree of a menu has been
397 updated incrementally (a destructive operation), then that subtree
398 must somehow be wiped.
399
400 It is difficult to undo the destructive operation in lwlib because
401 a pointer back to lisp data needs to be hidden away somewhere. So
402 that an INCREMENTAL_TYPE widget_value can be recreated... Hmmmmm. */
403 if (any_changes ||
404 !XFRAME_MENUBAR_DATA (f)->menubar_contents_up_to_date)
405 #endif
406 set_frame_menubar (f, 1, 0);
407 UNGCPRO;
408 }
409 }
410
411 #ifdef ENERGIZE
412 extern int *get_psheets_for_buffer (Lisp_Object, int *);
413
414 static void
415 set_panel_button_sensitivity (struct frame *f, widget_value *data)
416 {
417 struct window *window = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
418 int current_buffer_psheets_count = 0;
419 int *current_buffer_psheets =
420 get_psheets_for_buffer (window->buffer, &current_buffer_psheets_count);
421 int panel_enabled = FRAME_X_DESIRED_PSHEETS (f) ||
422 current_buffer_psheets_count;
423 widget_value *val;
424 for (val = data->contents; val; val = val->next)
425 if (val->name && !strcmp (val->name, "sheet"))
426 {
427 val->enabled = panel_enabled;
428 return;
429 }
430 }
431 #endif /* ENERGIZE */
432
433 static widget_value *
434 compute_menubar_data (struct frame *f, Lisp_Object menubar, int deep_p)
435 {
436 widget_value *data;
437
438 if (NILP (menubar))
439 data = 0;
440 else
441 {
442 data = menu_item_descriptor_to_widget_value (menubar, MENUBAR_TYPE,
443 deep_p, 0);
444 #ifdef ENERGIZE
445 if (data)
446 set_panel_button_sensitivity (f, data);
447 #endif
448 }
449 return data;
450 }
451
452 static int
453 set_frame_menubar (struct frame *f, int deep_p, int first_time_p)
454 {
455 widget_value *data;
456 Lisp_Object menubar;
457 int menubar_visible;
458 long id;
459 /* As for the toolbar, the minibuffer does not have its own menubar. */
460 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
461
462 if (! FRAME_X_P (f))
463 return 0;
464
465 /***** first compute the contents of the menubar *****/
466
467 if (! first_time_p)
468 {
469 /* evaluate `current-menubar' in the buffer of the selected window
470 of the frame in question. */
471 menubar = symbol_value_in_buffer (Qcurrent_menubar, w->buffer);
472 }
473 else
474 {
475 /* That's a little tricky the first time since the frame isn't
476 fully initialized yet. */
477 menubar = Fsymbol_value (Qcurrent_menubar);
478 }
479
480 if (NILP (menubar))
481 {
482 menubar = Vblank_menubar;
483 menubar_visible = 0;
484 }
485 else
486 menubar_visible = !NILP (w->menubar_visible_p);
487
488 data = compute_menubar_data (f, menubar, deep_p);
489 if (!data || (!data->next && !data->contents))
490 abort ();
491
492 if (NILP (FRAME_MENUBAR_DATA (f)))
493 {
494 struct popup_data *mdata =
495 alloc_lcrecord (sizeof (struct popup_data), lrecord_popup_data);
496
497 mdata->id = new_lwlib_id ();
498 mdata->last_menubar_buffer = Qnil;
499 mdata->menubar_contents_up_to_date = 0;
500 XSETPOPUP_DATA (FRAME_MENUBAR_DATA (f), mdata);
501 }
502
503 /***** now store into the menubar widget, creating it if necessary *****/
504
505 id = XFRAME_MENUBAR_DATA (f)->id;
506 if (!FRAME_X_MENUBAR_WIDGET (f))
507 {
508 Widget parent = FRAME_X_CONTAINER_WIDGET (f);
509
510 assert (first_time_p);
511
512 /* It's the first time we've mapped the menubar so compute its
513 contents completely once. This makes sure that the menubar
514 components are created with the right type. */
515 if (!deep_p)
516 {
517 free_popup_widget_value_tree (data);
518 data = compute_menubar_data (f, menubar, 1);
519 }
520
521
522 FRAME_X_MENUBAR_WIDGET (f) =
523 lw_create_widget ("menubar", "menubar", id, data, parent,
524 0, pre_activate_callback,
525 popup_selection_callback, 0);
526
527 }
528 else
529 {
530 lw_modify_all_widgets (id, data, deep_p ? True : False);
531 }
532 free_popup_widget_value_tree (data);
533
534 XFRAME_MENUBAR_DATA (f)->menubar_contents_up_to_date = deep_p;
535 XFRAME_MENUBAR_DATA (f)->last_menubar_buffer =
536 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer;
537 return menubar_visible;
538 }
539
540
541 /* Called from x_create_widgets() to create the inital menubar of a frame
542 before it is mapped, so that the window is mapped with the menubar already
543 there instead of us tacking it on later and thrashing the window after it
544 is visible. */
545 int
546 x_initialize_frame_menubar (struct frame *f)
547 {
548 return set_frame_menubar (f, 1, 1);
549 }
550
551
552 static LWLIB_ID last_popup_menu_selection_callback_id;
553
554 static void
555 popup_menu_selection_callback (Widget widget, LWLIB_ID id,
556 XtPointer client_data)
557 {
558 last_popup_menu_selection_callback_id = id;
559 popup_selection_callback (widget, id, client_data);
560 /* lw_destroy_all_widgets() will be called from popup_down_callback() */
561 }
562
563 static void
564 popup_menu_down_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
565 {
566 if (popup_handled_p (id))
567 return;
568 assert (popup_up_p != 0);
569 ungcpro_popup_callbacks (id);
570 popup_up_p--;
571 /* if this isn't called immediately after the selection callback, then
572 there wasn't a menu selection. */
573 if (id != last_popup_menu_selection_callback_id)
574 popup_selection_callback (widget, id, (XtPointer) -1);
575 lw_destroy_all_widgets (id);
576 }
577
578
579 static void
580 make_dummy_xbutton_event (XEvent *dummy,
581 Widget daddy,
582 struct Lisp_Event *eev)
583 /* NULL for eev means query pointer */
584 {
585 XButtonPressedEvent *btn = (XButtonPressedEvent *) dummy;
586
587 btn->type = ButtonPress;
588 btn->serial = 0;
589 btn->send_event = 0;
590 btn->display = XtDisplay (daddy);
591 btn->window = XtWindow (daddy);
592 if (eev)
593 {
594 Position shellx, shelly, framex, framey;
595 Widget shell = XtParent (daddy);
596 btn->time = eev->timestamp;
597 btn->button = eev->event.button.button;
598 btn->root = RootWindowOfScreen (XtScreen (daddy));
599 btn->subwindow = (Window) NULL;
600 btn->x = eev->event.button.x;
601 btn->y = eev->event.button.y;
602 XtVaGetValues (shell, XtNx, &shellx, XtNy, &shelly, NULL);
603 XtVaGetValues (daddy, XtNx, &framex, XtNy, &framey, NULL);
604 btn->x_root = shellx + framex + btn->x;
605 btn->y_root = shelly + framey + btn->y;;
606 btn->state = ButtonPressMask; /* all buttons pressed */
607 }
608 else
609 {
610 /* CurrentTime is just ZERO, so it's worthless for
611 determining relative click times. */
612 struct device *d = get_device_from_display (XtDisplay (daddy));
613 btn->time = DEVICE_X_MOUSE_TIMESTAMP (d); /* event-Xt maintains this */
614 btn->button = 0;
615 XQueryPointer (btn->display, btn->window, &btn->root,
616 &btn->subwindow, &btn->x_root, &btn->y_root,
617 &btn->x, &btn->y, &btn->state);
618 }
619 }
620
621
622 #ifdef ENERGIZE
623 extern int desired_debuggerpanel_exposed_p;
624 extern int current_debuggerpanel_exposed_p;
625 extern int debuggerpanel_sheet;
626 extern void notify_energize_sheet_hidden (unsigned long);
627 #endif
628
629 static void
630 x_update_frame_menubar_internal (struct frame *f)
631 {
632 /* We assume the menubar contents has changed if the global flag is set,
633 or if the current buffer has changed, or if the menubar has never
634 been updated before.
635 */
636 int menubar_contents_changed =
637 (f->menubar_changed
638 || NILP (FRAME_MENUBAR_DATA (f))
639 || (!EQ (XFRAME_MENUBAR_DATA (f)->last_menubar_buffer,
640 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer)));
641
642 int menubar_was_visible = XtIsManaged (FRAME_X_MENUBAR_WIDGET (f));
643 int menubar_will_be_visible = menubar_was_visible;
644 int menubar_visibility_changed;
645 Cardinal new_num_top_widgets = 1; /* for the menubar */
646 Widget container = FRAME_X_CONTAINER_WIDGET (f);
647
648 #ifdef ENERGIZE
649 int *old_sheets = FRAME_X_CURRENT_PSHEETS (f);
650 int *new_sheets = FRAME_X_DESIRED_PSHEETS (f);
651 int old_count = FRAME_X_CURRENT_PSHEET_COUNT (f);
652 int new_count = FRAME_X_DESIRED_PSHEET_COUNT (f);
653 Lisp_Object old_buf = FRAME_X_CURRENT_PSHEET_BUFFER (f);
654 Lisp_Object new_buf = FRAME_X_DESIRED_PSHEET_BUFFER (f);
655 int psheets_changed = (old_sheets != new_sheets
656 || old_count != new_count
657 || !EQ (old_buf, new_buf));
658 int debuggerpanel_changed = (desired_debuggerpanel_exposed_p
659 != current_debuggerpanel_exposed_p);
660
661 if (desired_debuggerpanel_exposed_p && FRAME_X_TOP_WIDGETS (f) [1] == 0)
662 /* This happens when the frame was just created. */
663 debuggerpanel_changed = 1;
664
665 FRAME_X_CURRENT_PSHEETS (f) = FRAME_X_DESIRED_PSHEETS (f);
666 FRAME_X_CURRENT_PSHEET_COUNT (f) = FRAME_X_DESIRED_PSHEET_COUNT (f);
667 FRAME_X_CURRENT_PSHEET_BUFFER (f) = FRAME_X_DESIRED_PSHEET_BUFFER (f);
668 #endif /* ENERGIZE */
669
670 if (menubar_contents_changed)
671 menubar_will_be_visible = set_frame_menubar (f, 0, 0);
672
673 menubar_visibility_changed = menubar_was_visible != menubar_will_be_visible;
674
675 if (! (menubar_visibility_changed
676 #ifdef ENERGIZE
677 || psheets_changed || debuggerpanel_changed
678 #endif
679 ))
680 return;
681
682
683 /* Set menubar visibility */
684 if (menubar_visibility_changed)
685 (menubar_will_be_visible ? XtManageChild : XtUnmanageChild)
686 (FRAME_X_MENUBAR_WIDGET (f));
687
688
689 #ifdef ENERGIZE
690 /* Set debugger panel visibility */
691 if (debuggerpanel_changed)
692 {
693 Widget w;
694 int sheet = debuggerpanel_sheet;
695
696 w = lw_get_widget (sheet, container, 0);
697 if (desired_debuggerpanel_exposed_p)
698 {
699 if (! w)
700 w = lw_make_widget (sheet, container, 0);
701 FRAME_X_TOP_WIDGETS (f)[1] = w;
702 XtManageChild (w);
703 }
704 else
705 {
706 notify_energize_sheet_hidden (sheet);
707 if (w)
708 XtUnmanageChild (w);
709 }
710 }
711
712 /* Set psheet visibility. For the moment we just unmanage all the old
713 ones, and then manage all the new ones. If the number of psheets
714 ever becomes a large number (i.e. > 1), then we can worry about a
715 more sophisticated way of doing this. */
716 if (psheets_changed)
717 {
718 int i;
719 Widget w;
720 unsigned long sheet;
721
722 for (i=0; i<old_count; i++)
723 {
724 sheet = old_sheets[i];
725 w = lw_get_widget (sheet, container, 0);
726 notify_energize_sheet_hidden (sheet);
727 if (w)
728 XtUnmanageChild (w);
729 }
730
731 for (i=0; i<new_count; i++)
732 {
733 sheet = new_sheets[i];
734 /* #### This unconditional call to lw_make_widget() is a bad
735 idea. Doesn't it cause a memory leak if the widget
736 already exists?
737
738 #### How does Energize know that a sheet just got displayed?
739 #### Energize knows all. */
740 w = lw_make_widget (sheet, container, 0);
741 FRAME_X_TOP_WIDGETS (f)[2+i] = w;
742 XtManageChild (w);
743 }
744 }
745
746 new_num_top_widgets += 1+new_count;
747 #endif /* ENERGIZE */
748
749 /* Note that new_num_top_widgets doesn't need to reflect the actual
750 number of top widgets, but just the limit of FRAME_X_TOP_WIDGETS (f)[]. */
751 FRAME_X_NUM_TOP_WIDGETS (f) = new_num_top_widgets;
752 {
753 /* We want to end up as close in size as possible to what we
754 were before. So, ask the EmacsManager what size it wants
755 to be (suggesting the current size), and resize it to that
756 size. It in turn will call our query-geometry callback,
757 which will round the size to something that exactly fits
758 the text widget. */
759 XtWidgetGeometry req, repl;
760
761 req.request_mode = CWWidth | CWHeight;
762 XtVaGetValues (container,
763 XtNwidth, &req.width,
764 XtNheight, &req.height,
765 0);
766 XtQueryGeometry (container, &req, &repl);
767 EmacsManagerChangeSize (container, repl.width,
768 repl.height);
769 /* The window size might not have changed but the text size
770 did; thus, the base size might be incorrect. So update
771 it. */
772 EmacsShellUpdateSizeHints (FRAME_X_SHELL_WIDGET (f));
773 }
774
775 #ifdef ENERGIZE
776 /* Give back the focus to emacs if no psheets are displayed anymore */
777 if (psheets_changed)
778 {
779 Lisp_Object frame;
780 XSETFRAME (frame, f);
781 Fselect_frame (frame);
782 }
783 #endif /* ENERGIZE */
784 }
785
786 static void
787 x_update_frame_menubars (struct frame *f)
788 {
789 assert (FRAME_X_P (f));
790
791 x_update_frame_menubar_internal (f);
792
793 /* #### This isn't going to work right now that this function works on
794 a per-frame, not per-device basis. Guess what? I don't care. */
795 #ifdef ENERGIZE
796 current_debuggerpanel_exposed_p = desired_debuggerpanel_exposed_p;
797 #endif
798 }
799
800 static void
801 x_free_frame_menubars (struct frame *f)
802 {
803 Widget menubar_widget;
804
805 assert (FRAME_X_P (f));
806
807 menubar_widget = FRAME_X_MENUBAR_WIDGET (f);
808 if (menubar_widget)
809 {
810 LWLIB_ID id = XFRAME_MENUBAR_DATA (f)->id;
811 lw_destroy_all_widgets (id);
812 XFRAME_MENUBAR_DATA (f)->id = 0;
813 }
814
815 #ifdef ENERGIZE
816 {
817 /* Also destroy this frame's psheets */
818 Widget parent = FRAME_X_CONTAINER_WIDGET (f);
819 int *sheets = FRAME_X_CURRENT_PSHEETS (f);
820 int i = FRAME_X_CURRENT_PSHEET_COUNT (f);
821 while (i--)
822 {
823 unsigned long sheet = sheets [i];
824 Widget w = lw_get_widget (sheet, parent, 0);
825 if (w)
826 lw_destroy_widget (w);
827 }
828 FRAME_X_CURRENT_PSHEET_COUNT (f) = 0;
829
830 /* Is this necessary? */
831 sheets = FRAME_X_DESIRED_PSHEETS (f);
832 i = FRAME_X_DESIRED_PSHEET_COUNT (f);
833 while (i--)
834 {
835 unsigned long sheet = sheets [i];
836 Widget w = lw_get_widget (sheet, parent, 0);
837 if (w)
838 lw_destroy_widget (w);
839 }
840 FRAME_X_DESIRED_PSHEET_COUNT (f) = 0;
841
842 /* sigh... debugger panel is special... */
843 if (debuggerpanel_sheet)
844 {
845 Widget w = lw_get_widget (debuggerpanel_sheet, parent, 0);
846 if (w)
847 lw_destroy_widget (w);
848 }
849 }
850 #endif /* ENERGIZE */
851 }
852
853 static void
854 x_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
855 {
856 int menu_id;
857 struct frame *f = selected_frame ();
858 widget_value *data;
859 Widget parent;
860 Widget menu;
861 struct Lisp_Event *eev = NULL;
862 XEvent xev;
863 Lisp_Object frame = Qnil;
864
865 XSETFRAME (frame, f);
866 CHECK_X_FRAME (frame);
867 parent = FRAME_X_SHELL_WIDGET (f);
868
869 if (!NILP (event))
870 {
871 CHECK_LIVE_EVENT (event);
872 eev= XEVENT (event);
873 if (eev->event_type != button_press_event
874 && eev->event_type != button_release_event)
875 wrong_type_argument (Qmouse_event_p, event);
876 }
877 else if (!NILP (Vthis_command_keys))
878 {
879 /* if an event wasn't passed, use the last event of the event sequence
880 currently being executed, if that event is a mouse event */
881 eev = XEVENT (Vthis_command_keys); /* last event first */
882 if (eev->event_type != button_press_event
883 && eev->event_type != button_release_event)
884 eev = NULL;
885 }
886 make_dummy_xbutton_event (&xev, parent, eev);
887
888 if (SYMBOLP (menu_desc))
889 menu_desc = Fsymbol_value (menu_desc);
890 CHECK_CONS (menu_desc);
891 CHECK_STRING (XCAR (menu_desc));
892 data = menu_item_descriptor_to_widget_value (menu_desc, POPUP_TYPE, 1, 1);
893
894 if (! data) error ("no menu");
895
896 menu_id = new_lwlib_id ();
897 menu = lw_create_widget ("popup", "popup" /* data->name */, menu_id, data,
898 parent, 1, 0,
899 popup_menu_selection_callback,
900 popup_menu_down_callback);
901 free_popup_widget_value_tree (data);
902
903 gcpro_popup_callbacks (menu_id);
904
905 /* Setting zmacs-region-stays is necessary here because executing a command
906 from a menu is really a two-command process: the first command (bound to
907 the button-click) simply pops up the menu, and returns. This causes a
908 sequence of magic-events (destined for the popup-menu widget) to begin.
909 Eventually, a menu item is selected, and a menu-event blip is pushed onto
910 the end of the input stream, which is then executed by the event loop.
911
912 So there are two command-events, with a bunch of magic-events between
913 them. We don't want the *first* command event to alter the state of the
914 region, so that the region can be available as an argument for the second
915 command.
916 */
917 if (zmacs_regions)
918 zmacs_region_stays = 1;
919
920 popup_up_p++;
921 lw_popup_menu (menu, &xev);
922 /* this speeds up display of pop-up menus */
923 XFlush (XtDisplay (parent));
924 }
925
926
927 void
928 syms_of_menubar_x (void)
929 {
930 }
931
932 void
933 console_type_create_menubar_x (void)
934 {
935 CONSOLE_HAS_METHOD (x, update_frame_menubars);
936 CONSOLE_HAS_METHOD (x, free_frame_menubars);
937 CONSOLE_HAS_METHOD (x, popup_menu);
938 }
939
940 void
941 vars_of_menubar_x (void)
942 {
943 last_popup_menu_selection_callback_id = -1;
944
945 #if defined (LWLIB_MENUBARS_LUCID)
946 Fprovide (intern ("lucid-menubars"));
947 #elif defined (LWLIB_MENUBARS_MOTIF)
948 Fprovide (intern ("motif-menubars"));
949 #elif defined (LWLIB_MENUBARS_ATHENA)
950 Fprovide (intern ("athena-menubars"));
951 #endif
952 }