.\"remove .ig hn for full docs .de hi .ig eh .. .de eh .. .TH "" 3 "" "Version 3.0" "Free Widget Foundation" .SH NAME XfwfSlider2 .SH 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. .SS "Public variables" .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. 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 .TE .ps .TP .I "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 \fIthumbColor\fP resource. It is also possible to tile the thumb with a pixmap, see below. .hi .nf Pixel thumbColor = XtDefaultBackground .fi .eh .TP .I "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 \fIthumbColor\fP and \fIthumbPixmap\fP are set, the pixmap takes precedence. .hi .nf Pixmap thumbPixmap = NULL .fi .eh .TP .I "XtNminsize" The minimum size of the thumb is by default 20 pixels. It can be set with the \fIminsize\fP resource. .hi .nf Dimension minsize = 20 .fi .eh .TP .I "XtNthumbFrameWidth" The width of the frame around the thumb is independent of the frame around the whole widget. It can be set with \fIthumbFrameWidth\fP. .hi .nf Dimension thumbFrameWidth = 2 .fi .eh .TP .I "XtNthumbFrameType" The style of the frame around the thumb is set with \fIthumbFrameType\fP. By default, it is \fIXfwfRaised\fP. 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 \fIshadowScheme\fP, \fItopShadowColor\fP, \fItopShadowStipple\fP, etc, also influence the frame of the thumb. .hi .nf FrameType thumbFrameType = XfwfRaised .fi .eh .TP .I "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 \fIscrollResponse\fP function with a reason other than \fIXfwfSNotify\fP. The \fIcall_data\fP parameter of the callback routines is a pointer to an \fIXfwfScrollInfo\fP structure, which looks like this: \fItypedef struct _XfwfScrollInfo { XfwfSReason reason; XfwfSFlags flags; float vpos, vsize, hpos, hsize;} XfwfScrollInfo\fP. .hi .nf XtCallbackList scrollCallback = NULL .fi .eh .TP .I "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 \fIXtGetValues\fP as the resource \fIXtNscrollResponse\fP. This resource can only be queried, not set. .hi .nf XtCallbackProc scrollResponse = scroll_response .fi .eh .TP .I "XtNframeWidth" The default frame width is changed from 0 to 2. .hi .nf frameWidth = 2 .fi .eh .TP .I "XtNframeType" The default frame type is now \fIXfwfSunken\fP. .hi .nf frameType = XfwfSunken .fi .eh .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfLabel Name Class Type Default XtNlabel XtCLabel String NULL XtNtablist XtCTablist String NULL XtNfont XtCFont FontStruct XtDefaultFont XtNforeground XtCForeground Pixel XtDefaultForeground XtNalignment XtCAlignment Alignment 0 XtNtopMargin XtCTopMargin Dimension 2 XtNbottomMargin XtCBottomMargin Dimension 2 XtNleftMargin XtCLeftMargin Dimension 2 XtNrightMargin XtCRightMargin Dimension 2 XtNshrinkToFit XtCShrinkToFit Boolean False XtNrvStart XtCRvStart Int 0 XtNrvLength XtCRvLength Int 0 .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfBoard Name Class Type Default XtNabs_x XtCAbs_x Position 0 XtNrel_x XtCRel_x Float "0.0" XtNabs_y XtCAbs_y Position 0 XtNrel_y XtCRel_y Float "0.0" XtNabs_width XtCAbs_width Position 0 XtNrel_width XtCRel_width Float "1.0" XtNabs_height XtCAbs_height Position 0 XtNrel_height XtCRel_height Float "1.0" XtNhunit XtCHunit Float "1.0" XtNvunit XtCVunit Float "1.0" XtNlocation XtCLocation String NULL .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfFrame Name Class Type Default XtNcursor XtCCursor Cursor None XtNframeType XtCFrameType FrameType XfwfRaised XtNframeWidth XtCFrameWidth Dimension 0 XtNouterOffset XtCOuterOffset Dimension 0 XtNinnerOffset XtCInnerOffset Dimension 0 XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL .TE .ps .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 .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 \fIscroll.h\fP header file is needed for the \fIXfwfScrollInfo\fP structure. .nf .B incl .fi The current size and position of the thumb can be queried with the function \fIgetThumb\fP. It fills the \fIinfo\fP argument with the current values. .nf XfwfGetThumb( $, XfwfScrollInfo * info) .fi .hi { 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; } .eh To change the position of the thumb, a call to \fImoveThumb\fP can be used. The arguments must be two numbers between 0 and 1. The thumb is moved with \fIXCopyArea\fP. This is a convenience function. The standard interface is through the \fIscrollResponse\fP resource. In the Slider2 widget, that resource is connected to the \fIscroll_response\fP method. .nf XfwfMoveThumb( $, double x, double y) .fi .hi { 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); } .eh Resizing the thumb is done with \fIresizeThumb\fP. The two arguments must be between 0 and 1. This is a convenience function. The standard interface is through the \fIscrollResponse\fP resource. In the Slider2 widget, that resource is connected to the \fIscroll_response\fP method. .nf XfwfResizeThumb( $, double wd, double ht) .fi .hi { 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); } .eh .SS "Translations" The \fIstart\fP action should be bound to a mouse button press, because it needs the coordinates of the mouse. The \fIdrag\fP action is bound to mouse movement and the \fIfinish\fP action is normally bound to a release of the mouse button. .nf : start() .fi .nf : drag() .fi .nf : finish() .fi .hi .SS "Actions" .TP .I "start The \fIstart\fP action checks the position of the mouse and if it was outside the thumb, it calls the \fIscrollCallback\fP. 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. .hi .nf 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; } } .fi .eh .TP .I "finish The \fIfinish\fP 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 \fIdrag_in_progress\fP to False and call the drop callbacks. .hi .nf 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); } } .fi .eh .TP .I "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. .hi .nf 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); } .fi .eh .hi .hi .SH "Importss" .nf .B incl "stip4.bm" .fi .nf .B incl .fi .hi .hi .SS "Private variables" The position and size of the thumb are controlled by four variables that can assume values between 0 and 1. If \fIthumb_x\fP is 0, the thumb is located against the left side, if it is 1, the thumb is put against the right side. If \fIthumb_wd\fP is 1, the thumb is as large as possible, if it is 0, it will have its minimum width \fIminsize\fP. .nf float thumb_x .fi .nf float thumb_y .fi .nf float thumb_wd .fi .nf float thumb_ht .fi A boolean variable is set to when a draggin action has started, but not yet finished. .nf Boolean drag_in_progress .fi During a drag operation, the thumb is kept at a fixed offset from the moving mouse. The offset is stored in two local variables. .nf int m_delta_x .fi .nf int m_delta_y .fi We also need three more GC's for the thumb and the light and dark parts of the thumb's frame. .nf GC thumbgc .fi .nf GC thumblightgc .fi .nf GC thumbdarkgc .fi .hi .hi .SH "Class variables" The Core variable \fIcompress_exposure\fP is OR'ed with \fIXtExposeGraphicsExpose\fP, in order to get graphics expose events delivered to the \fIexpose\fP method. .nf compress_exposure = XtExposeCompressMultiple |XtExposeGraphicsExpose .fi .hi .hi .SS "Methods" The \fIcompute_thumb\fP method returns the position and size of the thumb in pixels. .nf 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; } .fi The \fIcompute_inside\fP method of the Label class returns the area inside the frame, but the label of Slider2 widget should appear in the thumb. Therefore the \fIcompute_inside\fP method is redefined. This means that the \fIexpose\fP method of the Label class can still be used, because it calls this function to establish the position of the text. .nf 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; } .fi The \fIexpose\fP 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. .nf 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); } .fi The \fIinitialize\fP method only needs to set the local variables. The \fIgraygc\fP 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, \fIgc\fP and \fIrv_gc\fP must be defined differently. The two new GC's are also initialized. .nf 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($); } .fi The following routine's name, \fImove_thumb\fP, 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. .nf 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); } } .fi The \fIcompute_info\fP 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. .nf 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); } .fi The \fIset_values\fP method changes the GC's when needed. A change in \fIminsize\fP 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. .nf 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; } .fi The method \fIscroll_response\fP is exported via the \fIscrollResponse\fP resource. It has the format of a callback function, so that it can be registered as a callback in the \fIscrollCallback\fP list of some other widget. The \fIclient_data\fP must be a pointer to the Slider2 widget itself, the \fIcall_data\fP is a pointer to an \fIXfwfScrollInfo\fP structure. The widget \fIwdg\fP 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 \fIexpose\fP, but if only the position changed, the thumb can be moved with the \fImove_thumb\fP method, which is much faster. \fBdef\fP range(x) = (0.0 <=(x )(x )<=1.0 ) .nf 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); } } .fi .hi .hi .SH "Utilities" The \fIcreate_gc\fP routine creates the GCs for the text. .nf 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); } .fi The \fIcreate_graygc\fP routine creates the GC that grays the label in the thumb. .nf 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); } .fi \fIcreate_thumbgc\fP creates the GC that draw the background in the thumb. .nf 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); } .fi The \fIcreate_thumblightgc\fP functions makes the GC for drawing the light parts of the thumb's frame. .nf create_thumblightgc($) { XtGCMask mask; XGCValues values; if ($thumblightgc != NULL) XtReleaseGC($, $thumblightgc); switch ($shadowScheme) { case XfwfColor: mask = GCForeground; values.foreground = $topShadowColor; break; case XfwfStipple: mask = GCFillStyle | GCStipple | GCForeground | GCBackground; values.fill_style = FillOpaqueStippled; values.background = $thumbColor; values.stipple = $topShadowStipple; 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); } .fi The \fIcreate_thumbdarkgc\fP routines does the same for the dark parts of the thumb's frame. .nf create_thumbdarkgc($) { XtGCMask mask; XGCValues values; if ($thumbdarkgc != NULL) XtReleaseGC($, $thumbdarkgc); switch ($shadowScheme) { case XfwfColor: mask = GCForeground; values.foreground = $bottomShadowColor; break; case XfwfStipple: mask = GCFillStyle | GCStipple | GCForeground | GCBackground; values.fill_style = FillOpaqueStippled; values.stipple = $bottomShadowStipple; 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); } .fi .hi