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 const 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_ARROWS_POSITION WSAMinEnd
69 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
71 static void destroyScroller(Scroller
* sPtr
);
72 static void paintScroller(Scroller
* sPtr
);
74 static void willResizeScroller(W_ViewDelegate
* self
, WMView
* view
, unsigned int *width
, unsigned int *height
);
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
);
80 W_ViewDelegate _ScrollerViewDelegate
= {
88 WMScroller
*WMCreateScroller(WMWidget
* parent
)
92 sPtr
= wmalloc(sizeof(Scroller
));
93 sPtr
->widgetClass
= WC_Scroller
;
95 sPtr
->view
= W_CreateView(W_VIEW(parent
));
100 sPtr
->view
->self
= sPtr
;
102 sPtr
->view
->delegate
= &_ScrollerViewDelegate
;
104 sPtr
->flags
.documentFullyVisible
= 1;
106 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
107 | ClientMessageMask
, handleEvents
, sPtr
);
109 W_ResizeView(sPtr
->view
, SCROLLER_WIDTH
, SCROLLER_WIDTH
);
110 sPtr
->flags
.arrowsPosition
= DEFAULT_ARROWS_POSITION
;
112 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
113 | EnterWindowMask
| LeaveWindowMask
| ButtonMotionMask
, handleActionEvents
, sPtr
);
115 sPtr
->flags
.hitPart
= WSNoPart
;
117 sPtr
->floatValue
= 0.0;
118 sPtr
->knobProportion
= 1.0;
123 void WMSetScrollerArrowsPosition(WMScroller
* sPtr
, WMScrollArrowPosition position
)
125 sPtr
->flags
.arrowsPosition
= position
;
126 if (sPtr
->view
->flags
.realized
) {
131 static void willResizeScroller(W_ViewDelegate
* self
, WMView
* view
, unsigned int *width
, unsigned int *height
)
133 WMScroller
*sPtr
= (WMScroller
*) view
->self
;
135 /* Parameter not used, but tell the compiler that it is ok */
138 if (*width
> *height
) {
139 sPtr
->flags
.horizontal
= 1;
140 *height
= SCROLLER_WIDTH
;
142 sPtr
->flags
.horizontal
= 0;
143 *width
= SCROLLER_WIDTH
;
147 void WMSetScrollerAction(WMScroller
* sPtr
, WMAction
* action
, void *clientData
)
149 CHECK_CLASS(sPtr
, WC_Scroller
);
151 sPtr
->action
= action
;
153 sPtr
->clientData
= clientData
;
156 void WMSetScrollerParameters(WMScroller
* sPtr
, float floatValue
, float knobProportion
)
159 * This value represents 1 pixel on a 4k wide screen, it makes
160 * a good minimum; this ensure a non-null value to avoid
161 * potential division-by-0.
162 * Please note that there is another size check when drawing
163 * the knob to make sure it will remain selectable.
165 static const float min_knob_proportion
= 1.0 / 4096.0;
167 CHECK_CLASS(sPtr
, WC_Scroller
);
169 assert(!isnan(floatValue
));
171 if (floatValue
< 0.0F
)
172 sPtr
->floatValue
= 0.0F
;
173 else if (floatValue
> 1.0F
)
174 sPtr
->floatValue
= 1.0F
;
176 sPtr
->floatValue
= floatValue
;
178 if (knobProportion
<= min_knob_proportion
) {
180 sPtr
->knobProportion
= min_knob_proportion
;
181 sPtr
->flags
.documentFullyVisible
= 0;
183 } else if (knobProportion
>= 1.0F
) {
185 sPtr
->knobProportion
= 1.0F
;
186 sPtr
->flags
.documentFullyVisible
= 1;
189 sPtr
->knobProportion
= knobProportion
;
190 sPtr
->flags
.documentFullyVisible
= 0;
193 if (sPtr
->view
->flags
.realized
)
196 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
199 float WMGetScrollerKnobProportion(WMScroller
* sPtr
)
201 CHECK_CLASS(sPtr
, WC_Scroller
);
203 return sPtr
->knobProportion
;
206 float WMGetScrollerValue(WMScroller
* sPtr
)
208 CHECK_CLASS(sPtr
, WC_Scroller
);
210 return sPtr
->floatValue
;
213 WMScrollerPart
WMGetScrollerHitPart(WMScroller
* sPtr
)
215 CHECK_CLASS(sPtr
, WC_Scroller
);
217 return sPtr
->flags
.hitPart
;
220 static void paintArrow(WMScroller
* sPtr
, Drawable d
, int part
)
222 * part- 0 paints the decrement arrow, 1 the increment arrow
225 WMView
*view
= sPtr
->view
;
226 WMScreen
*scr
= view
->screen
;
230 #ifndef DOUBLE_BUFFER
231 GC gc
= scr
->lightGC
;
234 if (part
== 0) { /* decrement button */
235 if (sPtr
->flags
.horizontal
) {
236 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
237 ofs
= view
->size
.width
- 2 * (BUTTON_SIZE
+ 1) - 1;
241 if (sPtr
->flags
.decrDown
)
242 arrow
= scr
->hiLeftArrow
;
244 arrow
= scr
->leftArrow
;
247 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
248 ofs
= view
->size
.height
- 2 * (BUTTON_SIZE
+ 1) - 1;
252 if (sPtr
->flags
.decrDown
)
253 arrow
= scr
->hiUpArrow
;
255 arrow
= scr
->upArrow
;
258 #ifndef DOUBLE_BUFFER
259 if (sPtr
->flags
.decrDown
)
260 gc
= WMColorGC(scr
->white
);
262 } else { /* increment button */
263 if (sPtr
->flags
.horizontal
) {
264 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
265 ofs
= view
->size
.width
- BUTTON_SIZE
+ 1 - 3;
267 ofs
= 2 + BUTTON_SIZE
+ 1;
269 if (sPtr
->flags
.incrDown
)
270 arrow
= scr
->hiRightArrow
;
272 arrow
= scr
->rightArrow
;
274 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
275 ofs
= view
->size
.height
- BUTTON_SIZE
+ 1 - 3;
277 ofs
= 2 + BUTTON_SIZE
+ 1;
279 if (sPtr
->flags
.incrDown
)
280 arrow
= scr
->hiDownArrow
;
282 arrow
= scr
->downArrow
;
285 #ifndef DOUBLE_BUFFER
286 if (sPtr
->flags
.incrDown
)
291 if (sPtr
->flags
.horizontal
) {
293 #ifndef DOUBLE_BUFFER
294 XFillRectangle(scr
->display
, d
, gc
, ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
296 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
297 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
298 ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
299 #endif /* DOUBLE_BUFFER */
300 W_DrawRelief(scr
, d
, ofs
, 2, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
303 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
304 XSetClipOrigin(scr
->display
, scr
->clipGC
,
305 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
307 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
308 0, 0, arrow
->width
, arrow
->height
,
309 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
311 } else { /* vertical */
314 #ifndef DOUBLE_BUFFER
315 XFillRectangle(scr
->display
, d
, gc
, 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
317 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
318 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
319 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
320 #endif /* DOUBLE_BUFFER */
321 W_DrawRelief(scr
, d
, 2, ofs
, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
325 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
326 XSetClipOrigin(scr
->display
, scr
->clipGC
,
327 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
328 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
329 0, 0, arrow
->width
, arrow
->height
,
330 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
334 static int knobLength(Scroller
* sPtr
)
338 if (sPtr
->flags
.horizontal
)
339 length
= sPtr
->view
->size
.width
- 4;
341 length
= sPtr
->view
->size
.height
- 4;
343 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
344 length
-= 2 * (BUTTON_SIZE
+ 1);
347 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5F
);
348 /* keep minimum size */
349 if (tmp
< BUTTON_SIZE
)
355 static void paintScroller(Scroller
* sPtr
)
357 WMView
*view
= sPtr
->view
;
358 WMScreen
*scr
= view
->screen
;
362 Drawable d
= view
->window
;
368 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
, view
->size
.height
, scr
->depth
);
369 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0, view
->size
.width
, view
->size
.height
);
372 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0, view
->size
.width
- 1, view
->size
.height
- 1);
373 #ifndef DOUBLE_BUFFER
374 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1, view
->size
.width
- 3, view
->size
.height
- 3);
377 if (sPtr
->flags
.horizontal
)
378 length
= view
->size
.width
- 4;
380 length
= view
->size
.height
- 4;
382 if (sPtr
->flags
.documentFullyVisible
) {
383 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2, view
->size
.width
- 4, view
->size
.height
- 4);
386 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
387 length
-= (BUTTON_SIZE
+ 1) * 2;
388 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
389 ofs
+= (BUTTON_SIZE
+ 1) * 2;
390 length
-= (BUTTON_SIZE
+ 1) * 2;
393 knobL
= (float)knobLength(sPtr
);
395 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
397 if (sPtr
->flags
.horizontal
) {
399 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, ofs
, 2, (int)knobP
, view
->size
.height
- 4);
402 #ifndef DOUBLE_BUFFER
403 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
404 ofs
+ (int)knobP
+ 2, 2 + 2, (int)knobL
- 4, view
->size
.height
- 4 - 4);
406 W_DrawRelief(scr
, d
, ofs
+ (int)knobP
, 2, (int)knobL
, view
->size
.height
- 4, WRRaised
);
408 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
410 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
411 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->width
- 1) / 2,
412 (view
->size
.height
- scr
->scrollerDimple
->height
- 1) / 2);
415 if ((int)(knobP
+ knobL
) < length
)
416 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
417 ofs
+ (int)(knobP
+ knobL
), 2,
418 length
- (int)(knobP
+ knobL
), view
->size
.height
- 4);
422 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
423 2, ofs
, view
->size
.width
- 4, (int)knobP
);
426 #ifndef DOUBLE_BUFFER
427 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
428 2 + 2, ofs
+ (int)knobP
+ 2, view
->size
.width
- 4 - 4, (int)knobL
- 4);
430 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
432 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
433 (view
->size
.width
- scr
->scrollerDimple
->width
- 1) / 2,
434 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->height
- 1) / 2);
436 W_DrawRelief(scr
, d
, 2, ofs
+ (int)knobP
, view
->size
.width
- 4, (int)knobL
, WRRaised
);
439 if ((int)(knobP
+ knobL
) < length
)
440 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
441 2, ofs
+ (int)(knobP
+ knobL
),
442 view
->size
.width
- 4, length
- (int)(knobP
+ knobL
));
445 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
446 paintArrow(sPtr
, d
, 0);
447 paintArrow(sPtr
, d
, 1);
452 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0, view
->size
.width
, view
->size
.height
, 0, 0);
453 XFreePixmap(scr
->display
, d
);
457 static void handleEvents(XEvent
* event
, void *data
)
459 Scroller
*sPtr
= (Scroller
*) data
;
461 CHECK_CLASS(data
, WC_Scroller
);
463 switch (event
->type
) {
465 if (event
->xexpose
.count
== 0)
470 destroyScroller(sPtr
);
476 * locatePointInScroller-
477 * Return the part of the scroller where the point is located.
479 static WMScrollerPart
locatePointInScroller(Scroller
* sPtr
, int x
, int y
, int alternate
)
481 int width
= sPtr
->view
->size
.width
;
482 int height
= sPtr
->view
->size
.height
;
483 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
486 /* if there is no knob... */
487 if (sPtr
->flags
.documentFullyVisible
)
490 if (sPtr
->flags
.horizontal
)
496 * | | |###########| |#####| | |
497 * | < | > |###########| O |#####| < | > |
498 * | | |###########| |#####| | |
501 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
505 if (sPtr
->flags
.horizontal
) {
513 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
514 if (sPtr
->flags
.horizontal
) {
528 if (sPtr
->flags
.horizontal
) {
529 slotL
= p5
= p6
= width
;
531 slotL
= p5
= p6
= height
;
535 knobL
= knobLength(sPtr
);
536 p3
= p2
+ (int)((float)(slotL
- knobL
) * sPtr
->floatValue
);
539 /* uses a mix of the NS and Win ways of doing scroll page */
541 return alternate
? WSDecrementPage
: WSDecrementLine
;
543 return alternate
? WSIncrementPage
: WSIncrementLine
;
545 return WSDecrementPage
;
549 return WSIncrementPage
;
551 return alternate
? WSDecrementPage
: WSDecrementLine
;
553 return alternate
? WSIncrementPage
: WSIncrementLine
;
556 static void handlePush(Scroller
* sPtr
, int pushX
, int pushY
, int alternate
)
561 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
563 sPtr
->flags
.hitPart
= part
;
566 case WSIncrementLine
:
567 sPtr
->flags
.incrDown
= 1;
571 case WSIncrementPage
:
575 case WSDecrementLine
:
576 sPtr
->flags
.decrDown
= 1;
580 case WSDecrementPage
:
585 sPtr
->flags
.draggingKnob
= 1;
586 #ifndef STRICT_NEXT_BEHAVIOUR
587 if (sPtr
->flags
.horizontal
)
588 sPtr
->dragPoint
= pushX
;
590 sPtr
->dragPoint
= pushY
;
596 if (sPtr
->flags
.arrowsPosition
!= WSANone
)
597 buttonsLen
= 2 * (BUTTON_SIZE
+ 1);
601 if (sPtr
->flags
.horizontal
)
602 length
= sPtr
->view
->size
.width
- 4 - buttonsLen
;
604 length
= sPtr
->view
->size
.height
- 4 - buttonsLen
;
606 knobP
= (int)(sPtr
->floatValue
* (float)(length
- knobLength(sPtr
)));
608 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
609 sPtr
->dragPoint
-= 2 + buttonsLen
+ knobP
;
611 sPtr
->dragPoint
-= 2 + knobP
;
613 #endif /* STRICT_NEXT_BEHAVIOUR */
614 /* This does not seem necesary here since we don't know yet if the
615 * knob will be dragged later. -Dan
616 handleMotion(sPtr, pushX, pushY); */
619 case WSDecrementWheel
:
620 case WSIncrementWheel
:
627 if (doAction
&& sPtr
->action
) {
628 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
630 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
634 static float floatValueForPoint(Scroller
* sPtr
, int point
)
636 float floatValue
= 0;
638 int slotOfs
, slotLength
, knobL
;
640 if (sPtr
->flags
.horizontal
)
641 slotLength
= sPtr
->view
->size
.width
- 4;
643 slotLength
= sPtr
->view
->size
.height
- 4;
646 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
647 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
648 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
649 slotOfs
+= (BUTTON_SIZE
+ 1) * 2;
650 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
653 knobL
= (float)knobLength(sPtr
);
654 #ifdef STRICT_NEXT_BEHAVIOUR
655 if (point
< slotOfs
+ knobL
/ 2)
656 position
= (float)(slotOfs
+ knobL
/ 2);
657 else if (point
> slotOfs
+ slotLength
- knobL
/ 2)
658 position
= (float)(slotOfs
+ slotLength
- knobL
/ 2);
660 position
= (float)point
;
662 floatValue
= (position
- (float)(slotOfs
+ slotLength
/ 2))
663 / (float)(slotLength
- knobL
);
665 /* Adjust the last point to lie inside the knob slot */
667 position
= (float)slotOfs
;
668 else if (point
> slotOfs
+ slotLength
)
669 position
= (float)(slotOfs
+ slotLength
);
671 position
= (float)point
;
673 /* Compute the float value */
674 floatValue
= (position
- (float)slotOfs
) / (float)(slotLength
- knobL
);
677 assert(!isnan(floatValue
));
681 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
)
683 if (sPtr
->flags
.draggingKnob
) {
687 if (sPtr
->flags
.horizontal
) {
693 #ifndef STRICT_NEXT_BEHAVIOUR
694 point
-= sPtr
->dragPoint
;
697 newFloatValue
= floatValueForPoint(sPtr
, point
);
698 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
700 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
701 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
706 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
708 sPtr
->flags
.hitPart
= part
;
710 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
711 sPtr
->flags
.decrDown
= 0;
712 sPtr
->flags
.incrDown
= 1;
713 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
714 sPtr
->flags
.incrDown
= 0;
715 sPtr
->flags
.decrDown
= 1;
716 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
717 sPtr
->flags
.incrDown
= 0;
718 sPtr
->flags
.decrDown
= 0;
723 static void autoScroll(void *clientData
)
725 Scroller
*sPtr
= (Scroller
*) clientData
;
728 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
729 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
731 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
734 static void handleActionEvents(XEvent
* event
, void *data
)
736 Scroller
*sPtr
= (Scroller
*) data
;
737 int wheelDecrement
, wheelIncrement
;
740 /* check if we're really dealing with a scroller, as something
741 * might have gone wrong in the event dispatching stuff */
742 CHECK_CLASS(sPtr
, WC_Scroller
);
744 id
= sPtr
->flags
.incrDown
;
745 dd
= sPtr
->flags
.decrDown
;
747 switch (event
->type
) {
753 WMDeleteTimerHandler(sPtr
->timerID
);
754 sPtr
->timerID
= NULL
;
756 sPtr
->flags
.incrDown
= 0;
757 sPtr
->flags
.decrDown
= 0;
761 /* FIXME: change Mod1Mask with something else */
762 if (sPtr
->flags
.documentFullyVisible
)
765 if (sPtr
->flags
.horizontal
) {
766 wheelDecrement
= WINGsConfiguration
.mouseWheelDown
;
767 wheelIncrement
= WINGsConfiguration
.mouseWheelUp
;
769 wheelDecrement
= WINGsConfiguration
.mouseWheelUp
;
770 wheelIncrement
= WINGsConfiguration
.mouseWheelDown
;
773 if (event
->xbutton
.button
== wheelDecrement
) {
774 if (event
->xbutton
.state
& ControlMask
) {
775 sPtr
->flags
.hitPart
= WSDecrementPage
;
776 } else if (event
->xbutton
.state
& ShiftMask
) {
777 sPtr
->flags
.hitPart
= WSDecrementLine
;
779 sPtr
->flags
.hitPart
= WSDecrementWheel
;
782 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
783 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
785 } else if (event
->xbutton
.button
== wheelIncrement
) {
786 if (event
->xbutton
.state
& ControlMask
) {
787 sPtr
->flags
.hitPart
= WSIncrementPage
;
788 } else if (event
->xbutton
.state
& ShiftMask
) {
789 sPtr
->flags
.hitPart
= WSIncrementLine
;
791 sPtr
->flags
.hitPart
= WSIncrementWheel
;
794 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
795 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
798 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
, (event
->xbutton
.state
& Mod1Mask
)
799 || event
->xbutton
.button
== Button2
);
800 /* continue scrolling if pushed on the buttons */
801 if (sPtr
->flags
.hitPart
== WSIncrementLine
|| sPtr
->flags
.hitPart
== WSDecrementLine
) {
802 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
, autoScroll
, sPtr
);
808 if (sPtr
->flags
.draggingKnob
) {
810 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
811 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
815 WMDeleteTimerHandler(sPtr
->timerID
);
816 sPtr
->timerID
= NULL
;
818 sPtr
->flags
.incrDown
= 0;
819 sPtr
->flags
.decrDown
= 0;
820 sPtr
->flags
.draggingKnob
= 0;
824 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
825 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
826 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
827 WMDeleteTimerHandler(sPtr
->timerID
);
828 sPtr
->timerID
= NULL
;
832 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
836 static void destroyScroller(Scroller
* sPtr
)
838 /* we don't want autoscroll try to scroll a freed widget */
840 WMDeleteTimerHandler(sPtr
->timerID
);