1 /* The lwlib interface to "xlwmenu" menus.
2 Copyright (C) 1992, 1994 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
22 #include <stdlib.h> /* for abort () */
23 #include <stdio.h> /* for abort () */
26 #include "lwlib-Xlw.h"
27 #include "lwlib-utils.h"
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CompositeP.h>
32 #include <X11/Shell.h>
34 #include "../src/EmacsManager.h"
36 #ifdef LWLIB_MENUBARS_LUCID
39 #ifdef LWLIB_SCROLLBARS_LUCID
40 #include "xlwscrollbar.h"
42 #ifdef LWLIB_TABS_LUCID
47 #include "lwlib-Xaw.h"
49 #include "../src/xmu.h"
54 #include <X11/Intrinsic.h>
55 #include <X11/StringDefs.h>
56 #include <X11/Shell.h>
57 #include <X11/Xaw/Form.h>
58 #include <X11/Xaw/Command.h>
61 #ifdef LWLIB_MENUBARS_LUCID
66 pre_hook (Widget w, XtPointer client_data, XtPointer call_data)
68 widget_instance* instance = (widget_instance*)client_data;
71 if (w->core.being_destroyed)
74 val = lw_get_widget_value_for_widget (instance, w);
76 /* #### - this code used to (for some random back_asswards reason) pass
77 the expression below in the call_data slot. For incremental menu
78 construction, this needs to go. I can't even figure out why it was done
79 this way in the first place...it's just a historical weirdism. --Stig */
80 call_data = (val ? val->call_data : NULL);
82 if (val && val->call_data)
83 abort(); /* #### - the call_data for the top_level
84 "menubar" widget_value used to be passed
85 back to the pre_hook. */
87 if (instance->info->pre_activate_cb)
88 instance->info->pre_activate_cb (w, instance->info->id, call_data);
92 pick_hook (Widget w, XtPointer client_data, XtPointer call_data)
94 widget_instance* instance = (widget_instance*)client_data;
95 widget_value* contents_val = (widget_value*)call_data;
96 widget_value* widget_val;
99 lw_callback post_activate_cb;
101 if (w->core.being_destroyed)
104 /* Grab these values before running any functions, in case running
105 the selection_cb causes the widget to be destroyed. */
106 id = instance->info->id;
107 post_activate_cb = instance->info->post_activate_cb;
109 widget_val = lw_get_widget_value_for_widget (instance, w);
110 widget_arg = widget_val ? widget_val->call_data : NULL;
112 if (instance->info->selection_cb &&
114 contents_val->enabled &&
115 !contents_val->contents)
116 instance->info->selection_cb (w, id, contents_val->call_data);
118 if (post_activate_cb)
119 post_activate_cb (w, id, widget_arg);
124 /* creation functions */
126 xlw_create_menubar (widget_instance* instance)
131 XtSetArg (al [0], XtNmenu, instance->info->val);
132 widget = XtCreateWidget (instance->info->name, xlwMenuWidgetClass,
133 instance->parent, al, 1);
134 XtAddCallback (widget, XtNopen, pre_hook, (XtPointer)instance);
135 XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
140 xlw_create_popup_menu (widget_instance* instance)
143 Widget popup_shell, widget;
145 popup_shell = XtCreatePopupShell (instance->info->name,
146 overrideShellWidgetClass,
147 instance->parent, NULL, 0);
148 XtSetArg (al [0], XtNmenu, instance->info->val);
149 XtSetArg (al [1], XtNhorizontal, False);
150 widget = XtCreateManagedWidget ("popup", xlwMenuWidgetClass,
152 XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
155 #endif /* LWLIB_MENUBARS_LUCID */
157 #ifdef LWLIB_SCROLLBARS_LUCID
159 xlw_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data)
161 widget_instance *instance = (widget_instance *) closure;
163 XlwScrollBarCallbackStruct *data =
164 (XlwScrollBarCallbackStruct *) call_data;
165 scroll_event event_data;
166 scrollbar_values *val;
169 if (!instance || widget->core.being_destroyed)
172 val = (scrollbar_values *) instance->info->val->scrollbar_data;
173 id = instance->info->id;
175 percent = (double) (data->value - 1) / (double) (INT_MAX - 1);
176 event_data.slider_value =
177 (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum;
179 if (event_data.slider_value > val->maximum - val->slider_size)
180 event_data.slider_value = val->maximum - val->slider_size;
181 else if (event_data.slider_value < val->minimum)
182 event_data.slider_value = val->minimum;
186 switch (data->event->type)
190 event_data.time = data->event->xkey.time;
194 event_data.time = data->event->xbutton.time;
197 event_data.time = data->event->xmotion.time;
201 event_data.time = data->event->xcrossing.time;
211 switch (data->reason)
213 case XmCR_DECREMENT: event_data.action = SCROLLBAR_LINE_UP; break;
214 case XmCR_INCREMENT: event_data.action = SCROLLBAR_LINE_DOWN; break;
215 case XmCR_PAGE_DECREMENT: event_data.action = SCROLLBAR_PAGE_UP; break;
216 case XmCR_PAGE_INCREMENT: event_data.action = SCROLLBAR_PAGE_DOWN; break;
217 case XmCR_TO_TOP: event_data.action = SCROLLBAR_TOP; break;
218 case XmCR_TO_BOTTOM: event_data.action = SCROLLBAR_BOTTOM; break;
219 case XmCR_DRAG: event_data.action = SCROLLBAR_DRAG; break;
220 case XmCR_VALUE_CHANGED: event_data.action = SCROLLBAR_CHANGE; break;
221 default: event_data.action = SCROLLBAR_CHANGE; break;
224 if (instance->info->pre_activate_cb)
225 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
228 #define add_scrollbar_callback(resource) \
229 XtAddCallback (scrollbar, resource, xlw_scrollbar_callback, (XtPointer) instance)
231 /* #### Does not yet support horizontal scrollbars. */
233 xlw_create_scrollbar (widget_instance *instance, int vertical)
237 static XtCallbackRec callbacks[2] =
238 { {xlw_scrollbar_callback, NULL}, {NULL, NULL} };
240 callbacks[0].closure = (XtPointer) instance;
242 XtSetArg (al[ac], XmNminimum, 1); ac++;
243 XtSetArg (al[ac], XmNmaximum, INT_MAX); ac++;
244 XtSetArg (al[ac], XmNincrement, 1); ac++;
245 XtSetArg (al[ac], XmNpageIncrement, 1); ac++;
246 XtSetArg (al[ac], XmNorientation, (vertical ? XmVERTICAL : XmHORIZONTAL)); ac++;
248 XtSetArg (al[ac], XmNdecrementCallback, callbacks); ac++;
249 XtSetArg (al[ac], XmNdragCallback, callbacks); ac++;
250 XtSetArg (al[ac], XmNincrementCallback, callbacks); ac++;
251 XtSetArg (al[ac], XmNpageDecrementCallback, callbacks); ac++;
252 XtSetArg (al[ac], XmNpageIncrementCallback, callbacks); ac++;
253 XtSetArg (al[ac], XmNtoBottomCallback, callbacks); ac++;
254 XtSetArg (al[ac], XmNtoTopCallback, callbacks); ac++;
255 XtSetArg (al[ac], XmNvalueChangedCallback, callbacks); ac++;
257 return XtCreateWidget (instance->info->name, xlwScrollBarWidgetClass,
258 instance->parent, al, ac);
262 xlw_create_vertical_scrollbar (widget_instance *instance)
264 return xlw_create_scrollbar (instance, 1);
268 xlw_create_horizontal_scrollbar (widget_instance *instance)
270 return xlw_create_scrollbar (instance, 0);
274 xlw_update_scrollbar (widget_instance *instance, Widget widget,
277 if (val->scrollbar_data)
279 scrollbar_values *data = val->scrollbar_data;
280 int widget_sliderSize, widget_val;
281 int new_sliderSize, new_value;
285 /* First size and position the scrollbar widget. */
286 XtSetArg (al [0], XtNx, data->scrollbar_x);
287 XtSetArg (al [1], XtNy, data->scrollbar_y);
288 XtSetArg (al [2], XtNwidth, data->scrollbar_width);
289 XtSetArg (al [3], XtNheight, data->scrollbar_height);
290 XtSetValues (widget, al, 4);
292 /* Now size the scrollbar's slider. */
293 XtSetArg (al [0], XmNsliderSize, &widget_sliderSize);
294 XtSetArg (al [1], XmNvalue, &widget_val);
295 XtGetValues (widget, al, 2);
297 percent = (double) data->slider_size /
298 (double) (data->maximum - data->minimum);
299 percent = (percent > 1.0 ? 1.0 : percent);
300 new_sliderSize = (int) ((double) (INT_MAX - 1) * percent);
302 percent = (double) (data->slider_position - data->minimum) /
303 (double) (data->maximum - data->minimum);
304 percent = (percent > 1.0 ? 1.0 : percent);
305 new_value = (int) ((double) (INT_MAX - 1) * percent);
307 if (new_sliderSize > INT_MAX - 1)
308 new_sliderSize = INT_MAX - 1;
309 else if (new_sliderSize < 1)
312 if (new_value > (INT_MAX - new_sliderSize))
313 new_value = INT_MAX - new_sliderSize;
314 else if (new_value < 1)
317 if (new_sliderSize != widget_sliderSize || new_value != widget_val)
318 XlwScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1, False);
322 #endif /* LWLIB_SCROLLBARS_LUCID */
324 #ifdef LWLIB_TABS_LUCID
327 [[ lwlib is such an incredible hairy crock. I just cannot believe
328 it! There are random dependencies between functions, there is a
329 total lack of genericity, even though it initially appears to be
330 generic. It should all be junked and begun again. Building tabs are
331 an example - in theory we should be able to reuse a lot of the
332 general stuff because we want to put labels of whatever toolkit we
333 are using in the tab. Instead we have to hack it by hand. ]]
334 While lwlib is a hairy crock, whoever wrote that seems to misunderstand
335 Falk's tab control widget. The tab control widget has *two* kinds of
336 children: *widgets*, which all occupy a *single* pane below the row of
337 tabs---this is where the labels created in build_tabs_in_widget go, and
338 *gadgets*, the tabs themselves, which do *not* draw themselves, but
339 rather are drawn by the control. In fact, in XEmacs the true widget
340 children are *never* visible! So this case is not a problem in the
341 design of lwlib, but rather of Falk's widget. -- sjt */
343 xlw_tab_control_callback (Widget w, XtPointer client_data, XtPointer call_data)
345 /* call data is the topmost widget */
346 widget_instance* instance = (widget_instance*)client_data;
347 Widget top = (Widget)call_data;
348 char *name = XtName (top);
349 widget_value* widget_val;
350 XtPointer widget_arg;
352 lw_callback post_activate_cb;
354 if (w->core.being_destroyed)
357 /* Grab these values before running any functions, in case running
358 the selection_cb causes the widget to be destroyed. */
359 id = instance->info->id;
360 post_activate_cb = instance->info->post_activate_cb;
362 /* search for the widget_val for the selected tab */
363 for (widget_val = instance->info->val->contents; widget_val;
364 widget_val = widget_val->next)
366 if (!strcmp (widget_val->name, name))
370 widget_arg = widget_val ? widget_val->call_data : NULL;
372 if (instance->info->selection_cb &&
374 widget_val->enabled &&
375 !widget_val->contents)
376 instance->info->selection_cb (w, id, widget_arg);
378 if (post_activate_cb)
379 post_activate_cb (w, id, widget_arg);
383 xlw_create_tab_control (widget_instance *instance)
388 widget_value* val = instance->info->val;
390 XtSetArg (al [ac], XtNsensitive, val->enabled); ac++;
391 XtSetArg (al [ac], XtNmappedWhenManaged, False); ac++;
392 XtSetArg (al [ac], XtNorientation, XtorientHorizontal); ac++;
394 /* add any args the user supplied for creation time */
395 lw_add_value_args_to_args (val, al, &ac);
397 tab = XtCreateManagedWidget (val->name, tabsWidgetClass,
398 instance->parent, al, ac);
399 XtRemoveAllCallbacks (tab, XtNcallback);
400 XtAddCallback (tab, XtNcallback, xlw_tab_control_callback, (XtPointer)instance);
407 static void build_tabs_in_widget (widget_instance* instance, Widget widget,
410 widget_value* cur = val;
413 /* Children are always invisible, don't permit resizing. */
414 XtSetArg (al[0], XtNresizable, False);
416 for (cur = val; cur; cur = cur->next)
421 #ifdef LWLIB_WIDGETS_MOTIF
422 w = xm_create_label (widget, cur);
424 w = xaw_create_label (widget, cur);
426 XtSetValues (w, al, 1);
428 cur->change = NO_CHANGE;
433 xlw_update_tab_control (widget_instance* instance, Widget widget, widget_value* val)
436 unsigned int num_children;
438 widget_value *cur = 0;
440 XtRemoveAllCallbacks (widget, XtNcallback);
441 XtAddCallback (widget, XtNcallback, xlw_tab_control_callback, (XtPointer)instance);
443 if (val->change == STRUCTURAL_CHANGE
445 (val->contents && val->contents->change == STRUCTURAL_CHANGE))
447 destroy_all_children (widget);
448 build_tabs_in_widget (instance, widget, val->contents);
451 children = XtCompositeChildren (widget, &num_children);
454 for (i = 0, cur = val->contents; i < num_children; i++)
458 if (children [i]->core.being_destroyed
459 || strcmp (XtName (children [i]), cur->name))
462 if (lw_motif_widget_p (children [i]))
463 xm_update_one_widget (instance, children [i], cur, False);
466 if (lw_xaw_widget_p (children [i]))
467 xaw_update_one_widget (instance, children [i], cur, False);
471 XtFree ((char *) children);
476 #endif /* LWLIB_TABS_LUCID */
480 xlw_create_clip_window (widget_instance *instance)
485 widget_value* val = instance->info->val;
487 XtSetArg (al [ac], XtNmappedWhenManaged, FALSE); ac++;
488 XtSetArg (al [ac], XtNsensitive, TRUE); ac++;
489 /* add any args the user supplied for creation time */
490 lw_add_value_args_to_args (val, al, &ac);
492 /* Create a clip window to contain the subwidget. Incredibly the
493 XEmacs manager seems to be the most appropriate widget for
494 this. Nothing else is simple enough and yet does what is
496 clip = XtCreateManagedWidget (val->name,
497 emacsManagerWidgetClass,
498 instance->parent, al, ac);
504 const widget_creation_entry
505 xlw_creation_table [] =
507 #ifdef LWLIB_MENUBARS_LUCID
508 {"menubar", xlw_create_menubar},
509 {"popup", xlw_create_popup_menu},
511 #ifdef LWLIB_SCROLLBARS_LUCID
512 {"vertical-scrollbar", xlw_create_vertical_scrollbar},
513 {"horizontal-scrollbar", xlw_create_horizontal_scrollbar},
515 #ifdef LWLIB_TABS_LUCID
516 {"tab-control", xlw_create_tab_control},
519 {"clip-window", xlw_create_clip_window},
525 lw_lucid_widget_p (Widget widget)
527 WidgetClass the_class = XtClass (widget);
528 #ifdef LWLIB_MENUBARS_LUCID
529 if (the_class == xlwMenuWidgetClass)
532 #ifdef LWLIB_SCROLLBARS_LUCID
533 if (the_class == xlwScrollBarWidgetClass)
536 #ifdef LWLIB_TABS_LUCID
537 if (the_class == tabsWidgetClass)
540 #ifdef LWLIB_MENUBARS_LUCID
541 if (the_class == overrideShellWidgetClass)
543 XtClass (((CompositeWidget)widget)->composite.children [0])
544 == xlwMenuWidgetClass;
547 if (the_class == emacsManagerWidgetClass)
554 xlw_update_one_widget (widget_instance* instance, Widget widget,
555 widget_value* val, Boolean deep_p)
557 WidgetClass class = XtClass (widget);
561 #ifdef LWLIB_MENUBARS_LUCID
562 else if (class == xlwMenuWidgetClass)
566 if (XtIsShell (widget))
567 mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
569 mw = (XlwMenuWidget)widget;
570 XtSetArg (al [0], XtNmenu, val);
571 XtSetValues (widget, al, 1); /* #### mw unused! */
574 #ifdef LWLIB_SCROLLBARS_LUCID
575 else if (class == xlwScrollBarWidgetClass)
577 xlw_update_scrollbar (instance, widget, val);
580 #ifdef LWLIB_TABS_LUCID
581 else if (class == tabsWidgetClass)
583 xlw_update_tab_control (instance, widget, val);
586 /* Lastly update our global arg values. */
587 if (val->args && val->args->nargs)
588 XtSetValues (widget, val->args->args, val->args->nargs);
592 xlw_update_one_value (widget_instance* instance, Widget widget,
599 xlw_pop_instance (widget_instance* instance, Boolean up)
603 #ifdef LWLIB_MENUBARS_LUCID
605 xlw_popup_menu (Widget widget, XEvent *event)
609 if (!XtIsShell (widget))
612 if (event->type == ButtonPress || event->type == ButtonRelease)
614 mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
615 xlw_pop_up_menu (mw, (XButtonPressedEvent *)event);
620 #endif /* LWLIB_MENUBARS_LUCID */
622 \f/* Destruction of instances */
624 xlw_destroy_instance (widget_instance* instance)
626 if (instance->widget)
627 XtDestroyWidget (instance->widget);