diff options
Diffstat (limited to 'vendor/x11iraf/obm/ObmW/Common.man')
-rw-r--r-- | vendor/x11iraf/obm/ObmW/Common.man | 1226 |
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 |