aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm/ObmW/Common.man
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/x11iraf/obm/ObmW/Common.man')
-rw-r--r--vendor/x11iraf/obm/ObmW/Common.man1226
1 files changed, 1226 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/ObmW/Common.man b/vendor/x11iraf/obm/ObmW/Common.man
new file mode 100644
index 00000000..b64484ab
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/Common.man
@@ -0,0 +1,1226 @@
+.\"remove .ig hn for full docs
+.de hi
+.ig eh
+..
+.de eh
+..
+.TH "" 3 "" "Version 3.0" "Free Widget Foundation"
+.SH NAME
+XfwfCommon
+.SH DESCRIPTION
+The Common class is not meant to be instantiated. It only serves as
+the common superclass for a family of widgets, to ensure that these
+widgets have some common methods and resources. The Common class
+defines common types, symbolic constants, and type converters and it
+also provides the basis for keyboard traversal. The code for keyboard
+traversal is roughly based on that in the Xw widget set (created by
+Hewlett Packard), but it uses the \fIaccept_focus\fP method.
+
+When the resource \fItraversalOn\fP is set to \fITrue\fP (either at creation
+time, or via a \fIXtSetValues\fP later), a set of translations is added to
+the widget. If the widget's parent is also a subclass of Common, these
+translations will then implement keyboard traversal, using the cursor
+keys (up, down, prev, etc.) Of course, when the widget already uses
+these keys for other purposes, the keyboard traversal will not work.
+
+.SS "Public variables"
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+XfwfCommon
+Name Class Type Default
+XtNtraversalOn XtCTraversalOn Boolean True
+XtNhighlightThickness XtCHighlightThickness Dimension 2
+XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground
+XtNhighlightPixmap XtCHighlightPixmap Pixmap None
+XtNnextTop XtCNextTop Callback NULL
+XtNuserData XtCUserData Pointer NULL
+
+.TE
+.ps
+
+.TP
+.I "XtNtraversalOn"
+The resource \fItraversalOn\fP determines whether keyboard traversal is
+used. If it is \fITrue\fP initially, or if it is set to \fITrue\fP later, a
+set of translations will be added to the widget.
+
+
+
+.hi
+
+.nf
+Boolean traversalOn = True
+.fi
+
+.eh
+
+.TP
+.I "XtNhighlightThickness"
+Keyboard focus is indicated by border highlighting. When keyboard
+traversal is on and the widget receives the focus, the highlight border
+is filled with the highlight color or tile. If the widget does not
+have the focus, the area is left in the default background.
+
+
+
+.hi
+
+.nf
+Dimension highlightThickness = 2
+.fi
+
+.eh
+
+.TP
+.I "XtNhighlightColor"
+The highlight border can have a color or it can be tiled with a
+pixmap. Whichever of the resources \fIhighlightColor\fP or
+\fIhighlightPixmap\fP is set latest, is used. When both are set, the
+pixmap is used.
+
+
+
+.hi
+
+.nf
+Pixel highlightColor = <String>XtDefaultForeground
+.fi
+
+.eh
+
+.TP
+.I "XtNhighlightPixmap"
+The \fIhighlightPixmap\fP can be set to a pixmap with which the
+highlight border will be tiled. Only one of \fIhighlightPixmap\fP and
+\fIhighlightColor\fP can be set, see above.
+
+
+
+.hi
+
+.nf
+Pixmap highlightPixmap = None
+.fi
+
+.eh
+
+.TP
+.I "XtNnextTop"
+When an application has several top level windows, it should have a
+way of setting the focus between windows. The Enter key in any widget
+with keyboard traversal on normally invokes the \fItraverseNextTop\fP
+action, that will call the callbacks of the topmost Common (or
+subclass) widget in the hierarchy. The callback may set the focus to
+another top level widget, with \fIXtCallAcceptFocus\fP.
+
+
+
+.hi
+
+.nf
+<Callback> XtCallbackList nextTop = NULL
+.fi
+
+.eh
+
+.TP
+.I "XtNuserData"
+The resource \fIuserData\fP is provided for applications that want to
+attach their own data to a widget. It is not used by the widget itself
+in any way.
+
+
+
+.hi
+
+.nf
+<Pointer> XtPointer userData = NULL
+.fi
+
+.eh
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Composite
+Name Class Type Default
+XtNchildren XtCChildren WidgetList NULL
+insertPosition XtCInsertPosition XTOrderProc NULL
+numChildren XtCNumChildren Cardinal 0
+
+.TE
+.ps
+
+.ps-2
+.TS
+center box;
+cBsss
+lB|lB|lB|lB
+l|l|l|l.
+Core
+Name Class Type Default
+XtNx XtCX Position 0
+XtNy XtCY Position 0
+XtNwidth XtCWidth Dimension 0
+XtNheight XtCHeight Dimension 0
+borderWidth XtCBorderWidth Dimension 0
+XtNcolormap XtCColormap Colormap NULL
+XtNdepth XtCDepth Int 0
+destroyCallback XtCDestroyCallback XTCallbackList NULL
+XtNsensitive XtCSensitive Boolean True
+XtNtm XtCTm XTTMRec NULL
+ancestorSensitive XtCAncestorSensitive Boolean False
+accelerators XtCAccelerators XTTranslations NULL
+borderColor XtCBorderColor Pixel 0
+borderPixmap XtCBorderPixmap Pixmap NULL
+background XtCBackground Pixel 0
+backgroundPixmap XtCBackgroundPixmap Pixmap NULL
+mappedWhenManaged XtCMappedWhenManaged Boolean True
+XtNscreen XtCScreen Screen * NULL
+
+.TE
+.ps
+
+.SS "Exports"
+
+The type \fIAlignment\fP is actually an integer, but it is given a
+different name to allow a type converter to be installed for it.
+
+
+
+.nf
+
+.B type
+ Alignment = int
+.fi
+
+The symbolic constants can be added together to form an alignment.
+Various widgets use this to position labels, other widgets, etcetera.
+
+
+
+\fBdef\fP XfwfCenter = 0
+
+\fBdef\fP XfwfLeft = 1
+
+\fBdef\fP XfwfRight = 2
+
+\fBdef\fP XfwfTop = 4
+
+\fBdef\fP XfwfBottom = 8
+
+For convenience, the eight possible combinations also have symbolic
+names.
+
+
+
+\fBdef\fP XfwfTopLeft = (XfwfTop +XfwfLeft )
+
+\fBdef\fP XfwfTopRight = (XfwfTop +XfwfRight )
+
+\fBdef\fP XfwfBottomLeft = (XfwfBottom +XfwfLeft )
+
+\fBdef\fP XfwfBottomRight = (XfwfBottom +XfwfRight )
+
+The directions of traversal are used as arguments to the \fItraverse\fP
+method. They are probably only useful to subclasses.
+
+
+
+.nf
+
+.B type
+ TraversalDirection = enum {
+ TraverseLeft, TraverseRight, TraverseUp, TraverseDown,
+ TraverseNext, TraversePrev, TraverseHome, TraverseNextTop }
+.fi
+
+To know the inside area of a Common widget might be useful to other
+widgets than subclasses alone. Calling \fIXfwfCallComputeInside\fP will
+call the \fIcompute_inside\fP method, if available.
+
+.nf
+XfwfCallComputeInside( $, Position * x, Position * y, Dimension * w, Dimension * h)
+.fi
+
+.hi
+{
+ if (XtIsSubclass($, xfwfCommonWidgetClass) $compute_inside)
+ $compute_inside($, x, y, w, h);
+}
+.eh
+
+.hi
+.SS "Actions"
+
+When the widget receives or looses the focus, the border highlight
+is drawn or removed. This action function draws the highlight border
+and in case the widget has set \fItraversalOn\fP, it also sets the
+keyboard focus to the widget itself, or one of its children.
+
+However, FocusIn events may also be so-called virtual events, meaning
+that not the receiving widget, but one of its descendants gets the
+real focus. When \fIfocusIn\fP receives one of those, it removes the
+highlight border.
+
+.hi
+\fBdef\fP focus_detail(detail) =
+(detail ==NotifyAncestor ?"NotifyAncestor":detail ==NotifyVirtual ?"NotifyVirtual":detail ==NotifyInferior ?"NotifyInferior":detail ==NotifyNonlinear ?"NotifyNonlinear":detail ==NotifyNonlinearVirtual ?"NotifyNonlinearVirtual":detail ==NotifyPointer ?"NotifyPointer":detail ==NotifyPointerRoot ?"NotifyPointerRoot":detail ==NotifyDetailNone ?"NotifyDetailNone":"???")
+.eh
+
+.TP
+.I "focusIn
+
+.hi
+
+.nf
+void focusIn($, XEvent* event, String* params, Cardinal* num_params)
+{
+ Time time = CurrentTime;
+
+ if (event->type != FocusIn)
+ XtError("focusIn action may only be bound to FocusIn events");
+ if (! $traversalOn)
+ return;
+ if (event->xfocus.detail == NotifyAncestor
+ || event->xfocus.detail == NotifyInferior
+ || event->xfocus.detail == NotifyNonlinear) {
+ if (! $traversal_focus) (void) $accept_focus($, time);
+ } else if ($traversal_focus) {
+ $unhighlight_border($);
+ $traversal_focus = False;
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "focusOut
+
+This action removes the highlight border.
+
+.hi
+
+.nf
+void focusOut($, XEvent* event, String* params, Cardinal* num_params)
+{
+ if (event->type != FocusOut)
+ XtError("focusOut action may only be bound to FocusOut events");
+ if ($traversal_focus) {
+ $unhighlight_border($);
+ $traversal_focus = False;
+ }
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseDown
+
+This and the following actions all call the \fItraverse\fP method of the
+widget's parent, with the appropiate direction arguments.
+\fItraverseDown\fP tries to set the focus to a widget that is located
+roughly below the current one.
+
+.hi
+
+.nf
+void traverseDown($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseDown, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseUp
+
+The action tries to set the focus to a widget that is above the this
+one.
+
+.hi
+
+.nf
+void traverseUp($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseUp, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseLeft
+
+\fItraverseLeft\fP looks for a widget to the left of the current one and
+sets the keyboard focus to that.
+
+.hi
+
+.nf
+void traverseLeft($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseLeft, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseRight
+
+The action looks for a widget that will aceept the focus to the
+right of the current one.
+
+.hi
+
+.nf
+void traverseRight($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseRight, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseNext
+
+The next sibling gets the focus. The precise order is determined by
+the parent, but usually is will be the order in which the widgets were
+created. If there is no suitable sibling, the request is passed to the
+grandparent, so that an `aunt widget' or other relation can get the
+focus.
+
+.hi
+
+.nf
+void traverseNext($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseNext, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traversePrev
+
+The previous widget gets the focus. See also the description of
+\fItraverseNext\fP above.
+
+.hi
+
+.nf
+void traversePrev($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraversePrev, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseNextTop
+
+\fItraverseNextTop\fP finds the topmost ancestor that is a subclass of
+Common and lets it call the \fInextTop\fP callbacks that have been
+registered there. These callbacks can be used by an application that
+has multiple top level windows to set the focus to another window.
+
+.hi
+
+.nf
+void traverseNextTop($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseNextTop, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseHome
+
+The action sets the focus to the sibling widget that is closest to
+the upper left corner of the parent.
+
+.hi
+
+.nf
+void traverseHome($, XEvent* event, String* params, Cardinal* num_params)
+{
+ $traverse($, TraverseHome, $, event->xkey.time);
+}
+.fi
+
+.eh
+
+.TP
+.I "traverseCurrent
+
+The \fItraverseCurrent\fP action can be used by widgets to set the focus
+to themselves. It is not used in the set of translations that is added
+when \fItraversalOn\fP is set to \fITrue\fP.
+
+.hi
+
+.nf
+void traverseCurrent($, XEvent* event, String* params, Cardinal* num_params)
+{
+ Time time = CurrentTime;
+
+ if ($traversalOn) (void) $accept_focus($, time);
+}
+.fi
+
+.eh
+
+.hi
+
+.hi
+.SH "Importss"
+
+Most of the included files have to do with the \fIIcon\fP type. Six
+icons are preloaded.
+
+.nf
+
+.B incl
+ <stdio.h>
+.fi
+
+.nf
+
+.B incl
+ <X11/Xmu/Converters.h>
+.fi
+
+.nf
+
+.B incl
+ <Xfwf/Converters.h>
+.fi
+
+.hi
+
+.hi
+.SS "Private variables"
+
+\fIabs\fP, \fImin\fP and \fImax\fP are used often enough in various subclasses
+to define them here. They will end up in the private(!) header file.
+
+
+
+.nf
+ max
+.fi
+
+.nf
+ min
+.fi
+
+.nf
+ abs
+.fi
+
+A private variable is used to track the keyboard focus, but only
+while traversal is on. If \fItraversal_focus\fP is \fITrue\fP, it means that
+the widget has keyboard focus and that that focus is a result of
+keyboard traversal. It also means that the widget's border is
+highlighted, although that is only visible if the \fIhighlightThickness\fP
+is positive.
+
+
+
+.nf
+Boolean traversal_focus
+.fi
+
+The highlight border is filled with a color or a tile.
+
+
+
+.nf
+GC bordergc
+.fi
+
+.hi
+
+.hi
+.SH "Class variables"
+
+\fItraversal_trans\fP holds the compiled version of the
+\fIextraTranslations\fP.
+
+
+
+.nf
+XtTranslations traversal_trans = NULL
+.fi
+
+.hi
+
+.hi
+.SS "Methods"
+
+The type converter \fIcvtStringToAlignment\fP is installed in the
+\fIclass_initialize\fP method, after the quarks for the recognized strings
+are created.
+
+The converter from String to Icon needs one extra argument, viz., the
+widget for which the icon is loaded. An offset of 0 should give a
+pointer to the widget itself.
+
+.nf
+class_initialize()
+{
+ static XtConvertArgRec args[] = {
+ { XtWidgetBaseOffset, 0, sizeof(Widget) } };
+
+ XtSetTypeConverter(XtRString, "Alignment", cvtStringToAlignment,
+ NULL, 0, XtCacheNone, NULL);
+ XtSetTypeConverter("Alignment", XtRString, cvtAlignmentToString,
+ NULL, 0, XtCacheNone, NULL);
+ /* init_icon_quarks(); */
+ XtSetTypeConverter(XtRString, "Icon", cvtStringToIcon,
+ args, XtNumber(args), XtCacheNone, NULL);
+}
+.fi
+
+The \fIextraTranslations\fP are compiled into Xt's internal form and
+stored in a class variable \fItraversal_trans\fP, but only if that hasn't
+been done before. (It should have been done in the \fIclass_initialize\fP
+method, but wbuild's `\fI$\fP' syntax doesn't work there (yet)).
+
+If the widget has the \fItraversalOn\fP resource set, the translations are
+merged with the widgets existing translations.
+
+.nf
+initialize(Widget request, $, ArgList args, Cardinal * num_args)
+{
+ if ($traversal_trans == NULL)
+ $traversal_trans = XtParseTranslationTable(extraTranslations);
+ if ($traversalOn) {
+ XtAugmentTranslations($, $traversal_trans);
+ $visible_interest = True;
+ }
+ $traversal_focus = False;
+ $bordergc = NULL;
+ create_bordergc($);
+}
+.fi
+
+The \fIset_values\fP method checks if the keyboard traversal has been
+turned on and adds the traversal translations. (It can only be turned
+on, not turned off.)
+
+If something changes that causes the widget to loose keyboard focus,
+the parent is asked to put the focus somewhere else. Otherwise the
+whole application might suddenly loose keyboard focus.
+
+.nf
+Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args)
+{
+ Boolean need_redraw = False;
+ Widget parent = XtParent($);
+ Time time = CurrentTime;
+
+ if ($traversalOn != $old$traversalOn $traversalOn) {
+ XtAugmentTranslations($, $traversal_trans);
+ $visible_interest = True;
+ }
+ if (($sensitive != $old$sensitive
+ || $ancestor_sensitive != $old$ancestor_sensitive
+ || $traversalOn != $old$traversalOn)
+ $traversal_focus) {
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseHome, $, time);
+ }
+ if ($highlightThickness != $old$highlightThickness)
+ need_redraw = True;
+ if ($highlightPixmap != $old$highlightPixmap) {
+ create_bordergc($);
+ need_redraw = True;
+ } else if ($highlightColor != $old$highlightColor) {
+ $highlightPixmap = None;
+ create_bordergc($);
+ need_redraw = True;
+ }
+ return need_redraw;
+}
+.fi
+
+A new method \fIcompute_inside\fP is defined, that returns the area
+inside the highlight border. Subclasses should use this to compute
+their drawable area, in preference to computing it from \fI$width\fP and
+\fI$height\fP. Subclasses, such as the Frame widget, redefine the method
+if they add more border material.
+
+.nf
+compute_inside($, Position * x, Position * y, Dimension * w, Dimension * h)
+{
+ *x = $highlightThickness;
+ *y = $highlightThickness;
+ *w = $width - 2 * $highlightThickness;
+ *h = $height - 2 * $highlightThickness;
+}
+.fi
+
+The \fIexpose\fP method draws the highlight border, if there is one.
+
+.nf
+expose($, XEvent * event, Region region)
+{
+ if (! XtIsRealized($)) return;
+ if (region != NULL) XSetRegion(XtDisplay($), $bordergc, region);
+ if ($traversal_focus) $highlight_border($);
+ if (region != NULL) XSetClipMask(XtDisplay($), $bordergc, None);
+}
+.fi
+
+When the widget is destroyed and the widget still has the keyboard
+focus, the parent is asked to give it to another widget.
+
+.nf
+destroy($)
+{
+ Widget parent = XtParent($);
+ Time time = CurrentTime;
+
+ if ($traversal_focus) {
+ $sensitive = False;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseHome, $, time);
+ }
+}
+.fi
+
+The border highlight is drawn and removed with two methods, although
+few subclasses will want to redefine them. The methods are called by
+the \fIfocusIn\fP and \fIfocusOut\fP actions and \fIhighlight_border\fP is also
+called by \fIexpose\fP.
+
+.nf
+highlight_border($)
+{
+ XRectangle rect[4];
+
+ if ($highlightThickness == 0) return;
+
+ rect[0].x = 0;
+ rect[0].y = 0;
+ rect[0].width = $width;
+ rect[0].height = $highlightThickness;
+
+ rect[1].x = 0;
+ rect[1].y = 0;
+ rect[1].width = $highlightThickness;
+ rect[1].height = $height;
+
+ rect[2].x = $width - $highlightThickness;
+ rect[2].y = 0;
+ rect[2].width = $highlightThickness;
+ rect[2].height = $height;
+
+ rect[3].x = 0;
+ rect[3].y = $height - $highlightThickness;
+ rect[3].width = $width;
+ rect[3].height = $highlightThickness;
+
+ XFillRectangles(XtDisplay($), XtWindow($), $bordergc, rect[0], 4);
+}
+.fi
+
+.nf
+unhighlight_border($)
+{
+ if ($highlightThickness == 0) return;
+
+ XClearArea(XtDisplay($), XtWindow($),
+ 0, 0, $width, $highlightThickness, False);
+ XClearArea(XtDisplay($), XtWindow($),
+ 0, 0, $highlightThickness, $height, False);
+ XClearArea(XtDisplay($), XtWindow($),
+ $width - $highlightThickness, 0,
+ $highlightThickness, $height, False);
+ XClearArea(XtDisplay($), XtWindow($),
+ 0, $height - $highlightThickness,
+ $width, $highlightThickness, False);
+}
+.fi
+
+When the \fIaccept_focus\fP method is called, the widget should try to set
+the focus to itself or one of its children. If it succeeds, it returns
+\fITrue\fP else \fIFalse\fP. If there are children, each is asked in turn,
+until one is found that accepts the focus. If none is found, the
+widget checks it's own \fIsensitive\fP resource, to see if it can receive
+keyboard events. If so, it sets the focus to itself and returns
+\fITrue\fP, otherwise \fIFalse\fP.
+
+.nf
+Boolean accept_focus($, Time * time)
+{
+ int i;
+
+ if (! XtIsRealized($) || ! $sensitive || ! $traversalOn
+ || ! $visible || ! $ancestor_sensitive || ! $managed
+ || ! $mapped_when_managed || $being_destroyed) return False;
+ for (i = 0; i < $num_children; i++)
+ if (XtCallAcceptFocus($children[i], time)) return True;
+ if (! $traversal_focus) {
+ XSetInputFocus(XtDisplay($), XtWindow($), RevertToParent, *time);
+ $traversal_focus = True;
+ $highlight_border($);
+ }
+ return True;
+}
+.fi
+
+A Common widget (and most subclasses) return \fITrue\fP for
+\fIwould_accept_focus\fP, if the \fIsensitive\fP, \fIvisible\fP and \fItraversalOn\fP
+resources are set and none of the children wants the focus.
+
+.nf
+Boolean would_accept_focus($)
+{
+ int i;
+ Widget child;
+
+ if (! XtIsRealized($) || ! $sensitive || ! $visible || ! $traversalOn)
+ return False;
+ else {
+ for (i = 0; i < $num_children; i++) {
+ child = $children[i];
+ if (XtIsSubclass(child, xfwfCommonWidgetClass)
+ $child$would_accept_focus(child))
+ return False;
+ }
+ return True;
+ }
+}
+.fi
+
+The algorithm behind keyboard traversal
+
+* Handling focus events
+
+If a widget receives a (non-virtual) FocusIn event, this is usually
+caused by the \fIaccept_focus\fP method of that widget, except in the case
+that a top level widget receives the focus from the window manager. In
+the first case, the window can just draw the highlight border, in the
+second case, the widget should try to set the focus to one of its
+children.
+
+To be able to distinguish the two cases, the \fIaccept_focus\fP method
+sets the private instance variable \fItraversal_focus\fP to \fITrue\fP before
+it calls \fIXSetInputFocus\fP. The \fIfocusIn\fP action then checks this
+variable and if it is not set, calls the \fIaccept_focus\fP method.
+
+The \fIfocusOut\fP action resets \fItraversal_focus\fP to \fIFalse\fP.
+
+The \fItraversal_focus\fP variable can be interpreted to mean, that the
+widget has the keyboard focus and that it is because of keyboard
+traversal. At least in the Common widget, it can never be \fITrue\fP when
+\fItraversalOn\fP is not set. It can also only be \fITrue\fP when the widget
+actually has the focus, except in the short time between the
+\fIXSetInputFocus\fP call and the delivery of the \fIFocusIn\fP event.
+(However, this scheme depends on the \fIfocusOut\fP action for resetting
+\fItraversal_focus\fP to \fIFalse\fP, so, if the translation for the
+\fIFocusOut\fP event is overridden, it will break down.)
+
+* User events
+
+The \fItraverseXXX\fP actions can be bound to keyboard events. They call
+the \fItraverse\fP method, which will try to change the focus in the
+indicated direction. The directions are: Home, Up, Left, Down, Right,
+Next, Prev. Each direction can be considered a constraint or
+criterium for choosing the focus widget, e.g., `Up' selects the
+nearest widget that is above the current widget. `Next' and `Prev' are
+simpler, in that they do not check the distance, but only the order in
+the list of children.
+
+The \fItraverseCurrent\fP action is different. It is usually bound to a
+mouse click and its task is to set the focus to the widget itself. It
+does this by calling \fIaccept_focus\fP on itself.
+
+The \fItraverse\fP method looks for a widget in the indicated direction,
+within the same application. If the direction is not `Next' or `Prev',
+the method first recurses upwards, to the toplevel widget. From there
+it recurses down again, to all children, grandchildren, etc., looking
+for the widget that best matches the criterium. If a widget is found,
+the focus will be set to it with a call to \fIXSetInputFocus\fP. The
+private variable \fItraversal_focus\fP will be set to \fITrue\fP to indicate
+that the widget received the focus as a result of keyboard traversal,
+and not from the window manager or any other source.
+
+If the \fIdirection\fP argument is `Next' or `Prev', \fItraverse\fP will try
+to set the focus to a sister widget, using the \fIaccept_focus\fP method.
+If there is no suitable sister, the parent will be asked to find an
+aunt widget, and so on.
+
+Note that the \fItraverse\fP and \fIaccept_focus\fP methods of the Common
+widget only set the focus to a child, if the widget itself has
+\fItraversalOn\fP. Thus, setting \fItraversalOn\fP to \fIFalse\fP for a certain
+widget not only excludes the widget itself from keyboard traversal,
+but also all its children.
+
+The \fItraverse\fP function is a method and not a utility function,
+because it is expected that a few subclasses may want to redefine it.
+E.g., the (not yet existing) Group widget may want to limit traversal
+to widgets within itself. (And presumably define new actions to jump
+outside the group.)
+
+To check if a widget suits the criterium, two things must be
+determined: is the widget eligible for the focus and what is the
+distance between the widget and the target position. To be able to
+determine if the widget can accept the focus without actually setting
+it, a method \fIwould_accept_focus\fP is defined, that returns \fITrue\fP if
+the widget is willing to set the focus to itself.
+
+If the \fIdir\fP argument to \fItraverse\fP is \fITraverseNext\fP or
+\fITraversePrev\fP, the \fItraverse_to_next\fP or \fItraverse_to_prev\fP utility
+functions are called. Otherwise, the \fItraverse\fP method checks the
+class of the parent. If the parent is a subclass of \fIXfwfCommon\fP, it
+also has a \fItraverse\fP method and the task of finding a widget to
+traverse to is delegated to the parent. Otherwise, the desired widget
+is looked for with the help of a utility function.
+
+The \fIdir\fP argument is one of Home, Up, Down, Left, Right, Next or
+Prev. The \fIcurrent\fP argument holds the widget that currently has the
+focus and relative to which the focus will have to move.
+
+\fBdef\fP LARGE_NUMBER = 2000000000
+
+.nf
+traverse($, TraversalDirection dir, Widget current, Time * time)
+{
+ Widget w, parent = XtParent($);
+ Position x, y;
+ int distance = LARGE_NUMBER;
+
+ if (dir == TraverseNextTop)
+ traverse_to_next_top($, current, time);
+ else if (dir == TraverseNext)
+ traverse_to_next($, current, time);
+ else if (dir == TraversePrev)
+ traverse_to_prev($, current, time);
+ else if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, dir, current, time);
+ else {
+ switch (dir) {
+ case TraverseHome: x = 0; y = 0; break;
+ case TraverseLeft: x = 0; y = $current$height/2; break;
+ case TraverseDown: x = $current$width/2; y = $current$height; break;
+ case TraverseRight: x = $current$width; y = $current$height/2; break;
+ case TraverseUp: x = $current$width/2; y = 0; break;
+ }
+ if (dir != TraverseHome) XtTranslateCoords(current, x, y, x, y);
+ if (traverse_to_direction($, dir, x, y, w, distance))
+ XtCallAcceptFocus(w, time);
+ }
+}
+.fi
+
+To choose a color that is somewhat darker or lighter than another
+color, the function \fIchoose_color\fP queries the RGB values of a pixel
+and multiplies them with a factor. If all goes well, the function
+returns \fITrue\fP. If the chosen color ends up being the same as the
+original, the color gray75 is returned instead.
+
+It is defined as a method, to make it accessible to subclasses. There
+seems to be no need to make it available globally.
+
+.nf
+Boolean choose_color($, double factor, Pixel base, Pixel * result)
+{
+ XColor color1, color2, dummy;
+
+ color1.pixel = base;
+ XQueryColor(XtDisplay($), DefaultColormapOfScreen(XtScreen($)), color1);
+ color2.red = min(65535, factor * color1.red);
+ color2.green = min(65535, factor * color1.green);
+ color2.blue = min(65535, factor * color1.blue);
+ if (! XAllocColor(XtDisplay($),
+ DefaultColormapOfScreen(XtScreen($)), color2))
+ return False;
+ if (base == color2.pixel) {
+ if (! XAllocNamedColor(XtDisplay($),
+ DefaultColormapOfScreen(XtScreen($)), "gray75",
+ color2, dummy))
+ return False;
+ }
+ *result = color2.pixel;
+ return True;
+}
+.fi
+
+The method \fIlighter_color\fP uses \fIchoose_color\fP to compute a color
+that is 1.5 times as bright as the color passed in as argument. The
+function result is \fITrue\fP if a color was allocated, else \fIFalse\fP.
+
+.nf
+Boolean lighter_color($, Pixel base, Pixel * result)
+{
+ return choose_color($, 1.5, base, result);
+}
+.fi
+
+The method \fIdarker_color\fP uses \fIchoose_color\fP to compute a color
+that is 2/3 times as bright as the color passed in as argument. The
+function result is \fITrue\fP if a color was allocated, else \fIFalse\fP.
+
+.nf
+Boolean darker_color($, Pixel base, Pixel * result)
+{
+ return choose_color($, 0.667, base, result);
+}
+.fi
+
+.hi
+
+.hi
+.SH "Utilities"
+
+The converter \fIcvtStringToAlignment\fP converts strings like `right',
+`top left' and `bottom center' to values of type \fIAlignment\fP.
+
+\fBdef\fP done(type, value) =
+do {
+ if (to->addr != NULL) {
+ if (to->size < sizeof(type)) {
+ to->size = sizeof(type);
+ return False;
+ }
+ *(type*)(to->addr) = (value);
+ } else {
+ static type static_val;
+ static_val = (value);
+ to->addr = (XtPointer)static_val;
+ }
+ to->size = sizeof(type);
+ return True;
+ }while (0 )
+
+.nf
+Boolean cvtStringToAlignment(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ Alignment a = 0;
+ char c, *t, *s = (char*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtStringToAlignment", "wrongParameters",
+ "XtToolkitError",
+ "String to Alignment conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+
+ while (*s) {
+ for (; isspace(*s); s++) ;
+ for (t = s; *t ! isspace(*t); t++) ;
+ c = *t;
+ *t = '\\0';
+ if (XmuCompareISOLatin1(s, "top") == 0) a |= XfwfTop;
+ else if (XmuCompareISOLatin1(s, "bottom") == 0) a |= XfwfBottom;
+ else if (XmuCompareISOLatin1(s, "center") == 0) ; /* skip */
+ else if (XmuCompareISOLatin1(s, "left") == 0) a |= XfwfLeft;
+ else if (XmuCompareISOLatin1(s, "right") == 0) a |= XfwfRight;
+ else {
+ XtDisplayStringConversionWarning(display, (char*) from->addr,
+ "Alignment");
+ break;
+ }
+ *t = c;
+ s = t;
+ }
+ done(Alignment, a);
+}
+.fi
+
+The converter \fIcvtAlignmentToString\fP does the reverse: it convertes values of type \fIAlignment\fP (\fIint\fP's) to strings.
+
+.nf
+Boolean cvtAlignmentToString(Display * display, XrmValuePtr args, Cardinal * num_args, XrmValuePtr from, XrmValuePtr to, XtPointer * converter_data)
+{
+ Alignment *a = (Alignment*) from->addr;
+
+ if (*num_args != 0)
+ XtAppErrorMsg(XtDisplayToApplicationContext(display),
+ "cvtAlignmentToString", "wrongParameters",
+ "XtToolkitError",
+ "Alignment to String conversion needs no arguments",
+ (String*) NULL, (Cardinal*) NULL);
+ switch (*a) {
+ case XfwfCenter: done(String, "center");
+ case XfwfBottom: done(String, "bottom");
+ case XfwfTop: done(String, "top");
+ case XfwfLeft: done(String, "left");
+ case XfwfRight: done(String, "right");
+ case XfwfBottom + XfwfLeft: done(String, "bottom left");
+ case XfwfBottom + XfwfRight: done(String, "bottom right");
+ case XfwfTop + XfwfLeft: done(String, "top left");
+ case XfwfTop + XfwfRight: done(String, "top right");
+ default: done(String, "unknown");
+ }
+}
+.fi
+
+The following string is the set of translations that will be added
+to any widget that has \fItraversalOn\fP set to \fITrue\fP. The string is
+compiled into Xt's internal representation by the \fIclass_initialize\fP
+method.
+
+.nf
+char extraTranslations[] = "\\
+ <FocusIn>: focusIn()\\n\\
+ <FocusOut>: focusOut()\\n\\
+ <Key>Up: traverseUp()\\n\\
+ <Key>Down: traverseDown()\\n\\
+ <Key>Left: traverseLeft()\\n\\
+ <Key>Right: traverseRight()\\n\\
+ <Key>Next: traverseNext()\\n\\
+ ~Shift<Key>Tab: traverseNext()\\n\\
+ <Key>Prior: traversePrev()\\n\\
+ Shift<Key>Tab: traversePrev()\\n\\
+ <Key>KP_Enter: traverseNextTop()\\n\\
+ <Key>Home: traverseHome()"
+.fi
+
+The \fIcreate_bordergc\fP function creates a new GC for filling the
+highlight border with.
+
+.nf
+create_bordergc($)
+{
+ XtGCMask mask;
+ XGCValues values;
+
+ if ($bordergc) XtReleaseGC($, $bordergc);
+ if ($highlightPixmap != None) {
+ mask = GCFillStyle | GCTile;
+ values.fill_style = FillTiled;
+ values.tile = $highlightPixmap;
+ } else {
+ mask = GCFillStyle | GCForeground;
+ values.fill_style = FillSolid;
+ values.foreground = $highlightColor;
+ }
+ $bordergc = XtGetGC($, mask, values);
+}
+.fi
+
+The \fItraverse_to_direction\fP function returns the nearest child,
+grandchild, etc. in the indicated direction that is willing to accept
+the focus. It returns \fIFalse\fP if no widget is found. The position is the
+absolute coordinates, i.e., relative to the root window. The \fIdistance\fP
+argument holds the distance from \fIx,y\fP of the best widget so far. If the
+function finds a better one, it will return the new distance through
+this parameter.
+
+.nf
+Boolean traverse_to_direction($, TraversalDirection dir, int x, int y, Widget * found, int * distance)
+{
+ int i;
+ Widget child, w;
+ Position rx, ry;
+ int dist;
+ Boolean found_child = False;
+
+ if (! $traversalOn) return False;
+ /*
+ * First recurse to all descendants
+ */
+ for (i = 0; i < $num_children; i++)
+ if (XtIsSubclass($children[i], xfwfCommonWidgetClass)
+ traverse_to_direction($children[i], dir, x, y, found, distance))
+ found_child = True;
+ if (found_child) return True;
+ /*
+ * No child found, now check own position and distance
+ */
+ switch (dir) {
+ case TraverseHome: rx = 0; ry = 0; break;
+ case TraverseLeft: rx = $width; ry = $height/2; break;
+ case TraverseDown: rx = $width/2; ry = 0; break;
+ case TraverseRight: rx = 0; ry = $height/2; break;
+ case TraverseUp: rx = $width/2; ry = $height; break;
+ }
+ XtTranslateCoords($, rx, ry, rx, ry);
+ if ((dir == TraverseUp ry > y)
+ || (dir == TraverseLeft rx > x)
+ || (dir == TraverseDown ry < y)
+ || (dir == TraverseRight rx < x)) return False;
+ dist = (rx - x)*(rx - x) + (ry - y)*(ry - y);
+ if (dist >= *distance) return False;
+ /*
+ * We are the best so far, but do we want the focus?
+ */
+ if (! $would_accept_focus($)) return False;
+ *distance = dist;
+ *found = $;
+ return True;
+}
+.fi
+
+The \fItraverse_to_next\fP routine looks for the \fIcurrent\fP widget among
+its children. If it is found, all children following it will be tried
+until one accepts the focus. If no child does, the routine will try to
+ask the parent to find a sister widget instead.
+
+.nf
+traverse_to_next($, Widget current, Time * time)
+{
+ int i = 0;
+ Widget parent = XtParent($);
+
+ while (i < $num_children $children[i] != current) i++;
+ for (i++; i < $num_children; i++)
+ if (XtCallAcceptFocus($children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseNext, $, time);
+}
+.fi
+
+\fItraverse_to_prev\fP looks for the \fIcurrent\fP widget among the children,
+if it is found, all children before it will be asked in turn to accept
+the focus. If none does, the parent is asked to set the focus to a
+sister instead.
+
+.nf
+traverse_to_prev($, Widget current, Time * time)
+{
+ int i = 0;
+ Widget parent = XtParent($);
+
+ while (i < $num_children $children[i] != current) i++;
+ for (i--; i >= 0; i--)
+ if (XtCallAcceptFocus($children[i], time)) return;
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraversePrev, $, time);
+}
+.fi
+
+.nf
+traverse_to_next_top($, Widget current, Time * time)
+{
+ Widget parent = XtParent($);
+
+ if (XtIsSubclass(parent, xfwfCommonWidgetClass))
+ $parent$traverse(parent, TraverseNextTop, current, time);
+ else
+ XtCallCallbackList($, $nextTop, NULL);
+}
+.fi
+
+.hi