(3)

NAME
XfwfSlider2

DESCRIPTION
A Slider2 widget consists of a rectangular area in which a `thumb' can be moved about. A Slider2 is typically used to pan or scroll another window; as such is can replace two scrollbars. The thumb can be dragged with the mouse, or the mouse can be clicked next to the thumb, to move it in the direction of the mouse. The thumb may contain one or more lines of text, although there is usually no room for more than one or two words. The widget has three callbacks. The thumb position and size are not controled by resources, but by calling a function.

  Public variables
XfwfSlider2
Name | Class | Type | Default
XtNthumbColor | XtCThumbColor | Pixel | XtDefaultBackground
XtNthumbPixmap | XtCThumbPixmap | Pixmap | NULL
XtNminsize | XtCMinsize | Dimension | 20
XtNthumbFrameWidth | XtCThumbFrameWidth | Dimension | 2
XtNthumbFrameType | XtCThumbFrameType | FrameType | XfwfRaised
XtNscrollCallback | XtCScrollCallback | Callback | NULL
XtNscrollResponse | XtCScrollResponse | XTCallbackProc | scroll_response

XtNthumbColor
    The color of the thumb is by default set to the default background color of the display, but it can be changed with the thumbColor resource. It is also possible to tile the thumb with a pixmap, see below.

    Pixel  thumbColor = <String>XtDefaultBackground

XtNthumbPixmap
    Instead of a color, the thumb can also be tiled with a pixmap. However, there is currently no converter from string to pixmap, so this resource can only be set from the application, not from resource files. If both thumbColor and thumbPixmap are set, the pixmap takes precedence.

    Pixmap  thumbPixmap = NULL

XtNminsize
    The minimum size of the thumb is by default 20 pixels. It can be set with the minsize resource.

    Dimension  minsize = 20

XtNthumbFrameWidth
    The width of the frame around the thumb is independent of the frame around the whole widget. It can be set with thumbFrameWidth.

    Dimension  thumbFrameWidth = 2

XtNthumbFrameType
    The style of the frame around the thumb is set with thumbFrameType. By default, it is XfwfRaised. Note that there are no resources to control the shadow scheme of the thumb independently from that of the outer frame. That means that the resources shadowScheme, lightColor, lightStipple, etc, also influence the frame of the thumb.

    FrameType  thumbFrameType = XfwfRaised

XtNscrollCallback
    The routines on the callback list are called whenever the user manipulates the slider and also when the Slider2 receives a call on its scrollResponse function with a reason other than XfwfSNotify. The call_data parameter of the callback routines is a pointer to an XfwfScrollInfo structure, which looks like this: typedef struct _XfwfScrollInfo { XfwfSReason reason; XfwfSFlags flags; float vpos, vsize, hpos, hsize;} XfwfScrollInfo.

    <Callback> XtCallbackList  scrollCallback = NULL

XtNscrollResponse
    The Slider2 widget provides has a method for dealing with scroll requests from the application or from other widgets. A pointer to that function can be retrieved with XtGetValues as the resource XtNscrollResponse. This resource can only be queried, not set.

    XtCallbackProc  scrollResponse = scroll_response

XtNframeWidth
    The default frame width is changed from 0 to 2.

     frameWidth = 2

XtNframeType
    The default frame type is now XfwfSunken.

     frameType = XfwfSunken
    XfwfLabel
    Name | Class | Type | Default
    XtNlabel | XtCLabel | String | NULL
    XtNfont | XtCFont | FontStruct | XtDefaultFont
    XtNforeground | XtCForeground | Pixel | XtDefaultForeground
    XtNalignment | XtCAlignment | Alignment | 0
    XtNmargin | XtCMargin | Int | 2
    XtNshrinkToFit | XtCShrinkToFit | Boolean | False
    XtNrvStart | XtCRvStart | Int | 0
    XtNrvLength | XtCRvLength | Int | 0
    XfwfBoard
    Name | Class | Type | Default
    XtNabs_x | XtCAbs_x | Int | 0
    XtNrel_x | XtCRel_x | Float | "0.0"
    XtNabs_y | XtCAbs_y | Int | 0
    XtNrel_y | XtCRel_y | Float | "0.0"
    XtNabs_width | XtCAbs_width | Int | 0
    XtNrel_width | XtCRel_width | Float | "1.0"
    XtNabs_height | XtCAbs_height | Int | 0
    XtNrel_height | XtCRel_height | Float | "1.0"
    XtNhunit | XtCHunit | Float | "1.0"
    XtNvunit | XtCVunit | Float | "1.0"
    XtNlocation | XtCLocation | String | NULL
    XfwfFrame
    Name | Class | Type | Default
    XtNcursor | XtCCursor | Cursor | None
    XtNframeType | XtCFrameType | FrameType | XfwfRaised
    XtNframeWidth | XtCFrameWidth | Dimension | 0
    XtNframeOffset | XtCFrameOffset | Dimension | 0
    XtNshadowScheme | XtCShadowScheme | ShadowScheme | XfwfAuto
    XtNlightColor | XtCLightColor | Pixel | XtDefaultBackground
    XtNdarkColor | XtCDarkColor | Pixel | XtDefaultForeground
    XtNlightStipple | XtCLightStipple | Bitmap | NULL
    XtNdarkStipple | XtCDarkStipple | Bitmap | NULL
    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
    Composite
    Name | Class | Type | Default
    XtNchildren | XtCChildren | WidgetList | NULL
    insertPosition | XtCInsertPosition | XTOrderProc | NULL
    numChildren | XtCNumChildren | Cardinal | 0
    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
    XtNtranslations | XtCTranslations | XTTranslations | 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

  Exports
The scroll.h header file is needed for the XfwfScrollInfo structure.
incl
 <Xfwf/scroll.h>
The current size and position of the thumb can be queried with the function getThumb. It fills the info argument with the current values.
XfwfGetThumb( $, XfwfScrollInfo * info)
{
    if (! XtIsSubclass($, xfwfSlider2WidgetClass))
    XtError("XfwfGetThumb called with incorrect widget type");
    info->reason = XfwfSNotify;
    info->flags = XFWF_VPOS | XFWF_VSIZE | XFWF_HPOS | XFWF_HSIZE;
    info->vpos = $thumb_y;
    info->vsize = $thumb_ht;
    info->hpos = $thumb_x;
    info->hsize = $thumb_wd; } To change the position of the thumb, a call to moveThumb can be used. The arguments must be two numbers between 0 and 1. The thumb is moved with XCopyArea. This is a convenience function. The standard interface is through the scrollResponse resource. In the Slider2 widget, that resource is connected to the scroll_response method.
XfwfMoveThumb( $, double  x, double  y)
{
    XfwfScrollInfo info;
    if (! XtIsSubclass($, xfwfSlider2WidgetClass))
    XtError("XfwfMoveThumb called with incorrect widget type");
    if (x < 0.0 || x > 1.0 || y < 0.0 || y > 1.0)
    XtError("XfwfMoveThumb called with incorrect arguments");
    info.flags = XFWF_VPOS | XFWF_HPOS;
    info.reason = XfwfSNotify;
    info.vpos = y;
    info.hpos = x;
    $scroll_response(NULL, $, info); } Resizing the thumb is done with resizeThumb. The two arguments must be between 0 and 1. This is a convenience function. The standard interface is through the scrollResponse resource. In the Slider2 widget, that resource is connected to the scroll_response method.
XfwfResizeThumb( $, double  wd, double  ht)
{
    XfwfScrollInfo info;
    if (! XtIsSubclass($, xfwfSlider2WidgetClass))
    XtError("XfwfResizeThumb called with incorrect widget type");
    if (wd < 0.0 || wd > 1.0 || ht < 0.0 || ht > 1.0)
    XtError("XfwfResizeThumb called with incorrect arguments");
    info.reason = XfwfSNotify;
    info.flags = XFWF_VSIZE | XFWF_HSIZE;
    info.vsize = ht;
    info.hsize = wd;
    $scroll_response(NULL, $, info); }

  Translations
The start action should be bound to a mouse button press, because it needs the coordinates of the mouse. The drag action is bound to mouse movement and the finish action is normally bound to a release of the mouse button.
<Btn1Down>: start()
<Btn1Motion>: drag()
<Btn1Up>: finish()

  Actions

start
    The start action checks the position of the mouse and if it was outside the thumb, it calls the scrollCallback. Otherwise, it only records the position. Note that the mouse may have been to the left as well as below the thumb, causing the callbacks to be called twice.
    void start($, XEvent* event, String* params, Cardinal* num_params)
    {
        Dimension w, h;
        Position x, y;
        XfwfScrollInfo info;
        Boolean outside = False;
        if (event->type != ButtonPress  event->type != ButtonRelease
    	 event->type != MotionNotify)
    	XtError("The start action must be bound to a mouse event");
        $compute_thumb($, x, y, w, h);
        if (event->xbutton.x < x) {			/* Left of thumb */
    	info.reason = XfwfSPageLeft;
    	info.flags = XFWF_HPOS;			/* Suggest a value: */
    	info.hpos = max(0.0, $thumb_x - $thumb_wd);
    	outside = True;
    	XtCallCallbackList($, $scrollCallback, info);
        }
        if (event->xbutton.x >= x + w) {		/* Right of thumb */
    	info.reason = XfwfSPageRight;
    	info.flags = XFWF_HPOS;			/* Suggest a value: */
    	info.hpos = min(1.0, $thumb_x + $thumb_wd);
    	outside = True;
    	XtCallCallbackList($, $scrollCallback, info);
        }
        if (event->xbutton.y < y) {			/* Above thumb */
    	info.reason = XfwfSPageUp;
    	info.flags = XFWF_VPOS;			/* Suggest a value: */
    	info.vpos = max(0.0, $thumb_y - $thumb_ht);
    	outside = True;
    	XtCallCallbackList($, $scrollCallback, info);
        }
        if (event->xbutton.y >= y + h) {		/* Below thumb */
    	info.reason = XfwfSPageDown;
    	info.flags = XFWF_VPOS;			/* Suggest a value: */
    	info.vpos = min(1.0, $thumb_y + $thumb_ht);
    	outside = True;
    	XtCallCallbackList($, $scrollCallback, info);
        }
        if (! outside) {				/* Inside the thumb */
    	$drag_in_progress = True;
    	$m_delta_x = x - event->xbutton.x;
    	$m_delta_y = y - event->xbutton.y;
        }
    }

finish
    The finish action does nothing if this is the end of a click outside the thumb. The callbacks for this event have already been called. If this is the end of a drag action, we reset the flag drag_in_progress to False and call the drop callbacks.
    void finish($, XEvent* event, String* params, Cardinal* num_params)
    {
        XfwfScrollInfo info;
        if ($drag_in_progress) {
    	$drag_in_progress = False;
    	info.reason = XfwfSMove;
    	info.flags = XFWF_VPOS | XFWF_HPOS;
    	info.hpos = $thumb_x;
    	info.vpos = $thumb_y;
    	XtCallCallbackList($, $scrollCallback, info);
        }
    }

drag
    An application that can draw fast enough, may wish to redraw with every movement of the thumb, instead of only at the end of the drag action. The drag callback is provided for this purpose. It is called in the same way as the drop callback, with the current relative position of the thumb.
    void drag($, XEvent* event, String* params, Cardinal* num_params)
    {
        XfwfScrollInfo info;
        Dimension wd, ht, fwd, fht;
        Position oldx, oldy, newx, newy, fx, fy;
        float dum1, dum2;
        if (! $drag_in_progress) return;
        if (event->type != ButtonPress  event->type != ButtonRelease
    	 event->type != MotionNotify)
    	XtError("The drag action must be bound to a mouse event");
        $compute_thumb($, oldx, oldy, wd, ht);
        newx = event->xbutton.x + $m_delta_x;
        newy = event->xbutton.y + $m_delta_y;
        $compute_info($, newx, newy, wd, ht, $thumb_x, $thumb_y,dum1,dum2);
        $move_thumb($, oldx, oldy, wd, ht, newx, newy);
        info.reason = XfwfSDrag;
        info.flags = XFWF_VPOS | XFWF_HPOS;
        info.hpos = $thumb_x;
        info.vpos = $thumb_y;
        XtCallCallbackList($, $scrollCallback, info);
    }

Importss
incl
 "stip4.bm"
incl
 <stdio.h>

  Private variables
The position and size of the thumb are controlled by four variables that can assume values between 0 and 1. If thumb_x is 0, the thumb is located against the left side, if it is 1, the thumb is put against the right side. If thumb_wd is 1, the thumb is as large as possible, if it is 0, it will have its minimum width minsize.
float  thumb_x
float  thumb_y
float  thumb_wd
float  thumb_ht
A boolean variable is set to when a draggin action has started, but not yet finished.
Boolean  drag_in_progress
During a drag operation, the thumb is kept at a fixed offset from the moving mouse. The offset is stored in two local variables.
int  m_delta_x
int  m_delta_y
We also need three more GC's for the thumb and the light and dark parts of the thumb's frame.
GC  thumbgc
GC  thumblightgc
GC  thumbdarkgc

Class variables
The Core variable compress_exposure is OR'ed with XtExposeGraphicsExpose, in order to get graphics expose events delivered to the expose method.
compress_exposure = XtExposeCompressMultiple |XtExposeGraphicsExpose

  Methods
The compute_thumb method returns the position and size of the thumb in pixels.
compute_thumb($, Position * x, Position * y, Dimension * width, Dimension * height)
{
    Position fx, fy;
    Dimension fw, fh;
    #compute_inside($, fx, fy, fw, fh);
    *width = $thumb_wd * fw + 0.5;
    *height = $thumb_ht * fh + 0.5;
    if (*width < $minsize) *width = min(fw, $minsize);
    if (*height < $minsize) *height = min(fh, $minsize);
    *x = fx + $thumb_x * (fw - *width) + 0.5;
    *y = fy + $thumb_y * (fh - *height) + 0.5;
}
The compute_inside method of the Label class returns the area inside the frame, but the label of Slider2 widget should appear in the thumb. Therefore the compute_inside method is redefined. This means that the expose method of the Label class can still be used, because it calls this function to establish the position of the text.
compute_inside($, Position * x, Position * y, Dimension * w, Dimension * h)
{
    int tmp;
    $compute_thumb($, x, y, w, h);
    *x += $thumbFrameWidth;
    *y += $thumbFrameWidth;
    tmp = *w - 2 * $thumbFrameWidth;  *w = (tmp < 0) ? 0 : tmp;
    tmp = *h - 2 * $thumbFrameWidth;  *h = (tmp < 0) ? 0 : tmp;
}
The expose method of the superclass is called to draw the outer frame and the text inside the thumb. Only the frame of the thumb is drawn here.
expose($, XEvent * event, Region  region)
{
    Position x, y;
    Dimension wd, ht;
    if (! XtIsRealized($)) return;
    if (region != NULL) {
	XSetRegion(XtDisplay($), $thumbgc, region);
	XSetRegion(XtDisplay($), $thumbdarkgc, region);
	XSetRegion(XtDisplay($), $thumblightgc, region);
    }
    $compute_thumb($, x, y, wd, ht);
    XFillRectangle(XtDisplay($), XtWindow($), $thumbgc, x, y, wd, ht);
    XfwfDrawFrame($, x, y, wd, ht, $thumbFrameType, $thumbFrameWidth,
	       $thumblightgc, $thumbdarkgc);
    if (region != NULL) {
	XSetClipMask(XtDisplay($), $thumbgc, None);
	XSetClipMask(XtDisplay($), $thumbdarkgc, None);
	XSetClipMask(XtDisplay($), $thumblightgc, None);
    }
    #expose($, event, region);
}
The initialize method only needs to set the local variables. The graygc that is inherited from Label has to be defined differently, because it now should use the thumb's background, instead of the widget's. (It still doesn't work right when the thumb is tiled with a pixmap, however.) Likewise, gc and rv_gc must be defined differently. The two new GC's are also initialized.
initialize(Widget  request, $, ArgList  args, Cardinal * num_args)
{
    $thumb_x = $thumb_y = 0.0;
    $thumb_wd = $thumb_ht = 1.0;
    $drag_in_progress = False;
    create_thumbgc($);
    create_gc($);
    create_graygc($);
    $thumblightgc = NULL; create_thumblightgc($);
    $thumbdarkgc = NULL; create_thumbdarkgc($);
}
The following routine's name, move_thumb, indicates what it is used for, but not what it really does. It doesn't depend on the thumb at all, it simply copies a rectangle to another position in the window and clears the old rectangle to the background color.
move_thumb($, int  oldx, int  oldy, int  wd, int  ht, int  newx, int  newy)
{
    int h;
    XCopyArea(XtDisplay($), XtWindow($), XtWindow($),
	      DefaultGCOfScreen(XtScreen($)),
	      oldx, oldy, wd, ht, newx, newy);
    /* First check if the old and new areas do not overlap */
    if (newx + wd <= oldx || oldx + wd <= newx
	|| newy + ht <= oldy || oldy + ht <= newy) {
	XClearArea(XtDisplay($), XtWindow($), oldx, oldy, wd, ht, False);
	return;
    } else {					/* They do overlap */
	h = oldy - newy;
	if (h > 0)
	    XClearArea(XtDisplay($), XtWindow($), oldx, newy + ht, wd,h,False);
	else if (h < 0)
	    XClearArea(XtDisplay($), XtWindow($), oldx, oldy, wd, -h, False);
	if (newx < oldx)
	    XClearArea(XtDisplay($), XtWindow($), newx + wd,
		       max(oldy, newy), oldx - newx, ht - abs(h), False);
	else if (oldx < newx)
	    XClearArea(XtDisplay($), XtWindow($), oldx, max(oldy, newy),
		       newx - oldx, ht - abs(h), False);
    }
}
The compute_info method computes the relative position and size of the thumb, given its geometry in pixels. Before that, it makes sure the pixel values are within the frame and it adapts the values if needed.
compute_info($, Position * x, Position * y, Dimension * w, Dimension * h, float * thumb_x, float * thumb_y, float * thumb_wd, float * thumb_ht)
{
    Dimension fw, fh;
    Position fx, fy;
    #compute_inside($, fx, fy, fw, fh);
    *w = min(fw, max($minsize, *w));
    *h = min(fh, max($minsize, *h));
    *x = min(fx + fw - *w, max(fx, *x));
    *y = min(fy + fh - *h, max(fy, *y));
    *thumb_wd = ((float) *w)/fw;
    *thumb_ht = ((float) *h)/fh;
    *thumb_x = (*w == fw) ? 0.0 : ((float) (*x - fx))/(fw - *w);
    *thumb_y = (*h == fh) ? 0.0 : ((float) (*y - fy))/(fh - *h);
}
The set_values method changes the GC's when needed. A change in minsize doesn't necessarily cause a redraw; only if the current thumb size is less than the new minimum does the widget needs to be redrawn.
Boolean  set_values(Widget  old, Widget  request, $, ArgList  args, Cardinal * num_args)
{
    Boolean need_redisplay = False;
    Position x, y;
    Dimension w, h;
    if ($thumbPixmap != $old$thumbPixmap) {
	create_thumbgc($);
	need_redisplay = True;
    } else if ($thumbColor != $old$thumbColor) {
	$thumbPixmap = NULL;
	create_thumbgc($);
	need_redisplay = True;
    }
    if ($thumbFrameWidth != $old$thumbFrameWidth)
	need_redisplay = True;
    if ($thumbFrameType != $old$thumbFrameType)
	need_redisplay = True;
    if ($minsize != $old$minsize) {
	compute_thumb(old, x, y, w, h);
	if (w < $minsize || h < $minsize) need_redisplay = True;
    }
    if ($scrollResponse != $old$scrollResponse) {
	$scrollResponse = $old$scrollResponse;
	XtWarning("scrollResponse resource may only be queried, not set");
    }
    return need_redisplay;
}
The method scroll_response is exported via the scrollResponse resource. It has the format of a callback function, so that it can be registered as a callback in the scrollCallback list of some other widget. The client_data must be a pointer to the Slider2 widget itself, the call_data is a pointer to an XfwfScrollInfo structure. The widget wdg is the widget from whose callback list the function is called. If the size of the thumb changed, the area must be cleared and redrawn with expose, but if only the position changed, the thumb can be moved with the move_thumb method, which is much faster. def range(x) = (0.0 <=(x )(x )<=1.0 )
scroll_response(Widget  wdg, XtPointer  client_data, XtPointer  call_data)
{
    Widget self = (Widget) client_data;
    XfwfScrollInfo *inf = (XfwfScrollInfo *)call_data;
    XfwfScrollInfo new_info;
    float x, y, w, h;
    Position newx, newy, oldx, oldy;
    Dimension newwd, newht, oldwd, oldht, wd, ht;
    XEvent event;
    XRectangle rect;
    Region clip;
    Display *dpy = XtDisplay($);
    x = (inf->flagsXFWF_HPOS)  range(inf->hpos) ? inf->hpos : $thumb_x;
    y = (inf->flagsXFWF_VPOS)  range(inf->vpos) ? inf->vpos : $thumb_y;
    w = (inf->flagsXFWF_HSIZE)  range(inf->hsize) ? inf->hsize : $thumb_wd;
    h = (inf->flagsXFWF_VSIZE)  range(inf->vsize) ? inf->vsize : $thumb_ht;
    if ($thumb_wd != w || $thumb_ht != h) {	/* Size changed */
	if (XtIsRealized($))
	    $compute_thumb($, oldx, oldy, oldwd, oldht);
	$thumb_wd = w;
	$thumb_ht = h;
	$thumb_x = x;
	$thumb_y = y;
	if (XtIsRealized($)) {
	    $compute_thumb($, newx, newy, newwd, newht);
	    XClearArea(dpy, XtWindow($), oldx, oldy, oldwd, oldht, False);
	    event.xexpose.x = rect.x = newx;
	    event.xexpose.y = rect.y = newy;
	    event.xexpose.width = rect.width = newwd;
	    event.xexpose.height = rect.height = newht;
	    clip = XCreateRegion();
	    XUnionRectWithRegion(rect, clip, clip);
	    $expose($, event, clip);
	    XDestroyRegion(clip);
	}
    } else if ($thumb_x != x || $thumb_y != y) { /* Only position changed */
	if (XtIsRealized($))
	    $compute_thumb($, oldx, oldy, wd, ht);
	$thumb_x = x;
	$thumb_y = y;
	if (XtIsRealized($)) {
	    $compute_thumb($, newx, newy, wd, ht);
	    $move_thumb($, oldx, oldy, wd, ht, newx, newy);
	}
    }
    if (inf->reason != XfwfSNotify) {
	new_info = *inf;
	new_info.reason = XfwfSNotify;
	XtCallCallbackList($, $scrollCallback, new_info);
    }
}

Utilities
The create_gc routine creates the GCs for the text.
create_gc($)
{
    XtGCMask mask;
    XGCValues values;
    if ($gc != NULL) XtReleaseGC($, $gc);
    values.background = $thumbColor;
    values.foreground = $foreground;
    values.font = $font->fid;
    mask = GCFont | GCBackground | GCForeground;
    $gc = XtGetGC($, mask, values);
    if ($rv_gc != NULL) XtReleaseGC($, $rv_gc);
    values.foreground = $thumbColor;
    values.background = $foreground;
    values.font = $font->fid;
    mask = GCFont | GCBackground | GCForeground;
    $rv_gc = XtGetGC($, mask, values);
}
The create_graygc routine creates the GC that grays the label in the thumb.
create_graygc($)
{
    XtGCMask mask;
    XGCValues values;
    if ($graygc != NULL) XtReleaseGC($, $graygc);
    values.foreground = $thumbColor;
    values.stipple =
	XCreateBitmapFromData(XtDisplay($),
			      RootWindowOfScreen(XtScreen($)),
			      stip4_bits, stip4_width, stip4_height);
    values.fill_style = FillStippled;
    mask = GCForeground | GCStipple | GCFillStyle;
    $graygc = XtGetGC($, mask, values);
}
create_thumbgc creates the GC that draw the background in the thumb.
create_thumbgc($)
{
    XtGCMask mask;
    XGCValues values;
    if ($thumbgc != NULL) XtReleaseGC($, $thumbgc);
    if ($thumbPixmap != NULL) {
	mask = GCTile | GCFillStyle;
	values.tile = $thumbPixmap;
	values.fill_style = FillTiled;
    } else {
	mask = GCForeground;
	values.foreground = $thumbColor;
    }
    $thumbgc = XtGetGC($, mask, values);
}
The create_thumblightgc functions makes the GC for drawing the light parts of the thumb's frame.
create_thumblightgc($)
{
    XtGCMask mask;
    XGCValues values;
    if ($thumblightgc != NULL) XtReleaseGC($, $thumblightgc);
    switch ($shadowScheme) {
    case XfwfColor:
	mask = GCForeground;
	values.foreground = $lightColor;
	break;
    case XfwfStipple:
	mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
	values.fill_style = FillOpaqueStippled;
	values.background = $thumbColor;
	values.stipple = $lightStipple;
	values.foreground = WhitePixelOfScreen(XtScreen($));
	break;
    case XfwfAuto:
	if (DefaultDepthOfScreen(XtScreen($)) > 4
	     $lighter_color($, $thumbColor, values.foreground)) {
	    mask = GCForeground;
	} else {
	    mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
	    values.fill_style = FillOpaqueStippled;
	    values.background = $thumbColor;
	    values.foreground = WhitePixelOfScreen(XtScreen($));
	    values.stipple =
		XCreateBitmapFromData(XtDisplay($),
				      RootWindowOfScreen(XtScreen($)),
				      stip4_bits, stip4_width, stip4_height);
	}
	break;
    }
    $thumblightgc = XtGetGC($, mask, values);
}
The create_thumbdarkgc routines does the same for the dark parts of the thumb's frame.
create_thumbdarkgc($)
{
    XtGCMask mask;
    XGCValues values;
    if ($thumbdarkgc != NULL) XtReleaseGC($, $thumbdarkgc);
    switch ($shadowScheme) {
    case XfwfColor:
	mask = GCForeground;
	values.foreground = $darkColor;
	break;
    case XfwfStipple:
	mask = GCFillStyle | GCStipple | GCForeground | GCBackground;
	values.fill_style = FillOpaqueStippled;
	values.stipple = $darkStipple;
	values.foreground = BlackPixelOfScreen(XtScreen($));
	values.background = $thumbColor;
	break;
    case XfwfAuto:
	if (DefaultDepthOfScreen(XtScreen($)) > 4
	     $darker_color($, $thumbColor, values.foreground)) {
	    mask = GCForeground;
	} else {
	    mask = GCFillStyle | GCBackground | GCForeground | GCStipple;
	    values.fill_style = FillOpaqueStippled;
	    values.background = $thumbColor;
	    values.foreground = WhitePixelOfScreen(XtScreen($));
	    values.stipple =
		XCreateBitmapFromData(XtDisplay($),
				      RootWindowOfScreen(XtScreen($)),
				      stip4_bits, stip4_width, stip4_height);
	}
	break;
    }
    $thumbdarkgc = XtGetGC($, mask, values);
}