3 * Until FreeBSD gets their act together;
4 * http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
14 /* undefine will disable the autoadjusting of the knob dimple to be
15 * directly below the cursor
17 #undef STRICT_NEXT_BEHAVIOUR
19 #define AUTOSCROLL_INITIAL_DELAY 200
21 #define AUTOSCROLL_DELAY 40
23 char *WMScrollerDidScrollNotification
= "WMScrollerDidScrollNotification";
25 typedef struct W_Scroller
{
35 WMHandlerID timerID
; /* for continuous scrolling mode */
37 #ifndef STRICT_NEXT_BEHAVIOUR
38 int dragPoint
; /* point where the knob is being
42 WMScrollArrowPosition arrowsPosition
:4;
44 unsigned int horizontal
:1;
46 WMScrollerPart hitPart
:4;
49 unsigned int documentFullyVisible
:1; /* document is fully visible */
51 unsigned int prevSelected
:1;
53 unsigned int pushed
:1;
55 unsigned int incrDown
:1; /* whether increment button is down */
57 unsigned int decrDown
:1;
59 unsigned int draggingKnob
:1;
61 unsigned int configured
:1;
63 unsigned int redrawPending
:1;
67 #define DEFAULT_HEIGHT 60
68 #define DEFAULT_WIDTH SCROLLER_WIDTH
69 #define DEFAULT_ARROWS_POSITION WSAMinEnd
71 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
73 static void destroyScroller(Scroller
* sPtr
);
74 static void paintScroller(Scroller
* sPtr
);
76 static void willResizeScroller();
77 static void handleEvents(XEvent
* event
, void *data
);
78 static void handleActionEvents(XEvent
* event
, void *data
);
80 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
);
82 W_ViewDelegate _ScrollerViewDelegate
= {
90 WMScroller
*WMCreateScroller(WMWidget
* parent
)
94 sPtr
= wmalloc(sizeof(Scroller
));
95 sPtr
->widgetClass
= WC_Scroller
;
97 sPtr
->view
= W_CreateView(W_VIEW(parent
));
102 sPtr
->view
->self
= sPtr
;
104 sPtr
->view
->delegate
= &_ScrollerViewDelegate
;
106 sPtr
->flags
.documentFullyVisible
= 1;
108 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
109 | ClientMessageMask
, handleEvents
, sPtr
);
111 W_ResizeView(sPtr
->view
, DEFAULT_WIDTH
, DEFAULT_WIDTH
);
112 sPtr
->flags
.arrowsPosition
= DEFAULT_ARROWS_POSITION
;
114 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
115 | EnterWindowMask
| LeaveWindowMask
| ButtonMotionMask
, handleActionEvents
, sPtr
);
117 sPtr
->flags
.hitPart
= WSNoPart
;
119 sPtr
->floatValue
= 0.0;
120 sPtr
->knobProportion
= 1.0;
125 void WMSetScrollerArrowsPosition(WMScroller
* sPtr
, WMScrollArrowPosition position
)
127 sPtr
->flags
.arrowsPosition
= position
;
128 if (sPtr
->view
->flags
.realized
) {
133 static void willResizeScroller(W_ViewDelegate
* self
, WMView
* view
, unsigned int *width
, unsigned int *height
)
135 WMScroller
*sPtr
= (WMScroller
*) view
->self
;
137 if (*width
> *height
) {
138 sPtr
->flags
.horizontal
= 1;
139 *height
= SCROLLER_WIDTH
;
141 sPtr
->flags
.horizontal
= 0;
142 *width
= SCROLLER_WIDTH
;
146 void WMSetScrollerAction(WMScroller
* sPtr
, WMAction
* action
, void *clientData
)
148 CHECK_CLASS(sPtr
, WC_Scroller
);
150 sPtr
->action
= action
;
152 sPtr
->clientData
= clientData
;
155 void WMSetScrollerParameters(WMScroller
* sPtr
, float floatValue
, float knobProportion
)
157 CHECK_CLASS(sPtr
, WC_Scroller
);
159 assert(!isnan(floatValue
));
161 if (floatValue
< 0.0)
162 sPtr
->floatValue
= 0.0;
163 else if (floatValue
> 1.0)
164 sPtr
->floatValue
= 1.0;
166 sPtr
->floatValue
= floatValue
;
168 if (knobProportion
<= 0.0) {
170 sPtr
->knobProportion
= 0.0;
171 sPtr
->flags
.documentFullyVisible
= 0;
173 } else if (knobProportion
>= 1.0) {
175 sPtr
->knobProportion
= 1.0;
176 sPtr
->flags
.documentFullyVisible
= 1;
179 sPtr
->knobProportion
= knobProportion
;
180 sPtr
->flags
.documentFullyVisible
= 0;
183 if (sPtr
->view
->flags
.realized
)
186 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
189 float WMGetScrollerKnobProportion(WMScroller
* sPtr
)
191 CHECK_CLASS(sPtr
, WC_Scroller
);
193 return sPtr
->knobProportion
;
196 float WMGetScrollerValue(WMScroller
* sPtr
)
198 CHECK_CLASS(sPtr
, WC_Scroller
);
200 return sPtr
->floatValue
;
203 WMScrollerPart
WMGetScrollerHitPart(WMScroller
* sPtr
)
205 CHECK_CLASS(sPtr
, WC_Scroller
);
207 return sPtr
->flags
.hitPart
;
210 static void paintArrow(WMScroller
* sPtr
, Drawable d
, int part
)
212 * part- 0 paints the decrement arrow, 1 the increment arrow
215 WMView
*view
= sPtr
->view
;
216 WMScreen
*scr
= view
->screen
;
220 #ifndef DOUBLE_BUFFER
221 GC gc
= scr
->lightGC
;
224 if (part
== 0) { /* decrement button */
225 if (sPtr
->flags
.horizontal
) {
226 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
227 ofs
= view
->size
.width
- 2 * (BUTTON_SIZE
+ 1) - 1;
231 if (sPtr
->flags
.decrDown
)
232 arrow
= scr
->hiLeftArrow
;
234 arrow
= scr
->leftArrow
;
237 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
238 ofs
= view
->size
.height
- 2 * (BUTTON_SIZE
+ 1) - 1;
242 if (sPtr
->flags
.decrDown
)
243 arrow
= scr
->hiUpArrow
;
245 arrow
= scr
->upArrow
;
248 #ifndef DOUBLE_BUFFER
249 if (sPtr
->flags
.decrDown
)
250 gc
= WMColorGC(scr
->white
);
252 } else { /* increment button */
253 if (sPtr
->flags
.horizontal
) {
254 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
255 ofs
= view
->size
.width
- BUTTON_SIZE
+ 1 - 3;
257 ofs
= 2 + BUTTON_SIZE
+ 1;
259 if (sPtr
->flags
.incrDown
)
260 arrow
= scr
->hiRightArrow
;
262 arrow
= scr
->rightArrow
;
264 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
265 ofs
= view
->size
.height
- BUTTON_SIZE
+ 1 - 3;
267 ofs
= 2 + BUTTON_SIZE
+ 1;
269 if (sPtr
->flags
.incrDown
)
270 arrow
= scr
->hiDownArrow
;
272 arrow
= scr
->downArrow
;
275 #ifndef DOUBLE_BUFFER
276 if (sPtr
->flags
.incrDown
)
281 if (sPtr
->flags
.horizontal
) {
283 #ifndef DOUBLE_BUFFER
284 XFillRectangle(scr
->display
, d
, gc
, ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
286 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
287 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
288 ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
289 #endif /* DOUBLE_BUFFER */
290 W_DrawRelief(scr
, d
, ofs
, 2, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
293 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
294 XSetClipOrigin(scr
->display
, scr
->clipGC
,
295 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
297 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
298 0, 0, arrow
->width
, arrow
->height
,
299 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
301 } else { /* vertical */
304 #ifndef DOUBLE_BUFFER
305 XFillRectangle(scr
->display
, d
, gc
, 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
307 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
308 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
309 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
310 #endif /* DOUBLE_BUFFER */
311 W_DrawRelief(scr
, d
, 2, ofs
, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
315 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
316 XSetClipOrigin(scr
->display
, scr
->clipGC
,
317 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
318 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
319 0, 0, arrow
->width
, arrow
->height
,
320 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
324 static int knobLength(Scroller
* sPtr
)
328 if (sPtr
->flags
.horizontal
)
329 length
= sPtr
->view
->size
.width
- 4;
331 length
= sPtr
->view
->size
.height
- 4;
333 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
334 length
-= 2 * (BUTTON_SIZE
+ 1);
337 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5);
338 /* keep minimum size */
339 if (tmp
< BUTTON_SIZE
)
345 static void paintScroller(Scroller
* sPtr
)
347 WMView
*view
= sPtr
->view
;
348 WMScreen
*scr
= view
->screen
;
352 Drawable d
= view
->window
;
358 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
, view
->size
.height
, scr
->depth
);
359 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0, view
->size
.width
, view
->size
.height
);
362 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0, view
->size
.width
- 1, view
->size
.height
- 1);
363 #ifndef DOUBLE_BUFFER
364 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1, view
->size
.width
- 3, view
->size
.height
- 3);
367 if (sPtr
->flags
.horizontal
)
368 length
= view
->size
.width
- 4;
370 length
= view
->size
.height
- 4;
372 if (sPtr
->flags
.documentFullyVisible
) {
373 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2, view
->size
.width
- 4, view
->size
.height
- 4);
376 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
377 length
-= (BUTTON_SIZE
+ 1) * 2;
378 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
379 ofs
+= (BUTTON_SIZE
+ 1) * 2;
380 length
-= (BUTTON_SIZE
+ 1) * 2;
383 knobL
= (float)knobLength(sPtr
);
385 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
387 if (sPtr
->flags
.horizontal
) {
389 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, ofs
, 2, (int)knobP
, view
->size
.height
- 4);
392 #ifndef DOUBLE_BUFFER
393 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
394 ofs
+ (int)knobP
+ 2, 2 + 2, (int)knobL
- 4, view
->size
.height
- 4 - 4);
396 W_DrawRelief(scr
, d
, ofs
+ (int)knobP
, 2, (int)knobL
, view
->size
.height
- 4, WRRaised
);
398 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
400 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
401 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->width
- 1) / 2,
402 (view
->size
.height
- scr
->scrollerDimple
->height
- 1) / 2);
405 if ((int)(knobP
+ knobL
) < length
)
406 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
407 ofs
+ (int)(knobP
+ knobL
), 2,
408 length
- (int)(knobP
+ knobL
), view
->size
.height
- 4);
412 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
413 2, ofs
, view
->size
.width
- 4, (int)knobP
);
416 #ifndef DOUBLE_BUFFER
417 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
418 2 + 2, ofs
+ (int)knobP
+ 2, view
->size
.width
- 4 - 4, (int)knobL
- 4);
420 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
422 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
423 (view
->size
.width
- scr
->scrollerDimple
->width
- 1) / 2,
424 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->height
- 1) / 2);
426 W_DrawRelief(scr
, d
, 2, ofs
+ (int)knobP
, view
->size
.width
- 4, (int)knobL
, WRRaised
);
429 if ((int)(knobP
+ knobL
) < length
)
430 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
431 2, ofs
+ (int)(knobP
+ knobL
),
432 view
->size
.width
- 4, length
- (int)(knobP
+ knobL
));
435 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
436 paintArrow(sPtr
, d
, 0);
437 paintArrow(sPtr
, d
, 1);
442 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0, view
->size
.width
, view
->size
.height
, 0, 0);
443 XFreePixmap(scr
->display
, d
);
447 static void handleEvents(XEvent
* event
, void *data
)
449 Scroller
*sPtr
= (Scroller
*) data
;
451 CHECK_CLASS(data
, WC_Scroller
);
453 switch (event
->type
) {
455 if (event
->xexpose
.count
== 0)
460 destroyScroller(sPtr
);
466 * locatePointInScroller-
467 * Return the part of the scroller where the point is located.
469 static WMScrollerPart
locatePointInScroller(Scroller
* sPtr
, int x
, int y
, int alternate
)
471 int width
= sPtr
->view
->size
.width
;
472 int height
= sPtr
->view
->size
.height
;
473 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
476 /* if there is no knob... */
477 if (sPtr
->flags
.documentFullyVisible
)
480 if (sPtr
->flags
.horizontal
)
486 * | | |###########| |#####| | |
487 * | < | > |###########| O |#####| < | > |
488 * | | |###########| |#####| | |
491 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
495 if (sPtr
->flags
.horizontal
) {
503 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
504 if (sPtr
->flags
.horizontal
) {
518 if (sPtr
->flags
.horizontal
) {
519 slotL
= p5
= p6
= width
;
521 slotL
= p5
= p6
= height
;
525 knobL
= knobLength(sPtr
);
526 p3
= p2
+ (int)((float)(slotL
- knobL
) * sPtr
->floatValue
);
529 /* uses a mix of the NS and Win ways of doing scroll page */
531 return alternate
? WSDecrementPage
: WSDecrementLine
;
533 return alternate
? WSIncrementPage
: WSIncrementLine
;
535 return WSDecrementPage
;
539 return WSIncrementPage
;
541 return alternate
? WSDecrementPage
: WSDecrementLine
;
543 return alternate
? WSIncrementPage
: WSIncrementLine
;
546 static void handlePush(Scroller
* sPtr
, int pushX
, int pushY
, int alternate
)
551 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
553 sPtr
->flags
.hitPart
= part
;
556 case WSIncrementLine
:
557 sPtr
->flags
.incrDown
= 1;
561 case WSIncrementPage
:
565 case WSDecrementLine
:
566 sPtr
->flags
.decrDown
= 1;
570 case WSDecrementPage
:
575 sPtr
->flags
.draggingKnob
= 1;
576 #ifndef STRICT_NEXT_BEHAVIOUR
577 if (sPtr
->flags
.horizontal
)
578 sPtr
->dragPoint
= pushX
;
580 sPtr
->dragPoint
= pushY
;
586 if (sPtr
->flags
.arrowsPosition
!= WSANone
)
587 buttonsLen
= 2 * (BUTTON_SIZE
+ 1);
591 if (sPtr
->flags
.horizontal
)
592 length
= sPtr
->view
->size
.width
- 4 - buttonsLen
;
594 length
= sPtr
->view
->size
.height
- 4 - buttonsLen
;
596 knobP
= (int)(sPtr
->floatValue
* (float)(length
- knobLength(sPtr
)));
598 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
599 sPtr
->dragPoint
-= 2 + buttonsLen
+ knobP
;
601 sPtr
->dragPoint
-= 2 + knobP
;
603 #endif /* STRICT_NEXT_BEHAVIOUR */
604 /* This does not seem necesary here since we don't know yet if the
605 * knob will be dragged later. -Dan
606 handleMotion(sPtr, pushX, pushY); */
609 case WSDecrementWheel
:
610 case WSIncrementWheel
:
617 if (doAction
&& sPtr
->action
) {
618 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
620 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
624 static float floatValueForPoint(Scroller
* sPtr
, int point
)
626 float floatValue
= 0;
628 int slotOfs
, slotLength
, knobL
;
630 if (sPtr
->flags
.horizontal
)
631 slotLength
= sPtr
->view
->size
.width
- 4;
633 slotLength
= sPtr
->view
->size
.height
- 4;
636 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
637 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
638 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
639 slotOfs
+= (BUTTON_SIZE
+ 1) * 2;
640 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
643 knobL
= (float)knobLength(sPtr
);
644 #ifdef STRICT_NEXT_BEHAVIOUR
645 if (point
< slotOfs
+ knobL
/ 2)
646 position
= (float)(slotOfs
+ knobL
/ 2);
647 else if (point
> slotOfs
+ slotLength
- knobL
/ 2)
648 position
= (float)(slotOfs
+ slotLength
- knobL
/ 2);
650 position
= (float)point
;
652 floatValue
= (position
- (float)(slotOfs
+ slotLength
/ 2))
653 / (float)(slotLength
- knobL
);
655 /* Adjust the last point to lie inside the knob slot */
657 position
= (float)slotOfs
;
658 else if (point
> slotOfs
+ slotLength
)
659 position
= (float)(slotOfs
+ slotLength
);
661 position
= (float)point
;
663 /* Compute the float value */
664 floatValue
= (position
- (float)slotOfs
) / (float)(slotLength
- knobL
);
667 assert(!isnan(floatValue
));
671 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
)
673 if (sPtr
->flags
.draggingKnob
) {
677 if (sPtr
->flags
.horizontal
) {
683 #ifndef STRICT_NEXT_BEHAVIOUR
684 point
-= sPtr
->dragPoint
;
687 newFloatValue
= floatValueForPoint(sPtr
, point
);
688 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
690 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
691 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
696 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
698 sPtr
->flags
.hitPart
= part
;
700 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
701 sPtr
->flags
.decrDown
= 0;
702 sPtr
->flags
.incrDown
= 1;
703 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
704 sPtr
->flags
.incrDown
= 0;
705 sPtr
->flags
.decrDown
= 1;
706 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
707 sPtr
->flags
.incrDown
= 0;
708 sPtr
->flags
.decrDown
= 0;
713 static void autoScroll(void *clientData
)
715 Scroller
*sPtr
= (Scroller
*) clientData
;
718 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
719 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
721 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
724 static void handleActionEvents(XEvent
* event
, void *data
)
726 Scroller
*sPtr
= (Scroller
*) data
;
727 int wheelDecrement
, wheelIncrement
;
730 /* check if we're really dealing with a scroller, as something
731 * might have gone wrong in the event dispatching stuff */
732 CHECK_CLASS(sPtr
, WC_Scroller
);
734 id
= sPtr
->flags
.incrDown
;
735 dd
= sPtr
->flags
.decrDown
;
737 switch (event
->type
) {
743 WMDeleteTimerHandler(sPtr
->timerID
);
744 sPtr
->timerID
= NULL
;
746 sPtr
->flags
.incrDown
= 0;
747 sPtr
->flags
.decrDown
= 0;
751 /* FIXME: change Mod1Mask with something else */
752 if (sPtr
->flags
.documentFullyVisible
)
755 if (sPtr
->flags
.horizontal
) {
756 wheelDecrement
= WINGsConfiguration
.mouseWheelDown
;
757 wheelIncrement
= WINGsConfiguration
.mouseWheelUp
;
759 wheelDecrement
= WINGsConfiguration
.mouseWheelUp
;
760 wheelIncrement
= WINGsConfiguration
.mouseWheelDown
;
763 if (event
->xbutton
.button
== wheelDecrement
) {
764 if (event
->xbutton
.state
& ControlMask
) {
765 sPtr
->flags
.hitPart
= WSDecrementPage
;
766 } else if (event
->xbutton
.state
& ShiftMask
) {
767 sPtr
->flags
.hitPart
= WSDecrementLine
;
769 sPtr
->flags
.hitPart
= WSDecrementWheel
;
772 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
773 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
775 } else if (event
->xbutton
.button
== wheelIncrement
) {
776 if (event
->xbutton
.state
& ControlMask
) {
777 sPtr
->flags
.hitPart
= WSIncrementPage
;
778 } else if (event
->xbutton
.state
& ShiftMask
) {
779 sPtr
->flags
.hitPart
= WSIncrementLine
;
781 sPtr
->flags
.hitPart
= WSIncrementWheel
;
784 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
785 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
788 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
, (event
->xbutton
.state
& Mod1Mask
)
789 || event
->xbutton
.button
== Button2
);
790 /* continue scrolling if pushed on the buttons */
791 if (sPtr
->flags
.hitPart
== WSIncrementLine
|| sPtr
->flags
.hitPart
== WSDecrementLine
) {
792 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
, autoScroll
, sPtr
);
798 if (sPtr
->flags
.draggingKnob
) {
800 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
801 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
805 WMDeleteTimerHandler(sPtr
->timerID
);
806 sPtr
->timerID
= NULL
;
808 sPtr
->flags
.incrDown
= 0;
809 sPtr
->flags
.decrDown
= 0;
810 sPtr
->flags
.draggingKnob
= 0;
814 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
815 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
816 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
817 WMDeleteTimerHandler(sPtr
->timerID
);
818 sPtr
->timerID
= NULL
;
822 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
826 static void destroyScroller(Scroller
* sPtr
)
828 /* we don't want autoscroll try to scroll a freed widget */
830 WMDeleteTimerHandler(sPtr
->timerID
);