Index: configure.in =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/configure.in,v retrieving revision 1.111.2.36 diff -u -r1.111.2.36 configure.in --- configure.in 1999/07/22 07:32:39 1.111.2.36 +++ configure.in 1999/07/28 08:33:38 @@ -2886,8 +2886,9 @@ case "$with_scrollbars" in "" | "yes" ) with_scrollbars="lucid" ;; esac -case "$with_widgets" in "" | "yes" ) +case "$with_widgets" in "" | "yes" | "lucid") if test "$have_motif" = "yes"; then with_widgets="motif" + elif test "$have_xaw" = "yes"; then with_widgets="athena" else with_widgets=no fi ;; esac @@ -2911,6 +2912,10 @@ test "$with_menubars" = "lucid" && XE_APPEND(xlwmenu.o, lwlib_objs) test "$with_menubars" = "motif" && XE_APPEND(xlwmenu.o, lwlib_objs) test "$with_scrollbars" = "lucid" && XE_APPEND(xlwscrollbar.o, lwlib_objs) +test "$with_widgets" != "no" && XE_APPEND(xlwtabs.o xlwgcs.o, lwlib_objs) +case "$with_widgets" in athena* ) + XE_APPEND(xlwradio.o xlwcheckbox.o xlwgauge.o, lwlib_objs);; +esac case "$all_widgets" in *lucid* ) AC_DEFINE(NEED_LUCID) XE_APPEND(lwlib-Xlw.o, lwlib_objs) ;; @@ -2922,11 +2927,14 @@ case "$with_dialogs" in athena* ) AC_DEFINE(LWLIB_DIALOGS_ATHENA) ;; esac test "$with_scrollbars" = "athena3d" && AC_DEFINE(LWLIB_SCROLLBARS_ATHENA3D) test "$with_dialogs" = "athena3d" && AC_DEFINE(LWLIB_DIALOGS_ATHENA3D) +case "$with_widgets" in athena* ) AC_DEFINE(LWLIB_WIDGETS_ATHENA);; esac +test "$with_widgets" != "no" && AC_DEFINE(LWLIB_TABS_LUCID) test "$with_menubars" != "no" && AC_DEFINE(HAVE_MENUBARS) test "$with_scrollbars" != "no" && AC_DEFINE(HAVE_SCROLLBARS) test "$with_dialogs" != "no" && AC_DEFINE(HAVE_DIALOGS) test "$with_toolbars" != "no" && AC_DEFINE(HAVE_TOOLBARS) +test "$with_widgets" != "no" && AC_DEFINE(HAVE_WIDGETS) test "$with_menubars" = "lucid" && AC_DEFINE(LWLIB_MENUBARS_LUCID) test "$with_scrollbars" = "lucid" && AC_DEFINE(LWLIB_SCROLLBARS_LUCID) @@ -2934,6 +2942,7 @@ test "$with_menubars" = "motif" && AC_DEFINE(LWLIB_MENUBARS_MOTIF) test "$with_scrollbars" = "motif" && AC_DEFINE(LWLIB_SCROLLBARS_MOTIF) test "$with_dialogs" = "motif" && AC_DEFINE(LWLIB_DIALOGS_MOTIF) +test "$with_widgets" = "motif" && AC_DEFINE(LWLIB_WIDGETS_MOTIF) test "$with_menubars" != "no" && XE_ADD_OBJS(menubar.o) test "$with_scrollbars" != "no" && XE_ADD_OBJS(scrollbar.o) Index: lisp/gutter-items.el =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lisp/Attic/gutter-items.el,v retrieving revision 1.1.2.4 diff -u -r1.1.2.4 gutter-items.el --- lisp/gutter-items.el 1999/07/25 19:16:44 1.1.2.4 +++ lisp/gutter-items.el 1999/07/28 08:33:40 @@ -140,8 +140,11 @@ (vector 'tab-control :descriptor "Buffers" :properties (list :items (buffers-tab-items)))))) ;; This looks better than a 3d border - (set-specifier default-gutter-border-width 0 'global 'mswindows) - (set-specifier default-gutter gutter-string 'global 'mswindows))) + (mapcar '(lambda (x) + (when (valid-image-instantiator-format-p 'tab-control x) + (set-specifier default-gutter-border-width 0 'global x) + (set-specifier default-gutter gutter-string 'global x))) + (console-type-list)))) (defun update-tab-in-gutter (&optional notused) "Update the tab control in the gutter area." @@ -152,8 +155,18 @@ (resize-subwindow (glyph-image-instance gutter-buffers-tab) (gutter-pixel-width) nil))) +(defun remove-buffer-from-gutter-tab () + "Remove the current buffer from the tab control in the gutter area." + (when (valid-image-instantiator-format-p 'tab-control) + (set-image-instance-property (glyph-image-instance gutter-buffers-tab) + :items + (cdr (buffers-tab-items))) + (resize-subwindow (glyph-image-instance gutter-buffers-tab) + (gutter-pixel-width) nil))) + (add-tab-to-gutter) (add-hook 'switch-to-buffer-hooks 'update-tab-in-gutter) +(add-hook 'kill-buffer-hook 'remove-buffer-from-gutter-tab) (add-hook 'create-frame-hook 'update-tab-in-gutter) (provide 'gutter-items) Index: lwlib/Makefile.in.in =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/Makefile.in.in,v retrieving revision 1.14.2.2 diff -u -r1.14.2.2 Makefile.in.in --- lwlib/Makefile.in.in 1998/12/14 13:20:37 1.14.2.2 +++ lwlib/Makefile.in.in 1999/07/28 08:33:40 @@ -95,11 +95,18 @@ ## Following correct as of 19980312 -lwlib-Xaw.o: $(CONFIG_H) lwlib-Xaw.h lwlib-internal.h lwlib.h xlwmenu.h -lwlib-Xlw.o: $(CONFIG_H) lwlib-Xlw.h lwlib-internal.h lwlib.h xlwmenu.h xlwscrollbar.h +lwlib-Xaw.o: $(CONFIG_H) lwlib-Xaw.h lwlib-internal.h lwlib.h xlwmenu.h xlwradio.h \ +xlwgauge.h xlwcheckbox.h +lwlib-Xlw.o: $(CONFIG_H) lwlib-Xlw.h lwlib-internal.h lwlib.h xlwmenu.h xlwscrollbar.h \ +xlwtabs.h xlwgcs.h lwlib-Xm.o: $(CONFIG_H) lwlib-Xm.h lwlib-internal.h lwlib-utils.h lwlib.h xlwmenu.h lwlib-config.o: $(CONFIG_H) lwlib.h xlwmenu.h lwlib-utils.o: $(CONFIG_H) lwlib-utils.h lwlib.o: $(CONFIG_H) lwlib-Xaw.h lwlib-Xlw.h lwlib-Xm.h lwlib-internal.h lwlib-utils.h lwlib.h xlwmenu.h xlwmenu.o: $(CONFIG_H) lwlib.h xlwmenu.h xlwmenuP.h xlwscrollbar.o: $(CONFIG_H) xlwscrollbar.h xlwscrollbarP.h +xlwtabs.o: $(CONFIG_H) xlwtabs.h xlwtabsP.h +xlwradio.o: $(CONFIG_H) xlwradio.h xlwradioP.h +xlwcheckbox.o: $(CONFIG_H) xlwcheckbox.h xlwcheckboxP.h +xlwgauge.o: $(CONFIG_H) xlwgauge.h xlwgaugeP.h +xlwgcs.o: $(CONFIG_H) xlwgcs.h Index: lwlib/lwlib-Xaw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-Xaw.c,v retrieving revision 1.9 diff -u -r1.9 lwlib-Xaw.c --- lwlib/lwlib-Xaw.c 1998/01/19 01:57:47 1.9 +++ lwlib/lwlib-Xaw.c 1999/07/28 08:33:43 @@ -41,7 +41,15 @@ #include #include #endif - +#ifdef LWLIB_WIDGETS_ATHENA +#include +#include "xlwradio.h" +#include "xlwcheckbox.h" +#include "xlwgauge.h" +#if 0 +#include +#endif +#endif #include static void xaw_generic_callback (Widget, XtPointer, XtPointer); @@ -57,6 +65,14 @@ #ifdef LWLIB_DIALOGS_ATHENA || XtIsSubclass (widget, dialogWidgetClass) #endif +#ifdef LWLIB_WIDGETS_ATHENA + || XtIsSubclass (widget, labelWidgetClass) + || XtIsSubclass (widget, toggleWidgetClass) + || XtIsSubclass (widget, gaugeWidgetClass) +#if 0 + || XtIsSubclass (widget, textWidgetClass) +#endif +#endif ); } @@ -125,6 +141,16 @@ XtSetArg (al [0], XtNlabel, val->contents->value); XtSetValues (widget, al, 1); } +#endif /* LWLIB_DIALOGS_ATHENA */ +#ifdef LWLIB_WIDGETS_ATHENA + else if (XtClass (widget) == labelWidgetClass) + { + Arg al [1]; + XtSetArg (al [0], XtNlabel, val->contents->value); + XtSetValues (widget, al, 1); + } +#endif /* LWLIB_WIDGETS_ATHENA */ +#if defined (LWLIB_DIALOGS_ATHENA) || defined (LWLIB_WIDGETS_ATHENA) else if (XtIsSubclass (widget, commandWidgetClass)) { Dimension bw = 0; @@ -154,6 +180,14 @@ XtRemoveAllCallbacks (widget, XtNcallback); XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance); +#ifdef LWLIB_WIDGETS_ATHENA + /* set the selected state */ + if (XtIsSubclass (widget, toggleWidgetClass)) + { + XtSetArg (al [0], XtNstate, val->selected); + XtSetValues (widget, al, 1); + } +#endif /* LWLIB_WIDGETS_ATHENA */ } #endif /* LWLIB_DIALOGS_ATHENA */ } @@ -162,9 +196,34 @@ xaw_update_one_value (widget_instance *instance, Widget widget, widget_value *val) { - /* This function is not used by the scrollbars and those are the only - Athena widget implemented at the moment so do nothing. */ - return; +#ifdef LWLIB_WIDGETS_ATHENA + widget_value *old_wv; + + /* copy the call_data slot into the "return" widget_value */ + for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next) + if (!strcmp (val->name, old_wv->name)) + { + val->call_data = old_wv->call_data; + break; + } + + if (XtIsSubclass (widget, toggleWidgetClass)) + { + Arg al [1]; + XtSetArg (al [0], XtNstate, &val->selected); + XtGetValues (widget, al, 1); + val->edited = True; + } +#if 0 + else if (XtIsSubclass (widget, asciiTextWidgetClass)) + { + if (val->value) + free (val->value); + val->value = XawTextGetString (widget); + val->edited = True; + } +#endif +#endif /* LWLIB_WIDGETS_ATHENA */ } void @@ -440,7 +499,21 @@ Widget instance_widget; LWLIB_ID id; XtPointer user_data; +#ifdef LWLIB_WIDGETS_ATHENA + /* We want the selected status to change only when we decide it + should change. Yuck but correct. */ + if (XtIsSubclass (widget, toggleWidgetClass)) + { + Boolean check; + Arg al [1]; + + XtSetArg (al [0], XtNstate, &check); + XtGetValues (widget, al, 1); + XtSetArg (al [0], XtNstate, !check); + XtSetValues (widget, al, 1); + } +#endif /* LWLIB_WIDGETS_ATHENA */ lw_internal_update_other_instances (widget, closure, call_data); if (! instance) @@ -464,17 +537,26 @@ #else /* Damn! Athena doesn't give us a way to hang our own data on the buttons, so we have to go find it... I guess this assumes that - all instances of a button have the same call data. */ + all instances of a button have the same call data. + + ... Which is a totally bogus assumption --andyp */ { - widget_value *val = instance->info->val->contents; - char *name = XtName (widget); - while (val) + widget_value *val = instance->info->val; + /* If the widget is a buffer/gutter widget then we already have + the one we are looking for, so don't try and descend the widget + tree. */ + if (val->contents) { - if (val->name && !strcmp (val->name, name)) - break; - val = val->next; + char *name = XtName (widget); + val = val->contents; + while (val) + { + if (val->name && !strcmp (val->name, name)) + break; + val = val->next; + } + if (! val) abort (); } - if (! val) abort (); user_data = val->call_data; } #endif @@ -614,12 +696,151 @@ } #endif /* LWLIB_SCROLLBARS_ATHENA */ +#ifdef LWLIB_WIDGETS_ATHENA +/* glyph widgets */ +static Widget +xaw_create_button (widget_instance *instance) +{ + Arg al[20]; + int ac = 0; + Widget button = 0; + widget_value* val = instance->info->val; + + XtSetArg (al [ac], XtNsensitive, val->enabled); ac++; + XtSetArg (al [ac], XtNmappedWhenManaged, FALSE); ac++; + XtSetArg (al [ac], XtNjustify, XtJustifyCenter); ac++; + /* The highlight doesn't appear to be dynamically set which makes it + look ugly. I think this may be a LessTif bug but for now we just + get rid of it. */ + XtSetArg (al [ac], XtNhighlightThickness, (Dimension)0);ac++; + + /* add any args the user supplied for creation time */ + lw_add_value_args_to_args (val, al, &ac); + + if (!val->call_data) + button = XtCreateManagedWidget (val->name, labelWidgetClass, + instance->parent, al, ac); + + else + { + if (val->type == TOGGLE_TYPE || val->type == RADIO_TYPE) + { + XtSetArg (al [ac], XtNstate, val->selected); ac++; + button = XtCreateManagedWidget + (val->name, + val->type == TOGGLE_TYPE ? checkboxWidgetClass : radioWidgetClass, + instance->parent, al, ac); + } + else + { + button = XtCreateManagedWidget (val->name, commandWidgetClass, + instance->parent, al, ac); + } + XtRemoveAllCallbacks (button, XtNcallback); + XtAddCallback (button, XtNcallback, xaw_generic_callback, (XtPointer)instance); + } + + XtManageChild (button); + + return button; +} + +Widget +xaw_create_label (Widget parent, widget_value* val) +{ + Arg al[20]; + int ac = 0; + Widget label = 0; + + XtSetArg (al [ac], XtNsensitive, val->enabled); ac++; + XtSetArg (al [ac], XtNmappedWhenManaged, FALSE); ac++; + XtSetArg (al [ac], XtNjustify, XtJustifyCenter); ac++; + + /* add any args the user supplied for creation time */ + lw_add_value_args_to_args (val, al, &ac); + + label = XtCreateManagedWidget (val->name, labelWidgetClass, + parent, al, ac); + + return label; +} + +static Widget +xaw_create_progress (widget_instance *instance) +{ + Arg al[20]; + int ac = 0; + Widget scale = 0; + widget_value* val = instance->info->val; + + if (!val->call_data) + { + XtSetArg (al [ac], XtNsensitive, False); ac++; + } + else + { + XtSetArg (al [ac], XtNsensitive, val->enabled); ac++; + } + XtSetArg (al [ac], XtNmappedWhenManaged, FALSE); ac++; + XtSetArg (al [ac], XtNorientation, XtorientHorizontal); ac++; + XtSetArg (al [ac], XtNhighlightThickness, (Dimension)0);ac++; + XtSetArg (al [ac], XtNntics, (Cardinal)10);ac++; + + /* add any args the user supplied for creation time */ + lw_add_value_args_to_args (val, al, &ac); + + scale = XtCreateManagedWidget (val->name, gaugeWidgetClass, + instance->parent, al, ac); + /* add the callback */ + if (val->call_data) + XtAddCallback (scale, XtNgetValue, xaw_generic_callback, (XtPointer)instance); + + XtManageChild (scale); + + return scale; +} + +#if 0 +static Widget +xaw_create_text_field (widget_instance *instance) +{ + Arg al[20]; + int ac = 0; + Widget text = 0; + widget_value* val = instance->info->val; + + XtSetArg (al [ac], XtNsensitive, val->enabled && val->call_data); ac++; + XtSetArg (al [ac], XtNmappedWhenManaged, FALSE); ac++; + XtSetArg (al [ac], XtNhighlightThickness, (Dimension)0); ac++; + XtSetArg (al [ac], XtNtype, XawAsciiString); ac++; + XtSetArg (al [ac], XtNeditType, XawtextEdit); ac++; + + /* add any args the user supplied for creation time */ + lw_add_value_args_to_args (val, al, &ac); + + text = XtCreateManagedWidget (val->name, asciiTextWidgetClass, + instance->parent, al, ac); + XtManageChild (text); + + return text; +} +#endif +#endif /* LWLIB_WIDGETS_ATHENA */ + widget_creation_entry xaw_creation_table [] = { #ifdef LWLIB_SCROLLBARS_ATHENA - {"vertical-scrollbar", xaw_create_vertical_scrollbar}, - {"horizontal-scrollbar", xaw_create_horizontal_scrollbar}, + {"vertical-scrollbar", xaw_create_vertical_scrollbar }, + {"horizontal-scrollbar", xaw_create_horizontal_scrollbar }, +#endif +#ifdef LWLIB_WIDGETS_ATHENA + {"button", xaw_create_button }, +#if 0 + {"text-field", xaw_create_text_field }, #endif + {"progress", xaw_create_progress }, +#endif {NULL, NULL} }; + Index: lwlib/lwlib-Xaw.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-Xaw.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 lwlib-Xaw.h --- lwlib/lwlib-Xaw.h 1996/12/18 22:43:40 1.1.1.1 +++ lwlib/lwlib-Xaw.h 1999/07/28 08:33:43 @@ -8,6 +8,9 @@ Widget xaw_create_dialog (widget_instance* instance); +Widget +xaw_create_label (Widget parent, widget_value* val); + Boolean lw_xaw_widget_p (Widget widget); Index: lwlib/lwlib-Xlw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-Xlw.c,v retrieving revision 1.7 diff -u -r1.7 lwlib-Xlw.c --- lwlib/lwlib-Xlw.c 1998/01/19 01:57:48 1.7 +++ lwlib/lwlib-Xlw.c 1999/07/28 08:33:43 @@ -23,6 +23,7 @@ #include #include "lwlib-Xlw.h" +#include "lwlib-utils.h" #include #include #include @@ -34,6 +35,15 @@ #ifdef LWLIB_SCROLLBARS_LUCID #include "xlwscrollbar.h" #endif +#ifdef LWLIB_TABS_LUCID +#ifdef NEED_MOTIF +#include "lwlib-Xm.h" +#endif +#ifdef NEED_ATHENA +#include "lwlib-Xaw.h" +#endif +#include "xlwtabs.h" +#endif @@ -301,6 +311,144 @@ #endif /* LWLIB_SCROLLBARS_LUCID */ +#ifdef LWLIB_TABS_LUCID +/* tab control + + lwlib is such an incredible hairy crock. I just cannot believe + it! There are random dependencies between functions, there is a + total lack of genericity, even though it initially appears to be + generic. It should all be junked and begun again. Building tabs are + an example - in theory we should be able to reuse a lot of the + general stuff because we want to put labels of whatever toolkit we + are using in the tab. Instead we have to hack it by hand. */ +static void +xlw_tab_control_callback (Widget w, XtPointer client_data, XtPointer call_data) +{ + /* call data is the topmost widget */ + widget_instance* instance = (widget_instance*)client_data; + Widget top = (Widget)call_data; + char *name = XtName (top); + widget_value* widget_val; + XtPointer widget_arg; + LWLIB_ID id; + lw_callback post_activate_cb; + + if (w->core.being_destroyed) + return; + + /* Grab these values before running any functions, in case running + the selection_cb causes the widget to be destroyed. */ + id = instance->info->id; + post_activate_cb = instance->info->post_activate_cb; + + /* search for the widget_val for the selected tab */ + for (widget_val = instance->info->val->contents; widget_val; + widget_val = widget_val->next) + { + if (!strcmp (widget_val->name, name)) + break; + } + + widget_arg = widget_val ? widget_val->call_data : NULL; + + if (instance->info->selection_cb && + widget_val && + widget_val->enabled && + !widget_val->contents) + instance->info->selection_cb (w, id, widget_arg); + + if (post_activate_cb) + post_activate_cb (w, id, widget_arg); +} + +static Widget +xlw_create_tab_control (widget_instance *instance) +{ + Arg al[20]; + int ac = 0; + Widget tab = 0; + widget_value* val = instance->info->val; + + XtSetArg (al [ac], XtNsensitive, val->enabled); ac++; + XtSetArg (al [ac], XtNmappedWhenManaged, FALSE); ac++; + + /* add any args the user supplied for creation time */ + lw_add_value_args_to_args (val, al, &ac); + + tab = XtCreateManagedWidget (val->name, tabsWidgetClass, + instance->parent, al, ac); + XtRemoveAllCallbacks (tab, XtNcallback); + XtAddCallback (tab, XtNcallback, xlw_tab_control_callback, (XtPointer)instance); + + XtManageChild (tab); + + return tab; +} + +static void build_tabs_in_widget (widget_instance* instance, Widget widget, + widget_value* val) +{ + widget_value* cur = val; + for (cur = val; cur; cur = cur->next) + { + if (cur->value) + { +#ifdef LWLIB_WIDGETS_MOTIF + xm_create_label (widget, cur); +#else + xaw_create_label (widget, cur); +#endif + } + cur->change = NO_CHANGE; + } +} + +static void +xlw_update_tab_control (widget_instance* instance, Widget widget, widget_value* val) +{ + Widget* children; + unsigned int num_children; + int i; + widget_value *cur = 0; + + XtRemoveAllCallbacks (widget, XtNcallback); + XtAddCallback (widget, XtNcallback, xlw_tab_control_callback, (XtPointer)instance); + + if (val->change == STRUCTURAL_CHANGE + || + (val->contents && val->contents->change == STRUCTURAL_CHANGE)) + { + destroy_all_children (widget); + build_tabs_in_widget (instance, widget, val->contents); + } + + children = XtCompositeChildren (widget, &num_children); + if (children) + { + for (i = 0, cur = val->contents; i < num_children; i++) + { + if (!cur) + abort (); + if (children [i]->core.being_destroyed + || strcmp (XtName (children [i]), cur->name)) + continue; +#ifdef NEED_MOTIF + if (lw_motif_widget_p (children [i])) + xm_update_one_widget (instance, children [i], val, False); +#endif +#ifdef NEED_ATHENA + if (lw_xaw_widget_p (children [i])) + xaw_update_one_widget (instance, children [i], val, False); +#endif + cur = cur->next; + } + XtFree ((char *) children); + } + if (cur) + abort (); +} +#endif /* LWLIB_TABS_LUCID */ + widget_creation_entry xlw_creation_table [] = { @@ -312,6 +460,9 @@ {"vertical-scrollbar", xlw_create_vertical_scrollbar}, {"horizontal-scrollbar", xlw_create_horizontal_scrollbar}, #endif +#ifdef LWLIB_TABS_LUCID + {"tab-control", xlw_create_tab_control}, +#endif {NULL, NULL} }; @@ -327,6 +478,10 @@ if (the_class == xlwScrollBarWidgetClass) return True; #endif +#ifdef LWLIB_TABS_LUCID + if (the_class == tabsWidgetClass) + return True; +#endif #ifdef LWLIB_MENUBARS_LUCID if (the_class == overrideShellWidgetClass) return @@ -340,10 +495,8 @@ xlw_update_one_widget (widget_instance* instance, Widget widget, widget_value* val, Boolean deep_p) { - WidgetClass class; + WidgetClass class = XtClass (widget); - class = XtClass (widget); - if (0) ; #ifdef LWLIB_MENUBARS_LUCID @@ -363,6 +516,12 @@ else if (class == xlwScrollBarWidgetClass) { xlw_update_scrollbar (instance, widget, val); + } +#endif +#ifdef LWLIB_TABS_LUCID + else if (class == tabsWidgetClass) + { + xlw_update_tab_control (instance, widget, val); } #endif } Index: lwlib/lwlib-Xm.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-Xm.c,v retrieving revision 1.11.2.3 diff -u -r1.11.2.3 lwlib-Xm.c --- lwlib/lwlib-Xm.c 1999/07/05 16:35:14 1.11.2.3 +++ lwlib/lwlib-Xm.c 1999/07/28 08:33:47 @@ -60,10 +60,12 @@ #include #include #include +#ifdef LWLIB_WIDGETS_MOTIF #include #if XmVERSION > 1 #include #endif +#endif #ifdef LWLIB_MENUBARS_MOTIF static void xm_pull_down_callback (Widget, XtPointer, XtPointer); @@ -171,35 +173,6 @@ return result; } -#ifdef LWLIB_MENUBARS_MOTIF - -static void -destroy_all_children (Widget widget) -{ - Widget* children; - unsigned int number; - int i; - - children = XtCompositeChildren (widget, &number); - if (children) - { - /* Unmanage all children and destroy them. They will only be - * really destroyed when we get out of DispatchEvent. */ - for (i = 0; i < number; i++) - { - Widget child = children [i]; - if (!child->core.being_destroyed) - { - XtUnmanageChild (child); - XtDestroyWidget (child); - } - } - XtFree ((char *) children); - } -} - -#endif /* LWLIB_MENUBARS_MOTIF */ - #ifdef LWLIB_DIALOGS_MOTIF @@ -221,7 +194,7 @@ #endif /* LWLIB_DIALOGS_MOTIF */ -#if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) +#if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) /* update the label of anything subclass of a label */ static void @@ -777,12 +750,11 @@ XtSetArg (al [1], XmNuserData, val->call_data); XtSetValues (widget, al, 2); -#if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) +#if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) /* Common to all label like widgets */ if (XtIsSubclass (widget, xmLabelWidgetClass)) xm_update_label (instance, widget, val); -#endif /* defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) */ - +#endif class = XtClass (widget); /* Class specific things */ if (class == xmPushButtonWidgetClass || @@ -1566,9 +1538,10 @@ #endif /* LWLIB_SCROLLBARS_MOTIF */ +#ifdef LWLIB_WIDGETS_MOTIF /* glyph widgets */ static Widget -make_button (widget_instance *instance) +xm_create_button (widget_instance *instance) { Arg al[20]; int ac = 0; @@ -1615,14 +1588,21 @@ } static Widget -make_progress (widget_instance *instance) +xm_create_progress (widget_instance *instance) { Arg al[20]; int ac = 0; Widget scale = 0; widget_value* val = instance->info->val; - XtSetArg (al [ac], XmNsensitive, val->enabled); ac++; + if (!val->call_data) + { + XtSetArg (al [ac], XmNsensitive, False); ac++; + } + else + { + XtSetArg (al [ac], XmNsensitive, val->enabled); ac++; + } XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; XtSetArg (al [ac], XmNuserData, val->call_data); ac++; XtSetArg (al [ac], XmNmappedWhenManaged, FALSE); ac++; @@ -1631,9 +1611,6 @@ look ugly. I think this may be a LessTif bug but for now we just get rid of it. */ XtSetArg (al [ac], XmNhighlightThickness, (Dimension)0);ac++; - if (!val->call_data) - XtSetArg (al [ac], XmNsensitive, False); ac++; - /* add any args the user supplied for creation time */ lw_add_value_args_to_args (val, al, &ac); @@ -1648,7 +1625,7 @@ } static Widget -make_text_field (widget_instance *instance) +xm_create_text_field (widget_instance *instance) { Arg al[20]; int ac = 0; @@ -1677,9 +1654,34 @@ return text; } +Widget +xm_create_label (Widget parent, widget_value* val) +{ + Arg al[20]; + int ac = 0; + Widget label = 0; + + XtSetArg (al [ac], XmNsensitive, val->enabled); ac++; + XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; + XtSetArg (al [ac], XmNmappedWhenManaged, FALSE); ac++; + /* The highlight doesn't appear to be dynamically set which makes it + look ugly. I think this may be a LessTif bug but for now we just + get rid of it. */ + XtSetArg (al [ac], XmNhighlightThickness, (Dimension)0);ac++; + + /* add any args the user supplied for creation time */ + lw_add_value_args_to_args (val, al, &ac); + + label = XmCreateLabel (parent, val->name, al, ac); + + XtManageChild (label); + + return label; +} + #if XmVERSION > 1 static Widget -make_combo_box (widget_instance *instance) +xm_create_combo_box (widget_instance *instance) { Arg al[20]; int ac = 0; @@ -1708,6 +1710,7 @@ return combo; } #endif +#endif /* LWLIB_WIDGETS_MOTIF */ /* Table of functions to create widgets */ @@ -1723,12 +1726,14 @@ {"vertical-scrollbar", make_vertical_scrollbar}, {"horizontal-scrollbar", make_horizontal_scrollbar}, #endif - {"button", make_button}, - {"progress", make_progress}, - {"text-field", make_text_field}, +#ifdef LWLIB_WIDGETS_MOTIF + {"button", xm_create_button}, + {"progress", xm_create_progress}, + {"text-field", xm_create_text_field}, #if XmVERSION > 1 - {"combo-box", make_combo_box}, + {"combo-box", xm_create_combo_box}, #endif +#endif {NULL, NULL} }; @@ -1736,7 +1741,7 @@ void xm_destroy_instance (widget_instance* instance) { -#ifdef LWLIB_DIALOGS_MOTIF +#if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) /* It appears that this is used only for dialog boxes. */ Widget widget = instance->widget; /* recycle the dialog boxes */ @@ -1767,7 +1772,7 @@ XtDestroyWidget (instance->widget); } -#endif /* LWLIB_DIALOGS_MOTIF */ +#endif /* LWLIB_DIALOGS_MOTIF || LWLIB_WIDGETS_MOTIF */ } /* popup utility */ @@ -1920,7 +1925,7 @@ static void xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data) { -#if (defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_DIALOGS_MOTIF)) +#if (defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF)) /* We want the selected status to change only when we decide it should change. Yuck but correct. */ if (XtClass (widget) == xmToggleButtonWidgetClass Index: lwlib/lwlib-Xm.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-Xm.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 lwlib-Xm.h --- lwlib/lwlib-Xm.h 1996/12/18 22:43:39 1.1.1.1 +++ lwlib/lwlib-Xm.h 1999/07/28 08:33:47 @@ -8,6 +8,9 @@ Widget xm_create_dialog (widget_instance* instance); +Widget +xm_create_label (Widget parent, widget_value* val); + Boolean lw_motif_widget_p (Widget widget); Index: lwlib/lwlib-config.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-config.c,v retrieving revision 1.6 diff -u -r1.6 lwlib-config.c --- lwlib/lwlib-config.c 1998/01/19 01:57:48 1.6 +++ lwlib/lwlib-config.c 1999/07/28 08:33:47 @@ -88,3 +88,13 @@ int lwlib_does_not_support_dialogs; # endif #endif + +#ifdef LWLIB_WIDGETS_MOTIF +int lwlib_widgets_motif; +#else +# ifdef LWLIB_WIDGETS_ATHENA +int lwlib_widgets_athena; +# else +int lwlib_does_not_support_widgets; +# endif +#endif Index: lwlib/lwlib-internal.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-internal.h,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 lwlib-internal.h --- lwlib/lwlib-internal.h 1996/12/18 22:43:40 1.1.1.1 +++ lwlib/lwlib-internal.h 1999/07/28 08:33:47 @@ -52,6 +52,7 @@ /* get the widget_value for a widget in a given instance */ widget_value* lw_get_widget_value_for_widget (widget_instance* instance, Widget w); +void destroy_all_children (Widget widget); widget_info *lw_get_widget_info (LWLIB_ID id); Index: lwlib/lwlib-utils.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib-utils.c,v retrieving revision 1.5 diff -u -r1.5 lwlib-utils.c --- lwlib/lwlib-utils.c 1997/06/26 02:31:59 1.5 +++ lwlib/lwlib-utils.c 1999/07/28 08:33:47 @@ -31,6 +31,31 @@ #include #include "lwlib-utils.h" +void +destroy_all_children (Widget widget) +{ + Widget* children; + unsigned int number; + int i; + + children = XtCompositeChildren (widget, &number); + if (children) + { + /* Unmanage all children and destroy them. They will only be + * really destroyed when we get out of DispatchEvent. */ + for (i = 0; i < number; i++) + { + Widget child = children [i]; + if (!child->core.being_destroyed) + { + XtUnmanageChild (child); + XtDestroyWidget (child); + } + } + XtFree ((char *) children); + } +} + /* Redisplay the contents of the widget, without first clearing it. */ void XtNoClearRefreshWidget (Widget widget) Index: lwlib/lwlib.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/lwlib/lwlib.c,v retrieving revision 1.13.2.1 diff -u -r1.13.2.1 lwlib.c --- lwlib/lwlib.c 1999/06/25 14:16:43 1.13.2.1 +++ lwlib/lwlib.c 1999/07/28 08:33:50 @@ -1326,3 +1326,4 @@ *offset += wv->nargs; } } + Index: lwlib/xlwcheckbox.c =================================================================== RCS file: xlwcheckbox.c diff -N xlwcheckbox.c --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwcheckbox.c Wed Jul 28 01:33:52 1999 @@ -0,0 +1,420 @@ +/* Checkbox Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Checkbox.c 1.1 */ + +/* + * Checkbox.c - Checkbox button widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: June 30, 1997 + * + * Overview: This widget is identical to the Radio widget in behavior, + * except that the button is square and has a check mark. + */ + + +#include + +#include +#include +#include +#include +#include +#include "xlwcheckboxP.h" + + +/* by using the same size for the checkbox as for the diamond box, + * we can let the Radio widget do the vast majority of the work. + */ + +#define BOX_SIZE 8 +#define DRAW_CHECK 0 /* don't draw the check mark */ + +#define cclass(w) ((CheckboxWidgetClass)((w)->core.widget_class)) + +#ifdef _ThreeDP_h +#define swid(cw) ((cw)->threeD.shadow_width) +#else +#define swid(cw) ((cw)->core.border_width) +#endif + +#define bsize(cw) (cclass(cw)->radio_class.dsize) +#define bs(cw) (bsize(cw) + 2*swid(cw)) + + +#if DRAW_CHECK +#define check_width 14 +#define check_height 14 +static u_char check_bits[] = { + 0x00, 0x00, 0x00, 0x20, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x03, + 0x8c, 0x03, 0xde, 0x01, 0xff, 0x01, 0xfe, 0x00, 0xfc, 0x00, 0x78, 0x00, + 0x70, 0x00, 0x20, 0x00}; +#endif + + +/**************************************************************** + * + * Full class record constant + * + ****************************************************************/ + + +#if DRAW_CHECK +static char defaultTranslations[] = + ": highlight()\n\ + : unpress(draw) unhighlight()\n\ + : press()\n\ + ,: unpress(nodraw) toggle() notify()"; +#endif + + + +#define offset(field) XtOffsetOf(CheckboxRec, field) +static XtResource resources[] = { + {XtNtristate, XtCTristate, XtRBoolean, sizeof(Boolean), + offset(checkbox.tristate), XtRImmediate, (XtPointer)FALSE}, +} ; +#undef offset + + /* Member functions */ + +static void CheckboxClassInit() ; +static void CheckboxInit(); +#if DRAW_CHECK +static void CheckboxRealize() ; +#endif +static void DrawCheck() ; + + + /* Action procs */ +#if DRAW_CHECK +static void CheckboxPress(), CheckboxUnpress() ; +#endif +extern void RadioSet(), RadioUnset() ; + + + /* internal privates */ + +#if DRAW_CHECK +static XtActionsRec actionsList[] = +{ + {"press", CheckboxPress}, + {"unpress", CheckboxUnpress}, +} ; +#endif + +#define SuperClass ((RadioWidgetClass)&radioClassRec) + +CheckboxClassRec checkboxClassRec = { + { + (WidgetClass) SuperClass, /* superclass */ + "Checkbox", /* class_name */ + sizeof(CheckboxRec), /* size */ + CheckboxClassInit, /* class_initialize */ + NULL, /* class_part_initialize */ + FALSE, /* class_inited */ + CheckboxInit, /* initialize */ + NULL, /* initialize_hook */ +#if DRAW_CHECK + CheckboxRealize, /* realize */ + actionsList, /* actions */ + XtNumber(actionsList), /* num_actions */ +#else + XtInheritRealize, /* realize */ + NULL, /* actions */ + 0, /* num_actions */ +#endif + resources, /* resources */ + XtNumber(resources), /* resource_count */ + NULLQUARK, /* xrm_class */ + TRUE, /* compress_motion */ + TRUE, /* compress_exposure */ + TRUE, /* compress_enterleave */ + FALSE, /* visible_interest */ + NULL, /* destroy */ + XtInheritResize, /* resize */ + XtInheritExpose, /* expose */ + NULL, /* set_values */ + NULL, /* set_values_hook */ + XtInheritSetValuesAlmost, /* set_values_almost */ + NULL, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_private */ +#if DRAW_CHECK + defaultTranslations, /* tm_table */ +#else + XtInheritTranslations, /* tm_table */ +#endif + XtInheritQueryGeometry, /* query_geometry */ + XtInheritDisplayAccelerator, /* display_accelerator */ + NULL /* extension */ + }, /* CoreClass fields initialization */ + { + XtInheritChangeSensitive /* change_sensitive */ + }, /* SimpleClass fields initialization */ +#ifdef _ThreeDP_h + { + XtInheritXaw3dShadowDraw /* field not used */ + }, /* ThreeDClass fields initialization */ +#endif + { + 0 /* field not used */ + }, /* LabelClass fields initialization */ + { + 0 /* field not used */ + }, /* CommandClass fields initialization */ + { + RadioSet, /* Set Procedure. */ + RadioUnset, /* Unset Procedure. */ + NULL /* extension. */ + }, /* ToggleClass fields initialization */ + { + BOX_SIZE, + DrawCheck, /* draw procedure */ + NULL /* extension. */ + }, /* RadioClass fields initialization */ + { + NULL /* extension. */ + }, /* CheckboxClass fields initialization */ +}; + + /* for public consumption */ +WidgetClass checkboxWidgetClass = (WidgetClass) &checkboxClassRec; + + + + + + +/**************************************************************** + * + * Class Methods + * + ****************************************************************/ + +static void +CheckboxClassInit() +{ + XawInitializeWidgetSet(); +} + + +/*ARGSUSED*/ +static void +CheckboxInit(request, new, args, num_args) + Widget request, new; + ArgList args; + Cardinal *num_args; +{ +#if DRAW_CHECK + CheckboxWidget cw = (CheckboxWidget) new; + cw->checkbox.checkmark = None ; + cw->checkbox.checkmark_GC = None ; +#endif +} + + +#if DRAW_CHECK +static void +CheckboxRealize(w, valueMask, attributes) + Widget w ; + Mask *valueMask ; + XSetWindowAttributes *attributes ; +{ + CheckboxWidget cw = (CheckboxWidget) w; + XtGCMask value_mask, dynamic_mask, dontcare_mask ; + XGCValues values ; + + /* first, call superclass realize */ + (*checkboxWidgetClass->core_class.superclass->core_class.realize) + (w, valueMask, attributes); + + /* TODO: cache this via xmu */ + if( cw->checkbox.checkmark == None ) + cw->checkbox.checkmark = + XCreateBitmapFromData( XtDisplay(w), XtWindow(w), + check_bits,check_width,check_height); + + values.fill_style = FillStippled ; + values.stipple = cw->checkbox.checkmark ; + values.foreground = cw->label.foreground ; + value_mask = GCFillStyle | GCStipple | GCForeground ; + dynamic_mask = GCTileStipXOrigin | GCTileStipYOrigin ; + dontcare_mask = GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle | + GCFont | GCSubwindowMode | GCGraphicsExposures | + GCDashOffset | GCDashList | GCArcMode ; + cw->checkbox.checkmark_GC = + XtAllocateGC(w, 0, value_mask, &values, dynamic_mask, dontcare_mask) ; +} +#endif + + +/* Function Name: CheckboxDestroy + * Description: Destroy Callback for checkbox widget. + * Arguments: w - the checkbox widget that is being destroyed. + * junk, grabage - not used. + * Returns: none. + */ + +/* ARGSUSED */ +static void +CheckboxDestroy(w, junk, garbage) +Widget w; +XtPointer junk, garbage; +{ +#if DRAW_CHECK + CheckboxWidget cw = (CheckboxWidget) w; + + /* TODO: cache this via xmu */ + if( cw->checkbox.checkmark != None ) + XFreePixmap( XtDisplay(w), cw->checkbox.checkmark ) ; + if( cw->checkbox.checkmark_GC != None ) + XtReleaseGC(w, cw->checkbox.checkmark_GC) ; +#endif +} + + + +#if DRAW_CHECK +/************************************************************ + * + * Actions Procedures + * + ************************************************************/ + +/* ARGSUSED */ +static void +CheckboxPress(w,event,params,num_params) + Widget w; + XEvent *event; + String *params; /* unused */ + Cardinal *num_params; /* unused */ +{ + CheckboxWidget cw = (CheckboxWidget) w ; + if( !cw->checkbox.pressed ) { + cw->checkbox.pressed = TRUE ; + ((CheckboxWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w) ; + } +} + +static void +CheckboxUnpress(w,event,params,num_params) + Widget w; + XEvent *event; + String *params; /* unused */ + Cardinal *num_params; /* unused */ +{ + CheckboxWidget cw = (CheckboxWidget) w ; + int i ; + + if( cw->checkbox.pressed ) { + cw->checkbox.pressed = FALSE ; + if( *num_params > 0 && **params == 'd' ) + ((CheckboxWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w); + } +} +#endif + + + + + +/************************************************************ + * + * Internal Procedures + * + ************************************************************/ + +static void +DrawCheck(w) + Widget w ; +{ + CheckboxWidget cw = (CheckboxWidget) w ; + Display *dpy = XtDisplay(w) ; + Window win = XtWindow(w) ; + GC gc ; + +#ifdef _ThreeDP_h + XPoint pts[6] ; +#endif + Dimension s = swid(cw); + Dimension bsz = bsize(cw); + Position bx,by ; /* Check upper-left */ + Dimension bw,bh ; +#ifdef _ThreeDP_h + GC top, bot; +#endif + GC ctr ; + + /* foreground GC */ + gc = XtIsSensitive(w) ? cw->command.normal_GC : cw->label.gray_GC ; + + bw = bh = bs(cw) ; + bx = cw->label.internal_width ; + by = cw->core.height/2 - bh/2 ; + +#ifdef _ThreeDP_h + if( !cw->command.set ) { + top = cw->threeD.top_shadow_GC ; + bot = cw->threeD.bot_shadow_GC ; + } else { + top = cw->threeD.bot_shadow_GC ; + bot = cw->threeD.top_shadow_GC ; + } + ctr = cw->command.inverse_GC ; +#else + ctr = cw->command.set ? cw->command.normal_GC : cw->command.inverse_GC ; +#endif + + XFillRectangle(dpy,win,ctr, bx+s,by+s, bsz,bsz) ; + +#ifdef _ThreeDP_h + /* top-left shadow */ + pts[0].x = bx ; pts[0].y = by ; + pts[1].x = bw ; pts[1].y = 0 ; + pts[2].x = -s ; pts[2].y = s ; + pts[3].x = -bsz ; pts[3].y = 0 ; + pts[4].x = 0 ; pts[4].y = bsz ; + pts[5].x = -s ; pts[5].y = s ; + XFillPolygon(dpy,win,top, pts,6, Nonconvex,CoordModePrevious) ; + /* bottom-right shadow */ + pts[0].x = bx+bw ; pts[0].y = by+bh ; + pts[1].x = -bw ; pts[1].y = 0 ; + pts[2].x = s ; pts[2].y = -s ; + pts[3].x = bsz ; pts[3].y = 0 ; + pts[4].x = 0 ; pts[4].y = -bsz ; + pts[5].x = s ; pts[5].y = -s ; + XFillPolygon(dpy,win,bot, pts,6, Nonconvex,CoordModePrevious) ; +#else + XDrawRectangle(dpy,win,gc, bx+s,by+s, bsz,bsz) ; +#endif + +#if DRAW_CHECK + if( cw->command.set && cw->checkbox.checkmark_GC != None ) { + XSetTSOrigin(dpy,cw->checkbox.checkmark_GC, bx+s, by+s) ; + XFillRectangle(dpy,win,cw->checkbox.checkmark_GC, + bx+s, by+s, check_width,check_height) ; + } +#endif +} Index: lwlib/xlwcheckbox.h =================================================================== RCS file: xlwcheckbox.h diff -N xlwcheckbox.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwcheckbox.h Wed Jul 28 01:33:52 1999 @@ -0,0 +1,103 @@ +/* Checkbox Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Checkbox.h 1.1 */ + +/* + * Checkbox.h - Checkbox widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: June 30, 1997 + */ + +#ifndef _XawCheckbox_h +#define _XawCheckbox_h + +/*********************************************************************** + * + * Checkbox Widget + * + * The Checkbox widget is identical to the Radio widget in behavior but + * not in appearance. The Checkbox widget looks like a small diamond + * shaped button to the left of the label. + * + ***********************************************************************/ + +#include "xlwradio.h" + +/* Resources: + + Name Class RepType Default Value + ---- ----- ------- ------------- + tristate Tristate Boolean FALSE + + radioGroup RadioGroup Widget NULL + radioData RadioData Pointer (XPointer) Widget + state State Boolean Off + background Background Pixel XtDefaultBackground + bitmap Pixmap Pixmap None + border BorderColor Pixel XtDefaultForeground + borderWidth BorderWidth Dimension 1 + callback Callback Pointer NULL + cursor Cursor Cursor None + destroyCallback Callback Pointer NULL + font Font XFontStructx* XtDefaultFont + foreground Foreground Pixel XtDefaultForeground + height Height Dimension text height + highlightThickness Thickness Dimension 2 + insensitiveBorder sensitive Pixmap Gray + internalHeight Height Dimension 2 + internalWidth Width Dimension 4 + justify Justify XtJustify XtJustifyCenter + label Label String NULL + mappedWhenManaged MappedWhenManaged Boolean True + resize Resize Boolean True + sensitive Sensitive Boolean True + width Width Dimension text width + x Position Position 0 + y Position Position 0 + +*/ + +/* + * These should be in StringDefs.h but aren't so we will define + * them here if they are needed. + */ + + +#define XtCTristate "Tristate" + +#define XtNtristate "tristate" + +extern WidgetClass checkboxWidgetClass; + +typedef struct _CheckboxClassRec *CheckboxWidgetClass; +typedef struct _CheckboxRec *CheckboxWidget; + + +/************************************************************ + * + * Public Functions + * + ************************************************************/ + +#endif /* _XawCheckbox_h */ Index: lwlib/xlwcheckboxP.h =================================================================== RCS file: xlwcheckboxP.h diff -N xlwcheckboxP.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwcheckboxP.h Wed Jul 28 01:33:52 1999 @@ -0,0 +1,95 @@ +/* Checkbox Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + * CheckboxP.h - Private definitions for Checkbox widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: June 30, 1997 + */ + +#ifndef _XawCheckboxP_h +#define _XawCheckboxP_h + +#include "xlwcheckbox.h" +#include "xlwradioP.h" + +/************************************ + * + * Class structure + * + ***********************************/ + + /* New fields for the Checkbox widget class record */ +typedef struct _CheckboxClass { + XtPointer extension; +} CheckboxClassPart; + + /* Full class record declaration */ +typedef struct _CheckboxClassRec { + CoreClassPart core_class; + SimpleClassPart simple_class; +#ifdef _ThreeDP_h + ThreeDClassPart threeD_class; +#endif + LabelClassPart label_class; + CommandClassPart command_class; + ToggleClassPart toggle_class; + RadioClassPart radio_class; + CheckboxClassPart checkbox_class; +} CheckboxClassRec; + +extern CheckboxClassRec checkboxClassRec; + +/*************************************** + * + * Instance (widget) structure + * + **************************************/ + + /* New fields for the Checkbox widget record */ +typedef struct { + /* resources */ + Boolean tristate ; + + /* private data */ + Boolean pressed ; + Pixmap checkmark ; /* TODO: share these via xmu? */ + GC checkmark_GC ; + XtPointer extension; +} CheckboxPart; + + /* Full widget declaration */ +typedef struct _CheckboxRec { + CorePart core; + SimplePart simple; +#ifdef _ThreeDP_h + ThreeDPart threeD; +#endif + LabelPart label; + CommandPart command; + TogglePart toggle; + RadioPart radio; + CheckboxPart checkbox; +} CheckboxRec; + +#endif /* _XawCheckboxP_h */ Index: lwlib/xlwgauge.c =================================================================== RCS file: xlwgauge.c diff -N xlwgauge.c --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwgauge.c Wed Jul 28 01:33:55 1999 @@ -0,0 +1,1125 @@ +/* Gauge Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Gauge.c 1.2 */ + +/* + * Gauge.c - Gauge widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: July 9, 1997 + * + * Note: for fun and demonstration purposes, I have added selection + * capabilities to this widget. If you select the widget, you create + * a primary selection containing the current value of the widget in + * both integer and string form. If you copy into the widget, the + * primary selection is converted to an integer value and the gauge is + * set to that value. + */ + +/* TODO: display time instead of value + */ + +#define DEF_LEN 50 /* default width (or height for vertical gauge) */ +#define MIN_LEN 10 /* minimum reasonable width (height) */ +#define TIC_LEN 6 /* length of tic marks */ +#define GA_WID 3 /* width of gauge */ +#define MS_PER_SEC 1000 + +#include +#include +#include +#include +#include +#include "xlwgaugeP.h" + +#include +#include +#include +#include + +#include +#include + + + +/**************************************************************** + * + * Gauge resources + * + ****************************************************************/ + + +static char defaultTranslations[] = + ": select()\n\ + F1: select(CLIPBOARD)\n\ + : paste()\n\ + F2: paste(CLIPBOARD)" ; + + + +#define offset(field) XtOffsetOf(GaugeRec, field) +static XtResource resources[] = { + {XtNvalue, XtCValue, XtRInt, sizeof(int), + offset(gauge.value), XtRImmediate, (XtPointer)0}, + {XtNminValue, XtCMinValue, XtRInt, sizeof(int), + offset(gauge.v0), XtRImmediate, (XtPointer)0}, + {XtNmaxValue, XtCMaxValue, XtRInt, sizeof(int), + offset(gauge.v1), XtRImmediate, (XtPointer)100}, + {XtNntics, XtCNTics, XtRInt, sizeof(int), + offset(gauge.ntics), XtRImmediate, (XtPointer) 0}, + {XtNnlabels, XtCNLabels, XtRInt, sizeof(int), + offset(gauge.nlabels), XtRImmediate, (XtPointer) 0}, + {XtNlabels, XtCLabels, XtRStringArray, sizeof(String *), + offset(gauge.labels), XtRStringArray, NULL}, + {XtNautoScaleUp, XtCAutoScaleUp, XtRBoolean, sizeof(Boolean), + offset(gauge.autoScaleUp), XtRImmediate, FALSE}, + {XtNautoScaleDown, XtCAutoScaleDown, XtRBoolean, sizeof(Boolean), + offset(gauge.autoScaleDown), XtRImmediate, FALSE}, + {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation), + offset(gauge.orientation), XtRImmediate, (XtPointer)XtorientHorizontal}, + {XtNupdate, XtCInterval, XtRInt, sizeof(int), + offset(gauge.update), XtRImmediate, (XtPointer)0}, + {XtNgetValue, XtCCallback, XtRCallback, sizeof(XtPointer), + offset(gauge.getValue), XtRImmediate, (XtPointer)NULL}, +}; +#undef offset + + + + /* member functions */ + +static void GaugeClassInit(), GaugeInit() ; +static void GaugeResize(), GaugeExpose(), GaugeDestroy() ; +static Boolean GaugeSetValues() ; +static XtGeometryResult GaugeQueryGeometry() ; + + /* action procs */ + +static void GaugeSelect() ; +static void GaugePaste() ; + + /* internal privates */ + +static void GaugeSize() ; /* return preferred gauge size */ +static void AutoScale() ; /* re compute v0,v1 */ +static void MaxLabel() ; /* find max label size */ +static void EnableUpdate(), DisableUpdate() ; +static void GaugeGetValue() ; +static void GaugeMercury() ; + +static Boolean GaugeConvert() ; +static void GaugeLoseSel() ; +static void GaugeDoneSel() ; +static void GaugeGetSelCB() ; + +static GC Get_GC() ; + + +static XtActionsRec actionsList[] = +{ + {"select", GaugeSelect}, + {"paste", GaugePaste}, +} ; + + + +/**************************************************************** + * + * Full class record constant + * + ****************************************************************/ + +GaugeClassRec gaugeClassRec = { + { +/* core_class fields */ + /* superclass */ (WidgetClass) &labelClassRec, + /* class_name */ "Gauge", + /* widget_size */ sizeof(GaugeRec), + /* class_initialize */ GaugeClassInit, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ GaugeInit, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, /* TODO? */ + /* actions */ actionsList, + /* num_actions */ XtNumber(actionsList), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ GaugeDestroy, + /* resize */ GaugeResize, + /* expose */ GaugeExpose, + /* set_values */ GaugeSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ defaultTranslations, + /* query_geometry */ GaugeQueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + }, +/* Simple class fields initialization */ + { + /* change_sensitive */ XtInheritChangeSensitive + }, +#ifdef _ThreeDP_h +/* ThreeD class fields initialization */ + { + XtInheritXaw3dShadowDraw /* shadowdraw */ + }, +#endif +/* Label class fields initialization */ + { + /* ignore */ 0 + }, +/* Gauge class fields initialization */ + { + /* extension */ NULL + }, +}; + +WidgetClass gaugeWidgetClass = (WidgetClass)&gaugeClassRec; + + + + +/**************************************************************** + * + * Member Procedures + * + ****************************************************************/ + +static void +GaugeClassInit() +{ + XawInitializeWidgetSet(); + XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation, + NULL, 0) ; +} + + + +/* ARGSUSED */ +static void +GaugeInit(request, new, args, num_args) + Widget request, new; + ArgList args; + Cardinal *num_args; +{ + GaugeWidget gw = (GaugeWidget) new; + + if( gw->gauge.v0 == 0 && gw->gauge.v1 == 0 ) { + gw->gauge.autoScaleUp = gw->gauge.autoScaleDown = TRUE ; + AutoScale(gw) ; + } + + /* If size not explicitly set, set it to our preferred size now. */ + + if( request->core.width == 0 || request->core.height == 0 ) + { + Dimension w,h ; + GaugeSize(gw, &w,&h, DEF_LEN) ; + if( request->core.width == 0 ) + new->core.width = w ; + if( request->core.height == 0 ) + new->core.height = h ; + gw->core.widget_class->core_class.resize(new) ; + } + + gw->gauge.selected = None ; + gw->gauge.selstr = NULL ; + + if( gw->gauge.update > 0 ) + EnableUpdate(gw) ; + + gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel) ; +} + +static void +GaugeDestroy(w) + Widget w; +{ + GaugeWidget gw = (GaugeWidget)w; + + if( gw->gauge.selstr != NULL ) + XtFree(gw->gauge.selstr) ; + + if( gw->gauge.selected != None ) + XtDisownSelection(w, gw->gauge.selected, CurrentTime) ; + + XtReleaseGC(w, gw->gauge.inverse_GC) ; + + if( gw->gauge.update > 0 ) + DisableUpdate(gw) ; +} + + +/* React to size change from manager. Label widget will compute some + * internal stuff, but we need to override. + */ + +static void +GaugeResize(w) + Widget w; +{ + GaugeWidget gw = (GaugeWidget)w; + int size ; /* height (width) of gauge */ + int vmargin ; /* vertical (horizontal) margin */ + int hmargin ; /* horizontal (vertical) margin */ + + vmargin = gw->gauge.orientation == XtorientHorizontal ? + gw->label.internal_height : gw->label.internal_width ; + hmargin = gw->gauge.orientation == XtorientHorizontal ? + gw->label.internal_width : gw->label.internal_height ; + + /* TODO: need to call parent resize proc? I don't think so since + * we're recomputing everything from scratch anyway. + */ + + /* find total height (width) of contents */ + + size = GA_WID+2 ; /* gauge itself + edges */ + + if( gw->gauge.ntics > 1 ) /* tic marks */ + size += vmargin + TIC_LEN ; + + if( gw->gauge.nlabels > 1 ) + { + Dimension lwm, lw0, lw1 ; /* width of max, left, right labels */ + Dimension lh ; + + MaxLabel(gw,&lwm,&lh, &lw0,&lw1) ; + + if( gw->gauge.orientation == XtorientHorizontal ) + { + gw->gauge.margin0 = lw0 / 2 ; + gw->gauge.margin1 = lw1 / 2 ; + size += lh + vmargin ; + } + else + { + gw->gauge.margin0 = + gw->gauge.margin1 = lh / 2 ; + size += lwm + vmargin ; + } + } + else + gw->gauge.margin0 = gw->gauge.margin1 = 0 ; + + gw->gauge.margin0 += hmargin ; + gw->gauge.margin1 += hmargin ; + + /* Now distribute height (width) over components */ + + if( gw->gauge.orientation == XtorientHorizontal ) + gw->gauge.gmargin = (gw->core.height-size)/2 ; + else + gw->gauge.gmargin = (gw->core.width-size)/2 ; + + gw->gauge.tmargin = gw->gauge.gmargin + GA_WID+2 + vmargin ; + if( gw->gauge.ntics > 1 ) + gw->gauge.lmargin = gw->gauge.tmargin + TIC_LEN + vmargin ; + else + gw->gauge.lmargin = gw->gauge.tmargin ; +} + +/* + * Repaint the widget window + */ + +/* ARGSUSED */ +static void +GaugeExpose(w, event, region) + Widget w; + XEvent *event; + Region region; +{ + GaugeWidget gw = (GaugeWidget) w; +register Display *dpy = XtDisplay(w) ; +register Window win = XtWindow(w) ; + GC gc; /* foreground, background */ + GC gctop, gcbot ; /* dark, light shadows */ + + int len ; /* length (width or height) of widget */ + int hgt ; /* height (width) of widget */ + int e0,e1 ; /* ends of the gauge */ + int x ; + int y ; /* vertical (horizontal) position */ + int i ; + int v0 = gw->gauge.v0 ; + int v1 = gw->gauge.v1 ; + int value = gw->gauge.value ; + + gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC ; + + +#ifdef _ThreeDP_h + gctop = gw->threeD.bot_shadow_GC ; + gcbot = gw->threeD.top_shadow_GC ; +#else + gctop = gcbot = gc ; +#endif + + if( gw->gauge.orientation == XtorientHorizontal ) { + len = gw->core.width ; + hgt = gw->core.height ; + } else { + len = gw->core.height ; + hgt = gw->core.width ; + } + + /* if the gauge is selected, signify by drawing the background + * in a constrasting color. + */ + + if( gw->gauge.selected ) + { + XFillRectangle(dpy,win, gc, 0,0, w->core.width,w->core.height) ; + gc = gw->gauge.inverse_GC ; + } + + e0 = gw->gauge.margin0 ; /* left (top) end */ + e1 = len - gw->gauge.margin1 -1 ; /* right (bottom) end */ + + /* Draw the Gauge itself */ + + y = gw->gauge.gmargin ; + + if( gw->gauge.orientation == XtorientHorizontal ) /* horizontal */ + { + XDrawLine(dpy,win,gctop, e0+1,y, e1-1,y) ; + XDrawLine(dpy,win,gctop, e0,y+1, e0,y+GA_WID) ; + XDrawLine(dpy,win,gcbot, e0+1, y+GA_WID+1, e1-1, y+GA_WID+1) ; + XDrawLine(dpy,win,gcbot, e1,y+1, e1,y+GA_WID) ; + } + else /* vertical */ + { + XDrawLine(dpy,win,gctop, y,e0+1, y,e1-1) ; + XDrawLine(dpy,win,gctop, y+1,e0, y+GA_WID,e0) ; + XDrawLine(dpy,win,gcbot, y+GA_WID+1,e0+1, y+GA_WID+1, e1-1) ; + XDrawLine(dpy,win,gcbot, y+1,e1, y+GA_WID,e1) ; + } + + + /* draw the mercury */ + + GaugeMercury(dpy, win, gc, gw, 0,value) ; + + + if( gw->gauge.ntics > 1 ) + { + y = gw->gauge.tmargin ; + for(i=0; igauge.ntics; ++i) + { + x = e0 + i*(e1-e0-1)/(gw->gauge.ntics-1) ; + if( gw->gauge.orientation == XtorientHorizontal ) { + XDrawLine(dpy,win,gcbot, x,y+1, x,y+TIC_LEN-2) ; + XDrawLine(dpy,win,gcbot, x,y, x+1,y) ; + XDrawLine(dpy,win,gctop, x+1,y+1, x+1,y+TIC_LEN-2) ; + XDrawLine(dpy,win,gctop, x,y+TIC_LEN-1, x+1,y+TIC_LEN-1) ; + } + else { + XDrawLine(dpy,win,gcbot, y+1,x, y+TIC_LEN-2,x) ; + XDrawLine(dpy,win,gcbot, y,x, y,x+1) ; + XDrawLine(dpy,win,gctop, y+1,x+1, y+TIC_LEN-2,x+1) ; + XDrawLine(dpy,win,gctop, y+TIC_LEN-1,x, y+TIC_LEN-1,x+1) ; + } + } + } + + /* draw labels */ + if( gw->gauge.nlabels > 1 ) + { + char label[20], *s = label ; + int len, w,h =0 ; + + if( gw->gauge.orientation == XtorientHorizontal ) + y = gw->gauge.lmargin + gw->label.font->max_bounds.ascent - 1 ; + else { + y = gw->gauge.lmargin ; + h = gw->label.font->max_bounds.ascent / 2 ; + } + + for(i=0; igauge.nlabels; ++i) + { + if( gw->gauge.labels == NULL ) + sprintf(label, "%d", v0+i*(v1 - v0)/(gw->gauge.nlabels - 1)) ; + else + s = gw->gauge.labels[i] ; + if( s != NULL ) { + x = e0 + i*(e1-e0-1)/(gw->gauge.nlabels-1) ; + len = strlen(s) ; + if( gw->gauge.orientation == XtorientHorizontal ) { + w = XTextWidth(gw->label.font, s, len) ; + XDrawString(dpy,win,gc, x-w/2,y, s,len) ; + } + else { + XDrawString(dpy,win,gc, y,x+h, s,len) ; + } + } + } + } +} + + +/* + * Set specified arguments into widget + */ + +static Boolean +GaugeSetValues(old, request, new, args, num_args) + Widget old, request, new; + ArgList args; + Cardinal *num_args; +{ + GaugeWidget oldgw = (GaugeWidget) old; + GaugeWidget gw = (GaugeWidget) new; + Boolean was_resized = False; + + if( gw->gauge.selected != None ) { + XtDisownSelection(new, gw->gauge.selected, CurrentTime) ; + gw->gauge.selected = None ; + } + + /* Changes to v0,v1,labels, ntics, nlabels require resize & redraw. */ + /* Change to value requires redraw and possible resize if autoscale */ + + was_resized = + gw->gauge.v0 != oldgw->gauge.v0 || + gw->gauge.v1 != oldgw->gauge.v1 || + gw->gauge.ntics != oldgw->gauge.ntics || + gw->gauge.nlabels != oldgw->gauge.nlabels || + gw->gauge.labels != oldgw->gauge.labels ; + + if( (gw->gauge.autoScaleUp && gw->gauge.value > gw->gauge.v1) || + (gw->gauge.autoScaleDown && gw->gauge.value < gw->gauge.v1/3 )) + { + AutoScale(gw) ; + was_resized = TRUE ; + } + + if( was_resized ) { + if( gw->label.resize ) + GaugeSize(gw, &gw->core.width, &gw->core.height, DEF_LEN) ; + else + GaugeResize(new) ; + } + + if( gw->gauge.update != oldgw->gauge.update ) + { + if( gw->gauge.update > 0 ) + EnableUpdate(gw) ; + else + DisableUpdate(gw) ; + } + + if( gw->core.background_pixel != oldgw->core.background_pixel ) + { + XtReleaseGC(new, gw->gauge.inverse_GC) ; + gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel) ; + } + + return was_resized || gw->gauge.value != oldgw->gauge.value || + XtIsSensitive(old) != XtIsSensitive(new); +} + + +static XtGeometryResult +GaugeQueryGeometry(w, intended, preferred) + Widget w; + XtWidgetGeometry *intended, *preferred; +{ + register GaugeWidget gw = (GaugeWidget)w; + + if( intended->width == w->core.width && + intended->height == w->core.height ) + return XtGeometryNo ; + + preferred->request_mode = CWWidth | CWHeight; + GaugeSize(gw, &preferred->width, &preferred->height, DEF_LEN) ; + + if( (!(intended->request_mode & CWWidth) || + intended->width >= preferred->width) && + (!(intended->request_mode & CWHeight) || + intended->height >= preferred->height) ) + return XtGeometryYes; + else + return XtGeometryAlmost; +} + + + + +/**************************************************************** + * + * Action Procedures + * + ****************************************************************/ + +static void +GaugeSelect(w,event,params,num_params) + Widget w ; + XEvent *event ; + String *params ; + Cardinal *num_params ; +{ + GaugeWidget gw = (GaugeWidget)w ; + Atom seln = XA_PRIMARY ; + + if( gw->gauge.selected != None ) { + XtDisownSelection(w, gw->gauge.selected, CurrentTime) ; + gw->gauge.selected = None ; + } + + if( *num_params > 0 ) { + seln = XInternAtom(XtDisplay(w), params[0], False) ; + printf("atom %s is %ld\n", params[0], seln) ; + } + + if( ! XtOwnSelection(w, seln, event->xbutton.time, GaugeConvert, + GaugeLoseSel, GaugeDoneSel) ) + { + /* in real code, this error message would be replaced by + * something more elegant, or at least deleted + */ + + fprintf(stderr, "Gauge failed to get selection, try again\n") ; + } + else + { + gw->gauge.selected = TRUE ; + gw->gauge.selstr = (String)XtMalloc(4*sizeof(int)) ; + sprintf(gw->gauge.selstr, "%d", gw->gauge.value) ; + GaugeExpose(w) ; + } +} + + +static Boolean +GaugeConvert(w, selection, target, type, value, length, format) + Widget w ; + Atom *selection ; /* usually XA_PRIMARY */ + Atom *target ; /* requested target */ + Atom *type ; /* returned type */ + XPointer *value ; /* returned value */ + u_long *length ; /* returned length */ + int *format ; /* returned format */ +{ + GaugeWidget gw = (GaugeWidget)w ; + XSelectionRequestEvent *req ; + + printf( "requesting selection %s:%s\n", + XGetAtomName(XtDisplay(w),*selection), + XGetAtomName(XtDisplay(w),*target)); + + if( *target == XA_TARGETS(XtDisplay(w)) ) + { + Atom *rval, *stdTargets ; + u_long stdLength ; + + /* XmuConvertStandardSelection can handle this. This function + * will return a list of standard targets. We prepend TEXT, + * STRING and INTEGER to the list and return it. + */ + + req = XtGetSelectionRequest(w, *selection, NULL) ; + XmuConvertStandardSelection(w, req->time, selection, target, + type, (XPointer*)&stdTargets, &stdLength, format) ; + + *type = XA_ATOM ; /* TODO: needed? */ + *length = stdLength + 3 ; + rval = (Atom *) XtMalloc(sizeof(Atom)*(stdLength+3)) ; + *value = (XtPointer) rval ; + *rval++ = XA_INTEGER ; + *rval++ = XA_STRING ; + *rval++ = XA_TEXT(XtDisplay(w)) ; + bcopy((char *)stdTargets, (char *)rval, stdLength*sizeof(Atom)) ; + XtFree((char*) stdTargets) ; + *format = 8*sizeof(Atom) ; /* TODO: needed? */ + return True ; + } + + else if( *target == XA_INTEGER ) + { + *type = XA_INTEGER ; + *length = 1 ; + *value = (XtPointer) &gw->gauge.value ; + *format = 8*sizeof(int) ; + return True ; + } + + else if( *target == XA_STRING || + *target == XA_TEXT(XtDisplay(w)) ) + { + *type = *target ; + *length = strlen(gw->gauge.selstr)*sizeof(char) ; + *value = (XtPointer) gw->gauge.selstr ; + *format = 8 ; + return True ; + } + + else + { + /* anything else, we just give it to XmuConvertStandardSelection() */ + + req = XtGetSelectionRequest(w, *selection, NULL) ; + if( XmuConvertStandardSelection(w, req->time, selection, target, + type, value, length, format) ) + return True ; + else { + printf( + "Gauge: requestor is requesting unsupported selection %s:%s\n", + XGetAtomName(XtDisplay(w),*selection), + XGetAtomName(XtDisplay(w),*target)); + return False ; + } + } +} + + + +static void +GaugeLoseSel(w, selection) + Widget w ; + Atom *selection ; /* usually XA_PRIMARY */ +{ + GaugeWidget gw = (GaugeWidget)w ; + Display *dpy = XtDisplay(w) ; + Window win = XtWindow(w) ; + + if( gw->gauge.selstr != NULL ) { + XtFree(gw->gauge.selstr) ; + gw->gauge.selstr = NULL ; + } + + gw->gauge.selected = False ; + XClearWindow(dpy,win) ; + GaugeExpose(w) ; +} + + +static void +GaugeDoneSel(w, selection, target) + Widget w ; + Atom *selection ; /* usually XA_PRIMARY */ + Atom *target ; /* requested target */ +{ + /* selection done, anything to do? */ +} + + +static void +GaugePaste(w,event,params,num_params) + Widget w ; + XEvent *event ; + String *params ; + Cardinal *num_params ; +{ + Atom seln = XA_PRIMARY ; + + if( *num_params > 0 ) { + seln = XInternAtom(XtDisplay(w), params[0], False) ; + printf("atom %s is %ld\n", params[0], seln) ; + } + + /* try for integer value first */ + XtGetSelectionValue(w, seln, XA_INTEGER, + GaugeGetSelCB, (XtPointer)XA_INTEGER, + event->xbutton.time) ; +} + +static void +GaugeGetSelCB(w, client, selection, type, value, length, format) + Widget w ; + XtPointer client ; + Atom *selection ; + Atom *type ; + XtPointer value ; + u_long *length ; + int *format ; +{ + Display *dpy = XtDisplay(w) ; + Atom target = (Atom)client ; + int *iptr ; + char *cptr ; + + if( *type == XA_INTEGER ) { + iptr = (int *)value ; + XawGaugeSetValue(w, *iptr) ; + } + + else if( *type == XA_STRING || *type == XA_TEXT(dpy) ) { + cptr = (char *)value ; + XawGaugeSetValue(w, atoi(cptr)) ; + } + + /* failed, try string */ + else if( *type == None && target == XA_INTEGER ) + XtGetSelectionValue(w, *selection, XA_STRING, + GaugeGetSelCB, (XtPointer)XA_STRING, + CurrentTime) ; +} + + + +/**************************************************************** + * + * Public Procedures + * + ****************************************************************/ + + + /* Change gauge value. Only undraw or draw what needs to be + * changed. + */ + +void +XawGaugeSetValue(w, value) + Widget w ; + Cardinal value ; +{ + GaugeWidget gw = (GaugeWidget)w ; + int oldvalue ; + GC gc ; + + if( gw->gauge.selected != None ) { + XtDisownSelection(w, gw->gauge.selected, CurrentTime) ; + gw->gauge.selected = None ; + } + + if( !XtIsRealized(w) ) { + gw->gauge.value = value ; + return ; + } + + /* need to rescale? */ + if(( gw->gauge.autoScaleUp && value > gw->gauge.v1) || + (gw->gauge.autoScaleDown && value < gw->gauge.v1/3 )) + { + XtVaSetValues(w, XtNvalue, value, 0) ; + return ; + } + + oldvalue = gw->gauge.value ; + gw->gauge.value = value ; + + gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC ; + GaugeMercury(XtDisplay(w), XtWindow(w), gc, gw, oldvalue,value) ; +} + + +Cardinal +XawGaugeGetValue(w) + Widget w ; +{ + GaugeWidget gw = (GaugeWidget)w ; + return gw->gauge.value ; +} + + + + +/**************************************************************** + * + * Private Procedures + * + ****************************************************************/ + + /* draw the mercury over a specific region */ + +static void +GaugeMercury(dpy,win,gc, gw, val0,val1) + Display *dpy ; + Window win ; + GC gc ; + GaugeWidget gw ; + Cardinal val0,val1 ; +{ + int v0 = gw->gauge.v0 ; + int v1 = gw->gauge.v1 ; + int vd = v1 - v0 ; + Dimension len ; /* length (width or height) of gauge */ + Position e0, e1 ; /* gauge ends */ + Position p0, p1 ; /* mercury ends */ + int y ; /* vertical (horizontal) position */ + Boolean undraw = FALSE ; + + len = gw->gauge.orientation == XtorientHorizontal ? + gw->core.width : gw->core.height ; + + e0 = gw->gauge.margin0 ; /* left (top) end */ + e1 = len - gw->gauge.margin1 -1 ; /* right (bottom) end */ + + if( vd <= 0 ) vd = 1 ; + + if( val0 < v0 ) val0 = v0 ; + else if( val0 > v1 ) val0 = v1 ; + if( val1 < v0 ) val1 = v0 ; + else if( val1 > v1 ) val1 = v1 ; + + p0 = (val0-v0)*(e1-e0-1)/vd ; + p1 = (val1-v0)*(e1-e0-1)/vd ; + + if( p1 == p0 ) + return ; + + y = gw->gauge.gmargin ; + + if( p1 < p0 ) + { + Position tmp = p0 ; + p0 = p1 ; + p1 = tmp ; + gc = gw->label.normal_GC ; + XSetForeground(dpy,gc, gw->core.background_pixel) ; + undraw = TRUE ; + } + + if( gw->gauge.orientation == XtorientHorizontal ) + XFillRectangle(dpy,win,gc, e0+p0+1,y+1, p1-p0,GA_WID) ; + else + XFillRectangle(dpy,win,gc, y+1,e1-p1, GA_WID,p1-p0) ; + + if( undraw ) + XSetForeground(dpy,gc, gw->label.foreground) ; +} + + + +/* Search the labels, find the largest one. */ +/* TODO: handle vertical fonts? */ + +static void +MaxLabel(gw,wid,hgt, w0,w1) + GaugeWidget gw; + Dimension *wid, *hgt ; /* max label size */ + Dimension *w0,*w1 ; /* width of first, last labels */ +{ + char lstr[80], *lbl ; + int w ; + XFontStruct *font = gw->label.font ; + int i ; + int lw = 0; + int v0 = gw->gauge.v0 ; + int dv = gw->gauge.v1 - v0 ; + int n = gw->gauge.nlabels ; + + if( n > 0 ) + { + if( --n <= 0 ) {n = 1 ; v0 += dv/2 ;} + + /* loop through all labels, figure out how much room they + * need. + */ + w = 0 ; + for(i=0; igauge.nlabels; ++i) + { + if( gw->gauge.labels == NULL ) /* numeric labels */ + sprintf(lbl = lstr,"%d", v0 + i*dv/n) ; + else + lbl = gw->gauge.labels[i] ; + + if( lbl != NULL ) { + lw = XTextWidth(font, lbl, strlen(lbl)) ; + w = Max( w, lw ) ; + } + else + lw = 0 ; + + if( i == 0 && w0 != NULL ) *w0 = lw ; + } + if( w1 != NULL ) *w1 = lw ; + + *wid = w ; + *hgt = font->max_bounds.ascent + font->max_bounds.descent ; + } + else + *wid = *hgt = 0 ; +} + + +/* Determine the preferred size for this widget. choose 100x100 for + * debugging. + */ + +static void +GaugeSize(gw,wid,hgt, min_len) + GaugeWidget gw; + Dimension *wid, *hgt, min_len ; +{ + int w,h ; /* width, height of gauge */ + int vmargin ; /* vertical margin */ + int hmargin ; /* horizontal margin */ + + hmargin = gw->label.internal_width ; + vmargin = gw->label.internal_height ; + + /* find total height (width) of contents */ + + + /* find minimum size for undecorated gauge */ + + if( gw->gauge.orientation == XtorientHorizontal ) + { + w = min_len ; + h = GA_WID+2 ; /* gauge itself + edges */ + } + else + { + w = GA_WID+2 ; + h = min_len ; + } + + if( gw->gauge.ntics > 0 ) + { + if( gw->gauge.orientation == XtorientHorizontal ) + { + w = Max(w, gw->gauge.ntics*3) ; + h += vmargin + TIC_LEN ; + } + else + { + w += hmargin + TIC_LEN ; + h = Max(h, gw->gauge.ntics*3) ; + } + } + + + /* If labels are requested, this gets a little interesting. + * We want the end labels centered on the ends of the gauge and + * the centers of the labels evenly spaced. The labels at the ends + * will not be the same width, meaning that the gauge itself need + * not be centered in the widget. + * + * First, determine the spacing. This is the width of the widest + * label, plus the internal margin. Total length of the gauge is + * spacing * (nlabels-1). To this, we add half the width of the + * left-most label and half the width of the right-most label + * to get the entire desired width of the widget. + */ + if( gw->gauge.nlabels > 0 ) + { + Dimension lwm, lw0, lw1 ; /* width of max, left, right labels */ + Dimension lh ; + + MaxLabel(gw,&lwm,&lh, &lw0,&lw1) ; + + if( gw->gauge.orientation == XtorientHorizontal ) + { + lwm = (lwm+hmargin) * (gw->gauge.nlabels-1) + (lw0+lw1)/2 ; + w = Max(w, lwm) ; + h += lh + vmargin ; + } + else + { + lh = lh*gw->gauge.nlabels + (gw->gauge.nlabels - 1)*vmargin ; + h = Max(h, lh) ; + w += lwm + hmargin ; + } + } + + w += hmargin*2 ; + h += vmargin*2 ; + + *wid = w ; + *hgt = h ; +} + + + +static void +AutoScale(gw) + GaugeWidget gw; +{ + static int scales[3] = {1,2,5} ; + int sptr = 0, smult=1 ; + + if( gw->gauge.autoScaleDown ) + gw->gauge.v1 = 0 ; + while( gw->gauge.value > gw->gauge.v1 ) + { + if( ++sptr > 2 ) { + sptr = 0 ; + smult *= 10 ; + } + gw->gauge.v1 = scales[sptr] * smult ; + } +} + +static void +EnableUpdate(gw) + GaugeWidget gw ; +{ + gw->gauge.intervalId = + XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)gw), + gw->gauge.update * MS_PER_SEC, GaugeGetValue, + (XtPointer)gw) ; +} + +static void +DisableUpdate(gw) + GaugeWidget gw ; +{ + XtRemoveTimeOut(gw->gauge.intervalId) ; +} + +static void +GaugeGetValue(clientData, intervalId) + XtPointer clientData ; + XtIntervalId intervalId ; +{ + GaugeWidget gw = (GaugeWidget)clientData ; + Cardinal value ; + + if( gw->gauge.update > 0 ) + EnableUpdate(gw) ; + + if( gw->gauge.getValue != NULL ) + { + XtCallCallbackList((Widget)gw, gw->gauge.getValue, (XtPointer)&value); + XawGaugeSetValue((Widget)gw, value) ; + } +} + + +static GC +Get_GC(gw, fg) + GaugeWidget gw ; + Pixel fg ; +{ + XGCValues values ; +#define vmask GCForeground +#define umask (GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset\ + |GCFont|GCDashList|GCArcMode) + + values.foreground = fg ; + + return XtAllocateGC((Widget)gw, 0, vmask, &values, 0L, umask) ; +} Index: lwlib/xlwgauge.h =================================================================== RCS file: xlwgauge.h diff -N xlwgauge.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwgauge.h Wed Jul 28 01:33:55 1999 @@ -0,0 +1,184 @@ +/* Gauge Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Gauge.h 1.1 */ + +/* + * Gauge.h - Gauge widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: July 8, 1997 + */ + +#ifndef _XawGauge_h +#define _XawGauge_h + +/*********************************************************************** + * + * Gauge Widget + * + * The Gauge widget looks something like a thermometer. Application + * defines the values at the ends of the range and the current value + * and Gauge draws accordingly. Gauge does not accept input. + * + ***********************************************************************/ + +#include + +/* Resources: + + Name Class RepType Default Value + ---- ----- ------- ------------- + value Value Cardinal 0 + minValue MinValue Cardinal 0 + maxValue MaxValue Cardinal 100 + ntics NTics Cardinal 0 + + nlabels NLabels Cardinal 0 ++ + labels Labels String * NULL +++ + orientation Orientation XtOrientation horizontal + autoScaleUp AutoScaleUp Boolean FALSE ++++ + autoScaleDown AutoScaleDown Boolean FALSE ++++ + getValue Callback XtCallbackList NULL +++++ + update Interval int 0 (seconds) = disabled + + encoding Encoding unsigned char XawTextEncoding8bit + font Font XFontStruct* XtDefaultFont + foreground Foreground Pixel XtDefaultForeground + internalHeight Height Dimension 2 + internalWidth Width Dimension 4 + resize Resize Boolean True + background Background Pixel XtDefaultBackground + bitmap Pixmap Pixmap None + border BorderColor Pixel XtDefaultForeground + borderWidth BorderWidth Dimension 1 + cursor Cursor Cursor None + cursorName Cursor String NULL + destroyCallback Callback XtCallbackList NULL + height Height Dimension varies + insensitiveBorder Insensitive Pixmap Gray + mappedWhenManaged MappedWhenManaged Boolean True + pointerColor Foreground Pixel XtDefaultForeground + pointerColorBackground Background Pixel XtDefaultBackground + sensitive Sensitive Boolean True + width Width Dimension text width + x Position Position 0 + y Position Position 0 + + + Ntics sets the number of tic marks next to the gauge. If 0, no + tic marks will be drawn. + ++ Nlabels sets the number of labels next to the gauge. + +++ Labels is an array of nul-terminated strings to be used as labels. + If this field is NULL but nlabels is > 0, then numeric labels will be + provided. NOTE: the labels are not copied to any internal memory; they + must be stored in static memory provided by the appliction. + ++++ AutoScale allows the gauge to set its own value limits. Default is + False unless upper & lower limits are both 0. + + +++++ The GetValue() callback proc is called with these arguments: + static void + myGetValue(gauge, client, rval) + Widget gauge ; + XtPointer client ; + XtPointer rval ; + { + *(Cardinal *)rval = value ; + } + +*/ + +/* + * Resource names not provided in StringDefs.h + */ + +#ifndef XtNvalue +#define XtNvalue "value" +#define XtCValue "Value" +#endif + +#ifndef XtNorientation +#define XtNorientation "orientation" +#define XtCOrientation "Orientation" +#endif + +#define XtNntics "ntics" +#define XtCNTics "NTics" + +#ifndef XtNnlabels +#define XtNnlabels "nlabels" +#define XtCNLabels "NLabels" +#endif +#ifndef XtNlabels +#define XtNlabels "labels" +#define XtCLabels "Labels" +#endif + +#ifndef XtNminValue +#define XtNminValue "minValue" +#define XtCMinValue "MinValue" +#endif +#ifndef XtNmaxValue +#define XtNmaxValue "maxValue" +#define XtCMaxValue "MaxValue" +#endif + +#ifndef XtNautoScaleUp +#define XtNautoScaleUp "autoScaleUp" +#define XtCAutoScaleUp "AutoScaleUp" +#define XtNautoScaleDown "autoScaleDown" +#define XtCAutoScaleDown "AutoScaleDown" +#endif + +#ifndef XtNupdate +#define XtNupdate "update" +#endif + +#ifndef XtNgetValue +#define XtNgetValue "getValue" +#endif + + +/* Class record constants */ + +extern WidgetClass gaugeWidgetClass; + +typedef struct _GaugeClassRec *GaugeWidgetClass; +typedef struct _GaugeRec *GaugeWidget; + + +_XFUNCPROTOBEGIN + +extern void XawGaugeSetValue( +#if NeedFunctionPrototypes + Widget gauge, + Cardinal value +#endif +); + +extern Cardinal XawGaugeGetValue( +#if NeedFunctionPrototypes + Widget gauge +#endif +); + +_XFUNCPROTOEND + +#endif /* _XawGauge_h */ Index: lwlib/xlwgaugeP.h =================================================================== RCS file: xlwgaugeP.h diff -N xlwgaugeP.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwgaugeP.h Wed Jul 28 01:33:55 1999 @@ -0,0 +1,103 @@ +/* Gauge Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + * GaugeP.h - Gauge widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: July 9, 1997 + */ + +#ifndef _XawGaugeP_h +#define _XawGaugeP_h + +/*********************************************************************** + * + * Gauge Widget Private Data + * + * Gauge has little in common with the label widget, but can make use + * of some label resources, so is subclassed from label. + * + ***********************************************************************/ + +#include "xlwgauge.h" +#include + +/* New fields for the Gauge widget class record */ + +typedef struct {XtPointer extension;} GaugeClassPart; + +/* Full class record declaration */ +typedef struct _GaugeClassRec { + CoreClassPart core_class; + SimpleClassPart simple_class; +#ifdef _ThreeDP_h + ThreeDClassPart threeD_class; +#endif + LabelClassPart label_class; + GaugeClassPart gauge_class; +} GaugeClassRec; + +extern GaugeClassRec gaugeClassRec; + +/* New fields for the Gauge widget record */ +typedef struct { + /* resources */ + int value, v0,v1 ; + int ntics, nlabels ; + String *labels ; + XtOrientation orientation ; + Boolean autoScaleUp ; /* scales automatically */ + Boolean autoScaleDown ; /* scales automatically */ + int update ; /* update interval */ + XtCallbackList getValue ; /* proc to call to fetch a point */ + + /* private state */ + Dimension gmargin ; /* edges <-> gauge */ + Dimension tmargin ; /* top (left) edge <-> tic marks */ + Dimension lmargin ; /* tic marks <-> labels */ + Dimension margin0 ; /* left/bottom margin */ + Dimension margin1 ; /* right/top margin */ + XtIntervalId intervalId ; + Atom selected ; + String selstr ; /* selection string, if any */ + GC inverse_GC ; +} GaugePart; + + +/**************************************************************** + * + * Full instance record declaration + * + ****************************************************************/ + +typedef struct _GaugeRec { + CorePart core; + SimplePart simple; +#ifdef _ThreeDP_h + ThreeDPart threeD; +#endif + LabelPart label; + GaugePart gauge; +} GaugeRec; + +#endif /* _XawGaugeP_h */ Index: lwlib/xlwgcs.c =================================================================== RCS file: xlwgcs.c diff -N xlwgcs.c --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwgcs.c Wed Jul 28 01:33:55 1999 @@ -0,0 +1,483 @@ +/* Tabs Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Gcs.c 1.3 */ + +/* #### This code is duplicated many times within lwlib and XEmacs. It + should be modularised. */ +/* + * Gcs.c - Utility functions to allocate GCs. + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: Sept 29, 1998 + */ + +/* Functions: + * + * GC AllocFgGC(w, fg, font) + * Return a GC with foreground set as specified. + * If font is None, then the returned GC is allocated with font specified + * as a "don't care" value. + * + * GC + * AllocBackgroundGC(w, font) + * Return a GC with the foreground set to the widget's background color. + * + * GC + * AllocGreyGC(w, fg, font, contrast, gp, be_nice_to_cmap) + * Widget w ; + * Pixel fg ; + * Font font ; + * int contrast ; + * Pixmap *gp ; + * int be_nice_to_cmap ; + * + * Return a GC suitable for rendering a widget in its "inactive" color. + * Normally returns a GC with a color somewhere between the widget's + * background color and the specified foreground. If font is None, then + * the returned GC is allocated with font specified as "don't care". + * If be_nice_to_cmap is True, the returned GC is created using a 50% + * dither instead of a new color. + * + * The 'gp' argument is a pointer to a Pixmap value, used to cache the + * 50% dither pattern. If *gp points to a Pixmap value, it will be used + * as the source of the 50% dither pattern. If *gp is None, then a + * dither pattern will be created and stored in gp. If gp is NULL, then + * a dither pattern will be created but not returned. + * + * GC + * AllocTopShadowGC(w, contrast, be_nice_to_cmap) + * Return a GC suitable for rendering the "top shadow" decorations of + * a widget. Returns a GC with foreground computed from widget's + * background color and contrast. If be_nice_to_cmap is True, the + * returned GC will use a foreground color of white. If widget depth + * is 1, this function will use a foreground color of black. + * + * GC + * AllocBotShadowGC(w, contrast, be_nice_to_cmap) + * Return a GC suitable for rendering the "bottom shadow" decorations + * of a widget. Returns a GC with foreground computed from widget's + * background color and contrast. If be_nice_to_cmap is True, the + * returned GC will use a foreground color of black. + * + * GC + * AllocArmGC(w, contrast, gp, be_nice_to_cmap) + * Return a GC suitable for rendering the "armed" decorations of a + * widget. This GC would typically be used to fill in the widget's + * background. Returns a GC with foreground computed from widget's + * background color and contrast. If be_nice_to_cmap is True, the + * returned GC will use a foreground color of black and a 50% dither. + * + * The 'gp' argument is as described above. + * + * void + * Draw3dBox(w, x,y,wid,hgt,s, topgc, botgc) + * Utility function. Draws a raised shadow box with outside dimensions + * as specified by x,y,wid,hgt and shadow width specified by s. + * A lowered shadow box may be generated by swapping topgc and botgc. + * + */ + +#include + +#include +#include +#include +#include +#include + +#include "xlwgcs.h" + + /* Color & GC allocation. + * + * Frame widgets use the following graphics contexts: + * + * Foreground tab label text drawn this way + * Insensitive Fg foreground color greyed out. + * Background frame background color + * Top shadow upper-left highlight around widget + * Bottom shadow lower-right highlight around widget + * Arm shadow button pressed and ready to be released + * + * + * GC's are defined as follows, depending on attributes and + * window depth: + * + * Monochrome: + * Foreground = foreground color attribute or BlackPixel() + * Grey = Foreground color + 50% dither + * Background = background color attribute or WhitePixel() + * top shadow = foreground + * bottom shadow = foreground + * arm shadow = (what?) + * + * Color, beNiceToColormap=true: + * Foreground = foreground color attribute or BlackPixel() + * Grey = Foreground color + 50% dither + * Background = background color attribute or WhitePixel() + * top shadow = white + * bottom shadow = black + * arm shadow = (what?) + * + * Color, beNiceToColormap=false: + * Foreground = foreground color attribute or BlackPixel() + * Grey = (foreground color + background color)/2 + * Background = background color attribute or WhitePixel() + * top shadow = background * 1.2 + * bottom shadow = background * .6 + * arm shadow = background * .8 + * + * Special cases: + * If background is white, ?? + * if background is black, ?? + * + * + * If the widget's background is solid white or solid black, + * this code just picks some numbers. (The choice is designed + * to be compatibile with ThreeD interface.) + */ + + + +#if XtSpecificationRelease < 5 + +static GC XtAllocateGC(Widget, int, u_long, XGCValues *, u_long, u_long) ; + +#endif + + + /* return a GC with the specified foreground and optional font */ + +GC +AllocFgGC(w, fg, font) + Widget w; + Pixel fg ; + Font font ; +{ + XGCValues values ; + u_long vmask, dcmask ; + + values.foreground = fg ; + values.font = font ; + + if( font != None ) { + vmask = GCForeground|GCFont ; + dcmask = GCSubwindowMode|GCDashOffset| + GCDashList|GCArcMode|GCBackground|GCGraphicsExposures ; + } else { + vmask = GCForeground ; + dcmask = GCFont|GCSubwindowMode|GCDashOffset| + GCDashList|GCArcMode|GCBackground|GCGraphicsExposures ; + } + + return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ; +} + + + /* return gc with widget background color as the foreground */ + +GC +AllocBackgroundGC(w, font) + Widget w; + Font font ; +{ + return AllocFgGC(w, w->core.background_pixel, font) ; +} + + + /* Allocate an "inactive" GC. Color is grey (possibly via + * dither pattern). This function optionally returns the + * grey pixmap so the caller may cache it. + */ + +GC +AllocGreyGC(w, fg, font, contrast, be_nice_to_cmap) + Widget w ; + Pixel fg ; + Font font ; + int contrast ; + int be_nice_to_cmap ; +{ + XGCValues values ; + u_long vmask, dcmask ; + + values.foreground = fg ; + values.background = w->core.background_pixel ; + values.font = font ; + + if( font != None ) { + vmask = GCForeground|GCFont ; + dcmask = GCSubwindowMode|GCDashOffset| + GCDashList|GCArcMode|GCGraphicsExposures ; + } else { + vmask = GCForeground; + dcmask = GCFont|GCSubwindowMode|GCDashOffset| + GCDashList|GCArcMode|GCGraphicsExposures ; + } + + if( be_nice_to_cmap || w->core.depth == 1) + { + values.fill_style = FillStippled ; + values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ; + + vmask |= GCBackground|GCStipple|GCFillStyle ; + return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ; + } + else + { + values.foreground = + AllocGreyPixel(w, fg, values.background, contrast) ; + dcmask |= GCBackground ; + return XtAllocateGC(w, w->core.depth, vmask, &values, 0L, dcmask) ; + } +} + + /* return top-shadow gc. */ + +GC +AllocTopShadowGC(w, contrast, be_nice_to_cmap) + Widget w; + int contrast ; + int be_nice_to_cmap ; +{ + Screen *scr = XtScreen (w); + XGCValues values ; + + if( w->core.depth == 1 ) + values.foreground = BlackPixelOfScreen(scr) ; + else if( be_nice_to_cmap ) + values.foreground = WhitePixelOfScreen(scr) ; + else + values.foreground = AllocShadowPixel(w, 100+contrast) ; + + return XtAllocateGC(w, w->core.depth, + GCForeground, &values, + 0L, + GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures| + GCDashOffset|GCDashList|GCArcMode) ; +} + + /* return bottom-shadow gc. */ + +GC +AllocBotShadowGC(w, contrast, be_nice_to_cmap) + Widget w ; + int contrast ; + int be_nice_to_cmap ; +{ + Screen *scr = XtScreen (w); + XGCValues values ; + + if( w->core.depth == 1 || be_nice_to_cmap ) + values.foreground = BlackPixelOfScreen(scr) ; + else + values.foreground = AllocShadowPixel(w, 100-contrast) ; + + return XtAllocateGC(w, w->core.depth, + GCForeground, &values, + 0L, + GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures| + GCDashOffset|GCDashList|GCArcMode) ; +} + + /* return arm-shadow gc. */ + +GC +AllocArmGC(w, contrast, be_nice_to_cmap) + Widget w; + int contrast ; + int be_nice_to_cmap ; +{ + Screen *scr = XtScreen (w); + XGCValues values ; + + /* Not clear exactly what we should do here. Take a look at + * Xaw3d to see what they do. + */ + + if( w->core.depth == 1 || be_nice_to_cmap ) + { + values.background = w->core.background_pixel ; + if( values.background == BlackPixelOfScreen(scr) ) + values.foreground = WhitePixelOfScreen(scr) ; + else + values.foreground = BlackPixelOfScreen(scr) ; + values.fill_style = FillStippled ; + values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ; + + return XtAllocateGC(w, w->core.depth, + GCForeground|GCBackground|GCStipple|GCFillStyle, + &values, 0L, + GCFont|GCSubwindowMode|GCGraphicsExposures| + GCDashOffset|GCDashList|GCArcMode) ; + } + else { + values.foreground = AllocShadowPixel(w, 100-contrast) ; + return XtAllocateGC(w, w->core.depth, + GCForeground, &values, + 0L, + GCBackground|GCFont|GCSubwindowMode|GCGraphicsExposures| + GCDashOffset|GCDashList|GCArcMode) ; + } +} + + +Pixel +AllocShadowPixel(w, scale) + Widget w; + int scale ; +{ + XColor get_c, set_c ; + Display *dpy = XtDisplay(w) ; + Screen *scr = XtScreen(w) ; + Colormap cmap ; + Pixel maxColor ; + + cmap = w->core.colormap ; + + get_c.pixel = w->core.background_pixel ; + if( get_c.pixel == WhitePixelOfScreen(scr) || + get_c.pixel == BlackPixelOfScreen(scr) ) + { + /* what we *ought* to do is choose gray75 as the base color, + * or perhaps gray83. Instead, we choose colors that are + * the same as ThreeD would choose. + */ + if( scale > 100 ) scale = 200 - scale ; + set_c.red = set_c.green = set_c.blue = 65535*scale/100 ; + } + else + { + XQueryColor(dpy, cmap, &get_c) ; + /* adjust scale so that brightest component does not + * exceed 65535; otherwise hue would change. + */ + if( scale > 100 ) { + maxColor = Max(get_c.red, Max(get_c.green, get_c.blue)) ; + if( scale*maxColor > 65535*100 ) + scale = 65535*100/maxColor ; + } + set_c.red = scale * get_c.red / 100 ; + set_c.green = scale * get_c.green / 100 ; + set_c.blue = scale * get_c.blue / 100 ; + } + if( XAllocColor(dpy, cmap, &set_c) ) + return set_c.pixel ; + else if( scale > 100 ) + return WhitePixelOfScreen(scr) ; + else + return BlackPixelOfScreen(scr) ; +} + + + /* Allocate a pixel halfway between foreground and background */ + +Pixel +AllocGreyPixel(w, fg, bg, cnt) + Widget w ; + Pixel fg, bg ; + int cnt ; +{ + XColor get_cf, get_cb, set_c ; + Display *dpy = XtDisplay(w) ; + Colormap cmap ; + + cmap = w->core.colormap ; + + get_cf.pixel = fg ; + get_cb.pixel = bg ; + + XQueryColor(dpy, cmap, &get_cf) ; + XQueryColor(dpy, cmap, &get_cb) ; + + set_c.red = (get_cf.red * cnt + get_cb.red * (100-cnt)) / 100 ; + set_c.green = (get_cf.green * cnt + get_cb.green * (100-cnt)) / 100 ; + set_c.blue = (get_cf.blue * cnt + get_cb.blue * (100-cnt)) / 100 ; + + (void)XAllocColor(dpy, cmap, &set_c) ; + return set_c.pixel ; +} + + + + + + + + + /* draw a 3-d box */ + +void +Draw3dBox(w, x,y,wid,hgt,s, topgc, botgc) + Widget w ; + int x,y ; /* position */ + int wid,hgt,s ; /* outside dimensions, shadow wid */ + GC topgc ; + GC botgc ; +{ + Display *dpy = XtDisplay(w) ; + Window win = XtWindow(w) ; + + if( s == 0 ) return ; + + if( s == 1 ) { + XDrawLine(dpy,win,botgc, x,y+hgt-1, x+wid-1,y+hgt-1) ; + XDrawLine(dpy,win,botgc, x+wid-1,y, x+wid-1,y+hgt-1) ; + XDrawLine(dpy,win,topgc, x,y, x,y+hgt-1) ; + XDrawLine(dpy,win,topgc, x,y, x+wid-1,y) ; + } + else + { + XPoint pts[6] ; + + /* bottom-right shadow */ + pts[0].x = x ; pts[0].y = y + hgt ; + pts[1].x = s ; pts[1].y = -s ; + pts[2].x = wid-2*s ; pts[2].y = 0 ; + pts[3].x = 0 ; pts[3].y = -(hgt-2*s) ; + pts[4].x = s ; pts[4].y = -s ; + pts[5].x = 0 ; pts[5].y = hgt ; + XFillPolygon(dpy,win,botgc, pts,6, Nonconvex,CoordModePrevious) ; + + /* top-left shadow */ + pts[0].x = x ; pts[0].y = y ; + pts[1].x = wid ; pts[1].y = 0 ; + pts[2].x = -s ; pts[2].y = s ; + pts[3].x = -wid+2*s ; pts[3].y = 0 ; + pts[4].x = 0 ; pts[4].y = hgt-2*s ; + pts[5].x = -s ; pts[5].y = s ; + XFillPolygon(dpy,win,topgc, pts,6, Nonconvex,CoordModePrevious) ; + } +} + +#if XtSpecificationRelease < 5 + +static GC +XtAllocateGC(w, depth, mask, values, dynamic, dontcare) + Widget w ; + int depth ; + unsigned long mask, dynamic, dontcare ; + XGCValues *values ; +{ + return XtGetGC(w, mask, values) ; +} +#endif Index: lwlib/xlwgcs.h =================================================================== RCS file: xlwgcs.h diff -N xlwgcs.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwgcs.h Wed Jul 28 01:33:55 1999 @@ -0,0 +1,53 @@ +/* Tabs Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Gcs 1.3 */ + +#ifndef Gcs_h + +#ifdef __STDC__ + +extern GC AllocFgGC( Widget w, Pixel fg, Font font) ; +extern GC AllocBackgroundGC( Widget w, Font font) ; +extern GC AllocGreyGC( Widget w, Pixel fg, Font, int, int ) ; +extern GC AllocTopShadowGC( Widget w, int contrast, int ) ; +extern GC AllocBotShadowGC( Widget w, int contrast, int ) ; +extern GC AllocArmGC( Widget w, int contrast, int) ; +extern Pixel AllocShadowPixel(Widget, int scale) ; +extern Pixel AllocGreyPixel(Widget, Pixel fg, Pixel bg, int contrast) ; +extern void Draw3dBox(Widget w, int x, int y, int wid, int hgt, int s, + GC topgc, GC botgc) ; + +#else + +extern GC AllocFgGC() ; +extern GC AllocBackgroundGC() ; +extern GC AllocGreyGC() ; +extern GC AllocTopShadowGC() ; +extern GC AllocBotShadowGC() ; +extern GC AllocArmGC() ; +extern Pixel AllocShadowPixel() ; +extern Pixel AllocGreyPixel() ; +extern void Draw3dBox() ; + +#endif + +#define Gcs_h +#endif Index: lwlib/xlwradio.c =================================================================== RCS file: xlwradio.c diff -N xlwradio.c --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwradio.c Wed Jul 28 01:33:56 1999 @@ -0,0 +1,596 @@ +/* Radio Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Radio.c 1.1 */ + +/* + * Radio.c - Radio button widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: June 30, 1997 + * + * + * Overview: This widget is identical to the Toggle widget in behavior, + * but completely different in appearance. This widget looks like a small + * diamond-shaped button with a label to the right. + * + * To make this work, we subclass the Toggle widget to inherit its behavior + * and to inherit the label-drawing function from which Toggle is + * subclassed. We then completely replace the Expose, Set, Unset + * and Highlight member functions. + * + * The Set and Unset actions are slightly unorthodox. In Toggle's + * ClassInit function, Toggle searches the Command actions list and + * "steals" the Set and Unset functions, caching pointers to them in its + * class record. It then calls these functions from its own ToggleSet + * and Toggle actions. + * + * We, in turn, override the Set() and Unset() actions in our own ClassRec. + */ + + +#include + +#include +#include +#include +#include +#include +#include "xlwradioP.h" + +#define BOX_SIZE 13 + +#define rclass(w) ((RadioWidgetClass)((w)->core.widget_class)) + + +#ifdef _ThreeDP_h +#define swid(rw) ((rw)->threeD.shadow_width) +#else +#define swid(rw) ((rw)->core.border_width) +#endif + +#define bsize(rw) (rclass(rw)->radio_class.dsize) +#define bs(rw) (bsize(rw) + 2*swid(rw)) + + + +/**************************************************************** + * + * Full class record constant + * + ****************************************************************/ + + /* The translations table from Toggle do not need to be + * overridden by Radio + */ + + + /* Member functions */ + +static void RadioInit() ; +static void RadioExpose(), RadioResize() ; +static void RadioDestroy(), RadioClassInit(), RadioClassPartInit() ; +static Boolean RadioSetValues(); +static void DrawDiamond() ; +static XtGeometryResult RadioQueryGeometry(); + + + /* Action procs */ + + void RadioSet(), RadioUnset() ; +static void RadioHighlight(), RadioUnhighlight(); + + + /* internal privates */ + +static void RadioSize() ; /* find ideal size for widget */ + + /* The actions table from Toggle is almost perfect, but we need + * to override Highlight, Set, and Unset. + */ + +static XtActionsRec actionsList[] = +{ + {"highlight", RadioHighlight}, + {"unhighlight", RadioUnhighlight}, +}; + +#define SuperClass ((ToggleWidgetClass)&toggleClassRec) + +RadioClassRec radioClassRec = { + { + (WidgetClass) SuperClass, /* superclass */ + "Radio", /* class_name */ + sizeof(RadioRec), /* size */ + RadioClassInit, /* class_initialize */ + RadioClassPartInit, /* class_part_initialize */ + FALSE, /* class_inited */ + RadioInit, /* initialize */ + NULL, /* initialize_hook */ + XtInheritRealize, /* realize */ + actionsList, /* actions */ + XtNumber(actionsList), /* num_actions */ + NULL, /* resources */ + 0, /* resource_count */ + NULLQUARK, /* xrm_class */ + TRUE, /* compress_motion */ + TRUE, /* compress_exposure */ + TRUE, /* compress_enterleave */ + FALSE, /* visible_interest */ + NULL, /* destroy */ + RadioResize, /* resize */ + RadioExpose, /* expose */ + RadioSetValues, /* set_values */ + NULL, /* set_values_hook */ + XtInheritSetValuesAlmost, /* set_values_almost */ + NULL, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_private */ + XtInheritTranslations, /* tm_table */ + RadioQueryGeometry, /* query_geometry */ + XtInheritDisplayAccelerator, /* display_accelerator */ + NULL /* extension */ + }, /* CoreClass fields initialization */ + { + XtInheritChangeSensitive /* change_sensitive */ + }, /* SimpleClass fields initialization */ +#ifdef _ThreeDP_h + { + XtInheritXaw3dShadowDraw /* field not used */ + }, /* ThreeDClass fields initialization */ +#endif + { + 0 /* field not used */ + }, /* LabelClass fields initialization */ + { + 0 /* field not used */ + }, /* CommandClass fields initialization */ + { + RadioSet, /* Set Procedure. */ + RadioUnset, /* Unset Procedure. */ + NULL /* extension. */ + }, /* ToggleClass fields initialization */ + { + BOX_SIZE, + DrawDiamond, /* draw procedure */ + NULL /* extension. */ + } /* RadioClass fields initialization */ +}; + + /* for public consumption */ +WidgetClass radioWidgetClass = (WidgetClass) &radioClassRec; + + + + + + +/**************************************************************** + * + * Class Methods + * + ****************************************************************/ + +static void +RadioClassInit() +{ + XawInitializeWidgetSet(); +} + +static void +RadioClassPartInit(class) + WidgetClass class ; +{ + RadioWidgetClass c = (RadioWidgetClass) class ; + RadioWidgetClass super = (RadioWidgetClass)c->core_class.superclass ; + + if( c->radio_class.drawDiamond == NULL || + c->radio_class.drawDiamond == XtInheritDrawDiamond ) + { + c->radio_class.drawDiamond = super->radio_class.drawDiamond ; + } +} + + + + +/*ARGSUSED*/ +static void +RadioInit(request, new, args, num_args) + Widget request, new; + ArgList args; + Cardinal *num_args; +{ + RadioWidget rw = (RadioWidget) new; + RadioWidget rw_req = (RadioWidget) request; + Dimension w,h ; + + /* Select initial size for the widget */ + if( rw_req->core.width == 0 || rw_req->core.height == 0 ) + { + RadioSize(rw, &w,&h) ; + if( rw_req->core.width == 0 ) + rw->core.width = w ; + if( rw_req->core.height == 0 ) + rw->core.height = h ; + rw->core.widget_class->core_class.resize(new) ; + } +} + +/* Function Name: RadioDestroy + * Description: Destroy Callback for radio widget. + * Arguments: w - the radio widget that is being destroyed. + * junk, grabage - not used. + * Returns: none. + */ + +/* ARGSUSED */ +static void +RadioDestroy(w, junk, garbage) +Widget w; +XtPointer junk, garbage; +{ + /* TODO: get rid of this */ +} + + +/* React to size change from manager. Label widget will compute some internal + * stuff, but we need to override. This code requires knowledge of the + * internals of the Label widget. + */ + +static void +RadioResize(w) + Widget w ; +{ + RadioWidget rw = (RadioWidget)w ; + + /* call parent resize proc */ + SuperClass->core_class.resize(w) ; + + /* override label offset */ + + switch( rw->label.justify ) { + case XtJustifyLeft: + rw->label.label_x += bs(rw) + rw->label.internal_width ; + break ; + case XtJustifyRight: + break ; + case XtJustifyCenter: + default: + rw->label.label_x += (bs(rw) + rw->label.internal_width)/2 ; + break ; + } +} + + +/* + * Repaint the widget window. + */ + +static void +RadioExpose(w, event, region) + Widget w ; + XEvent *event ; + Region region ; +{ + RadioWidget rw = (RadioWidget) w ; + Display *dpy = XtDisplay(w) ; + Window win = XtWindow(w) ; + GC gc ; + Pixmap left_bitmap ; + extern WidgetClass labelWidgetClass ; + + /* Note: the Label widget examines the region to decide if anything + * needs to be drawn. I'm not sure that this is worth the effort, + * but it bears thinking on. + */ + + /* Command widget may sometimes override the label GC in order + * to draw inverse video. We don't use inverse video, so we need + * to restore the label's normal GC. + */ + rw->label.normal_GC = rw->command.normal_GC ; + + + /* Let label widget draw the label. If there was an lbm_x + * field, we could let Label draw the bitmap too. But there + * isn't, so we need to temporarily remove the bitmap and + * draw it ourself later. + */ + left_bitmap = rw->label.left_bitmap ; + rw->label.left_bitmap = None ; + labelWidgetClass->core_class.expose(w,event,region) ; + rw->label.left_bitmap = left_bitmap ; + + /* now manually draw the left bitmap. TODO: 3-d look, xaw-xpm */ + gc = XtIsSensitive(w) ? rw->label.normal_GC : rw->label.gray_GC ; + if( left_bitmap != None && rw->label.lbm_width > 0 ) + { + /* TODO: handle pixmaps */ + XCopyPlane(dpy, left_bitmap, win, gc, + 0,0, rw->label.lbm_width, rw->label.lbm_height, + (int) rw->label.internal_width*2 + bs(rw), + (int) rw->label.internal_height + rw->label.lbm_y, + (u_long) 1L) ; + } + + /* Finally, the button itself */ + ((RadioWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w) ; +} + + + + +/************************************************************ + * + * Set specified arguments into widget + * + ***********************************************************/ + + +/* ARGSUSED */ +static Boolean +RadioSetValues(current, request, new, args, num_args) + Widget current, request, new; + ArgList args; + Cardinal *num_args; +{ + RadioWidget oldrw = (RadioWidget) current; + RadioWidget newrw = (RadioWidget) new; + + /* Need to find out if the size of the widget changed. Set new size + * if it did and resize is permitted. One way to determine of the + * widget changed size would be to scan the args list. Another way + * is to compare the old and new widgets and see if any of several + * size-related fields have been changed. The Label widget chose the + * former method, but I choose the latter. + */ + + if( newrw->label.resize && + ( newrw->core.width != oldrw->core.width || + newrw->core.height != oldrw->core.height || + newrw->core.border_width != oldrw->core.border_width ) ) + { + RadioSize(newrw, &newrw->core.width, &newrw->core.height) ; + } + + return FALSE ; +} + +static XtGeometryResult +RadioQueryGeometry(w, intended, preferred) + Widget w ; + XtWidgetGeometry *intended, *preferred ; +{ + RadioWidget rw = (RadioWidget) w; + + preferred->request_mode = CWWidth | CWHeight; + RadioSize(rw, &preferred->width, &preferred->height) ; + + if ( ((intended->request_mode & (CWWidth | CWHeight)) + == (CWWidth | CWHeight)) && + intended->width == preferred->width && + intended->height == preferred->height) + return XtGeometryYes; + else if (preferred->width == w->core.width && + preferred->height == w->core.height) + return XtGeometryNo; + else + return XtGeometryAlmost; +} + + + + + +/************************************************************ + * + * Action Procedures + * + ************************************************************/ + +/* + * Draw the highlight border around the widget. The Command widget + * did this by drawing through a mask. We do it by just drawing the + * border. + */ + +static void +DrawHighlight(w,gc) + Widget w; + GC gc ; +{ + RadioWidget rw = (RadioWidget)w; + XRectangle rects[4] ; + Dimension ht = rw->command.highlight_thickness ; + + if( ht <= 0 || + ht > rw->core.width/2 || + ht > rw->core.height/2 ) + return ; + + if( ! XtIsRealized(w) ) + return ; + + rects[0].x = 0 ; rects[0].y = 0 ; + rects[0].width = rw->core.width ; rects[0].height = ht ; + rects[1].x = 0 ; rects[1].y = rw->core.height - ht ; + rects[1].width = rw->core.width ; rects[1].height = ht ; + rects[2].x = 0 ; rects[2].y = ht ; + rects[2].width = ht ; rects[2].height = rw->core.height - ht*2 ; + rects[3].x = rw->core.width - ht ; rects[3].y = ht ; + rects[3].width = ht ; rects[3].height = rw->core.height - ht*2 ; + XFillRectangles( XtDisplay(w), XtWindow(w), gc, rects, 4) ; +} + +static void +RadioHighlight(w,event,params,num_params) + Widget w ; + XEvent *event ; + String *params ; + Cardinal *num_params ; +{ + RadioWidget rw = (RadioWidget)w; + DrawHighlight(w, rw->command.normal_GC) ; +} + + +static void +RadioUnhighlight(w,event,params,num_params) + Widget w ; + XEvent *event ; + String *params ; + Cardinal *num_params ; +{ + RadioWidget rw = (RadioWidget)w; + DrawHighlight(w, rw->command.inverse_GC) ; +} + + +/* ARGSUSED */ +void +RadioSet(w,event,params,num_params) +Widget w; +XEvent *event; +String *params; /* unused */ +Cardinal *num_params; /* unused */ +{ + RadioWidget rw = (RadioWidget)w; + RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class ; + + if( rw->command.set ) + return ; + + rw->command.set = TRUE ; + if( XtIsRealized(w) ) + class->radio_class.drawDiamond(w) ; +} + + +/* ARGSUSED */ +void +RadioUnset(w,event,params,num_params) +Widget w; +XEvent *event; +String *params; /* unused */ +Cardinal *num_params; /* unused */ +{ + RadioWidget rw = (RadioWidget)w; + RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class ; + + if( ! rw->command.set ) + return ; + + rw->command.set = FALSE ; + if( XtIsRealized(w) ) + class->radio_class.drawDiamond(w) ; +} + + + + +/************************************************************ + * + * Internal Procedures + * + ************************************************************/ + + +/* Size of widget. Width is size of box plus width of border around + * box plus width of label plus three margins plus the size of the left + * bitmap, if any. Height is max(box,bitmap,label) plus two margins. + */ + +static void +RadioSize(rw, w,h) + RadioWidget rw ; + Dimension *w, *h ; +{ + *w = rw->label.label_width + bs(rw) + LEFT_OFFSET(rw) + + 3 * rw->label.internal_width ; + *h = Max( rw->label.label_height, bs(rw) ) + + 2 * rw->label.internal_width ; +} + + +static void +DrawDiamond(w) + Widget w ; +{ + RadioWidget rw = (RadioWidget) w ; + Display *dpy = XtDisplay(w) ; + Window win = XtWindow(w) ; + GC gc, gci ; + + XPoint pts[5] ; + Dimension del = bsize(rw)/2 ; + Position x,y ; /* diamond center */ +#ifdef _ThreeDP_h + int i=0; + Dimension s = swid(rw) ; + GC top, bot, ctr ; +#endif + gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC ; + + gci = rw->command.set ? rw->command.normal_GC : rw->command.inverse_GC ; + + x = rw->label.internal_width + bs(rw)/2 ; + y = rw->core.height/2 ; + +#ifdef _ThreeDP_h + if( ! rw->command.set ) { + top = rw->threeD.top_shadow_GC ; + bot = rw->threeD.bot_shadow_GC ; + ctr = gc ; /* TODO */ + } else { + top = rw->threeD.bot_shadow_GC ; + bot = rw->threeD.top_shadow_GC ; + ctr = gc ; /* TODO */ + } +#endif + + pts[0].x = x - del ; + pts[0].y = y ; + pts[1].x = x ; + pts[1].y = y - del ; + pts[2].x = x + del ; + pts[2].y = y ; + pts[3].x = x ; + pts[3].y = y + del ; + pts[4] = pts[0] ; + XFillPolygon(dpy,win,gci, pts,4, Convex, CoordModeOrigin) ; + +#ifdef _ThreeDP_h + for(i=0; i + +/* Resources: + + Name Class RepType Default Value + ---- ----- ------- ------------- + radioGroup RadioGroup Widget NULL + radioData RadioData Pointer (XPointer) Widget + state State Boolean Off + background Background Pixel XtDefaultBackground + bitmap Pixmap Pixmap None + border BorderColor Pixel XtDefaultForeground + borderWidth BorderWidth Dimension 1 + callback Callback Pointer NULL + cursor Cursor Cursor None + destroyCallback Callback Pointer NULL + font Font XFontStructx* XtDefaultFont + foreground Foreground Pixel XtDefaultForeground + height Height Dimension text height + highlightThickness Thickness Dimension 2 + insensitiveBorder sensitive Pixmap Gray + internalHeight Height Dimension 2 + internalWidth Width Dimension 4 + justify Justify XtJustify XtJustifyCenter + label Label String NULL + mappedWhenManaged MappedWhenManaged Boolean True + resize Resize Boolean True + sensitive Sensitive Boolean True + width Width Dimension text width + x Position Position 0 + y Position Position 0 + +*/ + +/* + * These should be in StringDefs.h but aren't so we will define + * them here if they are needed. + */ + + +extern WidgetClass radioWidgetClass; + +typedef struct _RadioClassRec *RadioWidgetClass; +typedef struct _RadioRec *RadioWidget; + + +/************************************************************ + * + * Public Functions + * + ************************************************************/ + +#endif /* _XawRadio_h */ Index: lwlib/xlwradioP.h =================================================================== RCS file: xlwradioP.h diff -N xlwradioP.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwradioP.h Wed Jul 28 01:33:56 1999 @@ -0,0 +1,106 @@ +/* Radio Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + * RadioP.h - Private definitions for Radio widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: June 30, 1997 + * + */ + +#ifndef _XawRadioP_h +#define _XawRadioP_h + +#include "xlwradio.h" +#include + +/*********************************************************************** + * + * Radio Widget Private Data + * + ***********************************************************************/ + +#define streq(a, b) ( strcmp((a), (b)) == 0 ) + +typedef void (*XawDiamondProc)() ; + +/************************************ + * + * Class structure + * + ***********************************/ + + /* New fields for the Radio widget class record */ +typedef struct _RadioClass { + Dimension dsize ; /* diamond size */ + XawDiamondProc drawDiamond ; + /* TODO: 3-d and xaw-xpm features? */ + XtPointer extension; +} RadioClassPart; + +#define XtInheritDrawDiamond ((XawDiamondProc)_XtInherit) + + /* Full class record declaration */ +typedef struct _RadioClassRec { + CoreClassPart core_class; + SimpleClassPart simple_class; +#ifdef _ThreeDP_h + ThreeDClassPart threeD_class; +#endif + LabelClassPart label_class; + CommandClassPart command_class; + ToggleClassPart toggle_class; + RadioClassPart radio_class; +} RadioClassRec; + +extern RadioClassRec radioClassRec; + +/*************************************** + * + * Instance (widget) structure + * + **************************************/ + + /* New fields for the Radio widget record */ +typedef struct { + /* resources */ + /* TODO: 3-d and xaw-xpm features? */ + + /* private data */ + XtPointer extension; +} RadioPart; + + /* Full widget declaration */ +typedef struct _RadioRec { + CorePart core; + SimplePart simple; +#ifdef _ThreeDP_h + ThreeDPart threeD; +#endif + LabelPart label; + CommandPart command; + TogglePart toggle; + RadioPart radio; +} RadioRec; + +#endif /* _XawRadioP_h */ Index: lwlib/xlwtabs.c =================================================================== RCS file: xlwtabs.c diff -N xlwtabs.c --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwtabs.c Wed Jul 28 01:33:59 1999 @@ -0,0 +1,1663 @@ +/* Tabs Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Tabs.c 1.16 */ + +/* + * Tabs.c - Index Tabs composite widget + * + * Author: Edward A. Falk + * falk@falconer.vip.best.com + * + * Date: July 29, 1997 + * + * + * Overall layout of this widget is as follows: + * + * ________ ,---------. _________ + * | label || Label || Label | \ tabs + * |________|| ||_________| / + * |+----------------------------+| \ + * || || | + * || child widget window || > frame + * |+----------------------------+| | + * +------------------------------+ / + * + * The height of the tabs includes the shadow width, top and bottom + * margins, and the height of the text. + * + * The height of the frame includes the top and bottom shadow width and the + * size of the child widget window. + * + * The tabs overlap the frame and each other vertically by the shadow + * width, so that when the topmost tab is drawn, it obliterates part of + * the frame. + */ + +/* TODO: min child height = tab height + * + */ + +#include + +#include +#include +#include +#include + +#include "xlwtabsP.h" +#include "xlwgcs.h" + +#define MIN_WID 10 +#define MIN_HGT 10 +#define INDENT 3 /* tabs indented from edge by this much */ +#define SPACING 0 /* distance between tabs */ +#define SHADWID 1 /* default shadow width */ +#define TABDELTA 2 /* top tab grows this many pixels when on top */ + + +/**************************************************************** + * + * IndexTabs Resources + * + ****************************************************************/ + +static char defaultTranslations[] = + ": select()" ; + +#define offset(field) XtOffsetOf(TabsRec, tabs.field) +static XtResource resources[] = { + + {XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, sizeof(Boolean), + offset(selectInsensitive), XtRImmediate, (XtPointer) True}, + { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), + offset(font), XtRString, XtDefaultFont}, + { XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension), + offset(internalWidth), XtRImmediate, (XtPointer)4 }, + { XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension), + offset(internalHeight), XtRImmediate, (XtPointer)4 }, + { XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension), + XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, + (XtPointer)0}, + { XtNtopWidget, XtCTopWidget, XtRWidget, sizeof(Widget), + offset(topWidget), XtRImmediate, NULL}, + { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), + offset(callbacks), XtRCallback, NULL}, + { XtNpopdownCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + offset(popdownCallbacks), XtRCallback, NULL}, + {XtNbeNiceToColormap, XtCBeNiceToColormap, XtRBoolean, sizeof(Boolean), + offset(be_nice_to_cmap), XtRImmediate, (XtPointer) True}, + {XtNtopShadowContrast, XtCTopShadowContrast, XtRInt, sizeof(int), + offset(top_shadow_contrast), XtRImmediate, (XtPointer) 20}, + {XtNbottomShadowContrast, XtCBottomShadowContrast, XtRInt, sizeof(int), + offset(bot_shadow_contrast), XtRImmediate, (XtPointer) 40}, + {XtNinsensitiveContrast, XtCInsensitiveContrast, XtRInt, sizeof(int), + offset(insensitive_contrast), XtRImmediate, (XtPointer) 33}, +}; +#undef offset + + + + /* constraint resources */ + +#define offset(field) XtOffsetOf(TabsConstraintsRec, tabs.field) +static XtResource tabsConstraintResources[] = { + {XtNtabLabel, XtCLabel, XtRString, sizeof(String), + offset(label), XtRString, NULL}, + {XtNtabLeftBitmap, XtCLeftBitmap, XtRBitmap, sizeof(Pixmap), + offset(left_bitmap), XtRImmediate, None}, + {XtNtabForeground, XtCForeground, XtRPixel, sizeof(Pixel), + offset(foreground), XtRString, XtDefaultForeground}, + {XtNresizable, XtCResizable, XtRBoolean, sizeof(Boolean), + offset(resizable), XtRImmediate, (XtPointer) True}, +} ; +#undef offset + + + + +#ifndef __STDC__ + + /* FORWARD REFERENCES: */ + + /* member functions */ + +static void TabsClassInit(); +static void TabsInit(); +static void TabsResize(); +static void TabsExpose(); +static void TabsDestroy(); +static void TabsRealize(); +static Boolean TabsSetValues(); +static XtGeometryResult TabsQueryGeometry(); +static XtGeometryResult TabsGeometryManager(); +static void TabsChangeManaged(); +static void TabsConstraintInitialize() ; +static Boolean TabsConstraintSetValues() ; + + /* action procs */ + +static void TabsSelect() ; + + /* internal privates */ + +static void TabsAllocGCs() ; /* get rendering GCs */ +static void TabsFreeGCs() ; /* return rendering GCs */ +static void DrawTabs() ; /* draw all tabs */ +static void DrawTab() ; /* draw one index tab */ +static void DrawFrame() ; /* draw frame around contents */ +static void DrawTrim() ; /* draw trim around a tab */ +static void DrawBorder() ; /* draw border */ +static void TabWidth() ; /* recompute tab size */ +static void MaxChild() ; +static int PreferredSize() ; /* compute preferred size */ +static int PreferredSize2() ; /* compute preferred size */ +static int PreferredSize3() ; /* compute preferred size */ +static void MakeSizeRequest() ; /* try to change size */ +static void getBitmapInfo() ; +static int TabLayout() ; /* lay out tabs */ +static void TabsShuffleRows() ; /* bring current tab to bottom row */ + +static void TabsAllocFgGC() ; +static void TabsAllocGreyGC() ; + +#else + +static void TabsClassInit() ; +static void TabsInit( Widget req, Widget new, ArgList, Cardinal *nargs) ; +static void TabsConstraintInitialize(Widget, Widget, ArgList, Cardinal *) ; +static void TabsRealize(Widget, Mask *, XSetWindowAttributes *) ; +static void TabsDestroy( Widget w) ; +static void TabsResize( Widget w) ; +static void TabsExpose( Widget w, XEvent *event, Region region) ; +static Boolean TabsSetValues(Widget, Widget, Widget, ArgList, Cardinal *) ; +static Boolean TabsConstraintSetValues(Widget, Widget, Widget, + ArgList, Cardinal *) ; +static XtGeometryResult TabsQueryGeometry(Widget, + XtWidgetGeometry *, XtWidgetGeometry *) ; +static XtGeometryResult TabsGeometryManager(Widget, + XtWidgetGeometry *, XtWidgetGeometry *) ; +static void TabsChangeManaged( Widget w) ; + +static void TabsSelect(Widget, XEvent *, String *, Cardinal *) ; + +static void DrawTabs( TabsWidget tw, int labels) ; +static void DrawTab( TabsWidget tw, Widget child, int labels) ; +static void DrawFrame( TabsWidget tw) ; +static void DrawTrim( TabsWidget, int x, int y, + int wid, int hgt, int bottom, int undraw) ; +static void DrawBorder( TabsWidget tw, Widget child, int undraw) ; + +static void TabWidth( Widget w) ; +static int TabLayout( TabsWidget, int wid, Dimension *r_hgt, + int query_only) ; +static void MaxChild( TabsWidget, Dimension *, Dimension *, Widget) ; +static void TabsShuffleRows( TabsWidget tw) ; +static int PreferredSize( TabsWidget, + Dimension *reply_width, Dimension *reply_height, + Dimension *reply_cw, Dimension *reply_ch) ; +static int PreferredSize2( TabsWidget, int cw, int ch, + Dimension *rw, Dimension *rh) ; +static int PreferredSize3( TabsWidget, int wid, int hgt, + Dimension *rw, Dimension *rh) ; +static void MakeSizeRequest(TabsWidget) ; + +static void TabsAllocGCs(TabsWidget) ; +static void TabsFreeGCs(TabsWidget) ; +static void getBitmapInfo( TabsWidget tw, TabsConstraints tab) ; +static void TabsAllocFgGC( TabsWidget tw) ; +static void TabsAllocGreyGC( TabsWidget tw) ; + +#endif + +#if XtSpecificationRelease < 5 +static GC XtAllocateGC() ; +#endif + +#define AddRect(i,xx,yy,w,h) \ + do{rects[(i)].x=(xx); rects[i].y=(yy); \ + rects[i].width=(w); rects[i].height=(h);}while(0) + +static XtActionsRec actionsList[] = + { + {"select", TabsSelect}, + } ; + + +/**************************************************************** +* +* Full class record constant +* +****************************************************************/ + +TabsClassRec tabsClassRec = { + { +/* core_class fields */ + /* superclass */ (WidgetClass) &constraintClassRec, + /* class_name */ "Tabs", + /* widget_size */ sizeof(TabsRec), + /* class_initialize */ TabsClassInit, + /* class_part_init */ NULL, /* TODO? */ + /* class_inited */ FALSE, + /* initialize */ TabsInit, + /* initialize_hook */ NULL, + /* realize */ TabsRealize, + /* actions */ actionsList, + /* num_actions */ XtNumber(actionsList), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ TRUE, + /* visible_interest */ FALSE, + /* destroy */ TabsDestroy, + /* resize */ TabsResize, + /* expose */ TabsExpose, + /* set_values */ TabsSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ defaultTranslations, + /* query_geometry */ TabsQueryGeometry, + /* display_accelerator*/ XtInheritDisplayAccelerator, + /* extension */ NULL + }, + { +/* composite_class fields */ + /* geometry_manager */ TabsGeometryManager, + /* change_managed */ TabsChangeManaged, + /* insert_child */ XtInheritInsertChild, /* TODO? */ + /* delete_child */ XtInheritDeleteChild, /* TODO? */ + /* extension */ NULL + }, + { +/* constraint_class fields */ + /* subresources */ tabsConstraintResources, + /* subresource_count */ XtNumber(tabsConstraintResources), + /* constraint_size */ sizeof(TabsConstraintsRec), + /* initialize */ TabsConstraintInitialize, + /* destroy */ NULL, + /* set_values */ TabsConstraintSetValues, + /* extension */ NULL, + }, + { +/* Tabs class fields */ + /* extension */ NULL, + } +}; + +WidgetClass tabsWidgetClass = (WidgetClass)&tabsClassRec; + + + +#ifdef DEBUG +#ifdef __STDC__ +#define assert(e) \ + ((e) || fprintf(stderr,"yak! %s at %s:%d\n",#e,__FILE__,__LINE__)) +#else +#define assert(e) \ + ((e) || fprintf(stderr,"yak! e at %s:%d\n",__FILE__,__LINE__)) +#endif +#else +#define assert(e) +#endif + + + + +/**************************************************************** + * + * Member Procedures + * + ****************************************************************/ + +static void +TabsClassInit() +{ + /* TODO: register converter for labels? */ +} + + + + /* Init a newly created tabs widget. Compute height of tabs + * and optionally compute size of widget. */ + +/* ARGSUSED */ + +static void +TabsInit(request, new, args, num_args) + Widget request, new; + ArgList args; + Cardinal *num_args; +{ + TabsWidget newTw = (TabsWidget)new; + + newTw->tabs.numRows = 0 ; + + /* height is easy, it's the same for all tabs: + * TODO: font height + height of tallest bitmap. + */ + newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ; + + if( newTw->tabs.font != NULL ) + newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent + + newTw->tabs.font->max_bounds.descent ; + + /* GC allocation is deferred until XtRealize() */ + + /* if size not explicitly set, set it to our preferred size now. */ + + if( request->core.width == 0 || request->core.height == 0 ) + { + Dimension w,h ; + PreferredSize(newTw, &w, &h, NULL,NULL) ; + if( request->core.width == 0 ) new->core.width = w ; + if( request->core.height == 0 ) new->core.height = h ; + XtClass(new)->core_class.resize(new) ; + } + + /* defer GC allocation, etc., until Realize() time. */ + newTw->tabs.foregroundGC = + newTw->tabs.backgroundGC = + newTw->tabs.greyGC = + newTw->tabs.topGC = + newTw->tabs.botGC = None ; + + newTw->tabs.grey50 = None ; + + newTw->tabs.needs_layout = False ; +} + + + /* Init the constraint part of a new tab child. Compute the + * size of the tab. + */ +/* ARGSUSED */ +static void +TabsConstraintInitialize(request, new, args, num_args) + Widget request, new ; + ArgList args ; + Cardinal *num_args; +{ + TabsConstraints tab = (TabsConstraints) new->core.constraints ; + tab->tabs.greyAlloc = False ; /* defer allocation of pixel */ + + getBitmapInfo((TabsWidget)XtParent(new), tab) ; + TabWidth(new) ; +} + + + + /* Called when tabs widget first realized. Create the window + * and allocate the GCs + */ + +static void +TabsRealize(w, valueMask, attributes) + Widget w; + Mask *valueMask; + XSetWindowAttributes *attributes; +{ + TabsWidget tw = (TabsWidget) w; + + attributes->bit_gravity = NorthWestGravity; + *valueMask |= CWBitGravity; + + /* TODO: shouldn't this chain to the parent's realize instead? */ + XtCreateWindow( w, (unsigned)InputOutput, (Visual *)CopyFromParent, + *valueMask, attributes); + + TabsAllocGCs(tw) ; +} + + + +static void +TabsDestroy(w) + Widget w ; +{ + TabsFreeGCs((TabsWidget)w) ; +} + + + /* Parent has resized us. This will require that the tabs be + * laid out again. + */ + +static void +TabsResize(w) + Widget w; +{ + TabsWidget tw = (TabsWidget) w; + int i ; + int num_children = tw->composite.num_children ; + Widget *childP ; + TabsConstraints tab ; + Dimension cw,ch,bw ; + + + /* Our size has now been dictated by the parent. Lay out the + * tabs, lay out the frame, lay out the children. Remember + * that the tabs overlap each other and the frame by shadowWidth. + * Also, the top tab is larger than the others, so if there's only + * one row, the widget must be made taller to accomodate this. + * + * Once the tabs are laid out, if there is more than one + * row, we may need to shuffle the rows to bring the top tab + * to the bottom row. + */ + + if( num_children > 0 && tw->composite.children != NULL ) + { + /* Loop through the tabs and assign rows & x positions */ + (void) TabLayout(tw, tw->core.width, NULL, False) ; + + /* assign a top widget, bring it to bottom row. */ + TabsShuffleRows(tw) ; + + /* now assign child positions & sizes. Positions are all the + * same: just inside the frame. Sizes are also all the same. + */ + + tw->tabs.child_width = cw = tw->core.width - 2 * SHADWID ; + tw->tabs.child_height = ch = + tw->core.height - tw->tabs.tab_total - 2 * SHADWID ; + + + for(i=0, childP=tw->composite.children; + i < num_children; + ++i, ++childP) + { + tab = (TabsConstraints) (*childP)->core.constraints ; + bw = tab->tabs.bwid ; + XtConfigureWidget(*childP, SHADWID,tw->tabs.tab_total+SHADWID, + cw-bw*2,ch-bw*2, bw) ; + } + } + + tw->tabs.needs_layout = False ; +} /* Resize */ + + + + /* Redraw entire Tabs widget */ + +/* ARGSUSED */ +static void +TabsExpose(w, event, region) + Widget w ; + XEvent *event ; + Region region ; +{ + TabsWidget tw = (TabsWidget) w; + + if( tw->tabs.needs_layout ) + XtClass(w)->core_class.resize(w) ; + + DrawTabs(tw, True) ; +} + + + /* Called when any Tabs widget resources are changed. */ + +/* ARGSUSED */ +static Boolean +TabsSetValues(current, request, new, args, num_args) + Widget current, request, new; + ArgList args; + Cardinal *num_args; +{ + TabsWidget curtw = (TabsWidget) current ; + TabsWidget tw = (TabsWidget) new ; + Boolean needRedraw = False ; + Widget *childP ; + int i ; + + + if( tw->tabs.font != curtw->tabs.font || + tw->tabs.internalWidth != curtw->tabs.internalWidth || + tw->tabs.internalHeight != curtw->tabs.internalHeight ) + { + tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID ; + + if( tw->tabs.font != NULL ) + tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent + + tw->tabs.font->max_bounds.descent ; + + /* Tab size has changed. Resize all tabs and request a new size */ + for(i=0, childP=tw->composite.children; + i < tw->composite.num_children; + ++i, ++childP) + TabWidth(*childP) ; + PreferredSize(tw, &tw->core.width, &tw->core.height, NULL,NULL) ; + needRedraw = True ; + tw->tabs.needs_layout = True ; + } + + /* TODO: if any color changes, need to recompute GCs and redraw */ + + if( tw->core.background_pixel != curtw->core.background_pixel || + tw->core.background_pixmap != curtw->core.background_pixmap ) + { + TabsFreeGCs(tw) ; + TabsAllocGCs(tw) ; + needRedraw = True ; + } + + if( tw->core.sensitive != curtw->core.sensitive ) + needRedraw = True ; + + /* If top widget changes, need to change stacking order, redraw tabs. + * Window system will handle the redraws. + */ + + if( tw->tabs.topWidget != curtw->tabs.topWidget ) + { + Widget w = curtw->tabs.topWidget ; + TabsConstraints tab = (TabsConstraints) w->core.constraints ; + + XRaiseWindow(XtDisplay(w), XtWindow(w)) ; + + if( tab->tabs.row != tw->tabs.numRows-1 ) + TabsShuffleRows(tw) ; + + needRedraw = True ; + } + + return needRedraw ; +} + + + /* Called when any child constraint resources change. */ + +/* ARGSUSED */ +static Boolean +TabsConstraintSetValues(current, request, new, args, num_args) + Widget current, request, new; + ArgList args; + Cardinal *num_args; +{ + TabsWidget tw = (TabsWidget) XtParent(new) ; + TabsConstraints ctab = (TabsConstraints) current->core.constraints ; + TabsConstraints tab = (TabsConstraints) new->core.constraints ; + + + /* if label changes, need to re-layout the entire widget */ + /* if foreground changes, need to redraw tab label */ + + /* TODO: only need resize of new bitmap has different dimensions + * from old bitmap. + */ + + if( tab->tabs.label != ctab->tabs.label || /* Tab size has changed. */ + tab->tabs.left_bitmap != ctab->tabs.left_bitmap ) + { + TabWidth(new) ; + tw->tabs.needs_layout = True ; + + if( tab->tabs.left_bitmap != ctab->tabs.left_bitmap ) + getBitmapInfo(tw, tab) ; + + /* If there are no subclass ConstraintSetValues procedures remaining + * to be invoked, and if the preferred size has changed, ask + * for a resize. + */ + if( XtClass((Widget)tw) == tabsWidgetClass ) + MakeSizeRequest(tw) ; + } + + + /* The child widget itself never needs a redisplay, but the parent + * Tabs widget might. + */ + + if( tw->tabs.needs_layout ) { + XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; + XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ; + } + + else if( tab->tabs.foreground != ctab->tabs.foreground ) + DrawTab(tw, new, True) ; + + return False ; +} + + + +/* + * Return preferred size. + */ + +static XtGeometryResult +TabsQueryGeometry(w, intended, preferred) + Widget w; + XtWidgetGeometry *intended, *preferred; +{ +register TabsWidget tw = (TabsWidget)w ; + + preferred->request_mode = CWWidth | CWHeight ; + PreferredSize(tw, &preferred->width, &preferred->height, NULL,NULL) ; + + if( intended->width == w->core.width && + intended->height == w->core.height ) + return XtGeometryNo ; + + if( (!(intended->request_mode & CWWidth) || + intended->width >= preferred->width) && + (!(intended->request_mode & CWHeight) || + intended->height >= preferred->height) ) + return XtGeometryYes; + else + return XtGeometryAlmost; +} + + + +/* + * Geometry Manager; called when a child wants to be resized. + */ + +static XtGeometryResult +TabsGeometryManager(w, req, reply) + Widget w; + XtWidgetGeometry *req; + XtWidgetGeometry *reply; /* RETURN */ + +{ + TabsWidget tw = (TabsWidget) XtParent(w); + Dimension s = SHADWID ; + TabsConstraints tab = (TabsConstraints)w->core.constraints; + XtGeometryResult result ; + + /* Position request always denied */ + + if( ((req->request_mode & CWX) && req->x != w->core.x) || + ((req->request_mode & CWY) && req->y != w->core.y) || + !tab->tabs.resizable ) + return XtGeometryNo ; + + /* Make all three fields in the request valid */ + if( !(req->request_mode & CWWidth) ) + req->width = w->core.width; + if( !(req->request_mode & CWHeight) ) + req->height = w->core.height; + if( !(req->request_mode & CWBorderWidth) ) + req->border_width = w->core.border_width; + + if( req->width == w->core.width && + req->height == w->core.height && + req->border_width == w->core.border_width ) + return XtGeometryNo ; + + /* Size changes must see if the new size can be accomodated. + * The Tabs widget keeps all of its children the same + * size. A request to shrink will be accepted only if the + * new size is still big enough for all other children. A + * request to shrink that is not big enough for all children + * returns an "almost" response with the new proposed size. + * A request to grow will be accepted only if the Tabs parent can + * grow to accomodate. + */ + + if (req->request_mode & (CWWidth | CWHeight | CWBorderWidth)) + { + Dimension rw,rh ; /* requested size, including borders */ + Dimension cw,ch ; /* other children's preferred size */ + Dimension mw,mh ; /* max of above; this is our target */ + Dimension aw,ah ; /* available size we can give child */ + Dimension th ; /* space used by tabs */ + Dimension wid,hgt ; /* Tabs widget size */ + + rw = req->width + 2*req->border_width ; + rh = req->height + 2*req->border_width ; + + /* find out what the resulting preferred size would be */ + + MaxChild(tw, &cw, &ch, w) ; + mw = Max(cw, rw) ; + mh = Max(ch, rh) ; + PreferredSize2(tw, mw,mh, &wid, &hgt) ; + + /* Ask to be resized to accomodate. */ + + if( wid != tw->core.width || hgt != tw->core.height ) + { + Dimension oldWid = tw->core.width, oldHgt = tw->core.height ; + XtWidgetGeometry myrequest, myreply ; + + myrequest.width = wid ; + myrequest.height = hgt ; + myrequest.request_mode = CWWidth | CWHeight ; + + /* If child is only querying, or if we're going to have to + * offer the child a compromise, then make this a query only. + */ + + if( (req->request_mode & XtCWQueryOnly) || rw < mw || rh < mh ) + myrequest.request_mode |= XtCWQueryOnly ; + + result = XtMakeGeometryRequest((Widget)tw, &myrequest, &myreply) ; + + /* !$@# Box widget changes the core size even if QueryOnly + * is set. I'm convinced this is a bug. At any rate, to work + * around the bug, we need to restore the core size after every + * query geometry request. This is only partly effective, + * as there may be other boxes further up the tree. + */ + if( myrequest.request_mode & XtCWQueryOnly ) { + tw->core.width = oldWid ; + tw->core.height = oldHgt ; + } + + /* based on the parent's response, determine what the + * resulting Tabs widget size would be. + */ + + switch( result ) { + case XtGeometryYes: + break ; + + case XtGeometryNo: + wid = tw->core.width ; + hgt = tw->core.height ; + break ; + + case XtGeometryAlmost: + wid = myreply.width ; + hgt = myreply.height ; + } + } + + /* Within the constraints imposed by the parent, what is + * the max size we can give the child? + */ + (void) TabLayout(tw, wid, &th, True) ; + aw = wid - 2*s ; + ah = hgt - th - 2*s ; + + /* OK, make our decision. If requested size is >= max sibling + * preferred size, AND requested size <= available size, then + * we accept. Otherwise, we offer a compromise. + */ + + if( rw == aw && rh == ah ) + { + /* Acceptable. If this wasn't a query, change *all* children + * to this size. + */ + if( req->request_mode & XtCWQueryOnly ) + return XtGeometryYes ; + else + { + Widget *childP ; + int i,bw ; + w->core.border_width = req->border_width ; + for(i=tw->composite.num_children, childP=tw->composite.children; + --i >= 0; ++childP) + { + bw = (*childP)->core.border_width ; + XtConfigureWidget(*childP, s,tw->tabs.tab_total+s, + rw-2*bw,rh-2*bw, bw) ; + } +#ifdef COMMENT + /* TODO: under what conditions will we need to redraw? */ + XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; + XtClass(tw)->core_class.expose((Widget)tw,NULL,NULL) ; +#endif /* COMMENT */ + return XtGeometryDone ; + } + } + + /* Cannot accede to child's request. Describe what we *can* do + * and return counter-offer. + */ + reply->width = aw - 2*req->border_width ; + reply->height = ah - 2*req->border_width ; + reply->border_width = req->border_width ; + reply->request_mode = CWWidth | CWHeight | CWBorderWidth ; + return XtGeometryAlmost ; + } + + return XtGeometryYes ; +} + + + + + /* The number of children we manage has changed; recompute + * size from scratch. + */ + +static void +TabsChangeManaged(w) + Widget w; +{ + TabsWidget tw = (TabsWidget)w ; + Widget *childP ; + int i ; + int n = tw->composite.num_children ; + + MakeSizeRequest(tw) ; + + XtClass(w)->core_class.resize(w) ; + if( XtIsRealized(w) ) + { + Display *dpy = XtDisplay(w) ; + XClearWindow(dpy, XtWindow(w)) ; + XtClass(w)->core_class.expose(w,NULL,NULL) ; + + /* make sure the top widget stays on top. This requires + * making sure that all new children are realized first. + */ + if( tw->tabs.topWidget != NULL ) { + for(i=0, childP=tw->composite.children; i < n; ++i, ++childP) + if( !XtIsRealized(*childP) ) + XtRealizeWidget(*childP) ; + XRaiseWindow(dpy, XtWindow(tw->tabs.topWidget)) ; + } + } +} + + + + +/**************************************************************** + * + * Action Procedures + * + ****************************************************************/ + + /* User clicks on a tab, figure out which one it was. */ + +/* ARGSUSED */ +static void +TabsSelect(w, event, params, num_params) + Widget w ; + XEvent *event ; + String *params ; + Cardinal *num_params ; +{ + TabsWidget tw = (TabsWidget) w ; + Widget *childP ; + Position x,y ; + Dimension h = tw->tabs.tab_height ; + int i ; + + /* TODO: is there an Xmu function or something to do this instead? */ + switch( event->type ) { + case ButtonPress: + case ButtonRelease: + x = event->xbutton.x ; y = event->xbutton.y ; break ; + case KeyPress: + case KeyRelease: + x = event->xkey.x ; y = event->xkey.y ; break ; + default: + return ; + } + + /* TODO: determine which tab was clicked, if any. Set that + * widget to be top of stacking order with XawTabsSetTop(). + */ + for(i=0, childP=tw->composite.children; + i < tw->composite.num_children; + ++i, ++childP) + { + TabsConstraints tab = (TabsConstraints)(*childP)->core.constraints; + if( x > tab->tabs.x && x < tab->tabs.x + tab->tabs.width && + y > tab->tabs.y && y < tab->tabs.y + h ) + { + if( *childP != tw->tabs.topWidget && + (XtIsSensitive(*childP) || tw->tabs.selectInsensitive) ) + XawTabsSetTop(*childP, True) ; + break ; + } + } +} + + + + + +/**************************************************************** + * + * Public Procedures + * + ****************************************************************/ + + + /* Set the top tab, optionally call all callbacks. */ +void +XawTabsSetTop(w, callCallbacks) + Widget w ; + int callCallbacks ; +{ + TabsWidget tw = (TabsWidget)w->core.parent ; + TabsConstraints tab ; + + if( !XtIsSubclass(w->core.parent, tabsWidgetClass) ) + { + char line[1024] ; + sprintf(line, "XawTabsSetTop: widget \"%s\" is not the child of a tabs widget.", XtName(w)) ; + XtAppWarning(XtWidgetToApplicationContext(w), line) ; + return ; + } + + if( callCallbacks ) + XtCallCallbackList(w, tw->tabs.popdownCallbacks, + (XtPointer)tw->tabs.topWidget) ; + + XRaiseWindow(XtDisplay(w), XtWindow(w)) ; + + tab = (TabsConstraints) w->core.constraints ; + if( tab->tabs.row == 0 ) + { + /* Easy case; undraw current top, undraw new top, assign new + * top, redraw all borders. + * We *could* just erase and execute a full redraw, but I like to + * reduce screen flicker. + */ + DrawBorder(tw, tw->tabs.topWidget, True) ; + DrawBorder(tw, w, True) ; + tw->tabs.topWidget = w ; + DrawTabs(tw, False) ; + } + else + { + tw->tabs.topWidget = w ; + TabsShuffleRows(tw) ; + XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; + XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ; + } + + if( callCallbacks ) + XtCallCallbackList(w, tw->tabs.callbacks, (XtPointer)w) ; +} + + + + +/**************************************************************** + * + * Private Procedures + * + ****************************************************************/ + + +static void +TabsAllocGCs(tw) + TabsWidget tw ; +{ + TabsAllocFgGC(tw) ; + TabsAllocGreyGC(tw) ; + tw->tabs.backgroundGC = AllocBackgroundGC((Widget)tw, None) ; + tw->tabs.topGC = AllocTopShadowGC((Widget)tw, + tw->tabs.top_shadow_contrast, tw->tabs.be_nice_to_cmap) ; + tw->tabs.botGC = AllocBotShadowGC((Widget)tw, + tw->tabs.bot_shadow_contrast, tw->tabs.be_nice_to_cmap) ; +} + + +static void +TabsFreeGCs(tw) + TabsWidget tw ; +{ + Widget w = (Widget) tw; + + XtReleaseGC(w, tw->tabs.foregroundGC) ; + XtReleaseGC(w, tw->tabs.greyGC) ; + XtReleaseGC(w, tw->tabs.backgroundGC) ; + XtReleaseGC(w, tw->tabs.topGC) ; + XtReleaseGC(w, tw->tabs.botGC) ; + XmuReleaseStippledPixmap(XtScreen(w), tw->tabs.grey50) ; +} + + + + + + /* Redraw entire Tabs widget */ + +static void +DrawTabs(tw, labels) + TabsWidget tw ; + int labels ; /* draw labels? */ +{ + Widget *childP ; + int i,j ; + Dimension s = SHADWID ; + Dimension th = tw->tabs.tab_height ; + Position y ; + TabsConstraints tab ; + + /* draw tabs and frames by row except for the top tab, which + * is drawn last. (This is inefficiently written, but should not + * be too slow as long as there are not a lot of rows.) + */ + + y = tw->tabs.numRows == 1 ? TABDELTA : 0 ; + for(i=0; itabs.numRows; ++i, y += th) + { + for(j=0, childP=tw->composite.children; + j < tw->composite.num_children; + ++j, ++childP) + { + tab = (TabsConstraints)(*childP)->core.constraints; + if( tab->tabs.row == i && *childP != tw->tabs.topWidget ) + DrawTab(tw, *childP, labels) ; + } + if( i != tw->tabs.numRows -1 ) + DrawTrim(tw, 0,y+th, tw->core.width, th+s, False,False) ; + } + + DrawFrame(tw) ; + + /* and now the top tab */ + if( tw->tabs.topWidget != NULL ) + DrawTab(tw, tw->tabs.topWidget, labels) ; +} + + + +/* Draw one tab. Corners are rounded very slightly. */ + +static void +DrawTab(tw, child, labels) + TabsWidget tw ; + Widget child ; + int labels ; /* draw label too? */ +{ + GC gc ; + + DrawBorder(tw, child, False) ; + + if( labels ) + { + TabsConstraints tab = (TabsConstraints)child->core.constraints; + Display *dpy = XtDisplay((Widget)tw) ; + Window win = XtWindow((Widget)tw) ; + String lbl = tab->tabs.label != NULL ? + tab->tabs.label : XtName(child) ; + + if( XtIsSensitive(child) ) + { + gc = tw->tabs.foregroundGC ; + XSetForeground(dpy, gc, tab->tabs.foreground) ; + } + else + { + /* grey pixel allocation deferred until now */ + if( !tab->tabs.greyAlloc ) + { + if( tw->tabs.be_nice_to_cmap || tw->core.depth == 1 ) + tab->tabs.grey = tab->tabs.foreground ; + else + tab->tabs.grey = AllocGreyPixel((Widget)tw, + tab->tabs.foreground, + tw->core.background_pixel, + tw->tabs.insensitive_contrast ) ; + tab->tabs.greyAlloc = True ; + } + gc = tw->tabs.greyGC ; + XSetForeground(dpy, gc, tab->tabs.grey) ; + } + + if( tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0 ) + { + if( tab->tabs.lbm_depth == 1 ) + XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc, + 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, + tab->tabs.x+tab->tabs.lbm_x, tab->tabs.y+tab->tabs.lbm_y, 1L) ; + else + XCopyArea(dpy, tab->tabs.left_bitmap, win,gc, + 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, + tab->tabs.x+tab->tabs.lbm_x, tab->tabs.y+tab->tabs.lbm_y) ; + } + + if( lbl != NULL && tw->tabs.font != NULL ) + XDrawString(dpy,win,gc, + tab->tabs.x+tab->tabs.l_x, tab->tabs.y+tab->tabs.l_y, + lbl,strlen(lbl)) ; + } +} + + + /* draw frame all the way around the child windows. */ + +static void +DrawFrame(tw) + TabsWidget tw ; +{ + GC topgc = tw->tabs.topGC ; + GC botgc = tw->tabs.botGC ; + Dimension s = SHADWID ; + Dimension ch = tw->tabs.child_height ; + + Draw3dBox((Widget)tw, 0,tw->tabs.tab_total, + tw->core.width, ch+2*s, s, topgc, botgc) ; +} + + + /* draw trim around a tab or underneath a row of tabs */ + +static void +DrawTrim(tw, x,y,wid,hgt, bottom, undraw) + TabsWidget tw ; /* widget */ + Position x,y ; /* upper-left corner */ + int wid,hgt ; /* total size */ + int bottom ; /* draw bottom? */ + int undraw ; /* undraw all */ +{ + Display *dpy = XtDisplay((Widget)tw) ; + Window win = XtWindow((Widget)tw) ; + GC bggc = tw->tabs.backgroundGC ; + GC topgc = undraw ? bggc : tw->tabs.topGC ; + GC botgc = undraw ? bggc : tw->tabs.botGC ; + + if( bottom ) + XDrawLine(dpy,win,bggc, x,y+hgt-1, x+wid-1,y+hgt-1) ; /* bottom */ + XDrawLine(dpy,win,topgc, x,y+2, x,y+hgt-2) ; /* left */ + XDrawPoint(dpy,win,topgc, x+1,y+1) ; /* corner */ + XDrawLine(dpy,win,topgc, x+2,y, x+wid-3,y) ; /* top */ + XDrawLine(dpy,win,botgc, x+wid-2,y+1, x+wid-2,y+hgt-2) ; /* right */ + XDrawLine(dpy,win,botgc, x+wid-1,y+2, x+wid-1,y+hgt-2) ; /* right */ +} + + +/* Draw one tab border. */ + +static void +DrawBorder(tw, child, undraw) + TabsWidget tw ; + Widget child ; + int undraw ; +{ + TabsConstraints tab = (TabsConstraints)child->core.constraints; + Position x = tab->tabs.x ; + Position y = tab->tabs.y ; + Dimension twid = tab->tabs.width ; + Dimension thgt = tw->tabs.tab_height ; + + /* top tab requires a little special attention; it overlaps + * neighboring tabs slightly, so the background must be cleared + * in the region of the overlap to partially erase those neighbors. + * TODO: is this worth doing with regions instead? + */ + if( child == tw->tabs.topWidget ) + { + Display *dpy = XtDisplay((Widget)tw) ; + Window win = XtWindow((Widget)tw) ; + GC bggc = tw->tabs.backgroundGC ; + XRectangle rects[3] ; + x -= TABDELTA ; + y -= TABDELTA ; + twid += TABDELTA*2 ; + thgt += TABDELTA ; + AddRect(0, x,y+1,twid,TABDELTA) ; + AddRect(1, x+1,y,TABDELTA,thgt) ; + AddRect(2, x+twid-TABDELTA-1,y,TABDELTA,thgt) ; + XFillRectangles(dpy,win,bggc, rects, 3) ; + } + + DrawTrim(tw, x,y,twid,thgt+1, child == tw->tabs.topWidget, undraw) ; +} + + + + + + /* GEOMETRY UTILITIES */ + + + /* Compute the size of a child's tab. Positions will be computed + * elsewhere. + * + * height: font height + vertical_space*2 + shadowWid*2 + * width: string width + horizontal_space*2 + shadowWid*2 + * + * All tabs are the same height, so this is computed elsewhere. + */ + +static void +TabWidth(w) + Widget w ; +{ + TabsConstraints tab = (TabsConstraints) w->core.constraints ; + TabsWidget tw = (TabsWidget)XtParent(w) ; + String lbl = tab->tabs.label != NULL ? + tab->tabs.label : XtName(w) ; + XFontStruct *font = tw->tabs.font ; + int iw = tw->tabs.internalWidth ; + + tab->tabs.width = iw + SHADWID*2 ; + tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ; + + if( tab->tabs.left_bitmap != None ) + { + tab->tabs.width += tab->tabs.lbm_width + iw ; + tab->tabs.l_x += tab->tabs.lbm_width + iw ; + tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ; + } + + if( lbl != NULL && font != NULL ) + { + tab->tabs.width += XTextWidth(font, lbl, strlen(lbl)) + iw ; + tab->tabs.l_y = (tw->tabs.tab_height + + tw->tabs.font->max_bounds.ascent - + tw->tabs.font->max_bounds.descent)/2 ; + } +} + + + + /* Lay out tabs to fit in given width. Compute x,y position and + * row number for each tab. Return number of rows and total height + * required by all tabs. If there is only one row, add TABDELTA + * height to the total. Rows are assigned bottom to top. + * + * Tabs are indented from the edges by INDENT. + * + * TODO: if they require more than two rows and the total height:width + * ratio is more than 2:1, then try something else. + */ + +static int +TabLayout(tw, wid, reply_height, query_only) + TabsWidget tw; + int wid ; /* amount of width to work with. */ + Dimension *reply_height; /* total height of tabs, may be NULL */ + int query_only ; /* just want #rows & total height */ +{ + int i, row ; + int num_children = tw->composite.num_children ; + Widget *childP ; + Dimension w ; + Position x,y ; + TabsConstraints tab ; + + /* Algorithm: loop through children, assign X positions. If a tab + * would extend beyond the right edge, start a new row. After all + * rows are assigned, make a second pass and assign Y positions. + */ + + if( num_children > 0 ) + { + /* Loop through the tabs and see how much space they need. */ + + row = 0 ; + x = INDENT ; + y = 0 ; + wid -= INDENT ; + for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP) + { + tab = (TabsConstraints) (*childP)->core.constraints ; + w = tab->tabs.width ; + if( x + w > wid ) { /* new row */ + ++row ; + x = INDENT ; + y += tw->tabs.tab_height ; + } + if( !query_only ) { + tab->tabs.x = x ; + tab->tabs.y = y ; + tab->tabs.row = row ; + } + x += w + SPACING ; + } + /* If there was only one row, increse the height by TABDELTA */ + if( ++row == 1 ) + { + y = TABDELTA ; + if( !query_only ) + for(i=num_children, childP=tw->composite.children; + --i >= 0 ; ++childP) + { + tab = (TabsConstraints) (*childP)->core.constraints ; + tab->tabs.y = y ; + } + } + y += tw->tabs.tab_height ; + } + else + row = y = 0 ; + + if( !query_only ) { + tw->tabs.tab_total = y ; + tw->tabs.numRows = row ; + } + + if( reply_height != NULL ) + *reply_height = y ; + + return row ; +} + + + + /* Find max preferred child size. Returned sizes include child + * border widths. */ + +static void +MaxChild(tw, reply_cw, reply_ch, except) + TabsWidget tw; + Dimension *reply_cw, *reply_ch; /* child widget size */ + Widget except ; /* ignore this child */ +{ + XtWidgetGeometry preferred ; + Dimension cw,ch ; /* child width, height */ + int i ; + int num_children = tw->composite.num_children ; + Widget *childP ; + TabsConstraints tab ; + + + cw = ch = 0 ; + + for(i=0, childP=tw->composite.children; i < num_children; ++i, ++childP) + { + tab = (TabsConstraints) (*childP)->core.constraints ; + if( *childP != except ) + { + (void) XtQueryGeometry(*childP, NULL, &preferred) ; + tab->tabs.bwid = preferred.border_width ; + + cw = Max(cw, preferred.width + 2*preferred.border_width) ; + ch = Max(ch, preferred.height + 2*preferred.border_width) ; + } + } + + *reply_cw = cw ; + *reply_ch = ch ; +} + + + + /* rotate row numbers to bring current widget to bottom row, + * compute y positions for all tabs + */ + +static void +TabsShuffleRows(tw) + TabsWidget tw; +{ + TabsConstraints tab ; + int move ; + int nrows ; + Widget *childP ; + Dimension th = tw->tabs.tab_height ; + Position bottom ; + int i ; + + /* There must be a top widget. If not, assign one. */ + if( tw->tabs.topWidget == NULL && tw->composite.children != NULL ) + tw->tabs.topWidget = *tw->composite.children ; + + if( tw->tabs.topWidget != NULL ) + { + nrows = tw->tabs.numRows ; + assert( nrows > 0 ) ; + + if( nrows > 1 ) + { + tab = (TabsConstraints) tw->tabs.topWidget->core.constraints ; + assert( tab != NULL ) ; + + /* how far to move top row */ + move = nrows - tab->tabs.row ; + bottom = tw->tabs.tab_total - th ; + + for(i=tw->composite.num_children, childP=tw->composite.children; + --i >= 0; + ++childP) + { + tab = (TabsConstraints) (*childP)->core.constraints ; + tab->tabs.row = (tab->tabs.row + move) % nrows ; + tab->tabs.y = bottom - tab->tabs.row * th ; + } + } + } +} + + + /* find preferred size. Ask children, find size of largest, + * add room for tabs & return. This can get a little involved, + * as we don't want to have too many rows of tabs; we may widen + * the widget to reduce # of rows. + */ + +static int +PreferredSize(tw, reply_width, reply_height, reply_cw, reply_ch) + TabsWidget tw; + Dimension *reply_width, *reply_height; /* total widget size */ + Dimension *reply_cw, *reply_ch; /* child widget size */ +{ + Dimension cw,ch ; /* child width, height */ + Dimension wid,hgt ; + Dimension rwid,rhgt ; + int nrow ; + + + /* find max desired child height */ + MaxChild(tw, &cw, &ch, NULL) ; + + wid = cw ; + hgt = ch ; + + for(;;) { + nrow = PreferredSize2(tw, wid,hgt, &rwid, &rhgt) ; + + /* Check for absurd results (more than 2 rows, high aspect + * ratio). Try wider size if needed. + * TODO: make sure this terminates. + * TODO: compute width a little more conservatively. + */ + + if( nrow > 2 && rhgt*2 > rwid*3 ) + wid = Max(wid*3/2, wid+20) ; + else + break ; + } + + *reply_width = rwid ; + *reply_height = rhgt ; + if( reply_cw != NULL ) *reply_cw = cw ; + if( reply_ch != NULL ) *reply_ch = ch ; + return nrow ; +} + + + /* Find preferred size, given size of children. */ + +static int +PreferredSize2(tw, cw,ch, reply_width, reply_height) + TabsWidget tw; + int cw,ch ; /* child width, height */ + Dimension *reply_width, *reply_height; /* total widget size */ +{ + Dimension s = SHADWID ; + + /* make room for shadow frame */ + cw += s*2 ; + ch += s*2 ; + + return PreferredSize3(tw, cw, ch, reply_width, reply_height) ; +} + + + /* Find preferred size, given size of children+shadow. */ + +static int +PreferredSize3(tw, wid,hgt, reply_width, reply_height) + TabsWidget tw; + Dimension wid,hgt ; /* child width, height */ + Dimension *reply_width, *reply_height; /* total widget size */ +{ + Dimension th ; /* space used by tabs */ + int nrows ; + + if( tw->composite.num_children > 0 ) + nrows = TabLayout(tw, wid, &th, True) ; + else { + th = 0 ; + nrows = 0 ; + } + + *reply_width = Max(wid, MIN_WID) ; + *reply_height = Max(th+hgt, MIN_HGT) ; + + return nrows ; +} + + +static void +MakeSizeRequest(tw) + TabsWidget tw ; +{ + Widget w = (Widget)tw ; + XtWidgetGeometry request, reply ; + XtGeometryResult result ; + Dimension cw,ch ; + + request.request_mode = CWWidth | CWHeight ; + PreferredSize(tw, &request.width, &request.height, &cw, &ch) ; + + if( request.width == tw->core.width && + request.height == tw->core.height ) + return ; + + result = XtMakeGeometryRequest(w, &request, &reply) ; + + if( result == XtGeometryAlmost ) + { + /* Bugger. Didn't get what we want, but were offered a + * compromise. If the width was too small, recompute + * based on the too-small width and try again. + * If the height was too small, make a wild-ass guess + * at a wider width and try again. + */ + + if( reply.width < request.width && reply.height >= request.height ) + { + Dimension s = SHADWID ; + ch += s*2 ; + PreferredSize3(tw, reply.width,ch, &request.width, &request.height); + result = XtMakeGeometryRequest(w, &request, &reply) ; + if( result == XtGeometryAlmost ) { + (void) XtMakeGeometryRequest(w, &reply, NULL) ; + } + } + + else + (void) XtMakeGeometryRequest(w, &reply, NULL) ; + } +} + + +static void +getBitmapInfo(tw, tab) + TabsWidget tw ; + TabsConstraints tab ; +{ + Window root ; + int x,y ; + unsigned int bw ; + + if( tab->tabs.left_bitmap == None || + !XGetGeometry(XtDisplay(tw), tab->tabs.left_bitmap, &root, &x, &y, + &tab->tabs.lbm_width, &tab->tabs.lbm_height, + &bw, &tab->tabs.lbm_depth) ) + tab->tabs.lbm_width = tab->tabs.lbm_height = 0 ; +} + + + + + /* Code copied & modified from Gcs.c. This version has dynamic + * foreground. + */ + +static void +TabsAllocFgGC(tw) + TabsWidget tw; +{ + Widget w = (Widget) tw; + XGCValues values ; + + values.background = tw->core.background_pixel ; + values.font = tw->tabs.font->fid ; + + tw->tabs.foregroundGC = + XtAllocateGC(w, w->core.depth, + GCBackground|GCFont, &values, + GCForeground, + GCSubwindowMode|GCDashOffset|GCGraphicsExposures| + GCDashList|GCArcMode) ; +} + +static void +TabsAllocGreyGC(tw) + TabsWidget tw; +{ + Widget w = (Widget) tw; + XGCValues values ; + + values.background = tw->core.background_pixel ; + values.font = tw->tabs.font->fid ; + + if( tw->tabs.be_nice_to_cmap || w->core.depth == 1) + { + values.fill_style = FillStippled ; + tw->tabs.grey50 = + values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ; + + tw->tabs.greyGC = + XtAllocateGC(w, w->core.depth, + GCBackground|GCFont|GCStipple|GCFillStyle, &values, + GCForeground, + GCSubwindowMode|GCDashOffset|GCGraphicsExposures| + GCDashList|GCArcMode) ; + } + else + { + tw->tabs.greyGC = + XtAllocateGC(w, w->core.depth, + GCFont, &values, + GCForeground, + GCBackground|GCSubwindowMode|GCDashOffset| + GCDashList|GCArcMode|GCGraphicsExposures) ; + } +} + +#if XtSpecificationRelease < 5 + +static GC +XtAllocateGC(w, depth, mask, values, dynamic, dontcare) + Widget w ; + int depth ; + unsigned long mask, dynamic, dontcare ; + XGCValues *values ; +{ + return XtGetGC(w, mask, values) ; +} + +#endif Index: lwlib/xlwtabs.h =================================================================== RCS file: xlwtabs.h diff -N xlwtabs.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwtabs.h Wed Jul 28 01:34:02 1999 @@ -0,0 +1,197 @@ +/* Tabs Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* $Id: Tabs.h,v 1.4 1999/06/23 18:19:12 falk Exp $ + * + * This widget manages one or more child widgets, exactly one of which is + * visible. Above the child widgets is a graphic that looks like index + * tabs from file folders. Each tab corresponds to one of the child widgets. + * By clicking on a tab, the user can bring the corresponding widget to + * the top of the stack. + */ + + +#ifndef _Tabs_h +#define _Tabs_h + +#include + + +/*********************************************************************** + * + * Tabs Widget (subclass of CompositeClass) + * + ***********************************************************************/ + +/* Parameters: + + Name Class RepType Default Value + ---- ----- ------- ------------- + font Font XFontStruct* XtDefaultFont + internalWidth Width Dimension 4 *1 + internalHeight Height Dimension 2 *1 + topWidget TopWidget Widget *2 + callback Callback XtCallbackList NULL *3 + popdownCallback Callback XtCallbackList NULL *4 + selectInsensitive SelectInsensitive Boolean True *5 + beNiceToColormap BeNiceToColormap Boolean False *6 + topShadowContrast TopShadowContrast int 20 + bottomShadowContrast BottomShadowContrast int 40 + insensitiveContrast InsensitiveContrast int 33 *7 + + background Background Pixel XtDefaultBackground + border BorderColor Pixel XtDefaultForeground + borderWidth BorderWidth Dimension 1 + destroyCallback Callback Pointer NULL + hSpace HSpace Dimension 4 + height Height Dimension 0 + mappedWhenManaged MappedWhenManaged Boolean True + orientation Orientation XtOrientation vertical + vSpace VSpace Dimension 4 + width Width Dimension 0 + x Position Position 0 + y Position Position 0 + + Notes: + + 1 internalWidth, internalHeight specify the margins around the text + in the tabs. + 2 topWidget identifies the widget which is currently visible. + 3 callbacks are called whenever the user selects a tab. Call_data is + the new top widget. + 4 popdownCallbacks are called whenever the user selects a tab. Call_data is + the old (no longer visible) top widget. Note that popdownCallbacks + are called before callbacks. + 5 SelectInsensitive determines whether or not insensitive children may + be selected anyway. + 6 BeNiceToColormap causes the Tabs widget to use fewer colors. + 7 InsensitiveContrast sets the contrast used for labels of insensitive widgets. + +*/ + +/* Constraint parameters: + Name Class RepType Default Value + ---- ----- ------- ------------- + tabLabel Label String widget name + tabLeftBitmap LeftBitmap Pixmap None + tabForeground Foreground Pixel XtDefaultForeground + resizable Resizable Boolean False +*/ + +/* New fields */ + +#ifndef XtNtabLabel +#define XtNtabLabel "tabLabel" +#define XtNtabForeground "tabForeground" +#endif + +#ifndef XtNtabLeftBitmap +#define XtNtabLeftBitmap "tabLeftBitmap" +#endif + +#ifndef XtCLeftBitmap +#define XtCLeftBitmap "LeftBitmap" +#endif + +#ifndef XtCResizable +#define XtCResizable "Resizable" +#endif + +#ifndef XtNselectInsensitive +#define XtNselectInsensitive "selectInsensitive" +#define XtCSelectInsensitive "SelectInsensitive" +#endif + +#ifndef XtNnlabels +#define XtNnlabels "nlabels" +#define XtCNLabels "NLabels" +#endif +#ifndef XtNlabels +#define XtNlabels "labels" +#define XtCLabels "Labels" +#endif + +#ifndef XtNtopWidget +#define XtNtopWidget "topWidget" +#define XtCTopWidget "TopWidget" +#endif + +#ifndef XtNhSpace +#define XtNhSpace "hSpace" +#define XtCHSpace "HSpace" +#define XtNvSpace "vSpace" +#define XtCVSpace "VSpace" +#endif + +#ifndef XtNresizable +#define XtNresizable "resizable" +#endif + +#ifndef XtNinsensitiveContrast +#define XtNinsensitiveContrast "insensitiveContrast" +#define XtCInsensitiveContrast "InsensitiveContrast" +#endif + +#ifndef XtNshadowWidth +#define XtNshadowWidth "shadowWidth" +#define XtCShadowWidth "ShadowWidth" +#define XtNtopShadowPixel "topShadowPixel" +#define XtCTopShadowPixel "TopShadowPixel" +#define XtNbottomShadowPixel "bottomShadowPixel" +#define XtCBottomShadowPixel "BottomShadowPixel" +#define XtNtopShadowContrast "topShadowContrast" +#define XtCTopShadowContrast "TopShadowContrast" +#define XtNbottomShadowContrast "bottomShadowContrast" +#define XtCBottomShadowContrast "BottomShadowContrast" +#endif + +#ifndef XtNtopShadowPixmap +#define XtNtopShadowPixmap "topShadowPixmap" +#define XtCTopShadowPixmap "TopShadowPixmap" +#define XtNbottomShadowPixmap "bottomShadowPixmap" +#define XtCBottomShadowPixmap "BottomShadowPixmap" +#endif + +#ifndef XtNbeNiceToColormap +#define XtNbeNiceToColormap "beNiceToColormap" +#define XtCBeNiceToColormap "BeNiceToColormap" +#define XtNbeNiceToColourmap "beNiceToColormap" +#define XtCBeNiceToColourmap "BeNiceToColormap" +#endif + +/* Class record constants */ + +extern WidgetClass tabsWidgetClass; + +typedef struct _TabsClassRec *TabsWidgetClass; +typedef struct _TabsRec *TabsWidget; + +_XFUNCPROTOBEGIN +extern void +XawTabsSetTop( +#if NeedFunctionPrototypes + Widget w, + int callCallbacks +#endif +) ; + +_XFUNCPROTOEND + +#endif /* _Tabs_h */ Index: lwlib/xlwtabsP.h =================================================================== RCS file: xlwtabsP.h diff -N xlwtabsP.h --- /dev/null Tue Jul 27 14:08:36 1999 +++ lwlib/xlwtabsP.h Wed Jul 28 01:34:02 1999 @@ -0,0 +1,131 @@ +/* Tabs Widget for XEmacs. + Copyright (C) 1999 Edward A. Falk + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: TabsP.h 1.4 */ + +/* + * TabsP.h - Private definitions for Index Tabs widget + */ + +#ifndef _TabsP_h +#define _TabsP_h + +/*********************************************************************** + * + * Tabs Widget Private Data + * + ***********************************************************************/ + +#include +#include "xlwtabs.h" + +/* New fields for the Tabs widget class record */ +typedef struct {XtPointer extension;} TabsClassPart; + +/* Full class record declaration */ +typedef struct _TabsClassRec { + CoreClassPart core_class; + CompositeClassPart composite_class; + ConstraintClassPart constraint_class; + TabsClassPart tabs_class; +} TabsClassRec; + +extern TabsClassRec tabsClassRec; + + + +/**************************************************************** + * + * instance record declaration + * + ****************************************************************/ + +/* New fields for the Tabs widget record */ +typedef struct { + /* resources */ + XFontStruct *font ; + Dimension internalHeight, internalWidth ; + Widget topWidget ; + XtCallbackList callbacks ; + XtCallbackList popdownCallbacks ; + Boolean selectInsensitive ; + Boolean be_nice_to_cmap ; + int top_shadow_contrast ; + int bot_shadow_contrast ; + int insensitive_contrast ; + + /* private state */ + GC foregroundGC ; + GC backgroundGC ; + GC greyGC ; + GC topGC ; + GC botGC ; + Dimension tab_height ; /* height of tabs (all the same) */ + /* Note: includes top shadow only */ + Dimension tab_total ; /* total height of all tabs */ + Dimension child_width, child_height; /* child size, including borders */ + Cardinal numRows ; + XtGeometryMask last_query_mode; + Boolean needs_layout ; + Pixmap grey50 ; /* TODO: cache this elsewhere */ +} TabsPart; + + +typedef struct _TabsRec { + CorePart core; + CompositePart composite; + ConstraintPart constraint; + TabsPart tabs; +} TabsRec; + + + + +/**************************************************************** + * + * constraint record declaration + * + ****************************************************************/ + +typedef struct _TabsConstraintsPart { + /* resources */ + String label ; + Pixmap left_bitmap ; + Pixel foreground ; + Boolean resizable ; + + /* private state */ + Pixel grey ; + Boolean greyAlloc ; + Dimension width ; /* tab width */ + Position x,y ; /* tab base position */ + short row ; /* tab row */ + Dimension bwid ; /* desired border width */ + Position l_x, l_y ; /* label position */ + Position lbm_x, lbm_y ; /* bitmap position */ + unsigned int lbm_width, lbm_height, lbm_depth ; +} TabsConstraintsPart ; + +typedef struct _TabsConstraintsRec { + TabsConstraintsPart tabs ; +} TabsConstraintsRec, *TabsConstraints ; + + +#endif /* _TabsP_h */ Index: man/internals/internals.texi =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/man/internals/internals.texi,v retrieving revision 1.17.2.6 diff -u -r1.17.2.6 internals.texi --- man/internals/internals.texi 1999/05/21 05:25:24 1.17.2.6 +++ man/internals/internals.texi 1999/07/28 08:34:33 @@ -7785,10 +7785,74 @@ stack-of-extents code, which does the heavy-duty algorithmic work of determining which extents overly a particular position. -@node Faces and Glyphs, Specifiers, Extents, Top -@chapter Faces and Glyphs +@node Faces, Glyphs, Extents, Top +@chapter Faces Not yet documented. + +@node Glyphs, Specifiers, Faces, Top +@chapter Glyphs + +Glyphs are graphical elements that can be displayed in XEmacs buffers or +gutters. We use the term graphical element here in the broadest possible +sense since glyphs can be as mundane as text to as arcane as a native +tab widget. + +In XEmacs, glyphs represent the uninstantiated state of graphical +elements, i.e. they hold all the information necessary to produce an +image on-screen but the image does not exist at this stage. + +Glyphs are lazily instantiated by calling one of the glyph +functions. This usually occurs within redisplay when +@code{Fglyph_height} is called. Instantiation causes an image-instance +to be created and cached. This cache is on a device basis for all glyphs +except glyph-widgets, and on a window basis for glyph widgets. The +caching is done by @code{image_instantiate} and is necessary because it +is generally possible to display an image-instance in multiple +domains. For instance if we create a Pixmap, we can actually display +this on multiple windows - even though we only need a single Pixmap +instance to do this. If caching wasn't done then it would be necessary +to create image-instances for every displayable occurrance of a glyph - +and every usage - and this would be extremely memory and cpu intensive. + +Widget-glyphs (a.k.a native widgets) are not cached in this way. This is +because widget-glyph image-instances on screen are toolkit windows, and +thus cannot be reused in multiple XEmacs domains. Thus widget-glyphs are +cached on a window basis. + +Any action on a glyph first consults the cache before actually +instantiating a widget. + +@node Widget-Glyphs in the MS-WIndows Environment +@section Widget-Glyphs in the MS-WIndows Environment + +To Do + +@node Widget-Glyphs in the X Environment +@section Widget-Glyphs in the X Environment + +Widget-glyphs under X make heavy use of lwlib for manipulating the +native toolkit objects. This is primarily so that different toolkits can +be supported for widget-glyphs, just as they are supported for features +such as menubars etc. + +Lwlib is extremely poorly documented and quite hairy so here is my +understanding of what goes on. + +Lwlib maintains a set of widget_instances which mirror the hierarchical +state of Xt widgets. I think this is so that widgets can be updated and +manipulated generically by the lwlib library. For instance +update_one_widget_instance can cope with multiple types of widget and +multiple types of toolkit. Each element in the widet hierarchy is updated +from its corresponding widget_instance by walking the widget_instance +tree recursively. + +This has desirable properties such as lw_modify_all_widgets which is +called from glyphs-x.c and updates all the properties of a widget +without having to know what the widget is or what toolkit it is from. +Unfortunately this also has hairy properrties such as making the lwlib +code quite complex. And of course lwlib has to know at some level what +the widget is and how to set its properties. @node Specifiers, Menus, Faces and Glyphs, Top @chapter Specifiers Index: src/config.h.in =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/config.h.in,v retrieving revision 1.49.2.10 diff -u -r1.49.2.10 config.h.in --- src/config.h.in 1999/06/23 22:05:21 1.49.2.10 +++ src/config.h.in 1999/07/28 08:34:37 @@ -597,12 +597,16 @@ #undef LWLIB_DIALOGS_MOTIF #undef LWLIB_DIALOGS_ATHENA #undef LWLIB_DIALOGS_ATHENA3D +#undef LWLIB_TABS_LUCID +#undef LWLIB_WIDGETS_MOTIF +#undef LWLIB_WIDGETS_ATHENA /* Other things that can be disabled by configure. */ #undef HAVE_MENUBARS #undef HAVE_SCROLLBARS #undef HAVE_DIALOGS #undef HAVE_TOOLBARS +#undef HAVE_WIDGETS #if defined (HAVE_MENUBARS) || defined (HAVE_DIALOGS) Index: src/event-Xt.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/event-Xt.c,v retrieving revision 1.41.2.10 diff -u -r1.41.2.10 event-Xt.c --- src/event-Xt.c 1999/07/22 06:19:55 1.41.2.10 +++ src/event-Xt.c 1999/07/28 08:34:44 @@ -1569,8 +1569,10 @@ break; case Expose: - x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, - event->xexpose.width, event->xexpose.height); + if (!check_for_ignored_expose (f, event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height)) + x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height); break; case GraphicsExpose: /* This occurs when an XCopyArea's source area was Index: src/event-msw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/event-msw.c,v retrieving revision 1.38.2.16 diff -u -r1.38.2.16 event-msw.c --- src/event-msw.c 1999/07/19 11:04:11 1.38.2.16 +++ src/event-msw.c 1999/07/28 08:34:51 @@ -1983,13 +1983,19 @@ case WM_PAINT: { PAINTSTRUCT paintStruct; + int x, y, width, height; frame = XFRAME (mswindows_find_frame (hwnd)); BeginPaint (hwnd, &paintStruct); - mswindows_redraw_exposed_area (frame, - paintStruct.rcPaint.left, paintStruct.rcPaint.top, - paintStruct.rcPaint.right, paintStruct.rcPaint.bottom); + x = paintStruct.rcPaint.left; + y = paintStruct.rcPaint.top; + width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; + height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; + + if (!check_for_ignored_expose (frame, x, y, width, height)) + mswindows_redraw_exposed_area (frame, x, y, width, height); + EndPaint (hwnd, &paintStruct); } break; Index: src/frame.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/frame.c,v retrieving revision 1.37.2.6 diff -u -r1.37.2.6 frame.c --- src/frame.c 1999/07/16 19:05:39 1.37.2.6 +++ src/frame.c 1999/07/28 08:34:59 @@ -209,6 +209,10 @@ /* cache of subwindows visible on frame */ f->subwindow_cachels = Dynarr_new (subwindow_cachel); + /* associated exposure ignore list */ + f->subwindow_exposures = 0; + f->subwindow_exposures_tail = 0; + /* Choose a buffer for the frame's root window. */ XWINDOW (root_window)->buffer = Qt; { Index: src/frame.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/frame.h,v retrieving revision 1.18.2.3 diff -u -r1.18.2.3 frame.h --- src/frame.h 1999/07/16 19:05:39 1.18.2.3 +++ src/frame.h 1999/07/28 08:35:03 @@ -94,6 +94,9 @@ /* subwindow cache elements for this frame */ subwindow_cachel_dynarr *subwindow_cachels; + struct expose_ignore* subwindow_exposures; + struct expose_ignore* subwindow_exposures_tail; + #ifdef HAVE_SCROLLBARS /* frame-local scrollbar information. See scrollbar.c. */ int scrollbar_y_offset; Index: src/glyphs-msw.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs-msw.c,v retrieving revision 1.21.2.19 diff -u -r1.21.2.19 glyphs-msw.c --- src/glyphs-msw.c 1999/07/19 11:04:12 1.21.2.19 +++ src/glyphs-msw.c 1999/07/28 08:35:08 @@ -1,5 +1,5 @@ /* mswindows-specific glyph objects. - Copyright (C) 1998, 99 Andy Piper. + Copyright (C) 1998, 1999 Andy Piper. This file is part of XEmacs. @@ -2071,7 +2071,7 @@ /* buttons checked or otherwise */ if ( EQ (IMAGE_INSTANCE_WIDGET_TYPE (p), Qbutton)) { - if (gui_item_selected_p (IMAGE_INSTANCE_WIDGET_SINGLE_ITEM (p))) + if (gui_item_selected_p (IMAGE_INSTANCE_WIDGET_ITEM (p))) SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (p), BM_SETCHECK, (WPARAM)BST_CHECKED, 0); else @@ -2101,7 +2101,7 @@ static int mswindows_register_widget_instance (Lisp_Object instance, Lisp_Object domain) { - return mswindows_register_gui_item (XIMAGE_INSTANCE_WIDGET_SINGLE_ITEM (instance), + return mswindows_register_gui_item (XIMAGE_INSTANCE_WIDGET_ITEM (instance), domain); } @@ -2198,6 +2198,8 @@ } +#ifdef HAVE_WIDGETS + /************************************************************************/ /* widgets */ /************************************************************************/ @@ -2392,7 +2394,7 @@ /* instantiate a tree view widget */ static HTREEITEM add_tree_item (Lisp_Object image_instance, - HWND wnd, HTREEITEM parent, Lisp_Object entry, + HWND wnd, HTREEITEM parent, Lisp_Object item, int children, Lisp_Object domain) { TV_INSERTSTRUCT tvitem; @@ -2403,39 +2405,21 @@ tvitem.item.mask = TVIF_TEXT | TVIF_CHILDREN; tvitem.item.cChildren = children; - if (VECTORP (entry)) + if (GUI_ITEMP (item)) { - /* we always maintain the real gui item at the head of the - list. We have to put them in the list in the first place - because the whole model assumes that the glyph instances have - references to all the associated data. If we didn't do this - GC would bite us badly. */ - Lisp_Object gui = gui_parse_item_keywords_no_errors (entry); - if (CONSP (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance))) - { - Lisp_Object rest = - Fcons (gui, XCDR (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance))); - Fsetcdr (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance), rest); - } - else - { - XIMAGE_INSTANCE_WIDGET_ITEM (image_instance) = - Fcons (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance), gui); - } - - tvitem.item.lParam = mswindows_register_gui_item (gui, domain); + tvitem.item.lParam = mswindows_register_gui_item (item, domain); tvitem.item.mask |= TVIF_PARAM; - GET_C_STRING_OS_DATA_ALLOCA (XGUI_ITEM (gui)->name, + GET_C_STRING_OS_DATA_ALLOCA (XGUI_ITEM (item)->name, tvitem.item.pszText); } else - GET_C_STRING_OS_DATA_ALLOCA (entry, tvitem.item.pszText); + GET_C_STRING_OS_DATA_ALLOCA (item, tvitem.item.pszText); tvitem.item.cchTextMax = strlen (tvitem.item.pszText); if ((ret = (HTREEITEM)SendMessage (wnd, TVM_INSERTITEM, 0, (LPARAM)&tvitem)) == 0) - signal_simple_error ("error adding tree view entry", entry); + signal_simple_error ("error adding tree view entry", item); return ret; } @@ -2492,46 +2476,31 @@ /* instantiate a tab control */ static TC_ITEM* add_tab_item (Lisp_Object image_instance, - HWND wnd, Lisp_Object entry, + HWND wnd, Lisp_Object item, Lisp_Object domain, int index) { TC_ITEM tvitem, *ret; tvitem.mask = TCIF_TEXT; - if (VECTORP (entry)) + if (GUI_ITEMP (item)) { - /* we always maintain the real gui item at the head of the - list. We have to put them in the list in the first place - because the whole model assumes that the glyph instances have - references to all the associated data. If we didn't do this - GC would bite us badly. */ - Lisp_Object gui = gui_parse_item_keywords_no_errors (entry); - if (CONSP (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance))) - { - Lisp_Object rest = - Fcons (gui, XCDR (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance))); - Fsetcdr (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance), rest); - } - else - { - XIMAGE_INSTANCE_WIDGET_ITEM (image_instance) = - Fcons (XIMAGE_INSTANCE_WIDGET_ITEM (image_instance), gui); - } - - tvitem.lParam = mswindows_register_gui_item (gui, domain); + tvitem.lParam = mswindows_register_gui_item (item, domain); tvitem.mask |= TCIF_PARAM; - GET_C_STRING_OS_DATA_ALLOCA (XGUI_ITEM (gui)->name, + GET_C_STRING_OS_DATA_ALLOCA (XGUI_ITEM (item)->name, tvitem.pszText); } else - GET_C_STRING_OS_DATA_ALLOCA (entry, tvitem.pszText); + { + CHECK_STRING (item); + GET_C_STRING_OS_DATA_ALLOCA (item, tvitem.pszText); + } tvitem.cchTextMax = strlen (tvitem.pszText); if ((ret = (TC_ITEM*)SendMessage (wnd, TCM_INSERTITEM, index, (LPARAM)&tvitem)) < 0) - signal_simple_error ("error adding tab entry", entry); + signal_simple_error ("error adding tab entry", item); return ret; } @@ -2553,7 +2522,7 @@ wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii); /* add items to the tab */ - LIST_LOOP (rest, Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), Q_items, Qnil)) + LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))) { add_tab_item (image_instance, wnd, XCAR (rest), domain, index); index++; @@ -2577,8 +2546,12 @@ /* delete the pre-existing items */ SendMessage (wnd, TCM_DELETEALLITEMS, 0, 0); + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = + Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)), + parse_gui_item_tree_children (val)); + /* add items to the tab */ - LIST_LOOP (rest, val) + LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))) { add_tab_item (image_instance, wnd, XCAR (rest), IMAGE_INSTANCE_SUBWINDOW_FRAME (ii), index); @@ -2753,6 +2726,7 @@ } return Qunbound; } +#endif /* HAVE_WIDGETS */ /************************************************************************/ @@ -2813,6 +2787,7 @@ #ifdef HAVE_GIF IIFORMAT_VALID_CONSOLE (mswindows, gif); #endif +#ifdef HAVE_WIDGETS /* button widget */ INITIALIZE_DEVICE_IIFORMAT (mswindows, button); IIFORMAT_HAS_DEVMETHOD (mswindows, button, property); @@ -2858,7 +2833,7 @@ INITIALIZE_DEVICE_IIFORMAT (mswindows, tab_control); IIFORMAT_HAS_DEVMETHOD (mswindows, tab_control, instantiate); IIFORMAT_HAS_DEVMETHOD (mswindows, tab_control, set_property); - +#endif /* windows bitmap format */ INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (bmp, "bmp"); IIFORMAT_HAS_METHOD (bmp, validate); Index: src/glyphs-widget.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/Attic/glyphs-widget.c,v retrieving revision 1.1.2.7 diff -u -r1.1.2.7 glyphs-widget.c --- src/glyphs-widget.c 1999/07/19 11:04:12 1.1.2.7 +++ src/glyphs-widget.c 1999/07/28 08:35:09 @@ -1,5 +1,5 @@ /* Widget-specific glyph objects. - Copyright (C) 1998 Andy Piper + Copyright (C) 1998, 1999 Andy Piper. This file is part of XEmacs. @@ -61,7 +61,7 @@ Lisp_Object Q_descriptor, Q_height, Q_width, Q_properties, Q_items; Lisp_Object Q_image, Q_text, Q_percent; -#define WIDGET_BORDER_HEIGHT 2 +#define WIDGET_BORDER_HEIGHT 4 #define WIDGET_BORDER_WIDTH 4 /* TODO: @@ -96,7 +96,7 @@ int ch=0, cw=0; widget_face_font_info (domain, face, &ch, &cw); if (height) - *height = th * (ch + 2 * WIDGET_BORDER_HEIGHT); + *height = th * ch + 2 * WIDGET_BORDER_HEIGHT; if (width) *width = tw * cw + 2 * WIDGET_BORDER_WIDTH; } @@ -318,7 +318,7 @@ IMAGE_INSTANCE_WIDGET_TYPE (ii) = type; IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil; IMAGE_INSTANCE_WIDGET_FACE (ii) = Vwidget_face; - IMAGE_INSTANCE_WIDGET_ITEM (ii) = allocate_gui_item (); + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item (); } /* Instantiate a button widget. Unfortunately instantiated widgets are @@ -341,6 +341,7 @@ Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height); Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image); + Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties); int pw=0, ph=0, tw=0, th=0; /* this just does pixel type sizing */ @@ -357,8 +358,7 @@ IMAGE_INSTANCE_WIDGET_FACE (ii) = Fget_face (face); /* data items for some widgets */ - IMAGE_INSTANCE_WIDGET_PROPS (ii) = - find_keyword_in_vector (instantiator, Q_properties); + IMAGE_INSTANCE_WIDGET_PROPS (ii) = props; /* retrieve the gui item information. This is easy if we have been provided with a vector, more difficult if we have just been given @@ -366,13 +366,23 @@ if (STRINGP (desc) || NILP (desc)) { /* big cheat - we rely on the fact that a gui item looks like an instantiator */ - IMAGE_INSTANCE_WIDGET_ITEM (ii) = + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = gui_parse_item_keywords_no_errors (instantiator); IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc; } else - IMAGE_INSTANCE_WIDGET_ITEM (ii) = + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = gui_parse_item_keywords_no_errors (desc); + + /* parse more gui items out of the properties */ + if (!NILP (props)) + { + Lisp_Object items = Fplist_get (props, Q_items, Qnil); + if (!NILP (items)) + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = + Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii), + parse_gui_item_tree_children (items)); + } /* normalize size information */ if (!NILP (width)) Index: src/glyphs-x.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs-x.c,v retrieving revision 1.49.2.14 diff -u -r1.49.2.14 glyphs-x.c --- src/glyphs-x.c 1999/07/19 11:04:13 1.49.2.14 +++ src/glyphs-x.c 1999/07/28 08:35:15 @@ -73,7 +73,7 @@ #include "file-coding.h" #endif -#ifdef LWLIB_USES_MOTIF +#ifdef LWLIB_WIDGETS_MOTIF #include #endif #include @@ -122,12 +122,16 @@ DEFINE_IMAGE_INSTANTIATOR_FORMAT (autodetect); +#ifdef HAVE_WIDGETS DEFINE_DEVICE_IIFORMAT (x, widget); DEFINE_DEVICE_IIFORMAT (x, button); DEFINE_DEVICE_IIFORMAT (x, progress_gauge); DEFINE_DEVICE_IIFORMAT (x, edit_field); DEFINE_DEVICE_IIFORMAT (x, combo_box); +DEFINE_DEVICE_IIFORMAT (x, tab_control); +#endif +void check_valid_item_list_1 (Lisp_Object items); static void cursor_font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, Lisp_Object pointer_fg, @@ -371,8 +375,7 @@ { if (IMAGE_INSTANCE_SUBWINDOW_ID (p)) { - XtUnmanageChild (IMAGE_INSTANCE_X_WIDGET_ID (p)); - XtDestroyWidget (IMAGE_INSTANCE_X_WIDGET_ID (p)); + lw_destroy_widget (IMAGE_INSTANCE_X_WIDGET_ID (p)); IMAGE_INSTANCE_SUBWINDOW_ID (p) = 0; } } @@ -2045,11 +2048,11 @@ { if (IMAGE_INSTANCE_TYPE (p) == IMAGE_WIDGET) { - widget_value* wv = xmalloc_widget_value (); - button_item_to_widget_value (IMAGE_INSTANCE_WIDGET_SINGLE_ITEM (p), - wv, 1, 1); + widget_value* wv = gui_items_to_widget_values + (IMAGE_INSTANCE_WIDGET_ITEMS (p)); lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (p), - wv, 1); + wv, True); + free_widget_value (wv); } } @@ -2147,6 +2150,9 @@ } } + +#ifdef HAVE_WIDGETS + /************************************************************************/ /* widgets */ /************************************************************************/ @@ -2168,12 +2174,12 @@ Arg al [32]; int ac = 0; int id = new_lwlib_id (); -#ifdef LWLIB_USES_MOTIF +#ifdef LWLIB_WIDGETS_MOTIF XmFontList fontList; #endif if (!DEVICE_X_P (d)) - signal_simple_error ("Not an mswindows device", device); + signal_simple_error ("Not an X device", device); /* have to set the type this late in case there is no device instantiation for a widget. But we can go ahead and do it without @@ -2201,7 +2207,7 @@ XtSetArg (al [ac], XtNbackground, bcolor.pixel); ac++; XtSetArg (al [ac], XtNforeground, fcolor.pixel); ac++; -#ifdef LWLIB_USES_MOTIF +#ifdef LWLIB_WIDGETS_MOTIF fontList = XmFontListCreate ((void*)FONT_INSTANCE_X_FONT (XFONT_INSTANCE (widget_face_font_info @@ -2215,6 +2221,8 @@ IMAGE_INSTANCE_WIDGET_FACE (ii), 0, 0)))); ac++; #endif + /* we cannot allow widgets to resize themselves */ + XtSetArg (al [ac], XtNresize, False); ac++; wv->nargs = ac; wv->args = al; @@ -2223,7 +2231,7 @@ False, 0, popup_selection_callback, 0); IMAGE_INSTANCE_X_WIDGET_LWID (ii) = id; -#ifdef LWLIB_USES_MOTIF +#ifdef LWLIB_WIDGETS_MOTIF XmFontListFree (fontList); #endif /* because the EmacsManager is the widgets parent we have to @@ -2311,7 +2319,7 @@ { Arg al [2]; int ac =0; -#ifdef LWLIB_USES_MOTIF +#ifdef LWLIB_WIDGETS_MOTIF XtSetArg (al [ac], XmNlabelType, XmPIXMAP); ac++; XtSetArg (al [ac], XmNlabelPixmap, XIMAGE_INSTANCE_X_PIXMAP (glyph));ac++; #else @@ -2418,6 +2426,47 @@ } } +static void +x_tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain) +{ + struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); + + widget_value * wv = + gui_items_to_widget_values (IMAGE_INSTANCE_WIDGET_ITEMS (ii)); + + x_widget_instantiate (image_instance, instantiator, pointer_fg, + pointer_bg, dest_mask, domain, "tab-control", wv); +} + +/* set the properties of a tab control */ +static Lisp_Object +x_tab_control_set_property (Lisp_Object image_instance, Lisp_Object prop, + Lisp_Object val) +{ + struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); + + if (EQ (prop, Q_items)) + { + widget_value * wv = 0; + check_valid_item_list_1 (val); + + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = + Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)), + parse_gui_item_tree_children (val)); + + wv = gui_items_to_widget_values (IMAGE_INSTANCE_WIDGET_ITEMS (ii)); + + lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (ii), wv, True); + + free_widget_value (wv); + return Qt; + } + return Qunbound; +} +#endif /* HAVE_WIDGETS */ + /************************************************************************/ /* initialization */ @@ -2477,7 +2526,7 @@ INITIALIZE_DEVICE_IIFORMAT (x, subwindow); IIFORMAT_HAS_DEVMETHOD (x, subwindow, instantiate); -#ifdef LWLIB_USES_MOTIF +#ifdef HAVE_WIDGETS /* button widget */ INITIALIZE_DEVICE_IIFORMAT (x, button); IIFORMAT_HAS_DEVMETHOD (x, button, property); @@ -2498,6 +2547,10 @@ INITIALIZE_DEVICE_IIFORMAT (x, combo_box); IIFORMAT_HAS_DEVMETHOD (x, combo_box, instantiate); #endif + /* tab control widget */ + INITIALIZE_DEVICE_IIFORMAT (x, tab_control); + IIFORMAT_HAS_DEVMETHOD (x, tab_control, instantiate); + IIFORMAT_HAS_DEVMETHOD (x, tab_control, set_property); #endif INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (cursor_font, "cursor-font"); IIFORMAT_VALID_CONSOLE (x, cursor_font); Index: src/glyphs.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs.c,v retrieving revision 1.23.2.15 diff -u -r1.23.2.15 glyphs.c --- src/glyphs.c 1999/07/05 07:28:24 1.23.2.15 +++ src/glyphs.c 1999/07/28 08:35:26 @@ -42,6 +42,7 @@ #include "frame.h" #include "chartab.h" #include "rangetab.h" +#include "blocktype.h" #ifdef HAVE_XPM #include @@ -122,6 +123,8 @@ static void glyph_property_was_changed (Lisp_Object glyph, Lisp_Object property, Lisp_Object locale); +static void register_ignored_expose (struct frame* f, int x, int y, int width, int height); + EXFUN (Fimage_instance_type, 1); EXFUN (Fglyph_type, 1); @@ -179,13 +182,20 @@ int i; struct image_instantiator_methods* meths = decode_image_instantiator_format (format, ERROR_ME_NOT); - struct console* console = decode_console (locale); - Lisp_Object contype = console ? CONSOLE_TYPE (console) : locale; + Lisp_Object contype = Qnil; + /* mess with the locale */ + if (!NILP (locale) && SYMBOLP (locale)) + contype = locale; + else + { + struct console* console = decode_console (locale); + contype = console ? CONSOLE_TYPE (console) : locale; + } /* nothing is valid in all locales */ if (EQ (format, Qnothing)) return 1; /* reject unknown formats */ - else if (!console || !meths) + else if (NILP (contype) || !meths) return 0; for (i = 0; i < Dynarr_length (meths->consoles); i++) @@ -622,7 +632,7 @@ markobj (IMAGE_INSTANCE_WIDGET_TYPE (i)); markobj (IMAGE_INSTANCE_WIDGET_PROPS (i)); markobj (IMAGE_INSTANCE_WIDGET_FACE (i)); - markobj (IMAGE_INSTANCE_WIDGET_ITEM (i)); + markobj (IMAGE_INSTANCE_WIDGET_ITEMS (i)); case IMAGE_SUBWINDOW: markobj (IMAGE_INSTANCE_SUBWINDOW_FRAME (i)); break; @@ -859,8 +869,8 @@ case IMAGE_WIDGET: if (!(EQ (IMAGE_INSTANCE_WIDGET_TYPE (i1), IMAGE_INSTANCE_WIDGET_TYPE (i2)) - && internal_equal (IMAGE_INSTANCE_WIDGET_ITEM (i1), - IMAGE_INSTANCE_WIDGET_ITEM (i2), + && internal_equal (IMAGE_INSTANCE_WIDGET_ITEMS (i1), + IMAGE_INSTANCE_WIDGET_ITEMS (i2), depth + 1) && internal_equal (IMAGE_INSTANCE_WIDGET_PROPS (i1), IMAGE_INSTANCE_WIDGET_PROPS (i2), @@ -915,7 +925,7 @@ hash = HASH4 (hash, internal_hash (IMAGE_INSTANCE_WIDGET_TYPE (i), depth + 1), internal_hash (IMAGE_INSTANCE_WIDGET_PROPS (i), depth + 1), - internal_hash (IMAGE_INSTANCE_WIDGET_ITEM (i), depth + 1)); + internal_hash (IMAGE_INSTANCE_WIDGET_ITEMS (i), depth + 1)); case IMAGE_SUBWINDOW: hash = HASH4 (hash, IMAGE_INSTANCE_SUBWINDOW_WIDTH (i), IMAGE_INSTANCE_SUBWINDOW_HEIGHT (i), @@ -3678,8 +3688,71 @@ Dynarr_atp (f->subwindow_cachels, elt)->updated = 0; } + /***************************************************************************** + * subwindow exposure ignorance * + *****************************************************************************/ +/* when we unmap subwindows the associated window system will generate + expose events. This we do not want as redisplay already copes with + the repainting necessary. Worse, we can get in an endless cycle of + redisplay if we are not careful. Thus we keep a per-frame list of + expose events that are going to come and ignore them as + required. */ + +struct expose_ignore_blocktype +{ + Blocktype_declare (struct expose_ignore); +} *the_expose_ignore_blocktype; + +int +check_for_ignored_expose (struct frame* f, int x, int y, int width, int height) +{ + struct expose_ignore *ei, *prev; + /* the ignore list is FIFO so we should generally get a match with + the first element in the list */ + for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next) + { + if (ei->x == x && ei->y == y && ei->width == width && ei->height == height) + { + if (!prev) + f->subwindow_exposures = ei->next; + else + prev->next = ei->next; + + if (ei == f->subwindow_exposures_tail) + f->subwindow_exposures_tail = prev; + + Blocktype_free (the_expose_ignore_blocktype, ei); + return 1; + } + prev = ei; + } + return 0; +} + +static void +register_ignored_expose (struct frame* f, int x, int y, int width, int height) +{ + struct expose_ignore *ei; + + ei = Blocktype_alloc (the_expose_ignore_blocktype); + + ei->next = NULL; + ei->x = x; + ei->y = y; + ei->width = width; + ei->height = height; + + if (f->subwindow_exposures_tail) + { + f->subwindow_exposures_tail->next = ei; + } + f->subwindow_exposures = ei; +} + + +/***************************************************************************** * subwindow functions * *****************************************************************************/ @@ -3734,6 +3807,8 @@ elt = get_subwindow_cachel_index (f, subwindow); cachel = Dynarr_atp (f->subwindow_cachels, elt); + /* make sure we don't get expose events */ + register_ignored_expose (f, cachel->x, cachel->y, cachel->width, cachel->height); cachel->x = -1; cachel->y = -1; cachel->being_displayed = 0; @@ -4195,6 +4270,9 @@ list6 (Qtext, Qmono_pixmap, Qcolor_pixmap, Qpointer, Qsubwindow, Qwidget)); staticpro (&Vimage_instance_type_list); + + the_expose_ignore_blocktype = + Blocktype_new (struct expose_ignore_blocktype); /* glyphs */ Index: src/glyphs.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/glyphs.h,v retrieving revision 1.18.2.13 diff -u -r1.18.2.13 glyphs.h --- src/glyphs.h 1999/07/05 07:28:25 1.18.2.13 +++ src/glyphs.h 1999/07/28 08:35:26 @@ -493,11 +493,11 @@ #define IMAGE_INSTANCE_WIDGET_TYPE(i) ((i)->u.subwindow.widget.type) #define IMAGE_INSTANCE_WIDGET_PROPS(i) ((i)->u.subwindow.widget.props) #define IMAGE_INSTANCE_WIDGET_FACE(i) ((i)->u.subwindow.widget.face) -#define IMAGE_INSTANCE_WIDGET_ITEM(i) ((i)->u.subwindow.widget.gui_item) -#define IMAGE_INSTANCE_WIDGET_SINGLE_ITEM(i) \ -(CONSP (IMAGE_INSTANCE_WIDGET_ITEM (i)) ? \ -XCAR (IMAGE_INSTANCE_WIDGET_ITEM (i)) : \ - IMAGE_INSTANCE_WIDGET_ITEM (i)) +#define IMAGE_INSTANCE_WIDGET_ITEMS(i) ((i)->u.subwindow.widget.gui_item) +#define IMAGE_INSTANCE_WIDGET_ITEM(i) \ +(CONSP (IMAGE_INSTANCE_WIDGET_ITEMS (i)) ? \ +XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (i)) : \ + IMAGE_INSTANCE_WIDGET_ITEMS (i)) #define IMAGE_INSTANCE_WIDGET_TEXT(i) XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (i))->name #define XIMAGE_INSTANCE_DEVICE(i) \ @@ -541,8 +541,8 @@ IMAGE_INSTANCE_WIDGET_FACE (XIMAGE_INSTANCE (i)) #define XIMAGE_INSTANCE_WIDGET_ITEM(i) \ IMAGE_INSTANCE_WIDGET_ITEM (XIMAGE_INSTANCE (i)) -#define XIMAGE_INSTANCE_WIDGET_SINGLE_ITEM(i) \ - IMAGE_INSTANCE_WIDGET_SINGLE_ITEM (XIMAGE_INSTANCE (i)) +#define XIMAGE_INSTANCE_WIDGET_ITEMS(i) \ + IMAGE_INSTANCE_WIDGET_ITEMS (XIMAGE_INSTANCE (i)) #define XIMAGE_INSTANCE_WIDGET_TEXT(i) \ IMAGE_INSTANCE_WIDGET_TEXT (XIMAGE_INSTANCE (i)) @@ -768,5 +768,16 @@ void unmap_subwindow (Lisp_Object subwindow); void map_subwindow (Lisp_Object subwindow, int x, int y); void update_frame_subwindows (struct frame *f); + +struct expose_ignore +{ + int x; + int y; + int width; + int height; + struct expose_ignore *next; +}; + +int check_for_ignored_expose (struct frame* f, int x, int y, int width, int height); #endif /* _XEMACS_GLYPHS_H_ */ Index: src/gui-x.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/gui-x.c,v retrieving revision 1.14.2.6 diff -u -r1.14.2.6 gui-x.c --- src/gui-x.c 1999/06/28 16:15:57 1.14.2.6 +++ src/gui-x.c 1999/07/28 08:35:29 @@ -448,7 +448,113 @@ return 1; } +/* parse tree's of gui items into widget_value hierarchies */ +static void gui_item_children_to_widget_values (Lisp_Object items, widget_value* parent); +static widget_value * +gui_items_to_widget_values_1 (Lisp_Object items, widget_value* parent, + widget_value* prev) +{ + widget_value* wv = 0; + Lisp_Object rest; + + assert ((parent || prev) && !(parent && prev)); + /* now walk the tree creating widget_values as appropriate */ + if (!CONSP (items)) + { + wv = xmalloc_widget_value(); + if (parent) + parent->contents = wv; + else + prev->next = wv; + if (!button_item_to_widget_value (items, wv, 0, 1)) + { + free_widget_value (wv); + if (parent) + parent->contents = 0; + else + prev->next = 0; + } + else + { + wv->value = xstrdup (wv->name); /* what a mess... */ + } + } + else + { + /* first one is the parent */ + if (CONSP (XCAR (items))) + signal_simple_error ("parent item must not be a list", XCAR (items)); + + if (parent) + wv = gui_items_to_widget_values_1 (XCAR (items), parent, 0); + else + wv = gui_items_to_widget_values_1 (XCAR (items), 0, prev); + /* the rest are the children */ + gui_item_children_to_widget_values (XCDR (items), wv); + } + return wv; +} + +static void +gui_item_children_to_widget_values (Lisp_Object items, widget_value* parent) +{ + widget_value* wv = 0, *prev = 0; + Lisp_Object rest; + CHECK_CONS (items); + + /* first one is master */ + prev = gui_items_to_widget_values_1 (XCAR (items), parent, 0); + /* the rest are the children */ + LIST_LOOP (rest, XCDR (items)) + { + Lisp_Object tab = XCAR (rest); + wv = gui_items_to_widget_values_1 (tab, 0, prev); + prev = wv; + } +} + +widget_value * +gui_items_to_widget_values (Lisp_Object items) +{ + /* !!#### This function has not been Mule-ized */ + /* This function can GC */ + widget_value *control = 0, *tmp = 0; + int count = specpdl_depth (); + Lisp_Object wv_closure, rest; + + if (NILP (items)) + signal_simple_error ("must have some items", items); + + /* Inhibit GC during this conversion. The reasons for this are + the same as in menu_item_descriptor_to_widget_value(); see + the large comment above that function. */ + record_unwind_protect (restore_gc_inhibit, + make_int (gc_currently_forbidden)); + gc_currently_forbidden = 1; + + /* Also make sure that we free the partially-created widget_value + tree on Lisp error. */ + control = xmalloc_widget_value(); + wv_closure = make_opaque_ptr (control); + record_unwind_protect (widget_value_unwind, wv_closure); + + gui_items_to_widget_values_1 (items, control, 0); + + /* mess about getting the data we really want */ + tmp = control; + control = control->contents; + tmp->next = 0; + tmp->contents = 0; + free_widget_value (tmp); + + /* No more need to free the half-filled-in structures. */ + set_opaque_ptr (wv_closure, 0); + unbind_to (count, Qnil); + + return control; +} + /* This is a kludge to make sure emacs can only link against a version of lwlib that was compiled in the right way. Emacs references symbols which correspond to the way it thinks lwlib was compiled, and if lwlib wasn't @@ -497,6 +603,11 @@ MACROLET (lwlib_dialogs_motif); #elif defined (HAVE_DIALOGS) MACROLET (lwlib_dialogs_athena); +#endif +#ifdef LWLIB_WIDGETS_MOTIF + MACROLET (lwlib_widgets_motif); +#elif defined (HAVE_WIDGETS) + MACROLET (lwlib_widgets_athena); #endif #undef MACROLET Index: src/gui-x.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/gui-x.h,v retrieving revision 1.5 diff -u -r1.5 gui-x.h --- src/gui-x.h 1998/03/31 20:11:48 1.5 +++ src/gui-x.h 1999/07/28 08:35:29 @@ -73,6 +73,7 @@ XtPointer client_data); int button_item_to_widget_value (Lisp_Object desc, widget_value *wv, int allow_text_field_p, int no_keys_p); +widget_value * gui_items_to_widget_values (Lisp_Object items); Lisp_Object menu_name_to_accelerator (char *name); char *menu_separator_style (CONST char *s); Lisp_Object widget_value_unwind (Lisp_Object closure); Index: src/gui.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/gui.c,v retrieving revision 1.10.2.8 diff -u -r1.10.2.8 gui.c --- src/gui.c 1999/06/25 14:16:47 1.10.2.8 +++ src/gui.c 1999/07/28 08:35:29 @@ -561,6 +561,56 @@ write_c_string (buf, printcharfun); } +/* parse a glyph descriptor into a tree of gui items. + + The gui_item slot of an image instance can be a single item or an + arbitrarily nested hierarchy of item lists. */ + +static Lisp_Object parse_gui_item_tree_item (Lisp_Object entry) +{ + Lisp_Object ret = entry; + if (VECTORP (entry)) + { + ret = gui_parse_item_keywords_no_errors (entry); + } + else if (STRINGP (entry)) + { + CHECK_STRING (entry); + } + else + signal_simple_error ("item must be a vector or a string", entry); + + return ret; +} + +Lisp_Object parse_gui_item_tree_children (Lisp_Object list) +{ + Lisp_Object rest, ret = Qnil; + CHECK_CONS (list); + /* recursively add items to the tree view */ + LIST_LOOP (rest, list) + { + Lisp_Object sub; + if (CONSP (XCAR (rest))) + sub = parse_gui_item_tree_list (XCAR (rest)); + else + sub = parse_gui_item_tree_item (XCAR (rest)); + + ret = Fcons (sub, ret); + } + /* make the order the same as the items we have parsed */ + return Fnreverse (ret); +} + +Lisp_Object parse_gui_item_tree_list (Lisp_Object list) +{ + Lisp_Object ret; + CHECK_CONS (list); + /* first one can never be a list */ + ret = parse_gui_item_tree_item (XCAR (list)); + return Fcons (ret, parse_gui_item_tree_children (XCDR (list))); +} + DEFINE_LRECORD_IMPLEMENTATION ("gui-item", gui_item, mark_gui_item, print_gui_item, 0, gui_item_equal, Index: src/gui.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/gui.h,v retrieving revision 1.6.2.5 diff -u -r1.6.2.5 gui.h --- src/gui.h 1999/06/25 14:16:47 1.6.2.5 +++ src/gui.h 1999/07/28 08:35:29 @@ -85,6 +85,8 @@ Lisp_Object allocate_gui_item (); void gui_item_init (Lisp_Object gui_item); +Lisp_Object parse_gui_item_tree_list (Lisp_Object list); +Lisp_Object parse_gui_item_tree_children (Lisp_Object list); /* this is mswindows biased but reasonably safe I think */ #define GUI_ITEM_ID_SLOTS 8 Index: src/gutter.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/Attic/gutter.c,v retrieving revision 1.1.2.3 diff -u -r1.1.2.3 gutter.c --- src/gutter.c 1999/07/21 07:42:16 1.1.2.3 +++ src/gutter.c 1999/07/28 08:35:32 @@ -20,7 +20,8 @@ /* Synched up with: Not in FSF. */ -/* Specifers ripped-off from toolbar.c */ +/* written by Andy Piper with specifiers partially + ripped-off from toolbar.c */ #include #include "lisp.h" @@ -345,7 +346,6 @@ int width, int height) { int g_x, g_y, g_width, g_height; - int newx, newy; get_gutter_coords (f, pos, &g_x, &g_y, &g_width, &g_height); @@ -360,13 +360,16 @@ if (f->current_display_lines) Dynarr_reset (f->current_display_lines); /* we have to do this in-case there were subwindows where we are - redrawing, unfortunately sometimes this also generates expose - events resulting in an endless cycle of redsplay. */ + redrawing, unfortunately this also generates expose events - + unless we are careful to ignore them - resulting in an endless + cycle of redsplay. */ +#if 0 newx = max (x, g_x); newy = max (y, g_y); width = min (x + width - newx, g_x + g_width - newx); height = min (y + height - newy, g_y + g_height - newy); - redisplay_unmap_subwindows_maybe (f, newx, newy, width, height); +#endif + redisplay_unmap_subwindows_maybe (f, g_x, g_y, g_width, g_height); /* Even if none of the gutter is in the area, the blank region at the very least must be because the first thing we did is verify Index: src/redisplay-output.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay-output.c,v retrieving revision 1.11.2.6 diff -u -r1.11.2.6 redisplay-output.c --- src/redisplay-output.c 1999/07/16 19:05:41 1.11.2.6 +++ src/redisplay-output.c 1999/07/28 08:35:36 @@ -1332,7 +1332,6 @@ int min_start, int max_end) { struct frame *f = XFRAME (w->frame); - struct device *d = XDEVICE (f->device); int ypos1, ypos2; int ddla_len = Dynarr_length (ddla); Index: tests/glyph-test.el =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/tests/Attic/glyph-test.el,v retrieving revision 1.1.2.10 diff -u -r1.1.2.10 glyph-test.el --- tests/glyph-test.el 1999/07/19 11:04:15 1.1.2.10 +++ tests/glyph-test.el 1999/07/28 08:35:36 @@ -8,6 +8,8 @@ (ding)) ; (setq ok-select (not ok-select))) +(defun fee () (interactive) (message "hello")) + ;; button in a group (setq ok-select nil) (set-extent-begin-glyph @@ -60,7 +62,7 @@ [tab-control :descriptor "My Tab" :face default :properties (:items (["One" foo] - ["Two" foo] + ["Two" fee] ["Three" foo]))]))) ;; progress gauge