upload tizen2.0 source
[framework/uifw/xorg/lib/libxaw.git] / src / Scrollbar.c
1 /***********************************************************
2
3 Copyright 1987, 1988, 1994, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
37
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
45
46 ******************************************************************/
47
48 #ifdef HAVE_CONFIG_H
49 #include <config.h>
50 #endif
51 #include <X11/IntrinsicP.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Xmu/Drawing.h>
54 #include <X11/Xaw/ScrollbarP.h>
55 #include <X11/Xaw/XawInit.h>
56 #include "Private.h"
57
58 #define NoButton        -1
59 #define PICKLENGTH(widget, x, y)                                        \
60 (((widget)->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
61
62 /*
63  * Class Methods
64  */
65 static void XawScrollbarClassInitialize(void);
66 static void XawScrollbarDestroy(Widget);
67 static void XawScrollbarInitialize(Widget, Widget, ArgList, Cardinal*_args);
68 static void XawScrollbarRealize(Widget, Mask*, XSetWindowAttributes*);
69 static void XawScrollbarRedisplay(Widget, XEvent*, Region);
70 static void XawScrollbarResize(Widget);
71 static Boolean XawScrollbarSetValues(Widget, Widget, Widget,
72                                      ArgList, Cardinal*);
73
74 /*
75  * Prototypes
76  */
77 static Boolean CompareEvents(XEvent*, XEvent*);
78 static void CreateGC(Widget);
79 static float FloatInRange(float, float, float);
80 static float FractionLoc(ScrollbarWidget, int, int);
81 static void ExtractPosition(XEvent*, Position*, Position*);
82 static int InRange(int, int, int);
83 static void FillArea(ScrollbarWidget, int, int, int);
84 static Bool LookAhead(Widget, XEvent*);
85 static void PaintThumb(ScrollbarWidget);
86 static Bool PeekNotifyEvent(Display*, XEvent*, char*);
87 static void SetDimensions(ScrollbarWidget);
88
89 /*
90  * Actions
91  */
92 static void EndScroll(Widget, XEvent*, String*, Cardinal*);
93 static void MoveThumb(Widget, XEvent*, String*, Cardinal*);
94 static void NotifyScroll(Widget, XEvent*, String*, Cardinal*);
95 static void NotifyThumb(Widget, XEvent*, String*, Cardinal*);
96 static void StartScroll(Widget, XEvent*, String*, Cardinal*);
97
98 /*
99  * Initialization
100  */
101 static char defaultTranslations[] =
102 "<Btn1Down>:"   "StartScroll(Forward)\n"
103 "<Btn2Down>:"   "StartScroll(Continuous) MoveThumb() NotifyThumb()\n"
104 "<Btn3Down>:"   "StartScroll(Backward)\n"
105 "<Btn2Motion>:" "MoveThumb() NotifyThumb()\n"
106 "<BtnUp>:"      "NotifyScroll(Proportional) EndScroll()\n";
107
108 static float floatZero = 0.0;
109
110 #define Offset(field) XtOffsetOf(ScrollbarRec, field)
111
112 static XtResource resources[] = {
113   {
114     XtNlength,
115     XtCLength,
116     XtRDimension,
117     sizeof(Dimension),
118     Offset(scrollbar.length),
119     XtRImmediate,
120     (XtPointer)1
121   },
122   {
123     XtNthickness,
124     XtCThickness,
125     XtRDimension,
126     sizeof(Dimension),
127     Offset(scrollbar.thickness),
128     XtRImmediate,
129     (XtPointer)14
130   },
131   {
132     XtNorientation,
133     XtCOrientation,
134     XtROrientation,
135     sizeof(XtOrientation),
136     Offset(scrollbar.orientation),
137     XtRImmediate,
138     (XtPointer)XtorientVertical
139   },
140   {
141     XtNscrollProc,
142     XtCCallback,
143     XtRCallback,
144     sizeof(XtPointer),
145     Offset(scrollbar.scrollProc),
146     XtRCallback,
147     NULL
148   },
149   {
150     XtNthumbProc,
151     XtCCallback,
152     XtRCallback,
153     sizeof(XtPointer),
154     Offset(scrollbar.thumbProc),
155     XtRCallback,
156     NULL
157   },
158   {
159     XtNjumpProc,
160     XtCCallback,
161     XtRCallback,
162     sizeof(XtPointer),
163     Offset(scrollbar.jumpProc),
164     XtRCallback,
165     NULL
166   },
167   {
168     XtNthumb,
169     XtCThumb,
170     XtRBitmap,
171     sizeof(Pixmap),
172     Offset(scrollbar.thumb),
173     XtRImmediate,
174     (XtPointer)XtUnspecifiedPixmap
175   },
176   {
177     XtNforeground,
178     XtCForeground,
179     XtRPixel,
180     sizeof(Pixel),
181     Offset(scrollbar.foreground),
182     XtRString,
183     XtDefaultForeground
184   },
185   {
186     XtNshown,
187     XtCShown,
188     XtRFloat,
189     sizeof(float),
190     Offset(scrollbar.shown),
191     XtRFloat,
192     (XtPointer)&floatZero
193   },
194   {
195     XtNtopOfThumb,
196     XtCTopOfThumb,
197     XtRFloat,
198     sizeof(float),
199     Offset(scrollbar.top),
200     XtRFloat,
201     (XtPointer)&floatZero
202   },
203   {
204     XtNscrollVCursor,
205     XtCCursor,
206     XtRCursor,
207     sizeof(Cursor),
208     Offset(scrollbar.verCursor),
209     XtRString,
210     "sb_v_double_arrow"
211   },
212   {
213     XtNscrollHCursor,
214     XtCCursor,
215     XtRCursor,
216     sizeof(Cursor),
217     Offset(scrollbar.horCursor),
218     XtRString,
219     "sb_h_double_arrow"
220   },
221   {
222     XtNscrollUCursor,
223     XtCCursor,
224     XtRCursor,
225     sizeof(Cursor),
226     Offset(scrollbar.upCursor),
227     XtRString,
228     "sb_up_arrow"
229   },
230   {
231     XtNscrollDCursor,
232     XtCCursor,
233     XtRCursor,
234     sizeof(Cursor),
235     Offset(scrollbar.downCursor),
236     XtRString,
237     "sb_down_arrow"
238   },
239   {
240     XtNscrollLCursor,
241     XtCCursor,
242     XtRCursor,
243     sizeof(Cursor),
244     Offset(scrollbar.leftCursor),
245     XtRString,
246     "sb_left_arrow"
247   },
248   {
249     XtNscrollRCursor,
250     XtCCursor,
251     XtRCursor,
252     sizeof(Cursor),
253     Offset(scrollbar.rightCursor),
254     XtRString,
255     "sb_right_arrow"
256   },
257   {
258     XtNminimumThumb,
259     XtCMinimumThumb,
260     XtRDimension,
261     sizeof(Dimension),
262     Offset(scrollbar.min_thumb),
263     XtRImmediate,
264     (XtPointer)7
265   },
266 };
267 #undef Offset
268
269 static XtActionsRec actions[] = {
270         {"StartScroll",         StartScroll},
271         {"MoveThumb",           MoveThumb},
272         {"NotifyThumb",         NotifyThumb},
273         {"NotifyScroll",        NotifyScroll},
274         {"EndScroll",           EndScroll},
275 };
276
277 #define Superclass (&simpleClassRec)
278 ScrollbarClassRec scrollbarClassRec = {
279   /* core */
280   {
281     (WidgetClass)&simpleClassRec,       /* superclass */
282     "Scrollbar",                        /* class_name */
283     sizeof(ScrollbarRec),               /* widget_size */
284     XawScrollbarClassInitialize,        /* class_initialize */
285     NULL,                               /* class_part_init */
286     False,                              /* class_inited */
287     XawScrollbarInitialize,             /* initialize */
288     NULL,                               /* initialize_hook */
289     XawScrollbarRealize,                /* realize */
290     actions,                            /* actions */
291     XtNumber(actions),                  /* num_actions */
292     resources,                          /* resources */
293     XtNumber(resources),                /* num_resources */
294     NULLQUARK,                          /* xrm_class */
295     True,                               /* compress_motion */
296     True,                               /* compress_exposure */
297     True,                               /* compress_enterleave */
298     False,                              /* visible_interest */
299     XawScrollbarDestroy,                /* destroy */
300     XawScrollbarResize,                 /* resize */
301     XawScrollbarRedisplay,              /* expose */
302     XawScrollbarSetValues,              /* set_values */
303     NULL,                               /* set_values_hook */
304     XtInheritSetValuesAlmost,           /* set_values_almost */
305     NULL,                               /* get_values_hook */
306     NULL,                               /* accept_focus */
307     XtVersion,                          /* version */
308     NULL,                               /* callback_private */
309     defaultTranslations,                /* tm_table */
310     XtInheritQueryGeometry,             /* query_geometry */
311     XtInheritDisplayAccelerator,        /* display_accelerator */
312     NULL,                               /* extension */
313   },
314   /* simple */
315   {
316     XtInheritChangeSensitive,           /* change_sensitive */
317   },
318   /* scrollbar */
319   {
320     NULL,                               /* extension */
321   },
322 };
323
324 WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec;
325
326 /*
327  * Implementation
328  */
329 static void
330 XawScrollbarClassInitialize(void)
331 {
332     XawInitializeWidgetSet();
333     XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
334                    NULL, 0);
335     XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString,
336                        NULL, 0, XtCacheNone, NULL);
337 }
338
339 /*
340  * Make sure the first number is within the range specified by the other
341  * two numbers.
342  */
343 static int
344 InRange(int num, int small, int big)
345 {
346     return ((num < small) ? small : ((num > big) ? big : num));
347 }
348
349 /*
350  * Same as above, but for floating numbers
351  */
352 static float
353 FloatInRange(float num, float small, float big)
354 {
355     return ((num < small) ? small : ((num > big) ? big : num));
356 }
357
358 /* Fill the area specified by top and bottom with the given pattern */
359 static float
360 FractionLoc(ScrollbarWidget w, int x, int y)
361 {
362     float   result;
363
364     result = PICKLENGTH(w, x / (float)XtWidth(w), y / (float)XtHeight(w));
365
366     return (FloatInRange(result, 0.0, 1.0));
367 }
368
369 static void
370 FillArea(ScrollbarWidget w, int top, int bottom, int thumb)
371 {
372     Dimension length;
373
374     top = XawMax(1, top);
375     if (w->scrollbar.orientation == XtorientHorizontal)
376     bottom = XawMin(bottom, XtWidth(w) - 1);
377     else
378     bottom = XawMin(bottom, XtHeight(w) - 1);
379
380     if (bottom <= top)
381         return;
382
383     length = bottom - top;
384
385     switch(thumb) {
386         /* Fill the new Thumb location */
387         case 1:
388             if (w->scrollbar.orientation == XtorientHorizontal)
389                 XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
390                                top, 1, length, XtHeight(w) - 2);
391             else
392                 XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
393                                1, top, XtWidth(w) - 2, length);
394             break;
395         /* Clear the old Thumb location */
396         case 0:
397             if (w->scrollbar.orientation == XtorientHorizontal)
398                 XClearArea(XtDisplay(w), XtWindow(w),
399                            top, 1, length, XtHeight(w) - 2, False);
400             else
401                 XClearArea(XtDisplay(w), XtWindow(w),
402                            1, top, XtWidth(w) - 2, length, False);
403             break;
404     }
405 }
406
407
408 /* Paint the thumb in the area specified by w->top and
409    w->shown.  The old area is erased.  The painting and
410    erasing is done cleverly so that no flickering will occur. */
411 static void
412 PaintThumb(ScrollbarWidget w)
413 {
414     Position oldtop, oldbot, newtop, newbot;
415
416     oldtop = w->scrollbar.topLoc;
417     oldbot = oldtop + w->scrollbar.shownLength;
418     newtop = w->scrollbar.length * w->scrollbar.top;
419     newbot = newtop + (int)(w->scrollbar.length * w->scrollbar.shown);
420     if (newbot < newtop + (int)w->scrollbar.min_thumb)
421         newbot = newtop + w->scrollbar.min_thumb;
422     w->scrollbar.topLoc = newtop;
423     w->scrollbar.shownLength = newbot - newtop;
424
425     if (XtIsRealized((Widget)w)) {
426         if (newtop < oldtop)
427             FillArea(w, newtop, XawMin(newbot, oldtop), 1);
428         if (newtop > oldtop)
429             FillArea(w, oldtop, XawMin(newtop, oldbot), 0);
430         if (newbot < oldbot)
431             FillArea(w, XawMax(newbot, oldtop), oldbot, 0);
432         if (newbot > oldbot)
433             FillArea(w, XawMax(newtop, oldbot), newbot, 1);
434     }
435 }
436
437 static void
438 SetDimensions(ScrollbarWidget w)
439 {
440     if (w->scrollbar.orientation == XtorientVertical) {
441         w->scrollbar.length = XtHeight(w);
442         w->scrollbar.thickness = XtWidth(w);
443     }
444     else {
445         w->scrollbar.length = XtWidth(w);
446         w->scrollbar.thickness = XtHeight(w);
447     }
448 }
449
450 static void
451 XawScrollbarDestroy(Widget w)
452 {
453     ScrollbarWidget sbw = (ScrollbarWidget)w;
454
455     XtReleaseGC(w, sbw->scrollbar.gc);
456 }
457
458 static void
459 CreateGC(Widget w)
460 {
461     ScrollbarWidget sbw = (ScrollbarWidget)w;
462     XGCValues gcValues;
463     XtGCMask mask;
464     unsigned int depth = 1;
465
466     if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
467         sbw->scrollbar.thumb = XmuCreateStippledPixmap(XtScreen(w),
468                                                        (Pixel)1, (Pixel)0,
469                                                        depth);
470     else if (sbw->scrollbar.thumb != None) {
471         Window root;
472         int x, y;
473         unsigned int width, height, bw;
474
475         XGetGeometry(XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
476                      &width, &height, &bw, &depth);
477     }
478
479     gcValues.foreground = sbw->scrollbar.foreground;
480     gcValues.background = sbw->core.background_pixel;
481     mask = GCForeground | GCBackground;
482
483     if (sbw->scrollbar.thumb != None) {
484         if (depth == 1) {
485             gcValues.fill_style = FillOpaqueStippled;
486             gcValues.stipple = sbw->scrollbar.thumb;
487             mask |= GCFillStyle | GCStipple;
488         }
489         else {
490             gcValues.fill_style = FillTiled;
491             gcValues.tile = sbw->scrollbar.thumb;
492             mask |= GCFillStyle | GCTile;
493         }
494     }
495     sbw->scrollbar.gc = XtGetGC(w, mask, &gcValues);
496 }
497
498 /* ARGSUSED */
499 static void
500 XawScrollbarInitialize(Widget request, Widget cnew,
501                        ArgList args, Cardinal *num_args)
502 {
503     ScrollbarWidget w = (ScrollbarWidget)cnew;
504
505     CreateGC(cnew);
506
507     if (XtWidth(w) == 0)
508         XtWidth(w) = w->scrollbar.orientation == XtorientVertical ?
509                         w->scrollbar.thickness : w->scrollbar.length;
510
511     if (XtHeight(w) == 0)
512         XtHeight(w) = w->scrollbar.orientation == XtorientHorizontal ?
513                         w->scrollbar.thickness : w->scrollbar.length;
514
515     SetDimensions(w);
516     w->scrollbar.direction = 0;
517     w->scrollbar.topLoc = 0;
518     w->scrollbar.shownLength = w->scrollbar.min_thumb;
519 }
520
521 static void
522 XawScrollbarRealize(Widget gw, Mask *valueMask,
523                     XSetWindowAttributes *attributes)
524 {
525     ScrollbarWidget w = (ScrollbarWidget)gw;
526
527     w->scrollbar.inactiveCursor = w->scrollbar.orientation == XtorientVertical ?
528                 w->scrollbar.verCursor : w->scrollbar.horCursor;
529
530     XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL);
531
532     /*
533      * The Simple widget actually stuffs the value in the valuemask
534      */
535     (*scrollbarWidgetClass->core_class.superclass->core_class.realize)
536         (gw, valueMask, attributes);
537 }
538
539 /*ARGSUSED*/
540 static Boolean
541 XawScrollbarSetValues(Widget current, Widget request, Widget desired,
542                       ArgList args, Cardinal *num_args)
543 {
544     ScrollbarWidget w = (ScrollbarWidget)current;
545     ScrollbarWidget dw = (ScrollbarWidget)desired;
546     Boolean redraw = False;
547
548     /*
549      * If these values are outside the acceptable range ignore them...
550      */
551     if (dw->scrollbar.top < 0.0 || dw->scrollbar.top > 1.0)
552         dw->scrollbar.top = w->scrollbar.top;
553
554     if (dw->scrollbar.shown < 0.0 || dw->scrollbar.shown > 1.0)
555         dw->scrollbar.shown = w->scrollbar.shown;
556
557     if (XtIsRealized (desired)) {
558         if (w->scrollbar.foreground != dw->scrollbar.foreground ||
559             w->core.background_pixel != dw->core.background_pixel ||
560             w->scrollbar.thumb != dw->scrollbar.thumb) {
561             XtReleaseGC((Widget)dw, w->scrollbar.gc);
562             CreateGC((Widget)dw);
563             redraw = True;
564         }
565         if (w->scrollbar.top != dw->scrollbar.top ||
566             w->scrollbar.shown != dw->scrollbar.shown)
567             redraw = True;
568     }
569
570     return (redraw);
571 }
572
573 static void
574 XawScrollbarResize(Widget gw)
575 {
576     /* ForgetGravity has taken care of background, but thumb may
577      * have to move as a result of the new size. */
578     SetDimensions((ScrollbarWidget)gw);
579     XawScrollbarRedisplay(gw, NULL, NULL);
580 }
581
582 /*ARGSUSED*/
583 static void
584 XawScrollbarRedisplay(Widget gw, XEvent *event, Region region)
585 {
586     ScrollbarWidget w = (ScrollbarWidget)gw;
587     int x, y;
588     unsigned int width, height;
589
590     if (Superclass->core_class.expose)
591         (*Superclass->core_class.expose)(gw, event, region);
592
593     if (w->scrollbar.orientation == XtorientHorizontal) {
594         x = w->scrollbar.topLoc;
595         y = 1;
596         width = w->scrollbar.shownLength;
597         height = XtHeight(w) - 2;
598     }
599     else {
600         x = 1;
601         y = w->scrollbar.topLoc;
602         width = XtWidth(w) - 2;
603         height = w->scrollbar.shownLength;
604     }
605
606     if (region == NULL ||
607         XRectInRegion(region, x, y, width, height) != RectangleOut) {
608         /* Forces entire thumb to be painted */
609         w->scrollbar.topLoc = -(w->scrollbar.length + 1);
610         PaintThumb(w);
611     }
612 }
613
614 /*ARGSUSED*/
615 static void
616 StartScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
617 {
618     ScrollbarWidget w = (ScrollbarWidget)gw;
619     Cursor cursor;
620     char direction;
621
622     if (w->scrollbar.direction != 0)    /* if we're already scrolling */
623         return;
624     if (*num_params > 0)
625         direction = *params[0];
626     else
627         direction = 'C';
628
629     w->scrollbar.direction = direction;
630
631     switch(direction) {
632         case 'B':
633         case 'b':
634             cursor = w->scrollbar.orientation == XtorientVertical ?
635                 w->scrollbar.downCursor : w->scrollbar.rightCursor;
636             break;
637         case 'F':
638         case 'f':
639             cursor = w->scrollbar.orientation == XtorientVertical ?
640                 w->scrollbar.upCursor : w->scrollbar.leftCursor;
641             break;
642         case 'C':
643         case 'c':
644              cursor = w->scrollbar.orientation == XtorientVertical ?
645                 w->scrollbar.rightCursor : w->scrollbar.upCursor;
646              break;
647         default:
648              return;    /* invalid invocation */
649     }
650
651     XtVaSetValues(gw, XtNcursor, cursor, NULL);
652
653     XFlush(XtDisplay(w));
654 }
655
656 static Boolean
657 CompareEvents(XEvent *oldEvent, XEvent *newEvent)
658 {
659 #define Check(field) if (newEvent->field != oldEvent->field) return (False)
660
661     Check(xany.display);
662     Check(xany.type);
663     Check(xany.window);
664
665     switch(newEvent->type) {
666         case MotionNotify:
667             Check(xmotion.state);
668             break;
669         case ButtonPress:
670         case ButtonRelease:
671             Check(xbutton.state);
672             Check(xbutton.button);
673             break;
674         case KeyPress:
675         case KeyRelease:
676             Check(xkey.state);
677             Check(xkey.keycode);
678             break;
679         case EnterNotify:
680         case LeaveNotify:
681             Check(xcrossing.mode);
682             Check(xcrossing.detail);
683             Check(xcrossing.state);
684             break;
685     }
686 #undef Check
687
688     return (True);
689 }
690
691 struct EventData {
692     XEvent *oldEvent;
693     int count;
694 };
695
696 static Bool
697 PeekNotifyEvent(Display *dpy, XEvent *event, char *args)
698 {
699     struct EventData *eventData = (struct EventData*)args;
700
701     return (++eventData->count == QLength(dpy)  /* since PeekIf blocks */
702             || CompareEvents(event, eventData->oldEvent));
703 }
704
705 static Bool
706 LookAhead(Widget w, XEvent *event)
707 {
708     XEvent newEvent;
709     struct EventData eventData;
710
711     if (QLength(XtDisplay(w)) == 0)
712         return (False);
713
714     eventData.count = 0;
715     eventData.oldEvent = event;
716
717     XPeekIfEvent(XtDisplay(w), &newEvent, PeekNotifyEvent, (char*)&eventData);
718
719     if (CompareEvents(event, &newEvent))
720         return (True);
721
722     return (False);
723 }
724
725 static void
726 ExtractPosition(XEvent *event, Position *x, Position *y)
727 {
728     switch(event->type) {
729         case MotionNotify:
730             *x = event->xmotion.x;
731             *y = event->xmotion.y;
732             break;
733         case ButtonPress:
734         case ButtonRelease:
735             *x = event->xbutton.x;
736             *y = event->xbutton.y;
737             break;
738         case KeyPress:
739         case KeyRelease:
740             *x = event->xkey.x;
741             *y = event->xkey.y;
742             break;
743         case EnterNotify:
744         case LeaveNotify:
745             *x = event->xcrossing.x;
746             *y = event->xcrossing.y;
747             break;
748         default:
749             *x = 0;
750             *y = 0;
751             break;
752     }
753 }
754
755 static void
756 NotifyScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
757 {
758     ScrollbarWidget w = (ScrollbarWidget)gw;
759     long call_data = 0;
760     char style;
761     Position x, y;
762
763     if (w->scrollbar.direction == 0)    /* if no StartScroll */
764         return;
765
766     if (LookAhead(gw, event))
767         return;
768
769     if (*num_params > 0)
770         style = *params[0];
771     else
772         style = 'P';
773
774     switch(style) {
775         case 'P':    /* Proportional */
776         case 'p':
777             ExtractPosition(event, &x, &y);
778             call_data = InRange(PICKLENGTH(w, x, y), 0, (int)w->scrollbar.length);
779             break;
780         case 'F':    /* FullLength */
781         case 'f':
782             call_data = w->scrollbar.length;
783             break;
784     }
785
786     switch(w->scrollbar.direction) {
787         case 'B':
788         case 'b':
789             call_data = -call_data;
790             /*FALLTHROUGH*/
791         case 'F':
792         case 'f':
793             XtCallCallbacks(gw, XtNscrollProc, (XtPointer)call_data);
794             break;
795         case 'C':
796         case 'c':    /* NotifyThumb has already called the thumbProc(s) */
797             break;
798     }
799 }
800
801 /*ARGSUSED*/
802 static void
803 EndScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
804 {
805     ScrollbarWidget w = (ScrollbarWidget)gw;
806
807     XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL);
808     XFlush(XtDisplay(w));               /* make sure it get propogated */
809
810     w->scrollbar.direction = 0;
811 }
812
813 /*ARGSUSED*/
814 static void
815 MoveThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params)
816 {
817     ScrollbarWidget w = (ScrollbarWidget)gw;
818     Position x, y;
819
820     if (w->scrollbar.direction == 0)    /* if no StartScroll */
821         return;
822
823     if (LookAhead(gw, event))
824         return;
825
826     if (!event->xmotion.same_screen)
827         return;
828
829     ExtractPosition(event, &x, &y);
830     w->scrollbar.top = FractionLoc(w, x, y);
831 }
832
833 /*ARGSUSED*/
834 static void
835 NotifyThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params)
836 {
837     ScrollbarWidget w = (ScrollbarWidget)gw;
838     union {
839         XtPointer xtp;
840         float xtf;
841     } xtpf;
842
843     if (w->scrollbar.direction == 0)    /* if no StartScroll */
844         return;
845
846     if (LookAhead(gw, event))
847         return;
848
849     /* thumbProc is not pretty, but is necessary for backwards
850        compatibility on those architectures for which it work{s,ed};
851        the intent is to pass a (truncated) float by value. */
852     xtpf.xtf = w->scrollbar.top;
853     XtCallCallbacks(gw, XtNthumbProc, xtpf.xtp);
854     XtCallCallbacks(gw, XtNjumpProc, (XtPointer)&w->scrollbar.top);
855
856     PaintThumb(w);
857 }
858
859 /*
860  *  Public routines
861  */
862 /* Set the scroll bar to the given location. */
863 void
864 XawScrollbarSetThumb(Widget gw,
865 #if NeedWidePrototypes
866                      double top, double shown
867 #else
868                      float top, float shown
869 #endif
870                      )
871 {
872     ScrollbarWidget w = (ScrollbarWidget)gw;
873
874     if (w->scrollbar.direction == 'c')  /* if still thumbing */
875         return;
876
877     w->scrollbar.top = top > 1.0 ? 1.0 : top >= 0.0 ? top : w->scrollbar.top;
878
879     w->scrollbar.shown = shown > 1.0 ? 1.0 : shown >= 0.0 ?
880                                 shown : w->scrollbar.shown;
881     PaintThumb(w);
882 }