6 /* undefine will disable the autoadjusting of the knob dimple to be
7 * directly below the cursor
9 #undef STRICT_NEXT_BEHAVIOUR
11 #define AUTOSCROLL_INITIAL_DELAY 200
13 #define AUTOSCROLL_DELAY 40
15 char *WMScrollerDidScrollNotification
= "WMScrollerDidScrollNotification";
17 typedef struct W_Scroller
{
27 WMHandlerID timerID
; /* for continuous scrolling mode */
29 #ifndef STRICT_NEXT_BEHAVIOUR
30 int dragPoint
; /* point where the knob is being
34 WMScrollArrowPosition arrowsPosition
:4;
36 unsigned int horizontal
:1;
38 WMScrollerPart hitPart
:4;
41 unsigned int documentFullyVisible
:1; /* document is fully visible */
43 unsigned int prevSelected
:1;
45 unsigned int pushed
:1;
47 unsigned int incrDown
:1; /* whether increment button is down */
49 unsigned int decrDown
:1;
51 unsigned int draggingKnob
:1;
53 unsigned int configured
:1;
55 unsigned int redrawPending
:1;
59 #define DEFAULT_HEIGHT 60
60 #define DEFAULT_WIDTH SCROLLER_WIDTH
61 #define DEFAULT_ARROWS_POSITION WSAMinEnd
63 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
65 static void destroyScroller(Scroller
* sPtr
);
66 static void paintScroller(Scroller
* sPtr
);
68 static void willResizeScroller();
69 static void handleEvents(XEvent
* event
, void *data
);
70 static void handleActionEvents(XEvent
* event
, void *data
);
72 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
);
74 W_ViewDelegate _ScrollerViewDelegate
= {
82 WMScroller
*WMCreateScroller(WMWidget
* parent
)
86 sPtr
= wmalloc(sizeof(Scroller
));
87 sPtr
->widgetClass
= WC_Scroller
;
89 sPtr
->view
= W_CreateView(W_VIEW(parent
));
94 sPtr
->view
->self
= sPtr
;
96 sPtr
->view
->delegate
= &_ScrollerViewDelegate
;
98 sPtr
->flags
.documentFullyVisible
= 1;
100 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
101 | ClientMessageMask
, handleEvents
, sPtr
);
103 W_ResizeView(sPtr
->view
, DEFAULT_WIDTH
, DEFAULT_WIDTH
);
104 sPtr
->flags
.arrowsPosition
= DEFAULT_ARROWS_POSITION
;
106 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
107 | EnterWindowMask
| LeaveWindowMask
| ButtonMotionMask
, handleActionEvents
, sPtr
);
109 sPtr
->flags
.hitPart
= WSNoPart
;
111 sPtr
->floatValue
= 0.0;
112 sPtr
->knobProportion
= 1.0;
117 void WMSetScrollerArrowsPosition(WMScroller
* sPtr
, WMScrollArrowPosition position
)
119 sPtr
->flags
.arrowsPosition
= position
;
120 if (sPtr
->view
->flags
.realized
) {
125 static void willResizeScroller(W_ViewDelegate
* self
, WMView
* view
, unsigned int *width
, unsigned int *height
)
127 WMScroller
*sPtr
= (WMScroller
*) view
->self
;
129 if (*width
> *height
) {
130 sPtr
->flags
.horizontal
= 1;
131 *height
= SCROLLER_WIDTH
;
133 sPtr
->flags
.horizontal
= 0;
134 *width
= SCROLLER_WIDTH
;
138 void WMSetScrollerAction(WMScroller
* sPtr
, WMAction
* action
, void *clientData
)
140 CHECK_CLASS(sPtr
, WC_Scroller
);
142 sPtr
->action
= action
;
144 sPtr
->clientData
= clientData
;
147 void WMSetScrollerParameters(WMScroller
* sPtr
, float floatValue
, float knobProportion
)
149 CHECK_CLASS(sPtr
, WC_Scroller
);
151 assert(!isnan(floatValue
));
153 if (floatValue
< 0.0)
154 sPtr
->floatValue
= 0.0;
155 else if (floatValue
> 1.0)
156 sPtr
->floatValue
= 1.0;
158 sPtr
->floatValue
= floatValue
;
160 if (knobProportion
<= 0.0) {
162 sPtr
->knobProportion
= 0.0;
163 sPtr
->flags
.documentFullyVisible
= 0;
165 } else if (knobProportion
>= 1.0) {
167 sPtr
->knobProportion
= 1.0;
168 sPtr
->flags
.documentFullyVisible
= 1;
171 sPtr
->knobProportion
= knobProportion
;
172 sPtr
->flags
.documentFullyVisible
= 0;
175 if (sPtr
->view
->flags
.realized
)
178 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
181 float WMGetScrollerKnobProportion(WMScroller
* sPtr
)
183 CHECK_CLASS(sPtr
, WC_Scroller
);
185 return sPtr
->knobProportion
;
188 float WMGetScrollerValue(WMScroller
* sPtr
)
190 CHECK_CLASS(sPtr
, WC_Scroller
);
192 return sPtr
->floatValue
;
195 WMScrollerPart
WMGetScrollerHitPart(WMScroller
* sPtr
)
197 CHECK_CLASS(sPtr
, WC_Scroller
);
199 return sPtr
->flags
.hitPart
;
202 static void paintArrow(WMScroller
* sPtr
, Drawable d
, int part
)
204 * part- 0 paints the decrement arrow, 1 the increment arrow
207 WMView
*view
= sPtr
->view
;
208 WMScreen
*scr
= view
->screen
;
212 #ifndef DOUBLE_BUFFER
213 GC gc
= scr
->lightGC
;
216 if (part
== 0) { /* decrement button */
217 if (sPtr
->flags
.horizontal
) {
218 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
219 ofs
= view
->size
.width
- 2 * (BUTTON_SIZE
+ 1) - 1;
223 if (sPtr
->flags
.decrDown
)
224 arrow
= scr
->hiLeftArrow
;
226 arrow
= scr
->leftArrow
;
229 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
230 ofs
= view
->size
.height
- 2 * (BUTTON_SIZE
+ 1) - 1;
234 if (sPtr
->flags
.decrDown
)
235 arrow
= scr
->hiUpArrow
;
237 arrow
= scr
->upArrow
;
240 #ifndef DOUBLE_BUFFER
241 if (sPtr
->flags
.decrDown
)
242 gc
= WMColorGC(scr
->white
);
244 } else { /* increment button */
245 if (sPtr
->flags
.horizontal
) {
246 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
247 ofs
= view
->size
.width
- BUTTON_SIZE
+ 1 - 3;
249 ofs
= 2 + BUTTON_SIZE
+ 1;
251 if (sPtr
->flags
.incrDown
)
252 arrow
= scr
->hiRightArrow
;
254 arrow
= scr
->rightArrow
;
256 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
257 ofs
= view
->size
.height
- BUTTON_SIZE
+ 1 - 3;
259 ofs
= 2 + BUTTON_SIZE
+ 1;
261 if (sPtr
->flags
.incrDown
)
262 arrow
= scr
->hiDownArrow
;
264 arrow
= scr
->downArrow
;
267 #ifndef DOUBLE_BUFFER
268 if (sPtr
->flags
.incrDown
)
273 if (sPtr
->flags
.horizontal
) {
275 #ifndef DOUBLE_BUFFER
276 XFillRectangle(scr
->display
, d
, gc
, ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
278 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
279 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
280 ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
281 #endif /* DOUBLE_BUFFER */
282 W_DrawRelief(scr
, d
, ofs
, 2, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
285 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
286 XSetClipOrigin(scr
->display
, scr
->clipGC
,
287 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
289 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
290 0, 0, arrow
->width
, arrow
->height
,
291 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
293 } else { /* vertical */
296 #ifndef DOUBLE_BUFFER
297 XFillRectangle(scr
->display
, d
, gc
, 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
299 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
300 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
301 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
302 #endif /* DOUBLE_BUFFER */
303 W_DrawRelief(scr
, d
, 2, ofs
, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
307 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
308 XSetClipOrigin(scr
->display
, scr
->clipGC
,
309 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
310 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
311 0, 0, arrow
->width
, arrow
->height
,
312 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
316 static int knobLength(Scroller
* sPtr
)
320 if (sPtr
->flags
.horizontal
)
321 length
= sPtr
->view
->size
.width
- 4;
323 length
= sPtr
->view
->size
.height
- 4;
325 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
326 length
-= 2 * (BUTTON_SIZE
+ 1);
329 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5);
330 /* keep minimum size */
331 if (tmp
< BUTTON_SIZE
)
337 static void paintScroller(Scroller
* sPtr
)
339 WMView
*view
= sPtr
->view
;
340 WMScreen
*scr
= view
->screen
;
344 Drawable d
= view
->window
;
350 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
, view
->size
.height
, scr
->depth
);
351 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0, view
->size
.width
, view
->size
.height
);
354 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0, view
->size
.width
- 1, view
->size
.height
- 1);
355 #ifndef DOUBLE_BUFFER
356 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1, view
->size
.width
- 3, view
->size
.height
- 3);
359 if (sPtr
->flags
.horizontal
)
360 length
= view
->size
.width
- 4;
362 length
= view
->size
.height
- 4;
364 if (sPtr
->flags
.documentFullyVisible
) {
365 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2, view
->size
.width
- 4, view
->size
.height
- 4);
368 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
369 length
-= (BUTTON_SIZE
+ 1) * 2;
370 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
371 ofs
+= (BUTTON_SIZE
+ 1) * 2;
372 length
-= (BUTTON_SIZE
+ 1) * 2;
375 knobL
= (float)knobLength(sPtr
);
377 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
379 if (sPtr
->flags
.horizontal
) {
381 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, ofs
, 2, (int)knobP
, view
->size
.height
- 4);
384 #ifndef DOUBLE_BUFFER
385 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
386 ofs
+ (int)knobP
+ 2, 2 + 2, (int)knobL
- 4, view
->size
.height
- 4 - 4);
388 W_DrawRelief(scr
, d
, ofs
+ (int)knobP
, 2, (int)knobL
, view
->size
.height
- 4, WRRaised
);
390 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
392 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
393 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->width
- 1) / 2,
394 (view
->size
.height
- scr
->scrollerDimple
->height
- 1) / 2);
397 if ((int)(knobP
+ knobL
) < length
)
398 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
399 ofs
+ (int)(knobP
+ knobL
), 2,
400 length
- (int)(knobP
+ knobL
), view
->size
.height
- 4);
404 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
405 2, ofs
, view
->size
.width
- 4, (int)knobP
);
408 #ifndef DOUBLE_BUFFER
409 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
410 2 + 2, ofs
+ (int)knobP
+ 2, view
->size
.width
- 4 - 4, (int)knobL
- 4);
412 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
414 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
415 (view
->size
.width
- scr
->scrollerDimple
->width
- 1) / 2,
416 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->height
- 1) / 2);
418 W_DrawRelief(scr
, d
, 2, ofs
+ (int)knobP
, view
->size
.width
- 4, (int)knobL
, WRRaised
);
421 if ((int)(knobP
+ knobL
) < length
)
422 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
423 2, ofs
+ (int)(knobP
+ knobL
),
424 view
->size
.width
- 4, length
- (int)(knobP
+ knobL
));
427 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
428 paintArrow(sPtr
, d
, 0);
429 paintArrow(sPtr
, d
, 1);
434 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0, view
->size
.width
, view
->size
.height
, 0, 0);
435 XFreePixmap(scr
->display
, d
);
439 static void handleEvents(XEvent
* event
, void *data
)
441 Scroller
*sPtr
= (Scroller
*) data
;
443 CHECK_CLASS(data
, WC_Scroller
);
445 switch (event
->type
) {
447 if (event
->xexpose
.count
== 0)
452 destroyScroller(sPtr
);
458 * locatePointInScroller-
459 * Return the part of the scroller where the point is located.
461 static WMScrollerPart
locatePointInScroller(Scroller
* sPtr
, int x
, int y
, int alternate
)
463 int width
= sPtr
->view
->size
.width
;
464 int height
= sPtr
->view
->size
.height
;
465 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
468 /* if there is no knob... */
469 if (sPtr
->flags
.documentFullyVisible
)
472 if (sPtr
->flags
.horizontal
)
478 * | | |###########| |#####| | |
479 * | < | > |###########| O |#####| < | > |
480 * | | |###########| |#####| | |
483 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
487 if (sPtr
->flags
.horizontal
) {
495 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
496 if (sPtr
->flags
.horizontal
) {
510 if (sPtr
->flags
.horizontal
) {
511 slotL
= p5
= p6
= width
;
513 slotL
= p5
= p6
= height
;
517 knobL
= knobLength(sPtr
);
518 p3
= p2
+ (int)((float)(slotL
- knobL
) * sPtr
->floatValue
);
521 /* uses a mix of the NS and Win ways of doing scroll page */
523 return alternate
? WSDecrementPage
: WSDecrementLine
;
525 return alternate
? WSIncrementPage
: WSIncrementLine
;
527 return WSDecrementPage
;
531 return WSIncrementPage
;
533 return alternate
? WSDecrementPage
: WSDecrementLine
;
535 return alternate
? WSIncrementPage
: WSIncrementLine
;
538 static void handlePush(Scroller
* sPtr
, int pushX
, int pushY
, int alternate
)
543 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
545 sPtr
->flags
.hitPart
= part
;
548 case WSIncrementLine
:
549 sPtr
->flags
.incrDown
= 1;
553 case WSIncrementPage
:
557 case WSDecrementLine
:
558 sPtr
->flags
.decrDown
= 1;
562 case WSDecrementPage
:
567 sPtr
->flags
.draggingKnob
= 1;
568 #ifndef STRICT_NEXT_BEHAVIOUR
569 if (sPtr
->flags
.horizontal
)
570 sPtr
->dragPoint
= pushX
;
572 sPtr
->dragPoint
= pushY
;
578 if (sPtr
->flags
.arrowsPosition
!= WSANone
)
579 buttonsLen
= 2 * (BUTTON_SIZE
+ 1);
583 if (sPtr
->flags
.horizontal
)
584 length
= sPtr
->view
->size
.width
- 4 - buttonsLen
;
586 length
= sPtr
->view
->size
.height
- 4 - buttonsLen
;
588 knobP
= (int)(sPtr
->floatValue
* (float)(length
- knobLength(sPtr
)));
590 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
591 sPtr
->dragPoint
-= 2 + buttonsLen
+ knobP
;
593 sPtr
->dragPoint
-= 2 + knobP
;
595 #endif /* STRICT_NEXT_BEHAVIOUR */
596 /* This does not seem necesary here since we don't know yet if the
597 * knob will be dragged later. -Dan
598 handleMotion(sPtr, pushX, pushY); */
601 case WSDecrementWheel
:
602 case WSIncrementWheel
:
609 if (doAction
&& sPtr
->action
) {
610 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
612 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
616 static float floatValueForPoint(Scroller
* sPtr
, int point
)
618 float floatValue
= 0;
620 int slotOfs
, slotLength
, knobL
;
622 if (sPtr
->flags
.horizontal
)
623 slotLength
= sPtr
->view
->size
.width
- 4;
625 slotLength
= sPtr
->view
->size
.height
- 4;
628 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
629 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
630 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
631 slotOfs
+= (BUTTON_SIZE
+ 1) * 2;
632 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
635 knobL
= (float)knobLength(sPtr
);
636 #ifdef STRICT_NEXT_BEHAVIOUR
637 if (point
< slotOfs
+ knobL
/ 2)
638 position
= (float)(slotOfs
+ knobL
/ 2);
639 else if (point
> slotOfs
+ slotLength
- knobL
/ 2)
640 position
= (float)(slotOfs
+ slotLength
- knobL
/ 2);
642 position
= (float)point
;
644 floatValue
= (position
- (float)(slotOfs
+ slotLength
/ 2))
645 / (float)(slotLength
- knobL
);
647 /* Adjust the last point to lie inside the knob slot */
649 position
= (float)slotOfs
;
650 else if (point
> slotOfs
+ slotLength
)
651 position
= (float)(slotOfs
+ slotLength
);
653 position
= (float)point
;
655 /* Compute the float value */
656 floatValue
= (position
- (float)slotOfs
) / (float)(slotLength
- knobL
);
659 assert(!isnan(floatValue
));
663 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
)
665 if (sPtr
->flags
.draggingKnob
) {
669 if (sPtr
->flags
.horizontal
) {
675 #ifndef STRICT_NEXT_BEHAVIOUR
676 point
-= sPtr
->dragPoint
;
679 newFloatValue
= floatValueForPoint(sPtr
, point
);
680 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
682 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
683 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
688 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
690 sPtr
->flags
.hitPart
= part
;
692 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
693 sPtr
->flags
.decrDown
= 0;
694 sPtr
->flags
.incrDown
= 1;
695 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
696 sPtr
->flags
.incrDown
= 0;
697 sPtr
->flags
.decrDown
= 1;
698 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
699 sPtr
->flags
.incrDown
= 0;
700 sPtr
->flags
.decrDown
= 0;
705 static void autoScroll(void *clientData
)
707 Scroller
*sPtr
= (Scroller
*) clientData
;
710 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
711 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
713 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
716 static void handleActionEvents(XEvent
* event
, void *data
)
718 Scroller
*sPtr
= (Scroller
*) data
;
719 int wheelDecrement
, wheelIncrement
;
722 /* check if we're really dealing with a scroller, as something
723 * might have gone wrong in the event dispatching stuff */
724 CHECK_CLASS(sPtr
, WC_Scroller
);
726 id
= sPtr
->flags
.incrDown
;
727 dd
= sPtr
->flags
.decrDown
;
729 switch (event
->type
) {
735 WMDeleteTimerHandler(sPtr
->timerID
);
736 sPtr
->timerID
= NULL
;
738 sPtr
->flags
.incrDown
= 0;
739 sPtr
->flags
.decrDown
= 0;
743 /* FIXME: change Mod1Mask with something else */
744 if (sPtr
->flags
.documentFullyVisible
)
747 if (sPtr
->flags
.horizontal
) {
748 wheelDecrement
= WINGsConfiguration
.mouseWheelDown
;
749 wheelIncrement
= WINGsConfiguration
.mouseWheelUp
;
751 wheelDecrement
= WINGsConfiguration
.mouseWheelUp
;
752 wheelIncrement
= WINGsConfiguration
.mouseWheelDown
;
755 if (event
->xbutton
.button
== wheelDecrement
) {
756 if (event
->xbutton
.state
& ControlMask
) {
757 sPtr
->flags
.hitPart
= WSDecrementPage
;
758 } else if (event
->xbutton
.state
& ShiftMask
) {
759 sPtr
->flags
.hitPart
= WSDecrementLine
;
761 sPtr
->flags
.hitPart
= WSDecrementWheel
;
764 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
765 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
767 } else if (event
->xbutton
.button
== wheelIncrement
) {
768 if (event
->xbutton
.state
& ControlMask
) {
769 sPtr
->flags
.hitPart
= WSIncrementPage
;
770 } else if (event
->xbutton
.state
& ShiftMask
) {
771 sPtr
->flags
.hitPart
= WSIncrementLine
;
773 sPtr
->flags
.hitPart
= WSIncrementWheel
;
776 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
777 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
780 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
, (event
->xbutton
.state
& Mod1Mask
)
781 || event
->xbutton
.button
== Button2
);
782 /* continue scrolling if pushed on the buttons */
783 if (sPtr
->flags
.hitPart
== WSIncrementLine
|| sPtr
->flags
.hitPart
== WSDecrementLine
) {
784 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
, autoScroll
, sPtr
);
790 if (sPtr
->flags
.draggingKnob
) {
792 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
793 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
797 WMDeleteTimerHandler(sPtr
->timerID
);
798 sPtr
->timerID
= NULL
;
800 sPtr
->flags
.incrDown
= 0;
801 sPtr
->flags
.decrDown
= 0;
802 sPtr
->flags
.draggingKnob
= 0;
806 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
807 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
808 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
809 WMDeleteTimerHandler(sPtr
->timerID
);
810 sPtr
->timerID
= NULL
;
814 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
818 static void destroyScroller(Scroller
* sPtr
)
820 /* we don't want autoscroll try to scroll a freed widget */
822 WMDeleteTimerHandler(sPtr
->timerID
);