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 memset(sPtr
, 0, sizeof(Scroller
));
89 sPtr
->widgetClass
= WC_Scroller
;
91 sPtr
->view
= W_CreateView(W_VIEW(parent
));
96 sPtr
->view
->self
= sPtr
;
98 sPtr
->view
->delegate
= &_ScrollerViewDelegate
;
100 sPtr
->flags
.documentFullyVisible
= 1;
102 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
103 | ClientMessageMask
, handleEvents
, sPtr
);
105 W_ResizeView(sPtr
->view
, DEFAULT_WIDTH
, DEFAULT_WIDTH
);
106 sPtr
->flags
.arrowsPosition
= DEFAULT_ARROWS_POSITION
;
108 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
109 | EnterWindowMask
| LeaveWindowMask
| ButtonMotionMask
, handleActionEvents
, sPtr
);
111 sPtr
->flags
.hitPart
= WSNoPart
;
113 sPtr
->floatValue
= 0.0;
114 sPtr
->knobProportion
= 1.0;
119 void WMSetScrollerArrowsPosition(WMScroller
* sPtr
, WMScrollArrowPosition position
)
121 sPtr
->flags
.arrowsPosition
= position
;
122 if (sPtr
->view
->flags
.realized
) {
127 static void willResizeScroller(W_ViewDelegate
* self
, WMView
* view
, unsigned int *width
, unsigned int *height
)
129 WMScroller
*sPtr
= (WMScroller
*) view
->self
;
131 if (*width
> *height
) {
132 sPtr
->flags
.horizontal
= 1;
133 *height
= SCROLLER_WIDTH
;
135 sPtr
->flags
.horizontal
= 0;
136 *width
= SCROLLER_WIDTH
;
140 void WMSetScrollerAction(WMScroller
* sPtr
, WMAction
* action
, void *clientData
)
142 CHECK_CLASS(sPtr
, WC_Scroller
);
144 sPtr
->action
= action
;
146 sPtr
->clientData
= clientData
;
149 void WMSetScrollerParameters(WMScroller
* sPtr
, float floatValue
, float knobProportion
)
151 CHECK_CLASS(sPtr
, WC_Scroller
);
153 assert(!isnan(floatValue
));
155 if (floatValue
< 0.0)
156 sPtr
->floatValue
= 0.0;
157 else if (floatValue
> 1.0)
158 sPtr
->floatValue
= 1.0;
160 sPtr
->floatValue
= floatValue
;
162 if (knobProportion
<= 0.0) {
164 sPtr
->knobProportion
= 0.0;
165 sPtr
->flags
.documentFullyVisible
= 0;
167 } else if (knobProportion
>= 1.0) {
169 sPtr
->knobProportion
= 1.0;
170 sPtr
->flags
.documentFullyVisible
= 1;
173 sPtr
->knobProportion
= knobProportion
;
174 sPtr
->flags
.documentFullyVisible
= 0;
177 if (sPtr
->view
->flags
.realized
)
180 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
183 float WMGetScrollerKnobProportion(WMScroller
* sPtr
)
185 CHECK_CLASS(sPtr
, WC_Scroller
);
187 return sPtr
->knobProportion
;
190 float WMGetScrollerValue(WMScroller
* sPtr
)
192 CHECK_CLASS(sPtr
, WC_Scroller
);
194 return sPtr
->floatValue
;
197 WMScrollerPart
WMGetScrollerHitPart(WMScroller
* sPtr
)
199 CHECK_CLASS(sPtr
, WC_Scroller
);
201 return sPtr
->flags
.hitPart
;
204 static void paintArrow(WMScroller
* sPtr
, Drawable d
, int part
)
206 * part- 0 paints the decrement arrow, 1 the increment arrow
209 WMView
*view
= sPtr
->view
;
210 WMScreen
*scr
= view
->screen
;
214 #ifndef DOUBLE_BUFFER
215 GC gc
= scr
->lightGC
;
218 if (part
== 0) { /* decrement button */
219 if (sPtr
->flags
.horizontal
) {
220 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
221 ofs
= view
->size
.width
- 2 * (BUTTON_SIZE
+ 1) - 1;
225 if (sPtr
->flags
.decrDown
)
226 arrow
= scr
->hiLeftArrow
;
228 arrow
= scr
->leftArrow
;
231 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
232 ofs
= view
->size
.height
- 2 * (BUTTON_SIZE
+ 1) - 1;
236 if (sPtr
->flags
.decrDown
)
237 arrow
= scr
->hiUpArrow
;
239 arrow
= scr
->upArrow
;
242 #ifndef DOUBLE_BUFFER
243 if (sPtr
->flags
.decrDown
)
244 gc
= WMColorGC(scr
->white
);
246 } else { /* increment button */
247 if (sPtr
->flags
.horizontal
) {
248 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
249 ofs
= view
->size
.width
- BUTTON_SIZE
+ 1 - 3;
251 ofs
= 2 + BUTTON_SIZE
+ 1;
253 if (sPtr
->flags
.incrDown
)
254 arrow
= scr
->hiRightArrow
;
256 arrow
= scr
->rightArrow
;
258 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
259 ofs
= view
->size
.height
- BUTTON_SIZE
+ 1 - 3;
261 ofs
= 2 + BUTTON_SIZE
+ 1;
263 if (sPtr
->flags
.incrDown
)
264 arrow
= scr
->hiDownArrow
;
266 arrow
= scr
->downArrow
;
269 #ifndef DOUBLE_BUFFER
270 if (sPtr
->flags
.incrDown
)
275 if (sPtr
->flags
.horizontal
) {
277 #ifndef DOUBLE_BUFFER
278 XFillRectangle(scr
->display
, d
, gc
, ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
280 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
281 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
282 ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
283 #endif /* DOUBLE_BUFFER */
284 W_DrawRelief(scr
, d
, ofs
, 2, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
287 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
288 XSetClipOrigin(scr
->display
, scr
->clipGC
,
289 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
291 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
292 0, 0, arrow
->width
, arrow
->height
,
293 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
295 } else { /* vertical */
298 #ifndef DOUBLE_BUFFER
299 XFillRectangle(scr
->display
, d
, gc
, 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
301 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
302 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
303 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
304 #endif /* DOUBLE_BUFFER */
305 W_DrawRelief(scr
, d
, 2, ofs
, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
309 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
310 XSetClipOrigin(scr
->display
, scr
->clipGC
,
311 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
312 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
313 0, 0, arrow
->width
, arrow
->height
,
314 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
318 static int knobLength(Scroller
* sPtr
)
322 if (sPtr
->flags
.horizontal
)
323 length
= sPtr
->view
->size
.width
- 4;
325 length
= sPtr
->view
->size
.height
- 4;
327 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
328 length
-= 2 * (BUTTON_SIZE
+ 1);
331 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5);
332 /* keep minimum size */
333 if (tmp
< BUTTON_SIZE
)
339 static void paintScroller(Scroller
* sPtr
)
341 WMView
*view
= sPtr
->view
;
342 WMScreen
*scr
= view
->screen
;
346 Drawable d
= view
->window
;
352 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
, view
->size
.height
, scr
->depth
);
353 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0, view
->size
.width
, view
->size
.height
);
356 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0, view
->size
.width
- 1, view
->size
.height
- 1);
357 #ifndef DOUBLE_BUFFER
358 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1, view
->size
.width
- 3, view
->size
.height
- 3);
361 if (sPtr
->flags
.horizontal
)
362 length
= view
->size
.width
- 4;
364 length
= view
->size
.height
- 4;
366 if (sPtr
->flags
.documentFullyVisible
) {
367 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2, view
->size
.width
- 4, view
->size
.height
- 4);
370 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
371 length
-= (BUTTON_SIZE
+ 1) * 2;
372 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
373 ofs
+= (BUTTON_SIZE
+ 1) * 2;
374 length
-= (BUTTON_SIZE
+ 1) * 2;
377 knobL
= (float)knobLength(sPtr
);
379 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
381 if (sPtr
->flags
.horizontal
) {
383 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, ofs
, 2, (int)knobP
, view
->size
.height
- 4);
386 #ifndef DOUBLE_BUFFER
387 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
388 ofs
+ (int)knobP
+ 2, 2 + 2, (int)knobL
- 4, view
->size
.height
- 4 - 4);
390 W_DrawRelief(scr
, d
, ofs
+ (int)knobP
, 2, (int)knobL
, view
->size
.height
- 4, WRRaised
);
392 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
394 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
395 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->width
- 1) / 2,
396 (view
->size
.height
- scr
->scrollerDimple
->height
- 1) / 2);
399 if ((int)(knobP
+ knobL
) < length
)
400 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
401 ofs
+ (int)(knobP
+ knobL
), 2,
402 length
- (int)(knobP
+ knobL
), view
->size
.height
- 4);
406 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
407 2, ofs
, view
->size
.width
- 4, (int)knobP
);
410 #ifndef DOUBLE_BUFFER
411 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
412 2 + 2, ofs
+ (int)knobP
+ 2, view
->size
.width
- 4 - 4, (int)knobL
- 4);
414 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
416 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
417 (view
->size
.width
- scr
->scrollerDimple
->width
- 1) / 2,
418 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->height
- 1) / 2);
420 W_DrawRelief(scr
, d
, 2, ofs
+ (int)knobP
, view
->size
.width
- 4, (int)knobL
, WRRaised
);
423 if ((int)(knobP
+ knobL
) < length
)
424 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
425 2, ofs
+ (int)(knobP
+ knobL
),
426 view
->size
.width
- 4, length
- (int)(knobP
+ knobL
));
429 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
430 paintArrow(sPtr
, d
, 0);
431 paintArrow(sPtr
, d
, 1);
436 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0, view
->size
.width
, view
->size
.height
, 0, 0);
437 XFreePixmap(scr
->display
, d
);
441 static void handleEvents(XEvent
* event
, void *data
)
443 Scroller
*sPtr
= (Scroller
*) data
;
445 CHECK_CLASS(data
, WC_Scroller
);
447 switch (event
->type
) {
449 if (event
->xexpose
.count
== 0)
454 destroyScroller(sPtr
);
460 * locatePointInScroller-
461 * Return the part of the scroller where the point is located.
463 static WMScrollerPart
locatePointInScroller(Scroller
* sPtr
, int x
, int y
, int alternate
)
465 int width
= sPtr
->view
->size
.width
;
466 int height
= sPtr
->view
->size
.height
;
467 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
470 /* if there is no knob... */
471 if (sPtr
->flags
.documentFullyVisible
)
474 if (sPtr
->flags
.horizontal
)
480 * | | |###########| |#####| | |
481 * | < | > |###########| O |#####| < | > |
482 * | | |###########| |#####| | |
485 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
489 if (sPtr
->flags
.horizontal
) {
497 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
498 if (sPtr
->flags
.horizontal
) {
512 if (sPtr
->flags
.horizontal
) {
513 slotL
= p5
= p6
= width
;
515 slotL
= p5
= p6
= height
;
519 knobL
= knobLength(sPtr
);
520 p3
= p2
+ (int)((float)(slotL
- knobL
) * sPtr
->floatValue
);
523 /* uses a mix of the NS and Win ways of doing scroll page */
525 return alternate
? WSDecrementPage
: WSDecrementLine
;
527 return alternate
? WSIncrementPage
: WSIncrementLine
;
529 return WSDecrementPage
;
533 return WSIncrementPage
;
535 return alternate
? WSDecrementPage
: WSDecrementLine
;
537 return alternate
? WSIncrementPage
: WSIncrementLine
;
540 static void handlePush(Scroller
* sPtr
, int pushX
, int pushY
, int alternate
)
545 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
547 sPtr
->flags
.hitPart
= part
;
550 case WSIncrementLine
:
551 sPtr
->flags
.incrDown
= 1;
555 case WSIncrementPage
:
559 case WSDecrementLine
:
560 sPtr
->flags
.decrDown
= 1;
564 case WSDecrementPage
:
569 sPtr
->flags
.draggingKnob
= 1;
570 #ifndef STRICT_NEXT_BEHAVIOUR
571 if (sPtr
->flags
.horizontal
)
572 sPtr
->dragPoint
= pushX
;
574 sPtr
->dragPoint
= pushY
;
580 if (sPtr
->flags
.arrowsPosition
!= WSANone
)
581 buttonsLen
= 2 * (BUTTON_SIZE
+ 1);
585 if (sPtr
->flags
.horizontal
)
586 length
= sPtr
->view
->size
.width
- 4 - buttonsLen
;
588 length
= sPtr
->view
->size
.height
- 4 - buttonsLen
;
590 knobP
= (int)(sPtr
->floatValue
* (float)(length
- knobLength(sPtr
)));
592 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
593 sPtr
->dragPoint
-= 2 + buttonsLen
+ knobP
;
595 sPtr
->dragPoint
-= 2 + knobP
;
597 #endif /* STRICT_NEXT_BEHAVIOUR */
598 /* This does not seem necesary here since we don't know yet if the
599 * knob will be dragged later. -Dan
600 handleMotion(sPtr, pushX, pushY); */
603 case WSDecrementWheel
:
604 case WSIncrementWheel
:
611 if (doAction
&& sPtr
->action
) {
612 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
614 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
618 static float floatValueForPoint(Scroller
* sPtr
, int point
)
620 float floatValue
= 0;
622 int slotOfs
, slotLength
, knobL
;
624 if (sPtr
->flags
.horizontal
)
625 slotLength
= sPtr
->view
->size
.width
- 4;
627 slotLength
= sPtr
->view
->size
.height
- 4;
630 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
631 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
632 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
633 slotOfs
+= (BUTTON_SIZE
+ 1) * 2;
634 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
637 knobL
= (float)knobLength(sPtr
);
638 #ifdef STRICT_NEXT_BEHAVIOUR
639 if (point
< slotOfs
+ knobL
/ 2)
640 position
= (float)(slotOfs
+ knobL
/ 2);
641 else if (point
> slotOfs
+ slotLength
- knobL
/ 2)
642 position
= (float)(slotOfs
+ slotLength
- knobL
/ 2);
644 position
= (float)point
;
646 floatValue
= (position
- (float)(slotOfs
+ slotLength
/ 2))
647 / (float)(slotLength
- knobL
);
649 /* Adjust the last point to lie inside the knob slot */
651 position
= (float)slotOfs
;
652 else if (point
> slotOfs
+ slotLength
)
653 position
= (float)(slotOfs
+ slotLength
);
655 position
= (float)point
;
657 /* Compute the float value */
658 floatValue
= (position
- (float)slotOfs
) / (float)(slotLength
- knobL
);
661 assert(!isnan(floatValue
));
665 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
)
667 if (sPtr
->flags
.draggingKnob
) {
671 if (sPtr
->flags
.horizontal
) {
677 #ifndef STRICT_NEXT_BEHAVIOUR
678 point
-= sPtr
->dragPoint
;
681 newFloatValue
= floatValueForPoint(sPtr
, point
);
682 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
684 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
685 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
690 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
692 sPtr
->flags
.hitPart
= part
;
694 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
695 sPtr
->flags
.decrDown
= 0;
696 sPtr
->flags
.incrDown
= 1;
697 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
698 sPtr
->flags
.incrDown
= 0;
699 sPtr
->flags
.decrDown
= 1;
700 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
701 sPtr
->flags
.incrDown
= 0;
702 sPtr
->flags
.decrDown
= 0;
707 static void autoScroll(void *clientData
)
709 Scroller
*sPtr
= (Scroller
*) clientData
;
712 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
713 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
715 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
718 static void handleActionEvents(XEvent
* event
, void *data
)
720 Scroller
*sPtr
= (Scroller
*) data
;
721 int wheelDecrement
, wheelIncrement
;
724 /* check if we're really dealing with a scroller, as something
725 * might have gone wrong in the event dispatching stuff */
726 CHECK_CLASS(sPtr
, WC_Scroller
);
728 id
= sPtr
->flags
.incrDown
;
729 dd
= sPtr
->flags
.decrDown
;
731 switch (event
->type
) {
737 WMDeleteTimerHandler(sPtr
->timerID
);
738 sPtr
->timerID
= NULL
;
740 sPtr
->flags
.incrDown
= 0;
741 sPtr
->flags
.decrDown
= 0;
745 /* FIXME: change Mod1Mask with something else */
746 if (sPtr
->flags
.documentFullyVisible
)
749 if (sPtr
->flags
.horizontal
) {
750 wheelDecrement
= WINGsConfiguration
.mouseWheelDown
;
751 wheelIncrement
= WINGsConfiguration
.mouseWheelUp
;
753 wheelDecrement
= WINGsConfiguration
.mouseWheelUp
;
754 wheelIncrement
= WINGsConfiguration
.mouseWheelDown
;
757 if (event
->xbutton
.button
== wheelDecrement
) {
758 if (event
->xbutton
.state
& ControlMask
) {
759 sPtr
->flags
.hitPart
= WSDecrementPage
;
760 } else if (event
->xbutton
.state
& ShiftMask
) {
761 sPtr
->flags
.hitPart
= WSDecrementLine
;
763 sPtr
->flags
.hitPart
= WSDecrementWheel
;
766 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
767 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
769 } else if (event
->xbutton
.button
== wheelIncrement
) {
770 if (event
->xbutton
.state
& ControlMask
) {
771 sPtr
->flags
.hitPart
= WSIncrementPage
;
772 } else if (event
->xbutton
.state
& ShiftMask
) {
773 sPtr
->flags
.hitPart
= WSIncrementLine
;
775 sPtr
->flags
.hitPart
= WSIncrementWheel
;
778 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
779 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
782 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
, (event
->xbutton
.state
& Mod1Mask
)
783 || event
->xbutton
.button
== Button2
);
784 /* continue scrolling if pushed on the buttons */
785 if (sPtr
->flags
.hitPart
== WSIncrementLine
|| sPtr
->flags
.hitPart
== WSDecrementLine
) {
786 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
, autoScroll
, sPtr
);
792 if (sPtr
->flags
.draggingKnob
) {
794 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
795 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
799 WMDeleteTimerHandler(sPtr
->timerID
);
800 sPtr
->timerID
= NULL
;
802 sPtr
->flags
.incrDown
= 0;
803 sPtr
->flags
.decrDown
= 0;
804 sPtr
->flags
.draggingKnob
= 0;
808 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
809 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
810 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
811 WMDeleteTimerHandler(sPtr
->timerID
);
812 sPtr
->timerID
= NULL
;
816 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
820 static void destroyScroller(Scroller
* sPtr
)
822 /* we don't want autoscroll try to scroll a freed widget */
824 WMDeleteTimerHandler(sPtr
->timerID
);