replaced free() with wfree() everywhere
[wmaker-crm.git] / WINGs / wscroller.c
blobfaa047a4fbfb22b9779a277914f477cf7e0b8f86
5 #include "WINGsP.h"
7 /* undefine will disable the autoadjusting of the knob dimple to be
8 * directly below the cursor
9 * DOES NOT WORK */
10 #undef STRICT_NEXT_BEHAVIOUR
12 #define AUTOSCROLL_INITIAL_DELAY 200
14 #define AUTOSCROLL_DELAY 40
17 typedef struct W_Scroller {
18 W_Class widgetClass;
19 W_View *view;
21 void *clientData;
22 WMAction *action;
24 float knobProportion;
25 float floatValue;
27 WMHandlerID timerID; /* for continuous scrolling mode */
29 #ifndef STRICT_NEXT_BEHAVIOUR
30 int dragPoint; /* point where the knob is being
31 * dragged */
32 #endif
33 struct {
34 WMScrollArrowPosition arrowsPosition:4;
36 unsigned int horizontal:1;
38 WMScrollerPart hitPart:4;
40 /* */
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;
56 } flags;
57 } Scroller;
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 = {
78 NULL,
79 NULL,
80 NULL,
81 NULL,
82 willResizeScroller
88 WMScroller*
89 WMCreateScroller(WMWidget *parent)
91 Scroller *sPtr;
93 sPtr = wmalloc(sizeof(Scroller));
94 memset(sPtr, 0, sizeof(Scroller));
96 sPtr->widgetClass = WC_Scroller;
98 sPtr->view = W_CreateView(W_VIEW(parent));
99 if (!sPtr->view) {
100 wfree(sPtr);
101 return NULL;
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;
121 return sPtr;
126 void
127 WMSetScrollerArrowsPosition(WMScroller *sPtr, WMScrollArrowPosition position)
129 sPtr->flags.arrowsPosition = position;
130 if (sPtr->view->flags.realized) {
131 paintScroller(sPtr);
136 static void
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;
145 } else {
146 sPtr->flags.horizontal = 0;
147 *width = SCROLLER_WIDTH;
152 void
153 WMSetScrollerAction(WMScroller *sPtr, WMAction *action, void *clientData)
155 CHECK_CLASS(sPtr, WC_Scroller);
157 sPtr->action = action;
159 sPtr->clientData = clientData;
163 void
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;
173 else
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;
186 } else {
187 sPtr->knobProportion = knobProportion;
188 sPtr->flags.documentFullyVisible = 0;
191 if (sPtr->view->flags.realized)
192 paintScroller(sPtr);
196 float
197 WMGetScrollerKnobProportion(WMScroller *sPtr)
199 CHECK_CLASS(sPtr, WC_Scroller);
201 return sPtr->knobProportion;
205 float
206 WMGetScrollerValue(WMScroller *sPtr)
208 CHECK_CLASS(sPtr, WC_Scroller);
210 return sPtr->floatValue;
214 WMScrollerPart
215 WMGetScrollerHitPart(WMScroller *sPtr)
217 CHECK_CLASS(sPtr, WC_Scroller);
219 return sPtr->flags.hitPart;
223 static void
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;
231 int ofs, bsize;
232 W_Pixmap *arrow;
234 #ifndef DOUBLE_BUFFER
235 GC gc = scr->lightGC;
236 #endif
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;
245 } else {
246 ofs = 2;
248 if (sPtr->flags.decrDown)
249 arrow = scr->hiLeftArrow;
250 else
251 arrow = scr->leftArrow;
253 } else {
254 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
255 ofs = view->size.height - 2*(bsize+1) - 1;
256 } else {
257 ofs = 2;
259 if (sPtr->flags.decrDown)
260 arrow = scr->hiUpArrow;
261 else
262 arrow = scr->upArrow;
265 #ifndef DOUBLE_BUFFER
266 if (sPtr->flags.decrDown)
267 gc = WMColorGC(scr->white);
268 #endif
269 } else { /* increment button */
270 if (sPtr->flags.horizontal) {
271 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
272 ofs = view->size.width - bsize+1 - 3;
273 } else {
274 ofs = 2 + bsize+1;
276 if (sPtr->flags.incrDown)
277 arrow = scr->hiRightArrow;
278 else
279 arrow = scr->rightArrow;
280 } else {
281 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
282 ofs = view->size.height - bsize+1 - 3;
283 } else {
284 ofs = 2 + bsize+1;
286 if (sPtr->flags.incrDown)
287 arrow = scr->hiDownArrow;
288 else
289 arrow = scr->downArrow;
292 #ifndef DOUBLE_BUFFER
293 if (sPtr->flags.incrDown)
294 gc = scr->whiteGC;
295 #endif
299 if (sPtr->flags.horizontal) {
301 /* paint button */
302 #ifndef DOUBLE_BUFFER
303 XFillRectangle(scr->display, d, gc,
304 ofs+1, 2+1, bsize+1-3, bsize-3);
305 #else
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);
312 /* paint arrow */
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 */
325 /* paint button */
326 #ifndef DOUBLE_BUFFER
327 XFillRectangle(scr->display, d, gc,
328 2+1, ofs+1, bsize-3, bsize+1-3);
329 #else
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);
336 /* paint arrow */
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);
350 static int
351 knobLength(Scroller *sPtr)
353 int tmp, length;
356 if (sPtr->flags.horizontal)
357 length = sPtr->view->size.width - 4;
358 else
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;
372 return tmp;
376 static void
377 paintScroller(Scroller *sPtr)
379 WMView *view = sPtr->view;
380 WMScreen *scr = view->screen;
381 #ifdef DOUBLE_BUFFER
382 Pixmap d;
383 #else
384 Drawable d = view->window;
385 #endif
386 int length, ofs;
387 float knobP, knobL;
390 #ifdef DOUBLE_BUFFER
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);
395 #endif
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);
402 #endif
404 if (sPtr->flags.horizontal)
405 length = view->size.width - 4;
406 else
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);
412 } else {
413 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
414 ofs = 0;
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;
419 } else {
420 ofs = 0;
423 knobL = (float)knobLength(sPtr);
425 knobP = sPtr->floatValue * ((float)length - knobL);
428 if (sPtr->flags.horizontal) {
429 /* before */
430 XFillRectangle(scr->display, d, scr->stippleGC,
431 ofs+2, 2, (int)knobP, view->size.height-4);
433 /* knob */
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);
438 #endif
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,
443 scr->copyGC, 0, 0,
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);
448 /* after */
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);
454 } else {
455 /* before */
456 if (knobP>0.0)
457 XFillRectangle(scr->display, d, scr->stippleGC,
458 2, ofs+2, view->size.width-4, (int)knobP);
460 /* knob */
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);
465 #endif
466 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
467 scr->copyGC, 0, 0,
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);
475 /* after */
476 if ((int)(knobP+knobL) < length)
477 XFillRectangle(scr->display, d, scr->stippleGC,
478 2, ofs+2+(int)(knobP+knobL),
479 view->size.width-4,
480 length-(int)(knobP+knobL));
483 if (sPtr->flags.arrowsPosition != WSANone) {
484 paintArrow(sPtr, d, 0);
485 paintArrow(sPtr, d, 1);
489 #ifdef DOUBLE_BUFFER
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);
493 #endif
498 static void
499 handleEvents(XEvent *event, void *data)
501 Scroller *sPtr = (Scroller*)data;
503 CHECK_CLASS(data, WC_Scroller);
506 switch (event->type) {
507 case Expose:
508 if (event->xexpose.count==0)
509 paintScroller(sPtr);
510 break;
512 case DestroyNotify:
513 destroyScroller(sPtr);
514 break;
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;
530 int knobL, slotL;
533 /* if there is no knob... */
534 if (sPtr->flags.documentFullyVisible)
535 return WSKnobSlot;
537 if (sPtr->flags.horizontal)
538 c = x;
539 else
540 c = y;
542 /* p1 p2 p3 p4 p5 p6
543 * | | |###########| |#####| | |
544 * | < | > |###########| O |#####| < | > |
545 * | | |###########| |#####| | |
548 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
549 p1 = 18;
550 p2 = 36;
552 if (sPtr->flags.horizontal) {
553 slotL = width - 36;
554 p5 = width;
555 } else {
556 slotL = height - 36;
557 p5 = height;
559 p6 = p5;
560 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
561 if (sPtr->flags.horizontal) {
562 slotL = width - 36;
563 p6 = width - 18;
564 } else {
565 slotL = height - 36;
566 p6 = height - 18;
568 p5 = p6 - 18;
570 p1 = p2 = 0;
571 } else {
572 /* no arrows */
573 p1 = p2 = 0;
575 if (sPtr->flags.horizontal) {
576 slotL = p5 = p6 = width;
577 } else {
578 slotL = p5 = p6 = height;
582 knobL = knobLength(sPtr);
583 p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
584 p4 = p3 + knobL;
586 /* uses a mix of the NS and Win ways of doing scroll page */
587 if (c <= p1)
588 return alternate ? WSDecrementPage : WSDecrementLine;
589 else if (c <= p2)
590 return alternate ? WSIncrementPage : WSIncrementLine;
591 else if (c <= p3)
592 return WSDecrementPage;
593 else if (c <= p4)
594 return WSKnob;
595 else if (c <= p5)
596 return WSIncrementPage;
597 else if (c <= p6)
598 return alternate ? WSDecrementPage : WSDecrementLine;
599 else
600 return alternate ? WSIncrementPage : WSIncrementLine;
605 static void
606 handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
608 WMScrollerPart part;
609 int doAction = 0;
611 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
613 sPtr->flags.hitPart = part;
615 switch (part) {
616 case WSIncrementLine:
617 sPtr->flags.incrDown = 1;
618 doAction = 1;
619 break;
621 case WSIncrementPage:
622 doAction = 1;
623 break;
625 case WSDecrementLine:
626 sPtr->flags.decrDown = 1;
627 doAction = 1;
628 break;
630 case WSDecrementPage:
631 doAction = 1;
632 break;
634 case WSKnob:
635 sPtr->flags.draggingKnob = 1;
636 #ifndef STRICT_NEXT_BEHAVIOUR
637 if (sPtr->flags.horizontal)
638 sPtr->dragPoint = pushX;
639 else
640 sPtr->dragPoint = pushY;
643 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
644 int length, knobP;
646 if (sPtr->flags.horizontal)
647 length = sPtr->view->size.width - 4;
648 else
649 length = sPtr->view->size.height - 4;
651 if (!noButtons)
652 length -= 36;
654 knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
656 if (sPtr->flags.arrowsPosition == WSAMinEnd)
657 sPtr->dragPoint -= 2 + (noButtons ? 0 : 36) + knobP;
658 else
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); */
665 break;
667 case WSKnobSlot:
668 case WSNoPart:
669 /* dummy */
670 break;
673 if (doAction && sPtr->action) {
674 (*sPtr->action)(sPtr, sPtr->clientData);
679 static float
680 floatValueForPoint(int slotOfs, int slotLength, int knobLength, int point)
682 float floatValue = 0;
683 float position;
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);
690 else
691 position = (float)point;
693 floatValue = (position-(float)(slotOfs+slotLength/2))
694 /(float)(slotLength-knobLength);
695 #else
696 /* Adjust the last point to lie inside the knob slot */
697 if (point < slotOfs)
698 position = (float)slotOfs;
699 else if (point > slotOfs + slotLength)
700 position = (float)(slotOfs + slotLength);
701 else
702 position = (float)point;
704 /* Compute the float value */
705 floatValue = (position-(float)slotOfs) / (float)(slotLength-knobLength);
706 #endif
708 return floatValue;
712 static void
713 handleMotion(Scroller *sPtr, int mouseX, int mouseY)
715 int slotOffset;
716 int slotLength;
717 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
719 if (sPtr->flags.arrowsPosition == WSAMinEnd)
720 slotOffset = 2 + (noButtons ? 0 : 36);
721 else
722 slotOffset = 2;
724 if (sPtr->flags.draggingKnob) {
725 float newFloatValue;
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),
731 mouseX);
732 } else {
733 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
734 newFloatValue = floatValueForPoint(slotOffset, slotLength,
735 (int)(slotLength*sPtr->knobProportion),
736 mouseY);
738 #else
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);
744 } else {
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);
752 if (sPtr->action) {
753 (*sPtr->action)(sPtr, sPtr->clientData);
755 } else {
756 int part;
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;
776 static void
777 autoScroll(void *clientData)
779 Scroller *sPtr = (Scroller*)clientData;
781 if (sPtr->action) {
782 (*sPtr->action)(sPtr, sPtr->clientData);
784 sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
788 static void
789 handleActionEvents(XEvent *event, void *data)
791 Scroller *sPtr = (Scroller*)data;
792 int id, dd;
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) {
803 case EnterNotify:
805 break;
807 case LeaveNotify:
808 if (sPtr->timerID) {
809 WMDeleteTimerHandler(sPtr->timerID);
810 sPtr->timerID = NULL;
812 sPtr->flags.incrDown = 0;
813 sPtr->flags.decrDown = 0;
814 break;
816 case ButtonPress:
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,
825 autoScroll, sPtr);
827 break;
829 case ButtonRelease:
830 if (sPtr->flags.draggingKnob) {
831 if (sPtr->action) {
832 (*sPtr->action)(sPtr, sPtr->clientData);
835 if (sPtr->timerID) {
836 WMDeleteTimerHandler(sPtr->timerID);
837 sPtr->timerID = NULL;
839 sPtr->flags.incrDown = 0;
840 sPtr->flags.decrDown = 0;
841 sPtr->flags.draggingKnob = 0;
842 break;
844 case MotionNotify:
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;
851 break;
853 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
854 paintScroller(sPtr);
859 static void
860 destroyScroller(Scroller *sPtr)
862 /* we don't want autoscroll try to scroll a freed widget */
863 if (sPtr->timerID) {
864 WMDeleteTimerHandler(sPtr->timerID);
867 wfree(sPtr);