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