7 /* undefine will disable the autoadjusting of the knob dimple to be
8 * directly below the cursor
10 #undef STRICT_NEXT_BEHAVIOUR
12 #define AUTOSCROLL_INITIAL_DELAY 200
14 #define AUTOSCROLL_DELAY 40
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;
61 #define DEFAULT_HEIGHT 60
62 #define DEFAULT_WIDTH SCROLLER_WIDTH
63 #define DEFAULT_ARROWS_POSITION WSAMinEnd
67 static void destroyScroller(Scroller
*sPtr
);
68 static void paintScroller(Scroller
*sPtr
);
70 static void willResizeScroller();
71 static void handleEvents(XEvent
*event
, void *data
);
72 static void handleActionEvents(XEvent
*event
, void *data
);
74 static void handleMotion(Scroller
*sPtr
, int mouseX
, int mouseY
);
77 W_ViewDelegate _ScrollerViewDelegate
= {
89 WMCreateScroller(WMWidget
*parent
)
93 sPtr
= wmalloc(sizeof(Scroller
));
94 memset(sPtr
, 0, sizeof(Scroller
));
96 sPtr
->widgetClass
= WC_Scroller
;
98 sPtr
->view
= W_CreateView(W_VIEW(parent
));
103 sPtr
->view
->self
= sPtr
;
105 sPtr
->view
->delegate
= &_ScrollerViewDelegate
;
107 sPtr
->flags
.documentFullyVisible
= 1;
109 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
110 |ClientMessageMask
, handleEvents
, sPtr
);
112 W_ResizeView(sPtr
->view
, DEFAULT_WIDTH
, DEFAULT_WIDTH
);
113 sPtr
->flags
.arrowsPosition
= DEFAULT_ARROWS_POSITION
;
115 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
|ButtonReleaseMask
116 |EnterWindowMask
|LeaveWindowMask
|ButtonMotionMask
,
117 handleActionEvents
, sPtr
);
119 sPtr
->flags
.hitPart
= WSNoPart
;
127 WMSetScrollerArrowsPosition(WMScroller
*sPtr
, WMScrollArrowPosition position
)
129 sPtr
->flags
.arrowsPosition
= position
;
130 if (sPtr
->view
->flags
.realized
) {
137 willResizeScroller(W_ViewDelegate
*self
, WMView
*view
,
138 unsigned int *width
, unsigned int *height
)
140 WMScroller
*sPtr
= (WMScroller
*)view
->self
;
142 if (*width
> *height
) {
143 sPtr
->flags
.horizontal
= 1;
144 *height
= SCROLLER_WIDTH
;
146 sPtr
->flags
.horizontal
= 0;
147 *width
= SCROLLER_WIDTH
;
153 WMSetScrollerAction(WMScroller
*sPtr
, WMAction
*action
, void *clientData
)
155 CHECK_CLASS(sPtr
, WC_Scroller
);
157 sPtr
->action
= action
;
159 sPtr
->clientData
= clientData
;
164 WMSetScrollerParameters(WMScroller
*sPtr
, float floatValue
,
165 float knobProportion
)
167 CHECK_CLASS(sPtr
, WC_Scroller
);
169 if (floatValue
< 0.0)
170 sPtr
->floatValue
= 0.0;
171 else if (floatValue
> 1.0)
172 sPtr
->floatValue
= 1.0;
174 sPtr
->floatValue
= floatValue
;
176 if (knobProportion
<= 0.0) {
178 sPtr
->knobProportion
= 0.0;
179 sPtr
->flags
.documentFullyVisible
= 0;
181 } else if (knobProportion
>= 1.0) {
183 sPtr
->knobProportion
= 1.0;
184 sPtr
->flags
.documentFullyVisible
= 1;
187 sPtr
->knobProportion
= knobProportion
;
188 sPtr
->flags
.documentFullyVisible
= 0;
191 if (sPtr
->view
->flags
.realized
)
197 WMGetScrollerKnobProportion(WMScroller
*sPtr
)
199 CHECK_CLASS(sPtr
, WC_Scroller
);
201 return sPtr
->knobProportion
;
206 WMGetScrollerValue(WMScroller
*sPtr
)
208 CHECK_CLASS(sPtr
, WC_Scroller
);
210 return sPtr
->floatValue
;
215 WMGetScrollerHitPart(WMScroller
*sPtr
)
217 CHECK_CLASS(sPtr
, WC_Scroller
);
219 return sPtr
->flags
.hitPart
;
224 paintArrow(WMScroller
*sPtr
, Drawable d
, int part
)
226 * part- 0 paints the decrement arrow, 1 the increment arrow
229 WMView
*view
= sPtr
->view
;
230 WMScreen
*scr
= view
->screen
;
234 #ifndef DOUBLE_BUFFER
235 GC gc
= scr
->lightGC
;
238 bsize
= SCROLLER_WIDTH
- 4;
241 if (part
== 0) { /* decrement button */
242 if (sPtr
->flags
.horizontal
) {
243 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
244 ofs
= view
->size
.width
- 2*(bsize
+1) - 1;
248 if (sPtr
->flags
.decrDown
)
249 arrow
= scr
->hiLeftArrow
;
251 arrow
= scr
->leftArrow
;
254 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
255 ofs
= view
->size
.height
- 2*(bsize
+1) - 1;
259 if (sPtr
->flags
.decrDown
)
260 arrow
= scr
->hiUpArrow
;
262 arrow
= scr
->upArrow
;
265 #ifndef DOUBLE_BUFFER
266 if (sPtr
->flags
.decrDown
)
267 gc
= WMColorGC(scr
->white
);
269 } else { /* increment button */
270 if (sPtr
->flags
.horizontal
) {
271 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
272 ofs
= view
->size
.width
- bsize
+1 - 3;
276 if (sPtr
->flags
.incrDown
)
277 arrow
= scr
->hiRightArrow
;
279 arrow
= scr
->rightArrow
;
281 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
282 ofs
= view
->size
.height
- bsize
+1 - 3;
286 if (sPtr
->flags
.incrDown
)
287 arrow
= scr
->hiDownArrow
;
289 arrow
= scr
->downArrow
;
292 #ifndef DOUBLE_BUFFER
293 if (sPtr
->flags
.incrDown
)
299 if (sPtr
->flags
.horizontal
) {
302 #ifndef DOUBLE_BUFFER
303 XFillRectangle(scr
->display
, d
, gc
,
304 ofs
+1, 2+1, bsize
+1-3, bsize
-3);
306 if ((!part
&&sPtr
->flags
.decrDown
) || (part
&&sPtr
->flags
.incrDown
))
307 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
308 ofs
+1, 2+1, bsize
+1-3, bsize
-3);
309 #endif /* DOUBLE_BUFFER */
310 W_DrawRelief(scr
, d
, ofs
, 2, bsize
, bsize
, WRRaised
);
313 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
314 XSetClipOrigin(scr
->display
, scr
->clipGC
,
315 ofs
+ (bsize
- arrow
->width
) / 2,
316 2 + (bsize
- arrow
->height
) / 2);
318 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
319 0, 0, arrow
->width
, arrow
->height
,
320 ofs
+ (bsize
- arrow
->width
) / 2,
321 2 + (bsize
- arrow
->height
) / 2);
323 } else { /* vertical */
326 #ifndef DOUBLE_BUFFER
327 XFillRectangle(scr
->display
, d
, gc
,
328 2+1, ofs
+1, bsize
-3, bsize
+1-3);
330 if ((!part
&&sPtr
->flags
.decrDown
) || (part
&&sPtr
->flags
.incrDown
))
331 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
),
332 2+1, ofs
+1, bsize
-3, bsize
+1-3);
333 #endif /* DOUBLE_BUFFER */
334 W_DrawRelief(scr
, d
, 2, ofs
, bsize
, bsize
, WRRaised
);
338 XSetClipMask(scr
->display
, scr
->clipGC
, arrow
->mask
);
339 XSetClipOrigin(scr
->display
, scr
->clipGC
,
340 2 + (bsize
- arrow
->width
) / 2,
341 ofs
+ (bsize
- arrow
->height
) / 2);
342 XCopyArea(scr
->display
, arrow
->pixmap
, d
, scr
->clipGC
,
343 0, 0, arrow
->width
, arrow
->height
,
344 2 + (bsize
- arrow
->width
) / 2,
345 ofs
+ (bsize
- arrow
->height
) / 2);
351 knobLength(Scroller
*sPtr
)
356 if (sPtr
->flags
.horizontal
)
357 length
= sPtr
->view
->size
.width
- 4;
359 length
= sPtr
->view
->size
.height
- 4;
361 if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
362 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
363 } else if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
364 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
367 tmp
= (int)((float)length
* sPtr
->knobProportion
+ 0.5);
368 /* keep minimum size */
369 if (tmp
< SCROLLER_WIDTH
-4)
370 tmp
= SCROLLER_WIDTH
-4;
377 paintScroller(Scroller
*sPtr
)
379 WMView
*view
= sPtr
->view
;
380 WMScreen
*scr
= view
->screen
;
384 Drawable d
= view
->window
;
391 d
= XCreatePixmap(scr
->display
, view
->window
, view
->size
.width
,
392 view
->size
.height
, scr
->depth
);
393 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 0, 0,
394 view
->size
.width
, view
->size
.height
);
397 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->black
), 0, 0,
398 view
->size
.width
-1, view
->size
.height
-1);
399 #ifndef DOUBLE_BUFFER
400 XDrawRectangle(scr
->display
, d
, WMColorGC(scr
->gray
), 1, 1,
401 view
->size
.width
-3, view
->size
.height
-3);
404 if (sPtr
->flags
.horizontal
)
405 length
= view
->size
.width
- 4;
407 length
= view
->size
.height
- 4;
409 if (sPtr
->flags
.documentFullyVisible
) {
410 XFillRectangle(scr
->display
, d
, scr
->stippleGC
, 2, 2,
411 view
->size
.width
-4, view
->size
.height
-4);
413 if (sPtr
->flags
.arrowsPosition
==WSAMaxEnd
) {
415 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
416 } else if (sPtr
->flags
.arrowsPosition
==WSAMinEnd
) {
417 ofs
= (SCROLLER_WIDTH
- 4 + 1)*2;
418 length
-= (SCROLLER_WIDTH
- 4 + 1)*2;
423 knobL
= (float)knobLength(sPtr
);
425 knobP
= sPtr
->floatValue
* ((float)length
- knobL
);
428 if (sPtr
->flags
.horizontal
) {
430 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
431 ofs
+2, 2, (int)knobP
, view
->size
.height
-4);
434 #ifndef DOUBLE_BUFFER
435 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
436 ofs
+2+(int)knobP
+2, 2+2, (int)knobL
-4,
437 view
->size
.height
-4-4);
439 W_DrawRelief(scr
, d
, ofs
+2+(int)knobP
, 2, (int)knobL
,
440 view
->size
.height
-4, WRRaised
);
442 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
444 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
445 ofs
+2+(int)knobP
+((int)knobL
-scr
->scrollerDimple
->width
-1)/2,
446 (view
->size
.height
-scr
->scrollerDimple
->height
-1)/2);
449 if ((int)(knobP
+knobL
) < length
)
450 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
451 ofs
+2+(int)(knobP
+knobL
), 2,
452 length
-(int)(knobP
+knobL
),
453 view
->size
.height
-4);
457 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
458 2, ofs
+2, view
->size
.width
-4, (int)knobP
);
461 #ifndef DOUBLE_BUFFER
462 XFillRectangle(scr
->display
, d
, scr
->lightGC
,
463 2+2, ofs
+2+(int)knobP
+2,
464 view
->size
.width
-4-4, (int)knobL
-4);
466 XCopyArea(scr
->display
, scr
->scrollerDimple
->pixmap
, d
,
468 scr
->scrollerDimple
->width
, scr
->scrollerDimple
->height
,
469 (view
->size
.width
-scr
->scrollerDimple
->width
-1)/2,
470 ofs
+2+(int)knobP
+((int)knobL
-scr
->scrollerDimple
->height
-1)/2);
472 W_DrawRelief(scr
, d
, 2, ofs
+2+(int)knobP
,
473 view
->size
.width
-4, (int)knobL
, WRRaised
);
476 if ((int)(knobP
+knobL
) < length
)
477 XFillRectangle(scr
->display
, d
, scr
->stippleGC
,
478 2, ofs
+2+(int)(knobP
+knobL
),
480 length
-(int)(knobP
+knobL
));
483 if (sPtr
->flags
.arrowsPosition
!= WSANone
) {
484 paintArrow(sPtr
, d
, 0);
485 paintArrow(sPtr
, d
, 1);
490 XCopyArea(scr
->display
, d
, view
->window
, scr
->copyGC
, 0, 0,
491 view
->size
.width
, view
->size
.height
, 0, 0);
492 XFreePixmap(scr
->display
, d
);
499 handleEvents(XEvent
*event
, void *data
)
501 Scroller
*sPtr
= (Scroller
*)data
;
503 CHECK_CLASS(data
, WC_Scroller
);
506 switch (event
->type
) {
508 if (event
->xexpose
.count
==0)
513 destroyScroller(sPtr
);
521 * locatePointInScroller-
522 * Return the part of the scroller where the point is located.
524 static WMScrollerPart
525 locatePointInScroller(Scroller
*sPtr
, int x
, int y
, int alternate
)
527 int width
= sPtr
->view
->size
.width
;
528 int height
= sPtr
->view
->size
.height
;
529 int c
, p1
, p2
, p3
, p4
, p5
, p6
;
533 /* if there is no knob... */
534 if (sPtr
->flags
.documentFullyVisible
)
537 if (sPtr
->flags
.horizontal
)
543 * | | |###########| |#####| | |
544 * | < | > |###########| O |#####| < | > |
545 * | | |###########| |#####| | |
548 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
) {
552 if (sPtr
->flags
.horizontal
) {
560 } else if (sPtr
->flags
.arrowsPosition
== WSAMaxEnd
) {
561 if (sPtr
->flags
.horizontal
) {
575 if (sPtr
->flags
.horizontal
) {
576 slotL
= p5
= p6
= width
;
578 slotL
= p5
= p6
= height
;
582 knobL
= knobLength(sPtr
);
583 p3
= p2
+ (int)((float)(slotL
-knobL
) * sPtr
->floatValue
);
586 /* uses a mix of the NS and Win ways of doing scroll page */
588 return alternate
? WSDecrementPage
: WSDecrementLine
;
590 return alternate
? WSIncrementPage
: WSIncrementLine
;
592 return WSDecrementPage
;
596 return WSIncrementPage
;
598 return alternate
? WSDecrementPage
: WSDecrementLine
;
600 return alternate
? WSIncrementPage
: WSIncrementLine
;
606 handlePush(Scroller
*sPtr
, int pushX
, int pushY
, int alternate
)
611 part
= locatePointInScroller(sPtr
, pushX
, pushY
, alternate
);
613 sPtr
->flags
.hitPart
= part
;
616 case WSIncrementLine
:
617 sPtr
->flags
.incrDown
= 1;
621 case WSIncrementPage
:
625 case WSDecrementLine
:
626 sPtr
->flags
.decrDown
= 1;
630 case WSDecrementPage
:
635 sPtr
->flags
.draggingKnob
= 1;
636 #ifndef STRICT_NEXT_BEHAVIOUR
637 if (sPtr
->flags
.horizontal
)
638 sPtr
->dragPoint
= pushX
;
640 sPtr
->dragPoint
= pushY
;
643 int noButtons
= (sPtr
->flags
.arrowsPosition
== WSANone
);
646 if (sPtr
->flags
.horizontal
)
647 length
= sPtr
->view
->size
.width
- 4;
649 length
= sPtr
->view
->size
.height
- 4;
654 knobP
= (int)(sPtr
->floatValue
* (float)(length
-knobLength(sPtr
)));
656 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
657 sPtr
->dragPoint
-= 2 + (noButtons
? 0 : 36) + knobP
;
659 sPtr
->dragPoint
-= 2 + knobP
;
661 #endif /* STRICT_NEXT_BEHAVIOUR */
662 /* This does not seem necesary here since we don't know yet if the
663 * knob will be dragged later. -Dan
664 handleMotion(sPtr, pushX, pushY); */
673 if (doAction
&& sPtr
->action
) {
674 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
680 floatValueForPoint(int slotOfs
, int slotLength
, int knobLength
, int point
)
682 float floatValue
= 0;
685 #ifdef STRICT_NEXT_BEHAVIOUR
686 if (point
< slotOfs
+ knobLength
/2)
687 position
= (float)(slotOfs
+ knobLength
/2);
688 else if (point
> slotOfs
+ slotLength
- knobLength
/2)
689 position
= (float)(slotOfs
+ slotLength
- knobLength
/2);
691 position
= (float)point
;
693 floatValue
= (position
-(float)(slotOfs
+slotLength
/2))
694 /(float)(slotLength
-knobLength
);
696 /* Adjust the last point to lie inside the knob slot */
698 position
= (float)slotOfs
;
699 else if (point
> slotOfs
+ slotLength
)
700 position
= (float)(slotOfs
+ slotLength
);
702 position
= (float)point
;
704 /* Compute the float value */
705 floatValue
= (position
-(float)slotOfs
) / (float)(slotLength
-knobLength
);
713 handleMotion(Scroller
*sPtr
, int mouseX
, int mouseY
)
717 int noButtons
= (sPtr
->flags
.arrowsPosition
== WSANone
);
719 if (sPtr
->flags
.arrowsPosition
== WSAMinEnd
)
720 slotOffset
= 2 + (noButtons
? 0 : 36);
724 if (sPtr
->flags
.draggingKnob
) {
726 #ifdef STRICT_NEXT_BEHAVIOUR
727 if (sPtr
->flags
.horizontal
) {
728 slotLength
= sPtr
->view
->size
.width
-4-(noButtons
? 0 : 36);
729 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
730 (int)(slotLength
*sPtr
->knobProportion
),
733 slotLength
= sPtr
->view
->size
.height
-4-(noButtons
? 0 : 36);
734 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
735 (int)(slotLength
*sPtr
->knobProportion
),
739 if (sPtr
->flags
.horizontal
) {
740 slotLength
= sPtr
->view
->size
.width
-4-(noButtons
? 0 : 36);
741 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
742 (int)(slotLength
*sPtr
->knobProportion
),
743 mouseX
-sPtr
->dragPoint
);
745 slotLength
= sPtr
->view
->size
.height
-4-(noButtons
? 0 : 36);
746 newFloatValue
= floatValueForPoint(slotOffset
, slotLength
,
747 (int)(slotLength
*sPtr
->knobProportion
),
748 mouseY
-sPtr
->dragPoint
);
750 #endif /* !STRICT_NEXT_BEHAVIOUR */
751 WMSetScrollerParameters(sPtr
, newFloatValue
, sPtr
->knobProportion
);
753 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
758 part
= locatePointInScroller(sPtr
, mouseX
, mouseY
, False
);
760 sPtr
->flags
.hitPart
= part
;
762 if (part
== WSIncrementLine
&& sPtr
->flags
.decrDown
) {
763 sPtr
->flags
.decrDown
= 0;
764 sPtr
->flags
.incrDown
= 1;
765 } else if (part
== WSDecrementLine
&& sPtr
->flags
.incrDown
) {
766 sPtr
->flags
.incrDown
= 0;
767 sPtr
->flags
.decrDown
= 1;
768 } else if (part
!= WSIncrementLine
&& part
!= WSDecrementLine
) {
769 sPtr
->flags
.incrDown
= 0;
770 sPtr
->flags
.decrDown
= 0;
777 autoScroll(void *clientData
)
779 Scroller
*sPtr
= (Scroller
*)clientData
;
782 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
784 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_DELAY
, autoScroll
, clientData
);
789 handleActionEvents(XEvent
*event
, void *data
)
791 Scroller
*sPtr
= (Scroller
*)data
;
795 /* check if we're really dealing with a scroller, as something
796 * might have gone wrong in the event dispatching stuff */
797 CHECK_CLASS(sPtr
, WC_Scroller
);
799 id
= sPtr
->flags
.incrDown
;
800 dd
= sPtr
->flags
.decrDown
;
802 switch (event
->type
) {
809 WMDeleteTimerHandler(sPtr
->timerID
);
810 sPtr
->timerID
= NULL
;
812 sPtr
->flags
.incrDown
= 0;
813 sPtr
->flags
.decrDown
= 0;
817 /* FIXME: change Mod1Mask with something else */
818 handlePush(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
,
819 (event
->xbutton
.state
& Mod1Mask
)
820 ||event
->xbutton
.button
==Button2
);
821 /* continue scrolling if pushed on the buttons */
822 if (sPtr
->flags
.hitPart
== WSIncrementLine
823 || sPtr
->flags
.hitPart
== WSDecrementLine
) {
824 sPtr
->timerID
= WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY
,
830 if (sPtr
->flags
.draggingKnob
) {
832 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
836 WMDeleteTimerHandler(sPtr
->timerID
);
837 sPtr
->timerID
= NULL
;
839 sPtr
->flags
.incrDown
= 0;
840 sPtr
->flags
.decrDown
= 0;
841 sPtr
->flags
.draggingKnob
= 0;
845 handleMotion(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
);
846 if (sPtr
->timerID
&& sPtr
->flags
.hitPart
!= WSIncrementLine
847 && sPtr
->flags
.hitPart
!= WSDecrementLine
) {
848 WMDeleteTimerHandler(sPtr
->timerID
);
849 sPtr
->timerID
= NULL
;
853 if (id
!= sPtr
->flags
.incrDown
|| dd
!= sPtr
->flags
.decrDown
)
860 destroyScroller(Scroller
*sPtr
)
862 /* we don't want autoscroll try to scroll a freed widget */
864 WMDeleteTimerHandler(sPtr
->timerID
);