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
7 and/or modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation, either version 3 of the
9 License, or (at your option) any later version.
11 The Lucid Widget Library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include <stdlib.h> /* for abort () */
21 #include <stdio.h> /* for abort () */
24 #include "lwlib-Xlw.h"
25 #include "lwlib-utils.h"
26 #include <X11/StringDefs.h>
27 #include <X11/IntrinsicP.h>
28 #include <X11/ObjectP.h>
29 #include <X11/CompositeP.h>
30 #include <X11/Shell.h>
32 #include "ui/X11/EmacsManager.h"
34 #ifdef LWLIB_MENUBARS_LUCID
37 #ifdef LWLIB_SCROLLBARS_LUCID
38 #include "xlwscrollbar.h"
40 #ifdef LWLIB_TABS_LUCID
45 #include "lwlib-Xaw.h"
47 #include "ui/X11/xmu.h"
51 #include <X11/Intrinsic.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h>
54 #include <X11/Xaw/Form.h>
55 #include <X11/Xaw/Command.h>
57 #ifdef LWLIB_MENUBARS_LUCID
61 static void pre_hook(Widget w, XtPointer client_data, XtPointer call_data)
63 widget_instance *instance = (widget_instance *) client_data;
66 if (w->core.being_destroyed)
69 val = lw_get_widget_value_for_widget(instance, w);
71 /* #### - this code used to (for some random back_asswards reason) pass
72 the expression below in the call_data slot. For incremental menu
73 construction, this needs to go. I can't even figure out why it was done
74 this way in the first place...it's just a historical weirdism. --Stig */
75 call_data = (val ? val->call_data : NULL);
77 if (val && val->call_data)
78 abort(); /* #### - the call_data for the top_level
79 "menubar" widget_value used to be passed
80 back to the pre_hook. */
82 if (instance->info->pre_activate_cb)
83 instance->info->pre_activate_cb(w, instance->info->id,
87 static void pick_hook(Widget w, XtPointer client_data, XtPointer call_data)
89 widget_instance *instance = (widget_instance *) client_data;
90 widget_value *contents_val = (widget_value *) call_data;
91 widget_value *widget_val;
94 lw_callback post_activate_cb;
96 if (w->core.being_destroyed)
99 /* Grab these values before running any functions, in case running
100 the selection_cb causes the widget to be destroyed. */
101 id = instance->info->id;
102 post_activate_cb = instance->info->post_activate_cb;
104 widget_val = lw_get_widget_value_for_widget(instance, w);
105 widget_arg = widget_val ? widget_val->call_data : NULL;
107 if (instance->info->selection_cb &&
108 contents_val && contents_val->enabled && !contents_val->contents)
109 instance->info->selection_cb(w, id, contents_val->call_data);
111 if (post_activate_cb)
112 post_activate_cb(w, id, widget_arg);
115 /* creation functions */
116 static Widget xlw_create_menubar(widget_instance * instance)
121 XtSetArg(al[0], XtNmenu, instance->info->val);
122 widget = XtCreateWidget(instance->info->name, xlwMenuWidgetClass,
123 instance->parent, al, 1);
124 XtAddCallback(widget, XtNopen, pre_hook, (XtPointer) instance);
125 XtAddCallback(widget, XtNselect, pick_hook, (XtPointer) instance);
129 static Widget xlw_create_popup_menu(widget_instance * instance)
132 Widget popup_shell, widget;
134 popup_shell = XtCreatePopupShell(instance->info->name,
135 overrideShellWidgetClass,
136 instance->parent, NULL, 0);
137 XtSetArg(al[0], XtNmenu, instance->info->val);
138 XtSetArg(al[1], XtNhorizontal, False);
139 widget = XtCreateManagedWidget("popup", xlwMenuWidgetClass,
141 XtAddCallback(widget, XtNselect, pick_hook, (XtPointer) instance);
144 #endif /* LWLIB_MENUBARS_LUCID */
146 #ifdef LWLIB_SCROLLBARS_LUCID
148 xlw_scrollbar_callback(Widget widget, XtPointer closure, XtPointer call_data)
150 widget_instance *instance = (widget_instance *) closure;
152 XlwScrollBarCallbackStruct *data =
153 (XlwScrollBarCallbackStruct *) call_data;
154 scroll_event event_data;
155 scrollbar_values *val;
158 if (!instance || widget->core.being_destroyed)
161 val = (scrollbar_values *) instance->info->val->scrollbar_data;
163 id = instance->info->id;
165 percent = (double)(data->value - 1) / (double)(INT_MAX - 1);
166 event_data.slider_value =
167 (int)(percent * (double)(val->maximum - val->minimum)) +
170 if (event_data.slider_value > val->maximum - val->slider_size)
171 event_data.slider_value = val->maximum - val->slider_size;
172 else if (event_data.slider_value < val->minimum)
173 event_data.slider_value = val->minimum;
176 switch (data->event->type) {
179 event_data.time = data->event->xkey.time;
183 event_data.time = data->event->xbutton.time;
186 event_data.time = data->event->xmotion.time;
190 event_data.time = data->event->xcrossing.time;
199 switch (data->reason) {
201 event_data.action = SCROLLBAR_LINE_UP;
204 event_data.action = SCROLLBAR_LINE_DOWN;
206 case XmCR_PAGE_DECREMENT:
207 event_data.action = SCROLLBAR_PAGE_UP;
209 case XmCR_PAGE_INCREMENT:
210 event_data.action = SCROLLBAR_PAGE_DOWN;
213 event_data.action = SCROLLBAR_TOP;
216 event_data.action = SCROLLBAR_BOTTOM;
219 event_data.action = SCROLLBAR_DRAG;
221 case XmCR_VALUE_CHANGED:
222 event_data.action = SCROLLBAR_CHANGE;
225 event_data.action = SCROLLBAR_CHANGE;
229 if (instance->info->pre_activate_cb)
230 instance->info->pre_activate_cb(widget, id,
231 (XtPointer) & event_data);
234 #define add_scrollbar_callback(resource) \
235 XtAddCallback (scrollbar, resource, xlw_scrollbar_callback, (XtPointer) instance)
237 /* #### Does not yet support horizontal scrollbars. */
238 static Widget xlw_create_scrollbar(widget_instance * instance, int vertical)
242 static XtCallbackRec callbacks[2] =
243 { {xlw_scrollbar_callback, NULL}, {NULL, NULL} };
245 callbacks[0].closure = (XtPointer) instance;
247 XtSetArg(al[ac], XmNminimum, 1);
249 XtSetArg(al[ac], XmNmaximum, INT_MAX);
251 XtSetArg(al[ac], XmNincrement, 1);
253 XtSetArg(al[ac], XmNpageIncrement, 1);
255 XtSetArg(al[ac], XmNorientation,
256 (vertical ? XmVERTICAL : XmHORIZONTAL));
259 XtSetArg(al[ac], XmNdecrementCallback, callbacks);
261 XtSetArg(al[ac], XmNdragCallback, callbacks);
263 XtSetArg(al[ac], XmNincrementCallback, callbacks);
265 XtSetArg(al[ac], XmNpageDecrementCallback, callbacks);
267 XtSetArg(al[ac], XmNpageIncrementCallback, callbacks);
269 XtSetArg(al[ac], XmNtoBottomCallback, callbacks);
271 XtSetArg(al[ac], XmNtoTopCallback, callbacks);
273 XtSetArg(al[ac], XmNvalueChangedCallback, callbacks);
276 return XtCreateWidget(instance->info->name, xlwScrollBarWidgetClass,
277 instance->parent, al, ac);
280 static Widget xlw_create_vertical_scrollbar(widget_instance * instance)
282 return xlw_create_scrollbar(instance, 1);
285 static Widget xlw_create_horizontal_scrollbar(widget_instance * instance)
287 return xlw_create_scrollbar(instance, 0);
291 xlw_update_scrollbar(widget_instance * instance, Widget widget,
294 if (val->scrollbar_data) {
295 scrollbar_values *data = val->scrollbar_data;
296 int widget_sliderSize, widget_val;
297 int new_sliderSize, new_value;
301 /* First size and position the scrollbar widget. */
302 XtSetArg(al[0], XtNx, data->scrollbar_x);
303 XtSetArg(al[1], XtNy, data->scrollbar_y);
304 XtSetArg(al[2], XtNwidth, data->scrollbar_width);
305 XtSetArg(al[3], XtNheight, data->scrollbar_height);
306 XtSetValues(widget, al, 4);
308 /* Now size the scrollbar's slider. */
309 XtSetArg(al[0], XmNsliderSize, &widget_sliderSize);
310 XtSetArg(al[1], XmNvalue, &widget_val);
311 XtGetValues(widget, al, 2);
313 percent = (double)data->slider_size /
314 (double)(data->maximum - data->minimum);
315 percent = (percent > 1.0 ? 1.0 : percent);
316 new_sliderSize = (int)((double)(INT_MAX - 1) * percent);
318 percent = (double)(data->slider_position - data->minimum) /
319 (double)(data->maximum - data->minimum);
320 percent = (percent > 1.0 ? 1.0 : percent);
321 new_value = (int)((double)(INT_MAX - 1) * percent);
323 if (new_sliderSize > INT_MAX - 1)
324 new_sliderSize = INT_MAX - 1;
325 else if (new_sliderSize < 1)
328 if (new_value > (INT_MAX - new_sliderSize))
329 new_value = INT_MAX - new_sliderSize;
330 else if (new_value < 1)
333 if (new_sliderSize != widget_sliderSize
334 || new_value != widget_val)
335 XlwScrollBarSetValues(widget, new_value, new_sliderSize,
340 #endif /* LWLIB_SCROLLBARS_LUCID */
342 #ifdef LWLIB_TABS_LUCID
345 lwlib is such an incredible hairy crock. I just cannot believe
346 it! There are random dependencies between functions, there is a
347 total lack of genericity, even though it initially appears to be
348 generic. It should all be junked and begun again. Building tabs are
349 an example - in theory we should be able to reuse a lot of the
350 general stuff because we want to put labels of whatever toolkit we
351 are using in the tab. Instead we have to hack it by hand. */
353 xlw_tab_control_callback(Widget w, XtPointer client_data, XtPointer call_data)
355 /* call data is the topmost widget */
356 widget_instance *instance = (widget_instance *) client_data;
357 Widget top = (Widget) call_data;
358 char *name = XtName(top);
359 widget_value *widget_val;
360 XtPointer widget_arg;
362 lw_callback post_activate_cb;
364 if (w->core.being_destroyed)
367 /* Grab these values before running any functions, in case running
368 the selection_cb causes the widget to be destroyed. */
369 id = instance->info->id;
370 post_activate_cb = instance->info->post_activate_cb;
372 /* search for the widget_val for the selected tab */
373 for (widget_val = instance->info->val->contents; widget_val;
374 widget_val = widget_val->next) {
375 if (!strcmp(widget_val->name, name))
379 widget_arg = widget_val ? widget_val->call_data : NULL;
381 if (instance->info->selection_cb &&
382 widget_val && widget_val->enabled && !widget_val->contents)
383 instance->info->selection_cb(w, id, widget_arg);
385 if (post_activate_cb)
386 post_activate_cb(w, id, widget_arg);
389 static Widget xlw_create_tab_control(widget_instance * instance)
394 widget_value *val = instance->info->val;
396 XtSetArg(al[ac], XtNsensitive, val->enabled);
398 XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
400 XtSetArg(al[ac], XtNorientation, XtorientHorizontal);
402 XtSetArg(al[ac], XtNresizable, False);
405 /* add any args the user supplied for creation time */
406 lw_add_value_args_to_args(val, al, &ac);
408 tab = XtCreateManagedWidget(val->name, tabsWidgetClass,
409 instance->parent, al, ac);
410 XtRemoveAllCallbacks(tab, XtNcallback);
411 XtAddCallback(tab, XtNcallback, xlw_tab_control_callback,
412 (XtPointer) instance);
419 static void build_tabs_in_widget(widget_instance * instance, Widget widget,
422 widget_value *cur = val;
423 for (cur = val; cur; cur = cur->next) {
425 #ifdef LWLIB_WIDGETS_MOTIF
426 xm_create_label(widget, cur);
428 xaw_create_label(widget, cur);
431 cur->change = NO_CHANGE;
436 xlw_update_tab_control(widget_instance * instance, Widget widget,
440 unsigned int num_children;
442 widget_value *cur = 0;
444 XtRemoveAllCallbacks(widget, XtNcallback);
445 XtAddCallback(widget, XtNcallback, xlw_tab_control_callback,
446 (XtPointer) instance);
448 if (val->change == STRUCTURAL_CHANGE
449 || (val->contents && val->contents->change == STRUCTURAL_CHANGE)) {
450 destroy_all_children(widget);
451 build_tabs_in_widget(instance, widget, val->contents);
454 children = XtCompositeChildren(widget, &num_children);
456 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,
467 if (lw_xaw_widget_p(children[i]))
468 xaw_update_one_widget(instance, children[i],
475 XtFree((char *)children);
480 #endif /* LWLIB_TABS_LUCID */
483 static Widget xlw_create_clip_window(widget_instance * instance)
488 widget_value *val = instance->info->val;
490 XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
492 XtSetArg(al[ac], XtNsensitive, TRUE);
494 /* add any args the user supplied for creation time */
495 lw_add_value_args_to_args(val, al, &ac);
497 /* Create a clip window to contain the subwidget. Incredibly the
498 XEmacs manager seems to be the most appropriate widget for
499 this. Nothing else is simple enough and yet does what is
501 clip = XtCreateManagedWidget(val->name,
502 emacsManagerWidgetClass,
503 instance->parent, al, ac);
509 const widget_creation_entry xlw_creation_table[] = {
510 #ifdef LWLIB_MENUBARS_LUCID
511 {"menubar", xlw_create_menubar},
512 {"popup", xlw_create_popup_menu},
514 #ifdef LWLIB_SCROLLBARS_LUCID
515 {"vertical-scrollbar", xlw_create_vertical_scrollbar},
516 {"horizontal-scrollbar", xlw_create_horizontal_scrollbar},
518 #ifdef LWLIB_TABS_LUCID
519 {"tab-control", xlw_create_tab_control},
522 {"clip-window", xlw_create_clip_window},
527 Boolean lw_lucid_widget_p(Widget widget)
529 WidgetClass the_class = XtClass(widget);
530 #ifdef LWLIB_MENUBARS_LUCID
531 if (the_class == xlwMenuWidgetClass)
534 #ifdef LWLIB_SCROLLBARS_LUCID
535 if (the_class == xlwScrollBarWidgetClass)
538 #ifdef LWLIB_TABS_LUCID
539 if (the_class == tabsWidgetClass)
542 #ifdef LWLIB_MENUBARS_LUCID
543 if (the_class == overrideShellWidgetClass)
545 XtClass(((CompositeWidget) widget)->composite.children[0])
546 == xlwMenuWidgetClass;
549 if (the_class == emacsManagerWidgetClass)
556 xlw_update_one_widget(widget_instance * instance, Widget widget,
557 widget_value * val, Boolean deep_p)
559 WidgetClass class = XtClass(widget);
562 #ifdef LWLIB_MENUBARS_LUCID
563 else if (class == xlwMenuWidgetClass) {
566 if (XtIsShell(widget))
567 mw = (XlwMenuWidget) ((CompositeWidget) widget)->
568 composite.children[0];
570 mw = (XlwMenuWidget) widget;
571 XtSetArg(al[0], XtNmenu, val);
572 XtSetValues(widget, al, 1); /* #### mw unused! */
575 #ifdef LWLIB_SCROLLBARS_LUCID
576 else if (class == xlwScrollBarWidgetClass) {
577 xlw_update_scrollbar(instance, widget, val);
580 #ifdef LWLIB_TABS_LUCID
581 else if (class == tabsWidgetClass) {
582 xlw_update_tab_control(instance, widget, val);
585 /* Lastly update our global arg values. */
586 if (val->args && val->args->nargs)
587 XtSetValues(widget, val->args->args, val->args->nargs);
591 xlw_update_one_value(widget_instance * instance, Widget widget,
597 void xlw_pop_instance(widget_instance * instance, Boolean up)
601 #ifdef LWLIB_MENUBARS_LUCID
602 void xlw_popup_menu(Widget widget, XEvent * event)
606 if (!XtIsShell(widget))
609 if (event->type == ButtonPress || event->type == ButtonRelease) {
610 mw = (XlwMenuWidget) ((CompositeWidget) widget)->composite.
612 xlw_pop_up_menu(mw, (XButtonPressedEvent *) event);
616 #endif /* LWLIB_MENUBARS_LUCID */
618 /* Destruction of instances */
619 void xlw_destroy_instance(widget_instance * instance)
621 if (instance->widget)
622 XtDestroyWidget(instance->widget);