7 /* undefine will disable the autoadjusting of the knob dimple to be
8 * directly below the cursor
10 #undef STRICT_NEXT_BEHAVIOUR
12 #define AUTOSCROLL_INITIAL_DELAY 200
14 #define AUTOSCROLL_DELAY 40
17 char *WMScrollerDidScrollNotification
= "WMScrollerDidScrollNotification";
21 typedef struct W_Scroller
{
31 WMHandlerID timerID
; /* for continuous scrolling mode */
33 #ifndef STRICT_NEXT_BEHAVIOUR
34 int dragPoint
; /* point where the knob is being
38 WMScrollArrowPosition arrowsPosition
:4;
40 unsigned int horizontal
:1;
42 WMScrollerPart hitPart
:4;
45 unsigned int documentFullyVisible
:1; /* document is fully visible */
47 unsigned int prevSelected
:1;
49 unsigned int pushed
:1;
51 unsigned int incrDown
:1; /* whether increment button is down */
53 unsigned int decrDown
:1;
55 unsigned int draggingKnob
:1;
57 unsigned int configured
:1;
59 unsigned int redrawPending
:1;
65 #define DEFAULT_HEIGHT 60
66 #define DEFAULT_WIDTH SCROLLER_WIDTH
67 #define DEFAULT_ARROWS_POSITION WSAMinEnd
71 static void destroyScroller(Scroller
*sPtr
);
72 static void paintScroller(Scroller
*sPtr
);
74 static void willResizeScroller();
75 static void handleEvents(XEvent
*event
, void *data
);
76 static void handleActionEvents(XEvent
*event
, void *data
);
78 static void handleMotion(Scroller
*sPtr
, int mouseX
, int mouseY
);
81 W_ViewDelegate _ScrollerViewDelegate
= {
93 WMCreateScroller(WMWidget
*parent
)
97 sPtr
= wmalloc(sizeof(Scroller
));
98 memset(sPtr
, 0, sizeof(Scroller
));
100 sPtr
->widgetClass
= WC_Scroller
;
102 sPtr
->view
= W_CreateView(W_VIEW(parent
));
107 sPtr
->view
->self
= sPtr
;
109 sPtr
->view
->delegate
= &_ScrollerViewDelegate
;
111 sPtr
->flags
.documentFullyVisible
= 1;
113 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
114 |ClientMessageMask
, handleEvents
, sPtr
);
116 W_ResizeView(sPtr
->view
, DEFAULT_WIDTH
, DEFAULT_WIDTH
);
117 sPtr
->flags
.arrowsPosition
= DEFAULT_ARROWS_POSITION
;
119 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
|ButtonReleaseMask
120 |EnterWindowMask
|LeaveWindowMask
|ButtonMotionMask
,
121 handleActionEvents
, sPtr
);
123 sPtr
->flags
.hitPart
= WSNoPart
;
131 WMSetScrollerArrowsPosition(WMScroller
*sPtr
, WMScrollArrowPosition position
)
133 sPtr
->flags
.arrowsPosition
= position
;
134 if (sPtr
->view
->flags
.realized
) {
141 willResizeScroller(W_ViewDelegate
*self
, WMView
*view
,
142 unsigned int *width
, unsigned int *height
)
144 WMScroller
*sPtr
= (WMScroller
*)view
->self
;
146 if (*width
> *height
) {
147 sPtr
->flags
.horizontal
= 1;
148 *height
= SCROLLER_WIDTH
;
150 sPtr
->flags
.horizontal
= 0;
151 *width
= SCROLLER_WIDTH
;
157 WMSetScrollerAction(WMScroller
*sPtr
, WMAction
*action
, void *clientData
)
159 CHECK_CLASS(sPtr
, WC_Scroller
);
161 sPtr
->action
= action
;
163 sPtr
->clientData
= clientData
;
168 WMSetScrollerParameters(WMScroller
*sPtr
, float floatValue
,
169 float knobProportion
)
171 CHECK_CLASS(sPtr
, WC_Scroller
);
173 if (floatValue
< 0.0)
174 sPtr
->floatValue
= 0.0;
175 else if (floatValue
> 1.0)
176 sPtr
->floatValue
= 1.0;
178 sPtr
->floatValue
= floatValue
;
180 if (knobProportion
<= 0.0) {
182 sPtr
->knobProportion
= 0.0;
183 sPtr
->flags
.documentFullyVisible
= 0;
185 } else if (knobProportion
>= 1.0) {
187 sPtr
->knobProportion
= 1.0;
188 sPtr
->flags
.documentFullyVisible
= 1;
191 sPtr
->knobProportion
= knobProportion
;
192 sPtr
->flags
.documentFullyVisible
= 0;
195 if (sPtr
->view
->flags
.realized
)
198 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);*/
203 WMGetScrollerKnobProportion(WMScroller
*sPtr
)
205 CHECK_CLASS(sPtr
, WC_Scroller
);
207 return sPtr
->knobProportion
;
212 WMGetScrollerValue(WMScroller
*sPtr
)
214 CHECK_CLASS(sPtr
, WC_Scroller
);
216 return sPtr
->floatValue
;
221 WMGetScrollerHitPart(WMScroller
*sPtr
)
223 CHECK_CLASS(sPtr
, WC_Scroller
);
225 return sPtr
->flags
.hitPart
;
230 paintArrow(WMScroller
*sPtr
, Drawable d
, int part
)
232 * part- 0 paints the decrement arrow, 1 the increment arrow
235 WMView
*view
= sPtr
->view
;
236 WMScreen
*scr
= view
->screen
;
240 #ifndef DOUBLE_BUFFER
241 GC gc
= scr
->lightGC
;
244 bsize
= SCROLLER_WIDTH
- 4;
247 if (part
== 0) { /* decrement button */
248 if (sPtr
->flags
.horizontal
) {
249 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
250 ofs
= view
->size
.width
- 2*(bsize
+1) - 1;
254 if (sPtr
->flags
.decrDown
)
255 arrow
= scr
->hiLeftArrow
;
257 arrow
= scr
->leftArrow
;
260 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
261 ofs
= view
->size
.height
- 2*(bsize
+1) - 1;
265 if (sPtr
->flags
.decrDown
)
266 arrow
= scr
->hiUpArrow
;
268 arrow
= scr
->upArrow
;
271 #ifndef DOUBLE_BUFFER
272 if (sPtr
->flags
.decrDown
)
273 gc
= WMColorGC(scr
->white
);
275 } else { /* increment button */
276 if (sPtr
->flags
.horizontal
) {
277 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
278 ofs
= view
->size
.width
- bsize
+1 - 3;
282 if (sPtr
->flags
.incrDown
)
283 arrow
= scr
->hiRightArrow
;
285 arrow
= scr
->rightArrow
;
287 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
288 ofs
= view
->size
.height
- bsize
+1 - 3;
292 if (sPtr
->flags
.incrDown
)
293 arrow
= scr
->hiDownArrow
;
295 arrow
= scr
->downArrow
;
298 #ifndef DOUBLE_BUFFER
299 if (sPtr
->flags
.incrDown
)
305 if (sPtr
->flags
.horizontal
) {
308 #ifndef DOUBLE_BUFFER
309 XFillRectangle(scr
->display
, d
, gc
,
310 ofs
+1, 2+1, bsize
+1-3, bsize
-3);
312 if ((!part
&&sPtr
->flags
.decrDown
) || (part
&&sPtr
->flags
.incrDown
))
313 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
314 ofs
+1, 2+1, bsize
+1-3, bsize
-3);
315 #endif /* DOUBLE_BUFFER */
316 W_DrawRelief(scr
, d
, ofs
, 2, bsize
, bsize
, WRRaised
);
319 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
320 XSetClipOrigin(scr
->display
, scr
->clipGC
,
321 ofs
+ (bsize
- arrow
->width
) / 2,
322 2 + (bsize
- arrow
->height
) / 2);
324 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
325 0, 0, arrow
->width
, arrow
->height
,
326 ofs
+ (bsize
- arrow
->width
) / 2,
327 2 + (bsize
- arrow
->height
) / 2);
329 } else { /* vertical */
332 #ifndef DOUBLE_BUFFER
333 XFillRectangle(scr
->display
, d
, gc
,
334 2+1, ofs
+1, bsize
-3, bsize
+1-3);
336 if ((!part
&&sPtr
->flags
.decrDown
) || (part
&&sPtr
->flags
.incrDown
))
337 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
338 2+1, ofs
+1, bsize
-3, bsize
+1-3);
339 #endif /* DOUBLE_BUFFER */
340 W_DrawRelief(scr
, d
, 2, ofs
, bsize
, bsize
, WRRaised
);
344 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
345 XSetClipOrigin(scr
->display
, scr
->clipGC
,
346 2 + (bsize
- arrow
->width
) / 2,
347 ofs
+ (bsize
- arrow
->height
) / 2);
348 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
349 0, 0, arrow
->width
, arrow
->height
,
350 2 + (bsize
- arrow
->width
) / 2,
351 ofs
+ (bsize
- arrow
->height
) / 2);
357 knobLength(Scroller
*sPtr
)
362 if (sPtr
->flags
.horizontal
)
363 length
= sPtr
->view
->size
.width
- 4;
365 length
= sPtr
->view
->size
.height
- 4;
367 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
368 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
369 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
370 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
373 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5);
374 /* keep minimum size */
375 if (tmp
< SCROLLER_WIDTH
-4)
376 tmp
= SCROLLER_WIDTH
-4;
383 paintScroller(Scroller
*sPtr
)
385 WMView
*view
= sPtr
->view
;
386 WMScreen
*scr
= view
->screen
;
390 Drawable d
= view
->window
;
397 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
,
398 view
->size
.height
, scr
->depth
);
399 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0,
400 view
->size
.width
, view
->size
.height
);
403 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0,
404 view
->size
.width
-1, view
->size
.height
-1);
405 #ifndef DOUBLE_BUFFER
406 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1,
407 view
->size
.width
-3, view
->size
.height
-3);
410 if (sPtr
->flags
.horizontal
)
411 length
= view
->size
.width
- 4;
413 length
= view
->size
.height
- 4;
415 if (sPtr
->flags
.documentFullyVisible
) {
416 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2,
417 view
->size
.width
-4, view
->size
.height
-4);
419 if (sPtr
->flags
.arrowsPosition
==WSAMaxEnd
) {
421 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
422 } else if (sPtr
->flags
.arrowsPosition
==WSAMinEnd
) {
423 ofs
= (SCROLLER_WIDTH
- 4 + 1)*2;
424 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
429 knobL
= (float)knobLength(sPtr
);
431 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
434 if (sPtr
->flags
.horizontal
) {
436 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
437 ofs
+2, 2, (int)knobP
, view
->size
.height
-4);
440 #ifndef DOUBLE_BUFFER
441 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
442 ofs
+2+(int)knobP
+2, 2+2, (int)knobL
-4,
443 view
->size
.height
-4-4);
445 W_DrawRelief(scr
, d
, ofs
+2+(int)knobP
, 2, (int)knobL
,
446 view
->size
.height
-4, WRRaised
);
448 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
450 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
451 ofs
+2+(int)knobP
+((int)knobL
-scr
->scrollerDimple
->width
-1)/2,
452 (view
->size
.height
-scr
->scrollerDimple
->height
-1)/2);
455 if ((int)(knobP
+knobL
) < length
)
456 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
457 ofs
+2+(int)(knobP
+knobL
), 2,
458 length
-(int)(knobP
+knobL
),
459 view
->size
.height
-4);
463 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
464 2, ofs
+2, view
->size
.width
-4, (int)knobP
);
467 #ifndef DOUBLE_BUFFER
468 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
469 2+2, ofs
+2+(int)knobP
+2,
470 view
->size
.width
-4-4, (int)knobL
-4);
472 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
474 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
475 (view
->size
.width
-scr
->scrollerDimple
->width
-1)/2,
476 ofs
+2+(int)knobP
+((int)knobL
-scr
->scrollerDimple
->height
-1)/2);
478 W_DrawRelief(scr
, d
, 2, ofs
+2+(int)knobP
,
479 view
->size
.width
-4, (int)knobL
, WRRaised
);
482 if ((int)(knobP
+knobL
) < length
)
483 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
484 2, ofs
+2+(int)(knobP
+knobL
),
486 length
-(int)(knobP
+knobL
));
489 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
490 paintArrow(sPtr
, d
, 0);
491 paintArrow(sPtr
, d
, 1);
496 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0,
497 view
->size
.width
, view
->size
.height
, 0, 0);
498 XFreePixmap(scr
->display
, d
);
505 handleEvents(XEvent
*event
, void *data
)
507 Scroller
*sPtr
= (Scroller
*)data
;
509 CHECK_CLASS(data
, WC_Scroller
);
512 switch (event
->type
) {
514 if (event
->xexpose
.count
==0)
519 destroyScroller(sPtr
);
527 * locatePointInScroller-
528 * Return the part of the scroller where the point is located.
530 static WMScrollerPart
531 locatePointInScroller(Scroller
*sPtr
, int x
, int y
, int alternate
)
533 int width
= sPtr
->view
->size
.width
;
534 int height
= sPtr
->view
->size
.height
;
535 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
539 /* if there is no knob... */
540 if (sPtr
->flags
.documentFullyVisible
)
543 if (sPtr
->flags
.horizontal
)
549 * | | |###########| |#####| | |
550 * | < | > |###########| O |#####| < | > |
551 * | | |###########| |#####| | |
554 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
558 if (sPtr
->flags
.horizontal
) {
566 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
567 if (sPtr
->flags
.horizontal
) {
581 if (sPtr
->flags
.horizontal
) {
582 slotL
= p5
= p6
= width
;
584 slotL
= p5
= p6
= height
;
588 knobL
= knobLength(sPtr
);
589 p3
= p2
+ (int)((float)(slotL
-knobL
) * sPtr
->floatValue
);
592 /* uses a mix of the NS and Win ways of doing scroll page */
594 return alternate
? WSDecrementPage
: WSDecrementLine
;
596 return alternate
? WSIncrementPage
: WSIncrementLine
;
598 return WSDecrementPage
;
602 return WSIncrementPage
;
604 return alternate
? WSDecrementPage
: WSDecrementLine
;
606 return alternate
? WSIncrementPage
: WSIncrementLine
;
612 handlePush(Scroller
*sPtr
, int pushX
, int pushY
, int alternate
)
617 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
619 sPtr
->flags
.hitPart
= part
;
622 case WSIncrementLine
:
623 sPtr
->flags
.incrDown
= 1;
627 case WSIncrementPage
:
631 case WSDecrementLine
:
632 sPtr
->flags
.decrDown
= 1;
636 case WSDecrementPage
:
641 sPtr
->flags
.draggingKnob
= 1;
642 #ifndef STRICT_NEXT_BEHAVIOUR
643 if (sPtr
->flags
.horizontal
)
644 sPtr
->dragPoint
= pushX
;
646 sPtr
->dragPoint
= pushY
;
649 int noButtons
= (sPtr
->flags
.arrowsPosition
== WSANone
);
652 if (sPtr
->flags
.horizontal
)
653 length
= sPtr
->view
->size
.width
- 4;
655 length
= sPtr
->view
->size
.height
- 4;
660 knobP
= (int)(sPtr
->floatValue
* (float)(length
-knobLength(sPtr
)));
662 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
663 sPtr
->dragPoint
-= 2 + (noButtons
? 0 : 36) + knobP
;
665 sPtr
->dragPoint
-= 2 + knobP
;
667 #endif /* STRICT_NEXT_BEHAVIOUR */
668 /* This does not seem necesary here since we don't know yet if the
669 * knob will be dragged later. -Dan
670 handleMotion(sPtr, pushX, pushY); */
679 if (doAction
&& sPtr
->action
) {
680 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
682 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
688 floatValueForPoint(int slotOfs
, int slotLength
, int knobLength
, int point
)
690 float floatValue
= 0;
693 #ifdef STRICT_NEXT_BEHAVIOUR
694 if (point
< slotOfs
+ knobLength
/2)
695 position
= (float)(slotOfs
+ knobLength
/2);
696 else if (point
> slotOfs
+ slotLength
- knobLength
/2)
697 position
= (float)(slotOfs
+ slotLength
- knobLength
/2);
699 position
= (float)point
;
701 floatValue
= (position
-(float)(slotOfs
+slotLength
/2))
702 /(float)(slotLength
-knobLength
);
704 /* Adjust the last point to lie inside the knob slot */
706 position
= (float)slotOfs
;
707 else if (point
> slotOfs
+ slotLength
)
708 position
= (float)(slotOfs
+ slotLength
);
710 position
= (float)point
;
712 /* Compute the float value */
713 floatValue
= (position
-(float)slotOfs
) / (float)(slotLength
-knobLength
);
721 handleMotion(Scroller
*sPtr
, int mouseX
, int mouseY
)
725 int noButtons
= (sPtr
->flags
.arrowsPosition
== WSANone
);
727 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
728 slotOffset
= 2 + (noButtons
? 0 : 36);
732 if (sPtr
->flags
.draggingKnob
) {
734 #ifdef STRICT_NEXT_BEHAVIOUR
735 if (sPtr
->flags
.horizontal
) {
736 slotLength
= sPtr
->view
->size
.width
-4-(noButtons
? 0 : 36);
737 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
738 (int)(slotLength
*sPtr
->knobProportion
),
741 slotLength
= sPtr
->view
->size
.height
-4-(noButtons
? 0 : 36);
742 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
743 (int)(slotLength
*sPtr
->knobProportion
),
747 if (sPtr
->flags
.horizontal
) {
748 slotLength
= sPtr
->view
->size
.width
-4-(noButtons
? 0 : 36);
749 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
750 (int)(slotLength
*sPtr
->knobProportion
),
751 mouseX
-sPtr
->dragPoint
);
753 slotLength
= sPtr
->view
->size
.height
-4-(noButtons
? 0 : 36);
754 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
755 (int)(slotLength
*sPtr
->knobProportion
),
756 mouseY
-sPtr
->dragPoint
);
758 #endif /* !STRICT_NEXT_BEHAVIOUR */
759 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
761 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
762 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
,
768 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
770 sPtr
->flags
.hitPart
= part
;
772 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
773 sPtr
->flags
.decrDown
= 0;
774 sPtr
->flags
.incrDown
= 1;
775 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
776 sPtr
->flags
.incrDown
= 0;
777 sPtr
->flags
.decrDown
= 1;
778 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
779 sPtr
->flags
.incrDown
= 0;
780 sPtr
->flags
.decrDown
= 0;
787 autoScroll(void *clientData
)
789 Scroller
*sPtr
= (Scroller
*)clientData
;
792 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
793 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
795 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
800 handleActionEvents(XEvent
*event
, void *data
)
802 Scroller
*sPtr
= (Scroller
*)data
;
806 /* check if we're really dealing with a scroller, as something
807 * might have gone wrong in the event dispatching stuff */
808 CHECK_CLASS(sPtr
, WC_Scroller
);
810 id
= sPtr
->flags
.incrDown
;
811 dd
= sPtr
->flags
.decrDown
;
813 switch (event
->type
) {
820 WMDeleteTimerHandler(sPtr
->timerID
);
821 sPtr
->timerID
= NULL
;
823 sPtr
->flags
.incrDown
= 0;
824 sPtr
->flags
.decrDown
= 0;
828 /* FIXME: change Mod1Mask with something else */
829 if (sPtr
->flags
.documentFullyVisible
)
831 if (event
->xbutton
.button
==WINGsConfiguration
.mouseWheelUp
) {
832 if (event
->xbutton
.state
& ControlMask
) {
833 sPtr
->flags
.hitPart
= WSDecrementPage
;
834 } else if (event
->xbutton
.state
& ShiftMask
) {
835 sPtr
->flags
.hitPart
= WSDecrementLine
;
837 sPtr
->flags
.hitPart
= WSDecrementWheel
;
840 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
841 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
,
844 } else if (event
->xbutton
.button
==WINGsConfiguration
.mouseWheelDown
) {
845 if (event
->xbutton
.state
& ControlMask
) {
846 sPtr
->flags
.hitPart
= WSIncrementPage
;
847 } else if (event
->xbutton
.state
& ShiftMask
) {
848 sPtr
->flags
.hitPart
= WSIncrementLine
;
850 sPtr
->flags
.hitPart
= WSIncrementWheel
;
853 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
854 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
,
858 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
,
859 (event
->xbutton
.state
& Mod1Mask
)
860 ||event
->xbutton
.button
==Button2
);
861 /* continue scrolling if pushed on the buttons */
862 if (sPtr
->flags
.hitPart
== WSIncrementLine
863 || sPtr
->flags
.hitPart
== WSDecrementLine
) {
864 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
,
871 if (sPtr
->flags
.draggingKnob
) {
873 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
874 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
,
879 WMDeleteTimerHandler(sPtr
->timerID
);
880 sPtr
->timerID
= NULL
;
882 sPtr
->flags
.incrDown
= 0;
883 sPtr
->flags
.decrDown
= 0;
884 sPtr
->flags
.draggingKnob
= 0;
888 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
889 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
890 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
891 WMDeleteTimerHandler(sPtr
->timerID
);
892 sPtr
->timerID
= NULL
;
896 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
903 destroyScroller(Scroller
*sPtr
)
905 /* we don't want autoscroll try to scroll a freed widget */
907 WMDeleteTimerHandler(sPtr
->timerID
);