1 /* vi:set ts=8 sts=4 sw=4 noet: */
2 /*
3  * MODIFIED ATHENA SCROLLBAR (USING ARROWHEADS AT ENDS OF TRAVEL)
4  * Modifications Copyright 1992 by Mitch Trachtenberg
5  * Rights, permissions, and disclaimer of warranty are as in the DEC and MIT
6  * notice below.
7  * $XConsortium: Scrollbar.c,v 1.72 94/04/17 20:12:40 kaleb Exp $
8  */
9 
10 /*
11  * Modified for Vim by Bill Foster and Bram Moolenaar
12  */
13 
14 /*
15 
16 Copyright (c) 1987, 1988, 1994	X Consortium
17 
18 Permission is hereby granted, free of charge, to any person obtaining a copy
19 of this software and associated documentation files (the "Software"), to deal
20 in the Software without restriction, including without limitation the rights
21 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 copies of the Software, and to permit persons to whom the Software is
23 furnished to do so, subject to the following conditions:
24 
25 The above copyright notice and this permission notice shall be included in all
26 copies or substantial portions of the Software.
27 
28 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE X
31 CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 
35 Except as contained in this notice, the name of the X Consortium shall not be
36 used in advertising or otherwise to promote the sale, use or other dealings in
37 this Software without prior written authorization from the X Consortium.
38 
39 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
40 
41 			All Rights Reserved
42 
43 Permission to use, copy, modify, and distribute this software and its
44 documentation for any purpose and without fee is hereby granted, provided that
45 the above copyright notice appear in all copies and that both that copyright
46 notice and this permission notice appear in supporting documentation, and that
47 the name of Digital not be used in advertising or publicity pertaining to
48 distribution of the software without specific, written prior permission.
49 
50 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
51 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL
52 BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
54 OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
55 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56 
57 */
58 
59 // ScrollBar.c
60 // created by weissman, Mon Jul  7 13:20:03 1986
61 // converted by swick, Thu Aug 27 1987
62 
63 #include "vim.h"
64 
65 #include <X11/IntrinsicP.h>
66 #include <X11/StringDefs.h>
67 
68 #include <X11/Xaw/XawInit.h>
69 #include "gui_at_sb.h"
70 
71 #include <X11/Xmu/Drawing.h>
72 
73 // Private definitions.
74 
75 static char defaultTranslations[] =
76     "<Btn1Down>: NotifyScroll()\n\
77      <Btn2Down>: MoveThumb() NotifyThumb()\n\
78      <Btn3Down>: NotifyScroll()\n\
79      <Btn4Down>: ScrollOneLineUp()\n\
80      Shift<Btn4Down>: ScrollPageUp()\n\
81      <Btn5Down>: ScrollOneLineDown()\n\
82      Shift<Btn5Down>: ScrollPageDown()\n\
83      <Btn1Motion>: HandleThumb()\n\
84      <Btn3Motion>: HandleThumb()\n\
85      <Btn2Motion>: MoveThumb() NotifyThumb()\n\
86      <BtnUp>: EndScroll()";
87 
88 static float floatZero = 0.0;
89 
90 #define Offset(field) XtOffsetOf(ScrollbarRec, field)
91 
92 static XtResource resources[] =
93 {
94   {XtNlength, XtCLength, XtRDimension, sizeof(Dimension),
95        Offset(scrollbar.length), XtRImmediate, (XtPointer) 1},
96   {XtNthickness, XtCThickness, XtRDimension, sizeof(Dimension),
97        Offset(scrollbar.thickness), XtRImmediate, (XtPointer) 14},
98   {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
99       Offset(scrollbar.orientation), XtRImmediate, (XtPointer) XtorientVertical},
100   {XtNscrollProc, XtCCallback, XtRCallback, sizeof(XtPointer),
101        Offset(scrollbar.scrollProc), XtRCallback, NULL},
102   {XtNthumbProc, XtCCallback, XtRCallback, sizeof(XtPointer),
103        Offset(scrollbar.thumbProc), XtRCallback, NULL},
104   {XtNjumpProc, XtCCallback, XtRCallback, sizeof(XtPointer),
105        Offset(scrollbar.jumpProc), XtRCallback, NULL},
106   {XtNthumb, XtCThumb, XtRBitmap, sizeof(Pixmap),
107        Offset(scrollbar.thumb), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
108   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
109        Offset(scrollbar.foreground), XtRString, XtDefaultForeground},
110   {XtNshown, XtCShown, XtRFloat, sizeof(float),
111        Offset(scrollbar.shown), XtRFloat, (XtPointer)&floatZero},
112   {XtNtopOfThumb, XtCTopOfThumb, XtRFloat, sizeof(float),
113        Offset(scrollbar.top), XtRFloat, (XtPointer)&floatZero},
114   {XtNmaxOfThumb, XtCMaxOfThumb, XtRFloat, sizeof(float),
115        Offset(scrollbar.max), XtRFloat, (XtPointer)&floatZero},
116   {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
117        Offset(scrollbar.min_thumb), XtRImmediate, (XtPointer) 7},
118   {XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
119        Offset(scrollbar.shadow_width), XtRImmediate, (XtPointer) 1},
120   {XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
121        Offset(scrollbar.top_shadow_pixel), XtRString, XtDefaultBackground},
122   {XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
123        Offset(scrollbar.bot_shadow_pixel), XtRString, XtDefaultForeground},
124   {XtNlimitThumb, XtCLimitThumb, XtRBool, sizeof(Bool),
125        Offset(scrollbar.limit_thumb), XtRImmediate, (XtPointer)0}
126 };
127 #undef Offset
128 
129 static void ClassInitialize(void);
130 static void Initialize(Widget, Widget, ArgList, Cardinal *);
131 static void Destroy(Widget);
132 static void Realize(Widget, Mask *, XSetWindowAttributes *);
133 static void Resize(Widget);
134 static void Redisplay(Widget, XEvent *, Region);
135 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
136 
137 static void HandleThumb(Widget, XEvent *, String *, Cardinal *);
138 static void MoveThumb(Widget, XEvent *, String *, Cardinal *);
139 static void NotifyThumb(Widget, XEvent *, String *, Cardinal *);
140 static void NotifyScroll(Widget, XEvent *, String *, Cardinal *);
141 static void EndScroll(Widget, XEvent *, String *, Cardinal *);
142 static void ScrollOneLineUp(Widget, XEvent *, String *, Cardinal *);
143 static void ScrollOneLineDown(Widget, XEvent *, String *, Cardinal *);
144 static void ScrollPageUp(Widget, XEvent *, String *, Cardinal *);
145 static void ScrollPageDown(Widget, XEvent *, String *, Cardinal *);
146 static void ScrollSome(Widget w, XEvent *event, int call_data);
147 static void _Xaw3dDrawShadows(Widget, XEvent *, Region, int);
148 static void AllocTopShadowGC(Widget);
149 static void AllocBotShadowGC(Widget);
150 
151 static XtActionsRec actions[] =
152 {
153     {"HandleThumb",	HandleThumb},
154     {"MoveThumb",	MoveThumb},
155     {"NotifyThumb",	NotifyThumb},
156     {"NotifyScroll",	NotifyScroll},
157     {"EndScroll",	EndScroll},
158     {"ScrollOneLineUp", ScrollOneLineUp},
159     {"ScrollOneLineDown", ScrollOneLineDown},
160     {"ScrollPageUp",	ScrollPageUp},
161     {"ScrollPageDown",	ScrollPageDown}
162 };
163 
164 
165 ScrollbarClassRec vim_scrollbarClassRec =
166 {
167   { // core fields
168     /* superclass	*/  (WidgetClass) &simpleClassRec,
169     /* class_name	*/  "Scrollbar",
170     /* size		*/  sizeof(ScrollbarRec),
171     /* class_initialize	*/  ClassInitialize,
172     /* class_part_init	*/  NULL,
173     /* class_inited	*/  FALSE,
174     /* initialize	*/  Initialize,
175     /* initialize_hook	*/  NULL,
176     /* realize		*/  Realize,
177     /* actions		*/  actions,
178     /* num_actions	*/  XtNumber(actions),
179     /* resources	*/  resources,
180     /* num_resources	*/  XtNumber(resources),
181     /* xrm_class	*/  NULLQUARK,
182     /* compress_motion	*/  TRUE,
183     /* compress_exposure*/  TRUE,
184     /* compress_enterleave*/	TRUE,
185     /* visible_interest */  FALSE,
186     /* destroy		*/  Destroy,
187     /* resize		*/  Resize,
188     /* expose		*/  Redisplay,
189     /* set_values	*/  SetValues,
190     /* set_values_hook	*/  NULL,
191     /* set_values_almost */ XtInheritSetValuesAlmost,
192     /* get_values_hook	*/  NULL,
193     /* accept_focus	*/  NULL,
194     /* version		*/  XtVersion,
195     /* callback_private */  NULL,
196     /* tm_table		*/  defaultTranslations,
197     /* query_geometry	*/  XtInheritQueryGeometry,
198     /* display_accelerator*/	XtInheritDisplayAccelerator,
199     /* extension	*/  NULL
200   },
201   { // simple fields
202     /* change_sensitive	*/  XtInheritChangeSensitive,
203 #ifndef OLDXAW
204     /* extension */	    NULL
205 #endif
206   },
207   { // scrollbar fields
208     /* empty	    */	    0
209   }
210 };
211 
212 WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec;
213 
214 #define NoButton -1
215 #define PICKLENGTH(widget, x, y) \
216     ((widget->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
217 #define AT_MIN(x,y)    ((x) < (y) ? (x) : (y))
218 #define AT_MAX(x,y)    ((x) > (y) ? (x) : (y))
219 
220 #define LINE_DELAY	300
221 #define PAGE_DELAY	300
222 #define LINE_REPEAT	 50
223 #define PAGE_REPEAT	250
224 
225     static void
ClassInitialize(void)226 ClassInitialize(void)
227 {
228     XawInitializeWidgetSet();
229     XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
230 	    (XtConvertArgList)NULL, (Cardinal)0 );
231 }
232 
233 #define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width
234 
235     static void
FillArea(ScrollbarWidget sbw,Position top,Position bottom,int fill,int draw_shadow)236 FillArea(
237     ScrollbarWidget	sbw,
238     Position		top,
239     Position		bottom,
240     int			fill,
241     int			draw_shadow)
242 {
243     int tlen = bottom - top;	// length of thumb in pixels
244     int sw, margin, floor;
245     int lx, ly, lw, lh;
246 
247     if (bottom <= 0 || bottom <= top)
248 	return;
249     sw = sbw->scrollbar.shadow_width;
250     if (sw < 0)
251 	sw = 0;
252     margin = MARGIN (sbw);
253     floor = sbw->scrollbar.length - margin + 2;
254 
255     if (sbw->scrollbar.orientation == XtorientHorizontal)
256     {
257 	lx = ((top < margin) ? margin : top);
258 	ly = sw;
259 	lw = (((top + tlen) > floor) ? floor - top : tlen);
260 	lh = sbw->core.height - 2 * sw;
261     }
262     else
263     {
264 	lx = sw;
265 	ly = ((top < margin) ? margin : top);
266 	lw = sbw->core.width - 2 * sw;
267 	lh = (((top + tlen) > floor) ? floor - top : tlen);
268     }
269     if (lh <= 0 || lw <= 0)
270 	return;
271 
272     if (draw_shadow)
273     {
274 	if (!(sbw->scrollbar.orientation == XtorientHorizontal))
275 	{
276 	    // Top border
277 	    XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
278 		    sbw->scrollbar.top_shadow_GC,
279 		    lx, ly, lx + lw - 1, ly);
280 
281 	    // Bottom border
282 	    XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
283 		    sbw->scrollbar.bot_shadow_GC,
284 		    lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
285 	}
286 	else
287 	{
288 	    // Left border
289 	    XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
290 		    sbw->scrollbar.top_shadow_GC,
291 		    lx, ly, lx, ly + lh - 1);
292 
293 	    // Right border
294 	    XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
295 		    sbw->scrollbar.bot_shadow_GC,
296 		    lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
297 	}
298 	return;
299     }
300 
301     if (fill)
302     {
303 	XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
304 		sbw->scrollbar.gc,
305 		lx, ly, (unsigned int) lw, (unsigned int) lh);
306 
307 	if (!(sbw->scrollbar.orientation == XtorientHorizontal))
308 	{
309 	    // Left border
310 	    XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
311 		    sbw->scrollbar.top_shadow_GC,
312 		    lx, ly, lx, ly + lh - 1);
313 
314 	    // Right border
315 	    XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
316 		    sbw->scrollbar.bot_shadow_GC,
317 		    lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
318 	}
319 	else
320 	{
321 	    // Top border
322 	    XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
323 		    sbw->scrollbar.top_shadow_GC,
324 		    lx, ly, lx + lw - 1, ly);
325 
326 	    // Bottom border
327 	    XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
328 		    sbw->scrollbar.bot_shadow_GC,
329 		    lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
330 	}
331     }
332     else
333     {
334 	XClearArea(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
335 		lx, ly, (unsigned int) lw, (unsigned int) lh, FALSE);
336     }
337 }
338 
339 /*
340  * Paint the thumb in the area specified by sbw->top and
341  * sbw->shown.	The old area is erased.  The painting and
342  * erasing is done cleverly so that no flickering will occur.
343  */
344     static void
PaintThumb(ScrollbarWidget sbw)345 PaintThumb(ScrollbarWidget sbw)
346 {
347     Position	    oldtop, oldbot, newtop, newbot;
348     Dimension	    margin, tzl;
349 
350     margin = MARGIN (sbw);
351     tzl = sbw->scrollbar.length - 2 * margin;
352     newtop = margin + (int)(tzl * sbw->scrollbar.top);
353     newbot = newtop + (int)(tzl * sbw->scrollbar.shown) + 1;
354     if (newbot < newtop + (int)sbw->scrollbar.min_thumb)
355 	newbot = newtop + sbw->scrollbar.min_thumb;
356 
357     oldtop = sbw->scrollbar.topLoc;
358     oldbot = oldtop + sbw->scrollbar.shownLength;
359     sbw->scrollbar.topLoc = newtop;
360     sbw->scrollbar.shownLength = newbot - newtop;
361     if (XtIsRealized ((Widget) sbw))
362     {
363 	if (newtop < oldtop)
364 	    FillArea(sbw, newtop, AT_MIN(newbot,	oldtop+1),1,0);
365 	if (newtop > oldtop)
366 	    FillArea(sbw, oldtop, AT_MIN(newtop,	oldbot	),0,0);
367 	if (newbot < oldbot)
368 	    FillArea(sbw, AT_MAX(newbot, oldtop),	oldbot,   0,0);
369 	if (newbot > oldbot)
370 	    FillArea(sbw, AT_MAX(newtop, oldbot-1), newbot,  1,0);
371 
372 	// Only draw the missing shadows
373 	FillArea(sbw, newtop, newbot, 0, 1);
374     }
375 }
376 
377     static void
PaintArrows(ScrollbarWidget sbw)378 PaintArrows(ScrollbarWidget sbw)
379 {
380     XPoint	point[6];
381     Dimension	thickness = sbw->scrollbar.thickness - 1;
382     Dimension	size;
383     Dimension	off;
384 
385     if (XtIsRealized((Widget) sbw))
386     {
387 	if ((int)thickness * 2 > (int)sbw->scrollbar.length)
388 	{
389 	    size = sbw->scrollbar.length / 2;
390 	    off = (int)(thickness - size) / 2;
391 	}
392 	else
393 	{
394 	    size = thickness;
395 	    off = 0;
396 	}
397 	point[0].x = off + sbw->scrollbar.shadow_width;
398 	point[0].y = size;
399 	point[1].x = thickness - off - sbw->scrollbar.shadow_width;
400 	point[1].y = size;
401 	point[2].x = thickness / 2;
402 	point[2].y = sbw->scrollbar.shadow_width;
403 
404 	point[3].x = off + sbw->scrollbar.shadow_width;
405 	point[3].y = sbw->scrollbar.length - size;
406 	point[4].x = thickness - off - sbw->scrollbar.shadow_width;
407 	point[4].y = sbw->scrollbar.length - size;
408 	point[5].x = thickness / 2;
409 	point[5].y = sbw->scrollbar.length - sbw->scrollbar.shadow_width - 1;
410 
411 	// horizontal arrows require that x and y coordinates be swapped
412 	if (sbw->scrollbar.orientation == XtorientHorizontal)
413 	{
414 	    int n;
415 	    int swap;
416 	    for (n = 0; n < 6; n++)
417 	    {
418 		swap = point[n].x;
419 		point[n].x = point[n].y;
420 		point[n].y = swap;
421 	    }
422 	}
423 	// draw the up/left arrow
424 	XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
425 		sbw->scrollbar.gc,
426 		point, 3,
427 		Convex, CoordModeOrigin);
428 	XDrawLines (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
429 		sbw->scrollbar.bot_shadow_GC,
430 		point, 3,
431 		CoordModeOrigin);
432 	XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
433 		sbw->scrollbar.top_shadow_GC,
434 		point[0].x, point[0].y,
435 		point[2].x, point[2].y);
436 	// draw the down/right arrow
437 	XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
438 		sbw->scrollbar.gc,
439 		point+3, 3,
440 		Convex, CoordModeOrigin);
441 	XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
442 		sbw->scrollbar.top_shadow_GC,
443 		point[3].x, point[3].y,
444 		point[4].x, point[4].y);
445 	XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
446 		sbw->scrollbar.top_shadow_GC,
447 		point[3].x, point[3].y,
448 		point[5].x, point[5].y);
449 	XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
450 		sbw->scrollbar.bot_shadow_GC,
451 		point[4].x, point[4].y,
452 		point[5].x, point[5].y);
453     }
454 }
455 
456     static void
Destroy(Widget w)457 Destroy(Widget w)
458 {
459     ScrollbarWidget sbw = (ScrollbarWidget) w;
460     if (sbw->scrollbar.timer_id != (XtIntervalId) 0)
461 	XtRemoveTimeOut (sbw->scrollbar.timer_id);
462     XtReleaseGC(w, sbw->scrollbar.gc);
463     XtReleaseGC(w, sbw->scrollbar.top_shadow_GC);
464     XtReleaseGC(w, sbw->scrollbar.bot_shadow_GC);
465 }
466 
467     static void
CreateGC(Widget w)468 CreateGC(Widget w)
469 {
470     ScrollbarWidget	sbw = (ScrollbarWidget) w;
471     XGCValues		gcValues;
472     XtGCMask		mask;
473     unsigned int	depth = 1;
474 
475     if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
476     {
477 	sbw->scrollbar.thumb = XmuCreateStippledPixmap (XtScreen(w),
478 		    (Pixel) 1, (Pixel) 0, depth);
479     }
480     else if (sbw->scrollbar.thumb != None)
481     {
482 	Window		root;
483 	int		x, y;
484 	unsigned int	width, height, bw;
485 
486 	if (XGetGeometry (XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
487 		&width, &height, &bw, &depth) == 0)
488 	    emsg(_("Scrollbar Widget: Could not get geometry of thumb pixmap."));
489     }
490 
491     gcValues.foreground = sbw->scrollbar.foreground;
492     gcValues.background = sbw->core.background_pixel;
493     mask = GCForeground | GCBackground;
494 
495     if (sbw->scrollbar.thumb != None)
496     {
497 	gcValues.fill_style = FillSolid;
498 	mask |= GCFillStyle;
499     }
500     // the creation should be non-caching, because
501     // we now set and clear clip masks on the gc returned
502     sbw->scrollbar.gc = XtGetGC (w, mask, &gcValues);
503 }
504 
505     static void
SetDimensions(ScrollbarWidget sbw)506 SetDimensions(ScrollbarWidget sbw)
507 {
508     if (sbw->scrollbar.orientation == XtorientVertical)
509     {
510 	sbw->scrollbar.length = sbw->core.height;
511 	sbw->scrollbar.thickness = sbw->core.width;
512     }
513     else
514     {
515 	sbw->scrollbar.length = sbw->core.width;
516 	sbw->scrollbar.thickness = sbw->core.height;
517     }
518 }
519 
520     static void
Initialize(Widget request UNUSED,Widget new,ArgList args UNUSED,Cardinal * num_args UNUSED)521 Initialize(
522     Widget	request UNUSED,	// what the client asked for
523     Widget	new,		// what we're going to give him
524     ArgList	args UNUSED,
525     Cardinal	*num_args UNUSED)
526 {
527     ScrollbarWidget sbw = (ScrollbarWidget) new;
528 
529     CreateGC(new);
530     AllocTopShadowGC(new);
531     AllocBotShadowGC(new);
532 
533     if (sbw->core.width == 0)
534 	sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical)
535 	    ? sbw->scrollbar.thickness : sbw->scrollbar.length;
536 
537     if (sbw->core.height == 0)
538 	sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal)
539 	    ? sbw->scrollbar.thickness : sbw->scrollbar.length;
540 
541     SetDimensions(sbw);
542     sbw->scrollbar.scroll_mode = SMODE_NONE;
543     sbw->scrollbar.timer_id = (XtIntervalId)0;
544     sbw->scrollbar.topLoc = 0;
545     sbw->scrollbar.shownLength = sbw->scrollbar.min_thumb;
546 }
547 
548     static void
Realize(Widget w,Mask * valueMask,XSetWindowAttributes * attributes)549 Realize(
550     Widget w,
551     Mask *valueMask,
552     XSetWindowAttributes *attributes)
553 {
554     // The Simple widget actually stuffs the value in the valuemask.
555     (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize)
556 	(w, valueMask, attributes);
557 }
558 
559     static Boolean
SetValues(Widget current,Widget request UNUSED,Widget desired,ArgList args UNUSED,Cardinal * num_args UNUSED)560 SetValues(
561     Widget  current,	    // what I am
562     Widget  request UNUSED, // what he wants me to be
563     Widget  desired,	    // what I will become
564     ArgList args UNUSED,
565     Cardinal *num_args UNUSED)
566 {
567     ScrollbarWidget	sbw = (ScrollbarWidget) current;
568     ScrollbarWidget	dsbw = (ScrollbarWidget) desired;
569     Boolean		redraw = FALSE;
570 
571 /*
572  * If these values are outside the acceptable range ignore them...
573  */
574     if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0)
575 	dsbw->scrollbar.top = sbw->scrollbar.top;
576 
577     if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0)
578 	dsbw->scrollbar.shown = sbw->scrollbar.shown;
579 
580 /*
581  * Change colors and stuff...
582  */
583     if (XtIsRealized(desired))
584     {
585 	if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground ||
586 		sbw->core.background_pixel != dsbw->core.background_pixel ||
587 		sbw->scrollbar.thumb != dsbw->scrollbar.thumb)
588 	{
589 	    XtReleaseGC(desired, sbw->scrollbar.gc);
590 	    CreateGC (desired);
591 	    redraw = TRUE;
592 	}
593 	if (sbw->scrollbar.top != dsbw->scrollbar.top ||
594 		sbw->scrollbar.shown != dsbw->scrollbar.shown)
595 	    redraw = TRUE;
596     }
597     return redraw;
598 }
599 
600     static void
Resize(Widget w)601 Resize(Widget w)
602 {
603     // ForgetGravity has taken care of background, but thumb may
604     // have to move as a result of the new size.
605     SetDimensions ((ScrollbarWidget) w);
606     Redisplay(w, (XEvent*) NULL, (Region)NULL);
607 }
608 
609 
610     static void
Redisplay(Widget w,XEvent * event,Region region)611 Redisplay(Widget w, XEvent *event, Region region)
612 {
613     ScrollbarWidget sbw = (ScrollbarWidget) w;
614     int x, y;
615     unsigned int width, height;
616 
617     _Xaw3dDrawShadows(w, event, region, FALSE);
618 
619     if (sbw->scrollbar.orientation == XtorientHorizontal)
620     {
621 	x = sbw->scrollbar.topLoc;
622 	y = 1;
623 	width = sbw->scrollbar.shownLength;
624 	height = sbw->core.height - 2;
625     }
626     else
627     {
628 	x = 1;
629 	y = sbw->scrollbar.topLoc;
630 	width = sbw->core.width - 2;
631 	height = sbw->scrollbar.shownLength;
632     }
633     if (region == NULL ||
634 	    XRectInRegion (region, x, y, width, height) != RectangleOut)
635     {
636 	// Forces entire thumb to be painted.
637 	sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1);
638 	PaintThumb (sbw);
639     }
640     // we'd like to be region aware here!!!!
641     PaintArrows(sbw);
642 }
643 
644 
645     static Boolean
CompareEvents(XEvent * oldEvent,XEvent * newEvent)646 CompareEvents(XEvent *oldEvent, XEvent *newEvent)
647 {
648 #define Check(field) \
649     do { \
650 	if (newEvent->field != oldEvent->field) \
651 	    return False; \
652     } while (0)
653 
654     Check(xany.display);
655     Check(xany.type);
656     Check(xany.window);
657 
658     switch (newEvent->type)
659     {
660 	case MotionNotify:
661 	    Check(xmotion.state);
662 	    break;
663 	case ButtonPress:
664 	case ButtonRelease:
665 	    Check(xbutton.state);
666 	    Check(xbutton.button);
667 	    break;
668 	case KeyPress:
669 	case KeyRelease:
670 	    Check(xkey.state);
671 	    Check(xkey.keycode);
672 	    break;
673 	case EnterNotify:
674 	case LeaveNotify:
675 	    Check(xcrossing.mode);
676 	    Check(xcrossing.detail);
677 	    Check(xcrossing.state);
678 	    break;
679     }
680 #undef Check
681 
682     return True;
683 }
684 
685 struct EventData
686 {
687     XEvent *oldEvent;
688     int count;
689 };
690 
691     static Bool
PeekNotifyEvent(Display * dpy,XEvent * event,char * args)692 PeekNotifyEvent(Display *dpy, XEvent *event, char *args)
693 {
694     struct EventData *eventData = (struct EventData*)args;
695 
696     return ((++eventData->count == QLength(dpy)) // since PeekIf blocks
697 	|| CompareEvents(event, eventData->oldEvent));
698 }
699 
700 
701     static Boolean
LookAhead(Widget w,XEvent * event)702 LookAhead(Widget w, XEvent *event)
703 {
704     XEvent newEvent;
705     struct EventData eventData;
706 
707     if (QLength (XtDisplay (w)) == 0)
708 	return False;
709 
710     eventData.count = 0;
711     eventData.oldEvent = event;
712 
713     XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
714 
715     return CompareEvents (event, &newEvent);
716 }
717 
718 
719     static void
ExtractPosition(XEvent * event,Position * x,Position * y,unsigned int * state)720 ExtractPosition(
721     XEvent	    *event,
722     Position	    *x,		// RETURN
723     Position	    *y,		// RETURN
724     unsigned int    *state)	// RETURN
725 {
726     switch (event->type)
727     {
728 	case MotionNotify:
729 	    *x = event->xmotion.x;
730 	    *y = event->xmotion.y;
731 	    if (state != NULL)
732 		*state = event->xmotion.state;
733 	    break;
734 	case ButtonPress:
735 	case ButtonRelease:
736 	    *x = event->xbutton.x;
737 	    *y = event->xbutton.y;
738 	    if (state != NULL)
739 		*state = event->xbutton.state;
740 	    break;
741 	case KeyPress:
742 	case KeyRelease:
743 	    *x = event->xkey.x;
744 	    *y = event->xkey.y;
745 	    if (state != NULL)
746 		*state = event->xkey.state;
747 	    break;
748 	case EnterNotify:
749 	case LeaveNotify:
750 	    *x = event->xcrossing.x;
751 	    *y = event->xcrossing.y;
752 	    if (state != NULL)
753 		*state = event->xcrossing.state;
754 	    break;
755 	default:
756 	    *x = 0; *y = 0;
757 	    if (state != NULL)
758 		*state = 0;
759     }
760 }
761 
762     static void
HandleThumb(Widget w,XEvent * event,String * params,Cardinal * num_params)763 HandleThumb(
764     Widget w,
765     XEvent *event,
766     String *params,
767     Cardinal *num_params)
768 {
769     Position x, y, loc;
770     ScrollbarWidget sbw = (ScrollbarWidget) w;
771 
772     ExtractPosition(event, &x, &y, (unsigned int *)NULL);
773     loc = PICKLENGTH(sbw, x, y);
774     // if the motion event puts the pointer in thumb, call Move and Notify
775     // also call Move and Notify if we're already in continuous scroll mode
776     if (sbw->scrollbar.scroll_mode == SMODE_CONT ||
777 	    (loc >= sbw->scrollbar.topLoc &&
778 	     loc <= sbw->scrollbar.topLoc + (int)sbw->scrollbar.shownLength))
779     {
780 	XtCallActionProc(w, "MoveThumb", event, params, *num_params);
781 	XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
782     }
783 }
784 
785     static void
RepeatNotify(XtPointer client_data,XtIntervalId * idp UNUSED)786 RepeatNotify(XtPointer client_data, XtIntervalId *idp UNUSED)
787 {
788     ScrollbarWidget sbw = (ScrollbarWidget) client_data;
789     int		    call_data;
790     char	    mode = sbw->scrollbar.scroll_mode;
791     unsigned long   rep;
792 
793     if (mode == SMODE_NONE || mode == SMODE_CONT)
794     {
795 	sbw->scrollbar.timer_id = (XtIntervalId)0;
796 	return;
797     }
798 
799     if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP)
800     {
801 	call_data = ONE_LINE_DATA;
802 	rep = LINE_REPEAT;
803     }
804     else
805     {
806 	call_data = ONE_PAGE_DATA;
807 	rep = PAGE_REPEAT;
808     }
809 
810     if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP)
811 	call_data = -call_data;
812 
813     XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)(long_u)call_data);
814 
815     sbw->scrollbar.timer_id =
816 	XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw),
817 		rep,
818 		RepeatNotify,
819 		client_data);
820 }
821 
822 /*
823  * Same as above, but for floating numbers.
824  */
825     static float
FloatInRange(float num,float small,float big)826 FloatInRange(float num, float small, float big)
827 {
828     return (num < small) ? small : ((num > big) ? big : num);
829 }
830 
831     static void
ScrollOneLineUp(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)832 ScrollOneLineUp(
833     Widget	w,
834     XEvent	*event,
835     String	*params UNUSED,
836     Cardinal	*num_params UNUSED)
837 {
838     ScrollSome(w, event, -ONE_LINE_DATA);
839 }
840 
841     static void
ScrollOneLineDown(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)842 ScrollOneLineDown(
843     Widget	w,
844     XEvent	*event,
845     String	*params UNUSED,
846     Cardinal	*num_params UNUSED)
847 {
848     ScrollSome(w, event, ONE_LINE_DATA);
849 }
850 
851     static void
ScrollPageDown(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)852 ScrollPageDown(
853     Widget	w,
854     XEvent	*event,
855     String	*params UNUSED,
856     Cardinal	*num_params UNUSED)
857 {
858     ScrollSome(w, event, ONE_PAGE_DATA);
859 }
860 
861     static void
ScrollPageUp(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)862 ScrollPageUp(
863     Widget	w,
864     XEvent	*event,
865     String	*params UNUSED,
866     Cardinal	*num_params UNUSED)
867 {
868     ScrollSome(w, event, -ONE_PAGE_DATA);
869 }
870 
871     static void
ScrollSome(Widget w,XEvent * event,int call_data)872 ScrollSome(
873     Widget	w,
874     XEvent	*event,
875     int		call_data)
876 {
877     ScrollbarWidget	sbw = (ScrollbarWidget) w;
878 
879     if (sbw->scrollbar.scroll_mode == SMODE_CONT)   // if scroll continuous
880 	return;
881 
882     if (LookAhead(w, event))
883 	return;
884 
885     sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
886     XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
887 }
888 
889     static void
NotifyScroll(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)890 NotifyScroll(
891     Widget	w,
892     XEvent	*event,
893     String	*params UNUSED,
894     Cardinal	*num_params UNUSED)
895 {
896     ScrollbarWidget sbw = (ScrollbarWidget) w;
897     Position	    x, y, loc;
898     Dimension	    arrow_size;
899     unsigned long   delay = 0;
900     int		    call_data = 0;
901     unsigned int    state;
902 
903     if (sbw->scrollbar.scroll_mode == SMODE_CONT)   // if scroll continuous
904 	return;
905 
906     if (LookAhead (w, event))
907 	return;
908 
909     ExtractPosition(event, &x, &y, &state);
910     loc = PICKLENGTH(sbw, x, y);
911 
912     if ((int)sbw->scrollbar.thickness * 2 > (int)sbw->scrollbar.length)
913 	arrow_size = sbw->scrollbar.length / 2;
914     else
915 	arrow_size = sbw->scrollbar.thickness;
916 
917     /*
918      * handle CTRL modifier
919      */
920     if (state & ControlMask)
921     {
922 	if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
923 	    call_data = END_PAGE_DATA;
924 	else
925 	    call_data = -END_PAGE_DATA;
926 	sbw->scrollbar.scroll_mode = SMODE_NONE;
927     }
928     /*
929      * handle first arrow zone
930      */
931     else if (loc < (Position)arrow_size)
932     {
933 	call_data = -ONE_LINE_DATA;
934 	sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
935 	delay = LINE_DELAY;
936     }
937 
938     /*
939      * handle last arrow zone
940      */
941     else if (loc > (Position)(sbw->scrollbar.length - arrow_size))
942     {
943 	call_data = ONE_LINE_DATA;
944 	sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN;
945 	delay = LINE_DELAY;
946     }
947 
948     /*
949      * handle zone "above" the thumb
950      */
951     else if (loc < sbw->scrollbar.topLoc)
952     {
953 	call_data = -ONE_PAGE_DATA;
954 	sbw->scrollbar.scroll_mode = SMODE_PAGE_UP;
955 	delay = PAGE_DELAY;
956     }
957 
958     /*
959      * handle zone "below" the thumb
960      */
961     else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
962     {
963 	call_data = ONE_PAGE_DATA;
964 	sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN;
965 	delay = PAGE_DELAY;
966     }
967 
968     if (call_data)
969 	XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
970 
971     // establish autoscroll
972     if (delay)
973 	sbw->scrollbar.timer_id =
974 	    XtAppAddTimeOut(XtWidgetToApplicationContext(w),
975 					   delay, RepeatNotify, (XtPointer)w);
976 }
977 
978     static void
EndScroll(Widget w,XEvent * event UNUSED,String * params UNUSED,Cardinal * num_params UNUSED)979 EndScroll(
980     Widget w,
981     XEvent *event UNUSED,
982     String *params UNUSED,
983     Cardinal *num_params UNUSED)
984 {
985     ScrollbarWidget sbw = (ScrollbarWidget) w;
986 
987     sbw->scrollbar.scroll_mode = SMODE_NONE;
988     // no need to remove any autoscroll timeout; it will no-op
989     // because the scroll_mode is SMODE_NONE
990     // but be sure to remove timeout in destroy proc
991 }
992 
993     static float
FractionLoc(ScrollbarWidget sbw,int x,int y)994 FractionLoc(ScrollbarWidget sbw, int x, int y)
995 {
996     int	    margin;
997     float   height, width;
998 
999     margin = MARGIN(sbw);
1000     x -= margin;
1001     y -= margin;
1002     height = (float)sbw->core.height - 2 * margin;
1003     width = (float)sbw->core.width - 2 * margin;
1004     return PICKLENGTH(sbw, x / width, y / height);
1005 }
1006 
1007     static void
MoveThumb(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)1008 MoveThumb(
1009     Widget	w,
1010     XEvent	*event,
1011     String	*params UNUSED,
1012     Cardinal	*num_params UNUSED)
1013 {
1014     ScrollbarWidget	sbw = (ScrollbarWidget)w;
1015     Position		x, y;
1016     float		top;
1017     char		old_mode = sbw->scrollbar.scroll_mode;
1018 
1019     sbw->scrollbar.scroll_mode = SMODE_CONT; // indicate continuous scroll
1020 
1021     if (LookAhead(w, event))
1022 	return;
1023 
1024     if (!event->xmotion.same_screen)
1025 	return;
1026 
1027     ExtractPosition(event, &x, &y, (unsigned int *)NULL);
1028 
1029     top = FractionLoc(sbw, x, y);
1030 
1031     if (old_mode != SMODE_CONT)		    // start dragging: set offset
1032     {
1033 	if (event->xbutton.button == Button2)
1034 	    sbw->scrollbar.scroll_off = sbw->scrollbar.shown / 2.;
1035 	else
1036 	    sbw->scrollbar.scroll_off = top - sbw->scrollbar.top;
1037     }
1038 
1039     top -= sbw->scrollbar.scroll_off;
1040     if (sbw->scrollbar.limit_thumb)
1041 	top = FloatInRange(top, 0.0,
1042 			sbw->scrollbar.max - sbw->scrollbar.shown + 0.000001);
1043     else
1044 	top = FloatInRange(top, 0.0, sbw->scrollbar.max);
1045 
1046     sbw->scrollbar.top = top;
1047     PaintThumb(sbw);
1048     XFlush(XtDisplay(w));   // re-draw it before Notifying
1049 }
1050 
1051 
1052     static void
NotifyThumb(Widget w,XEvent * event,String * params UNUSED,Cardinal * num_params UNUSED)1053 NotifyThumb(
1054     Widget	w,
1055     XEvent	*event,
1056     String	*params UNUSED,
1057     Cardinal	*num_params UNUSED)
1058 {
1059     ScrollbarWidget sbw = (ScrollbarWidget)w;
1060     // Use a union to avoid a warning for the weird conversion from float to
1061     // XtPointer.  Comes from Xaw/Scrollbar.c.
1062     union {
1063 	XtPointer xtp;
1064 	float xtf;
1065     } xtpf;
1066 
1067     if (LookAhead(w, event))
1068 	return;
1069 
1070     // thumbProc is not pretty, but is necessary for backwards
1071     // compatibility on those architectures for which it work{s,ed};
1072     // the intent is to pass a (truncated) float by value.
1073     xtpf.xtf = sbw->scrollbar.top;
1074     XtCallCallbacks(w, XtNthumbProc, xtpf.xtp);
1075     XtCallCallbacks(w, XtNjumpProc, (XtPointer)&sbw->scrollbar.top);
1076 }
1077 
1078     static void
AllocTopShadowGC(Widget w)1079 AllocTopShadowGC(Widget w)
1080 {
1081     ScrollbarWidget sbw = (ScrollbarWidget) w;
1082     XtGCMask	    valuemask;
1083     XGCValues	    myXGCV;
1084 
1085     valuemask = GCForeground;
1086     myXGCV.foreground = sbw->scrollbar.top_shadow_pixel;
1087     sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1088 }
1089 
1090     static void
AllocBotShadowGC(Widget w)1091 AllocBotShadowGC(Widget w)
1092 {
1093     ScrollbarWidget sbw = (ScrollbarWidget) w;
1094     XtGCMask	    valuemask;
1095     XGCValues	    myXGCV;
1096 
1097     valuemask = GCForeground;
1098     myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel;
1099     sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
1100 }
1101 
1102     static void
_Xaw3dDrawShadows(Widget gw,XEvent * event UNUSED,Region region,int out)1103 _Xaw3dDrawShadows(
1104     Widget  gw,
1105     XEvent  *event UNUSED,
1106     Region  region,
1107     int	    out)
1108 {
1109     XPoint  pt[6];
1110     ScrollbarWidget sbw = (ScrollbarWidget) gw;
1111     Dimension	s = sbw->scrollbar.shadow_width;
1112     /*
1113      * draw the shadows using the core part width and height,
1114      * and the scrollbar part shadow_width.
1115      *
1116      *	no point to do anything if the shadow_width is 0 or the
1117      *	widget has not been realized.
1118      */
1119     if (s > 0 && XtIsRealized(gw))
1120     {
1121 	Dimension   h = sbw->core.height;
1122 	Dimension   w = sbw->core.width;
1123 	Dimension   wms = w - s;
1124 	Dimension   hms = h - s;
1125 	Display	    *dpy = XtDisplay (gw);
1126 	Window	    win = XtWindow (gw);
1127 	GC	top, bot;
1128 
1129 	if (out)
1130 	{
1131 	    top = sbw->scrollbar.top_shadow_GC;
1132 	    bot = sbw->scrollbar.bot_shadow_GC;
1133 	}
1134 	else
1135 	{
1136 	    top = sbw->scrollbar.bot_shadow_GC;
1137 	    bot = sbw->scrollbar.top_shadow_GC;
1138 	}
1139 
1140 	// top-left shadow
1141 	if ((region == NULL) ||
1142 		(XRectInRegion (region, 0, 0, w, s) != RectangleOut) ||
1143 		(XRectInRegion (region, 0, 0, s, h) != RectangleOut))
1144 	{
1145 	    pt[0].x = 0;    pt[0].y = h;
1146 	    pt[1].x =	    pt[1].y = 0;
1147 	    pt[2].x = w;    pt[2].y = 0;
1148 	    pt[3].x = wms;  pt[3].y = s;
1149 	    pt[4].x =	    pt[4].y = s;
1150 	    pt[5].x = s;    pt[5].y = hms;
1151 	    XFillPolygon (dpy, win, top, pt, 6, Complex, CoordModeOrigin);
1152 	}
1153 
1154 	// bottom-right shadow
1155 	if ((region == NULL) ||
1156 		(XRectInRegion (region, 0, hms, w, s) != RectangleOut) ||
1157 		(XRectInRegion (region, wms, 0, s, h) != RectangleOut))
1158 	{
1159 	    pt[0].x = 0;    pt[0].y = h;
1160 	    pt[1].x = w;    pt[1].y = h;
1161 	    pt[2].x = w;    pt[2].y = 0;
1162 	    pt[3].x = wms;  pt[3].y = s;
1163 	    pt[4].x = wms;  pt[4].y = hms;
1164 	    pt[5].x = s;    pt[5].y = hms;
1165 	    XFillPolygon (dpy, win, bot, pt, 6, Complex, CoordModeOrigin);
1166 	}
1167     }
1168 }
1169 
1170 
1171 /*
1172  * Set the scroll bar to the given location.
1173  */
1174     void
vim_XawScrollbarSetThumb(Widget w,double top,double shown,double max)1175 vim_XawScrollbarSetThumb(Widget w, double top, double shown, double max)
1176 {
1177     ScrollbarWidget sbw = (ScrollbarWidget) w;
1178 
1179     if (sbw->scrollbar.scroll_mode == SMODE_CONT) // if still thumbing
1180 	return;
1181 
1182     sbw->scrollbar.max = (max > 1.0) ? 1.0 :
1183 		(max >= 0.0) ? max : sbw->scrollbar.max;
1184 
1185     sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max :
1186 		(top >= 0.0) ? top : sbw->scrollbar.top;
1187 
1188     sbw->scrollbar.shown = (shown > 1.0) ? 1.0 :
1189 		(shown >= 0.0) ? shown : sbw->scrollbar.shown;
1190 
1191     PaintThumb(sbw);
1192 }
1193