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(W_ViewDelegate
* self
, WMView
* view
, unsigned int *width
, unsigned int *height
);
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 /* Parameter not used, but tell the compiler that it is ok */
140 if (*width
> *height
) {
141 sPtr
->flags
.horizontal
= 1;
142 *height
= SCROLLER_WIDTH
;
144 sPtr
->flags
.horizontal
= 0;
145 *width
= SCROLLER_WIDTH
;
149 void WMSetScrollerAction(WMScroller
* sPtr
, WMAction
* action
, void *clientData
)
151 CHECK_CLASS(sPtr
, WC_Scroller
);
153 sPtr
->action
= action
;
155 sPtr
->clientData
= clientData
;
158 void WMSetScrollerParameters(WMScroller
* sPtr
, float floatValue
, float knobProportion
)
161 * This value represents 1 pixel on a 4k wide screen, it makes
162 * a good minimum; this ensure a non-null value to avoid
163 * potential division-by-0.
164 * Please note that there is another size check when drawing
165 * the knob to make sure it will remain selectable.
167 static const float min_knob_proportion
= 1.0 / 4096.0;
169 CHECK_CLASS(sPtr
, WC_Scroller
);
171 assert(!isnan(floatValue
));
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
<= min_knob_proportion
) {
182 sPtr
->knobProportion
= min_knob_proportion
;
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); */
201 float WMGetScrollerKnobProportion(WMScroller
* sPtr
)
203 CHECK_CLASS(sPtr
, WC_Scroller
);
205 return sPtr
->knobProportion
;
208 float WMGetScrollerValue(WMScroller
* sPtr
)
210 CHECK_CLASS(sPtr
, WC_Scroller
);
212 return sPtr
->floatValue
;
215 WMScrollerPart
WMGetScrollerHitPart(WMScroller
* sPtr
)
217 CHECK_CLASS(sPtr
, WC_Scroller
);
219 return sPtr
->flags
.hitPart
;
222 static void paintArrow(WMScroller
* sPtr
, Drawable d
, int part
)
224 * part- 0 paints the decrement arrow, 1 the increment arrow
227 WMView
*view
= sPtr
->view
;
228 WMScreen
*scr
= view
->screen
;
232 #ifndef DOUBLE_BUFFER
233 GC gc
= scr
->lightGC
;
236 if (part
== 0) { /* decrement button */
237 if (sPtr
->flags
.horizontal
) {
238 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
239 ofs
= view
->size
.width
- 2 * (BUTTON_SIZE
+ 1) - 1;
243 if (sPtr
->flags
.decrDown
)
244 arrow
= scr
->hiLeftArrow
;
246 arrow
= scr
->leftArrow
;
249 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
250 ofs
= view
->size
.height
- 2 * (BUTTON_SIZE
+ 1) - 1;
254 if (sPtr
->flags
.decrDown
)
255 arrow
= scr
->hiUpArrow
;
257 arrow
= scr
->upArrow
;
260 #ifndef DOUBLE_BUFFER
261 if (sPtr
->flags
.decrDown
)
262 gc
= WMColorGC(scr
->white
);
264 } else { /* increment button */
265 if (sPtr
->flags
.horizontal
) {
266 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
267 ofs
= view
->size
.width
- BUTTON_SIZE
+ 1 - 3;
269 ofs
= 2 + BUTTON_SIZE
+ 1;
271 if (sPtr
->flags
.incrDown
)
272 arrow
= scr
->hiRightArrow
;
274 arrow
= scr
->rightArrow
;
276 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
277 ofs
= view
->size
.height
- BUTTON_SIZE
+ 1 - 3;
279 ofs
= 2 + BUTTON_SIZE
+ 1;
281 if (sPtr
->flags
.incrDown
)
282 arrow
= scr
->hiDownArrow
;
284 arrow
= scr
->downArrow
;
287 #ifndef DOUBLE_BUFFER
288 if (sPtr
->flags
.incrDown
)
293 if (sPtr
->flags
.horizontal
) {
295 #ifndef DOUBLE_BUFFER
296 XFillRectangle(scr
->display
, d
, gc
, ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
298 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
299 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
300 ofs
+ 1, 2 + 1, BUTTON_SIZE
+ 1 - 3, BUTTON_SIZE
- 3);
301 #endif /* DOUBLE_BUFFER */
302 W_DrawRelief(scr
, d
, ofs
, 2, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
305 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
306 XSetClipOrigin(scr
->display
, scr
->clipGC
,
307 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
309 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
310 0, 0, arrow
->width
, arrow
->height
,
311 ofs
+ (BUTTON_SIZE
- arrow
->width
) / 2, 2 + (BUTTON_SIZE
- arrow
->height
) / 2);
313 } else { /* vertical */
316 #ifndef DOUBLE_BUFFER
317 XFillRectangle(scr
->display
, d
, gc
, 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
319 if ((!part
&& sPtr
->flags
.decrDown
) || (part
&& sPtr
->flags
.incrDown
))
320 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
321 2 + 1, ofs
+ 1, BUTTON_SIZE
- 3, BUTTON_SIZE
+ 1 - 3);
322 #endif /* DOUBLE_BUFFER */
323 W_DrawRelief(scr
, d
, 2, ofs
, BUTTON_SIZE
, BUTTON_SIZE
, WRRaised
);
327 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
328 XSetClipOrigin(scr
->display
, scr
->clipGC
,
329 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
330 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
331 0, 0, arrow
->width
, arrow
->height
,
332 2 + (BUTTON_SIZE
- arrow
->width
) / 2, ofs
+ (BUTTON_SIZE
- arrow
->height
) / 2);
336 static int knobLength(Scroller
* sPtr
)
340 if (sPtr
->flags
.horizontal
)
341 length
= sPtr
->view
->size
.width
- 4;
343 length
= sPtr
->view
->size
.height
- 4;
345 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
346 length
-= 2 * (BUTTON_SIZE
+ 1);
349 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5);
350 /* keep minimum size */
351 if (tmp
< BUTTON_SIZE
)
357 static void paintScroller(Scroller
* sPtr
)
359 WMView
*view
= sPtr
->view
;
360 WMScreen
*scr
= view
->screen
;
364 Drawable d
= view
->window
;
370 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
, view
->size
.height
, scr
->depth
);
371 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0, view
->size
.width
, view
->size
.height
);
374 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0, view
->size
.width
- 1, view
->size
.height
- 1);
375 #ifndef DOUBLE_BUFFER
376 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1, view
->size
.width
- 3, view
->size
.height
- 3);
379 if (sPtr
->flags
.horizontal
)
380 length
= view
->size
.width
- 4;
382 length
= view
->size
.height
- 4;
384 if (sPtr
->flags
.documentFullyVisible
) {
385 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2, view
->size
.width
- 4, view
->size
.height
- 4);
388 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
389 length
-= (BUTTON_SIZE
+ 1) * 2;
390 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
391 ofs
+= (BUTTON_SIZE
+ 1) * 2;
392 length
-= (BUTTON_SIZE
+ 1) * 2;
395 knobL
= (float)knobLength(sPtr
);
397 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
399 if (sPtr
->flags
.horizontal
) {
401 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, ofs
, 2, (int)knobP
, view
->size
.height
- 4);
404 #ifndef DOUBLE_BUFFER
405 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
406 ofs
+ (int)knobP
+ 2, 2 + 2, (int)knobL
- 4, view
->size
.height
- 4 - 4);
408 W_DrawRelief(scr
, d
, ofs
+ (int)knobP
, 2, (int)knobL
, view
->size
.height
- 4, WRRaised
);
410 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
412 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
413 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->width
- 1) / 2,
414 (view
->size
.height
- scr
->scrollerDimple
->height
- 1) / 2);
417 if ((int)(knobP
+ knobL
) < length
)
418 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
419 ofs
+ (int)(knobP
+ knobL
), 2,
420 length
- (int)(knobP
+ knobL
), view
->size
.height
- 4);
424 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
425 2, ofs
, view
->size
.width
- 4, (int)knobP
);
428 #ifndef DOUBLE_BUFFER
429 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
430 2 + 2, ofs
+ (int)knobP
+ 2, view
->size
.width
- 4 - 4, (int)knobL
- 4);
432 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
434 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
435 (view
->size
.width
- scr
->scrollerDimple
->width
- 1) / 2,
436 ofs
+ (int)knobP
+ ((int)knobL
- scr
->scrollerDimple
->height
- 1) / 2);
438 W_DrawRelief(scr
, d
, 2, ofs
+ (int)knobP
, view
->size
.width
- 4, (int)knobL
, WRRaised
);
441 if ((int)(knobP
+ knobL
) < length
)
442 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
443 2, ofs
+ (int)(knobP
+ knobL
),
444 view
->size
.width
- 4, length
- (int)(knobP
+ knobL
));
447 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
448 paintArrow(sPtr
, d
, 0);
449 paintArrow(sPtr
, d
, 1);
454 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0, view
->size
.width
, view
->size
.height
, 0, 0);
455 XFreePixmap(scr
->display
, d
);
459 static void handleEvents(XEvent
* event
, void *data
)
461 Scroller
*sPtr
= (Scroller
*) data
;
463 CHECK_CLASS(data
, WC_Scroller
);
465 switch (event
->type
) {
467 if (event
->xexpose
.count
== 0)
472 destroyScroller(sPtr
);
478 * locatePointInScroller-
479 * Return the part of the scroller where the point is located.
481 static WMScrollerPart
locatePointInScroller(Scroller
* sPtr
, int x
, int y
, int alternate
)
483 int width
= sPtr
->view
->size
.width
;
484 int height
= sPtr
->view
->size
.height
;
485 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
488 /* if there is no knob... */
489 if (sPtr
->flags
.documentFullyVisible
)
492 if (sPtr
->flags
.horizontal
)
498 * | | |###########| |#####| | |
499 * | < | > |###########| O |#####| < | > |
500 * | | |###########| |#####| | |
503 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
507 if (sPtr
->flags
.horizontal
) {
515 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
516 if (sPtr
->flags
.horizontal
) {
530 if (sPtr
->flags
.horizontal
) {
531 slotL
= p5
= p6
= width
;
533 slotL
= p5
= p6
= height
;
537 knobL
= knobLength(sPtr
);
538 p3
= p2
+ (int)((float)(slotL
- knobL
) * sPtr
->floatValue
);
541 /* uses a mix of the NS and Win ways of doing scroll page */
543 return alternate
? WSDecrementPage
: WSDecrementLine
;
545 return alternate
? WSIncrementPage
: WSIncrementLine
;
547 return WSDecrementPage
;
551 return WSIncrementPage
;
553 return alternate
? WSDecrementPage
: WSDecrementLine
;
555 return alternate
? WSIncrementPage
: WSIncrementLine
;
558 static void handlePush(Scroller
* sPtr
, int pushX
, int pushY
, int alternate
)
563 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
565 sPtr
->flags
.hitPart
= part
;
568 case WSIncrementLine
:
569 sPtr
->flags
.incrDown
= 1;
573 case WSIncrementPage
:
577 case WSDecrementLine
:
578 sPtr
->flags
.decrDown
= 1;
582 case WSDecrementPage
:
587 sPtr
->flags
.draggingKnob
= 1;
588 #ifndef STRICT_NEXT_BEHAVIOUR
589 if (sPtr
->flags
.horizontal
)
590 sPtr
->dragPoint
= pushX
;
592 sPtr
->dragPoint
= pushY
;
598 if (sPtr
->flags
.arrowsPosition
!= WSANone
)
599 buttonsLen
= 2 * (BUTTON_SIZE
+ 1);
603 if (sPtr
->flags
.horizontal
)
604 length
= sPtr
->view
->size
.width
- 4 - buttonsLen
;
606 length
= sPtr
->view
->size
.height
- 4 - buttonsLen
;
608 knobP
= (int)(sPtr
->floatValue
* (float)(length
- knobLength(sPtr
)));
610 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
611 sPtr
->dragPoint
-= 2 + buttonsLen
+ knobP
;
613 sPtr
->dragPoint
-= 2 + knobP
;
615 #endif /* STRICT_NEXT_BEHAVIOUR */
616 /* This does not seem necesary here since we don't know yet if the
617 * knob will be dragged later. -Dan
618 handleMotion(sPtr, pushX, pushY); */
621 case WSDecrementWheel
:
622 case WSIncrementWheel
:
629 if (doAction
&& sPtr
->action
) {
630 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
632 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
636 static float floatValueForPoint(Scroller
* sPtr
, int point
)
638 float floatValue
= 0;
640 int slotOfs
, slotLength
, knobL
;
642 if (sPtr
->flags
.horizontal
)
643 slotLength
= sPtr
->view
->size
.width
- 4;
645 slotLength
= sPtr
->view
->size
.height
- 4;
648 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
649 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
650 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
651 slotOfs
+= (BUTTON_SIZE
+ 1) * 2;
652 slotLength
-= (BUTTON_SIZE
+ 1) * 2;
655 knobL
= (float)knobLength(sPtr
);
656 #ifdef STRICT_NEXT_BEHAVIOUR
657 if (point
< slotOfs
+ knobL
/ 2)
658 position
= (float)(slotOfs
+ knobL
/ 2);
659 else if (point
> slotOfs
+ slotLength
- knobL
/ 2)
660 position
= (float)(slotOfs
+ slotLength
- knobL
/ 2);
662 position
= (float)point
;
664 floatValue
= (position
- (float)(slotOfs
+ slotLength
/ 2))
665 / (float)(slotLength
- knobL
);
667 /* Adjust the last point to lie inside the knob slot */
669 position
= (float)slotOfs
;
670 else if (point
> slotOfs
+ slotLength
)
671 position
= (float)(slotOfs
+ slotLength
);
673 position
= (float)point
;
675 /* Compute the float value */
676 floatValue
= (position
- (float)slotOfs
) / (float)(slotLength
- knobL
);
679 assert(!isnan(floatValue
));
683 static void handleMotion(Scroller
* sPtr
, int mouseX
, int mouseY
)
685 if (sPtr
->flags
.draggingKnob
) {
689 if (sPtr
->flags
.horizontal
) {
695 #ifndef STRICT_NEXT_BEHAVIOUR
696 point
-= sPtr
->dragPoint
;
699 newFloatValue
= floatValueForPoint(sPtr
, point
);
700 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
702 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
703 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
708 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
710 sPtr
->flags
.hitPart
= part
;
712 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
713 sPtr
->flags
.decrDown
= 0;
714 sPtr
->flags
.incrDown
= 1;
715 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
716 sPtr
->flags
.incrDown
= 0;
717 sPtr
->flags
.decrDown
= 1;
718 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
719 sPtr
->flags
.incrDown
= 0;
720 sPtr
->flags
.decrDown
= 0;
725 static void autoScroll(void *clientData
)
727 Scroller
*sPtr
= (Scroller
*) clientData
;
730 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
731 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
733 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
736 static void handleActionEvents(XEvent
* event
, void *data
)
738 Scroller
*sPtr
= (Scroller
*) data
;
739 int wheelDecrement
, wheelIncrement
;
742 /* check if we're really dealing with a scroller, as something
743 * might have gone wrong in the event dispatching stuff */
744 CHECK_CLASS(sPtr
, WC_Scroller
);
746 id
= sPtr
->flags
.incrDown
;
747 dd
= sPtr
->flags
.decrDown
;
749 switch (event
->type
) {
755 WMDeleteTimerHandler(sPtr
->timerID
);
756 sPtr
->timerID
= NULL
;
758 sPtr
->flags
.incrDown
= 0;
759 sPtr
->flags
.decrDown
= 0;
763 /* FIXME: change Mod1Mask with something else */
764 if (sPtr
->flags
.documentFullyVisible
)
767 if (sPtr
->flags
.horizontal
) {
768 wheelDecrement
= WINGsConfiguration
.mouseWheelDown
;
769 wheelIncrement
= WINGsConfiguration
.mouseWheelUp
;
771 wheelDecrement
= WINGsConfiguration
.mouseWheelUp
;
772 wheelIncrement
= WINGsConfiguration
.mouseWheelDown
;
775 if (event
->xbutton
.button
== wheelDecrement
) {
776 if (event
->xbutton
.state
& ControlMask
) {
777 sPtr
->flags
.hitPart
= WSDecrementPage
;
778 } else if (event
->xbutton
.state
& ShiftMask
) {
779 sPtr
->flags
.hitPart
= WSDecrementLine
;
781 sPtr
->flags
.hitPart
= WSDecrementWheel
;
784 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
785 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
787 } else if (event
->xbutton
.button
== wheelIncrement
) {
788 if (event
->xbutton
.state
& ControlMask
) {
789 sPtr
->flags
.hitPart
= WSIncrementPage
;
790 } else if (event
->xbutton
.state
& ShiftMask
) {
791 sPtr
->flags
.hitPart
= WSIncrementLine
;
793 sPtr
->flags
.hitPart
= WSIncrementWheel
;
796 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
797 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
800 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
, (event
->xbutton
.state
& Mod1Mask
)
801 || event
->xbutton
.button
== Button2
);
802 /* continue scrolling if pushed on the buttons */
803 if (sPtr
->flags
.hitPart
== WSIncrementLine
|| sPtr
->flags
.hitPart
== WSDecrementLine
) {
804 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
, autoScroll
, sPtr
);
810 if (sPtr
->flags
.draggingKnob
) {
812 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
813 WMPostNotificationName(WMScrollerDidScrollNotification
, sPtr
, NULL
);
817 WMDeleteTimerHandler(sPtr
->timerID
);
818 sPtr
->timerID
= NULL
;
820 sPtr
->flags
.incrDown
= 0;
821 sPtr
->flags
.decrDown
= 0;
822 sPtr
->flags
.draggingKnob
= 0;
826 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
827 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
828 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
829 WMDeleteTimerHandler(sPtr
->timerID
);
830 sPtr
->timerID
= NULL
;
834 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
838 static void destroyScroller(Scroller
* sPtr
)
840 /* we don't want autoscroll try to scroll a freed widget */
842 WMDeleteTimerHandler(sPtr
->timerID
);