- fixed a bug that made the scroller knob jump backwards when dragged (this
[wmaker-crm.git] / WINGs / wscroller.c
blobafe893c22a1797afe550d3264f34bdee3d595289
5 #include "WINGsP.h"
7 #include <math.h>
9 /* undefine will disable the autoadjusting of the knob dimple to be
10 * directly below the cursor
11 * DOES NOT WORK */
12 #undef STRICT_NEXT_BEHAVIOUR
14 #define AUTOSCROLL_INITIAL_DELAY 200
16 #define AUTOSCROLL_DELAY 40
19 char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
23 typedef struct W_Scroller {
24 W_Class widgetClass;
25 W_View *view;
27 void *clientData;
28 WMAction *action;
30 float knobProportion;
31 float floatValue;
33 WMHandlerID timerID; /* for continuous scrolling mode */
35 #ifndef STRICT_NEXT_BEHAVIOUR
36 int dragPoint; /* point where the knob is being
37 * dragged */
38 #endif
39 struct {
40 WMScrollArrowPosition arrowsPosition:4;
42 unsigned int horizontal:1;
44 WMScrollerPart hitPart:4;
46 /* */
47 unsigned int documentFullyVisible:1; /* document is fully visible */
49 unsigned int prevSelected:1;
51 unsigned int pushed:1;
53 unsigned int incrDown:1; /* whether increment button is down */
55 unsigned int decrDown:1;
57 unsigned int draggingKnob:1;
59 unsigned int configured:1;
61 unsigned int redrawPending:1;
62 } flags;
63 } Scroller;
67 #define DEFAULT_HEIGHT 60
68 #define DEFAULT_WIDTH SCROLLER_WIDTH
69 #define DEFAULT_ARROWS_POSITION WSAMinEnd
72 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
75 static void destroyScroller(Scroller *sPtr);
76 static void paintScroller(Scroller *sPtr);
78 static void willResizeScroller();
79 static void handleEvents(XEvent *event, void *data);
80 static void handleActionEvents(XEvent *event, void *data);
82 static void handleMotion(Scroller *sPtr, int mouseX, int mouseY);
85 W_ViewDelegate _ScrollerViewDelegate = {
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 willResizeScroller
96 WMScroller*
97 WMCreateScroller(WMWidget *parent)
99 Scroller *sPtr;
101 sPtr = wmalloc(sizeof(Scroller));
102 memset(sPtr, 0, sizeof(Scroller));
104 sPtr->widgetClass = WC_Scroller;
106 sPtr->view = W_CreateView(W_VIEW(parent));
107 if (!sPtr->view) {
108 wfree(sPtr);
109 return NULL;
111 sPtr->view->self = sPtr;
113 sPtr->view->delegate = &_ScrollerViewDelegate;
115 sPtr->flags.documentFullyVisible = 1;
117 WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask
118 |ClientMessageMask, handleEvents, sPtr);
120 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
121 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
123 WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
124 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
125 handleActionEvents, sPtr);
127 sPtr->flags.hitPart = WSNoPart;
129 sPtr->floatValue = 0.0;
130 sPtr->knobProportion = 1.0;
132 return sPtr;
137 void
138 WMSetScrollerArrowsPosition(WMScroller *sPtr, WMScrollArrowPosition position)
140 sPtr->flags.arrowsPosition = position;
141 if (sPtr->view->flags.realized) {
142 paintScroller(sPtr);
147 static void
148 willResizeScroller(W_ViewDelegate *self, WMView *view,
149 unsigned int *width, unsigned int *height)
151 WMScroller *sPtr = (WMScroller*)view->self;
153 if (*width > *height) {
154 sPtr->flags.horizontal = 1;
155 *height = SCROLLER_WIDTH;
156 } else {
157 sPtr->flags.horizontal = 0;
158 *width = SCROLLER_WIDTH;
163 void
164 WMSetScrollerAction(WMScroller *sPtr, WMAction *action, void *clientData)
166 CHECK_CLASS(sPtr, WC_Scroller);
168 sPtr->action = action;
170 sPtr->clientData = clientData;
174 void
175 WMSetScrollerParameters(WMScroller *sPtr, float floatValue,
176 float knobProportion)
178 CHECK_CLASS(sPtr, WC_Scroller);
180 assert(!isnan(floatValue));
182 if (floatValue < 0.0)
183 sPtr->floatValue = 0.0;
184 else if (floatValue > 1.0)
185 sPtr->floatValue = 1.0;
186 else
187 sPtr->floatValue = floatValue;
189 if (knobProportion <= 0.0) {
191 sPtr->knobProportion = 0.0;
192 sPtr->flags.documentFullyVisible = 0;
194 } else if (knobProportion >= 1.0) {
196 sPtr->knobProportion = 1.0;
197 sPtr->flags.documentFullyVisible = 1;
199 } else {
200 sPtr->knobProportion = knobProportion;
201 sPtr->flags.documentFullyVisible = 0;
204 if (sPtr->view->flags.realized)
205 paintScroller(sPtr);
207 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);*/
211 float
212 WMGetScrollerKnobProportion(WMScroller *sPtr)
214 CHECK_CLASS(sPtr, WC_Scroller);
216 return sPtr->knobProportion;
220 float
221 WMGetScrollerValue(WMScroller *sPtr)
223 CHECK_CLASS(sPtr, WC_Scroller);
225 return sPtr->floatValue;
229 WMScrollerPart
230 WMGetScrollerHitPart(WMScroller *sPtr)
232 CHECK_CLASS(sPtr, WC_Scroller);
234 return sPtr->flags.hitPart;
238 static void
239 paintArrow(WMScroller *sPtr, Drawable d, int part)
241 * part- 0 paints the decrement arrow, 1 the increment arrow
244 WMView *view = sPtr->view;
245 WMScreen *scr = view->screen;
246 int ofs;
247 W_Pixmap *arrow;
249 #ifndef DOUBLE_BUFFER
250 GC gc = scr->lightGC;
251 #endif
253 if (part == 0) { /* decrement button */
254 if (sPtr->flags.horizontal) {
255 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
256 ofs = view->size.width - 2*(BUTTON_SIZE+1) - 1;
257 } else {
258 ofs = 2;
260 if (sPtr->flags.decrDown)
261 arrow = scr->hiLeftArrow;
262 else
263 arrow = scr->leftArrow;
265 } else {
266 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
267 ofs = view->size.height - 2*(BUTTON_SIZE+1) - 1;
268 } else {
269 ofs = 2;
271 if (sPtr->flags.decrDown)
272 arrow = scr->hiUpArrow;
273 else
274 arrow = scr->upArrow;
277 #ifndef DOUBLE_BUFFER
278 if (sPtr->flags.decrDown)
279 gc = WMColorGC(scr->white);
280 #endif
281 } else { /* increment button */
282 if (sPtr->flags.horizontal) {
283 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
284 ofs = view->size.width - BUTTON_SIZE+1 - 3;
285 } else {
286 ofs = 2 + BUTTON_SIZE+1;
288 if (sPtr->flags.incrDown)
289 arrow = scr->hiRightArrow;
290 else
291 arrow = scr->rightArrow;
292 } else {
293 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
294 ofs = view->size.height - BUTTON_SIZE+1 - 3;
295 } else {
296 ofs = 2 + BUTTON_SIZE+1;
298 if (sPtr->flags.incrDown)
299 arrow = scr->hiDownArrow;
300 else
301 arrow = scr->downArrow;
304 #ifndef DOUBLE_BUFFER
305 if (sPtr->flags.incrDown)
306 gc = scr->whiteGC;
307 #endif
311 if (sPtr->flags.horizontal) {
313 /* paint button */
314 #ifndef DOUBLE_BUFFER
315 XFillRectangle(scr->display, d, gc,
316 ofs+1, 2+1, BUTTON_SIZE+1-3, BUTTON_SIZE-3);
317 #else
318 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
319 XFillRectangle(scr->display, d, WMColorGC(scr->white),
320 ofs+1, 2+1, BUTTON_SIZE+1-3, BUTTON_SIZE-3);
321 #endif /* DOUBLE_BUFFER */
322 W_DrawRelief(scr, d, ofs, 2, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
324 /* paint arrow */
325 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
326 XSetClipOrigin(scr->display, scr->clipGC,
327 ofs + (BUTTON_SIZE - arrow->width) / 2,
328 2 + (BUTTON_SIZE - arrow->height) / 2);
330 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
331 0, 0, arrow->width, arrow->height,
332 ofs + (BUTTON_SIZE - arrow->width) / 2,
333 2 + (BUTTON_SIZE - arrow->height) / 2);
335 } else { /* vertical */
337 /* paint button */
338 #ifndef DOUBLE_BUFFER
339 XFillRectangle(scr->display, d, gc,
340 2+1, ofs+1, BUTTON_SIZE-3, BUTTON_SIZE+1-3);
341 #else
342 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
343 XFillRectangle(scr->display, d, WMColorGC(scr->white),
344 2+1, ofs+1, BUTTON_SIZE-3, BUTTON_SIZE+1-3);
345 #endif /* DOUBLE_BUFFER */
346 W_DrawRelief(scr, d, 2, ofs, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
348 /* paint arrow */
350 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
351 XSetClipOrigin(scr->display, scr->clipGC,
352 2 + (BUTTON_SIZE - arrow->width) / 2,
353 ofs + (BUTTON_SIZE - arrow->height) / 2);
354 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
355 0, 0, arrow->width, arrow->height,
356 2 + (BUTTON_SIZE - arrow->width) / 2,
357 ofs + (BUTTON_SIZE - arrow->height) / 2);
362 static int
363 knobLength(Scroller *sPtr)
365 int tmp, length;
368 if (sPtr->flags.horizontal)
369 length = sPtr->view->size.width - 4;
370 else
371 length = sPtr->view->size.height - 4;
373 if (sPtr->flags.arrowsPosition != WSANone) {
374 length -= 2*(BUTTON_SIZE+1);
377 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
378 /* keep minimum size */
379 if (tmp < BUTTON_SIZE)
380 tmp = BUTTON_SIZE;
382 return tmp;
386 static void
387 paintScroller(Scroller *sPtr)
389 WMView *view = sPtr->view;
390 WMScreen *scr = view->screen;
391 #ifdef DOUBLE_BUFFER
392 Pixmap d;
393 #else
394 Drawable d = view->window;
395 #endif
396 int length, ofs;
397 float knobP, knobL;
400 #ifdef DOUBLE_BUFFER
401 d = XCreatePixmap(scr->display, view->window, view->size.width,
402 view->size.height, scr->depth);
403 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0,
404 view->size.width, view->size.height);
405 #endif
407 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0,
408 view->size.width-1, view->size.height-1);
409 #ifndef DOUBLE_BUFFER
410 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1,
411 view->size.width-3, view->size.height-3);
412 #endif
414 if (sPtr->flags.horizontal)
415 length = view->size.width - 4;
416 else
417 length = view->size.height - 4;
419 if (sPtr->flags.documentFullyVisible) {
420 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
421 view->size.width-4, view->size.height-4);
422 } else {
423 ofs = 2;
424 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
425 length -= (BUTTON_SIZE+1)*2;
426 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
427 ofs += (BUTTON_SIZE+1)*2;
428 length -= (BUTTON_SIZE+1)*2;
431 knobL = (float)knobLength(sPtr);
433 knobP = sPtr->floatValue * ((float)length - knobL);
435 if (sPtr->flags.horizontal) {
436 /* before */
437 XFillRectangle(scr->display, d, scr->stippleGC,
438 ofs, 2, (int)knobP, view->size.height-4);
440 /* knob */
441 #ifndef DOUBLE_BUFFER
442 XFillRectangle(scr->display, d, scr->lightGC,
443 ofs+(int)knobP+2, 2+2, (int)knobL-4,
444 view->size.height-4-4);
445 #endif
446 W_DrawRelief(scr, d, ofs+(int)knobP, 2, (int)knobL,
447 view->size.height-4, WRRaised);
449 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
450 scr->copyGC, 0, 0,
451 scr->scrollerDimple->width, scr->scrollerDimple->height,
452 ofs+(int)knobP+((int)knobL-scr->scrollerDimple->width-1)/2,
453 (view->size.height-scr->scrollerDimple->height-1)/2);
455 /* after */
456 if ((int)(knobP+knobL) < length)
457 XFillRectangle(scr->display, d, scr->stippleGC,
458 ofs+(int)(knobP+knobL), 2,
459 length-(int)(knobP+knobL),
460 view->size.height-4);
461 } else {
462 /* before */
463 if (knobP>0.0)
464 XFillRectangle(scr->display, d, scr->stippleGC,
465 2, ofs, view->size.width-4, (int)knobP);
467 /* knob */
468 #ifndef DOUBLE_BUFFER
469 XFillRectangle(scr->display, d, scr->lightGC,
470 2+2, ofs+(int)knobP+2,
471 view->size.width-4-4, (int)knobL-4);
472 #endif
473 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
474 scr->copyGC, 0, 0,
475 scr->scrollerDimple->width, scr->scrollerDimple->height,
476 (view->size.width-scr->scrollerDimple->width-1)/2,
477 ofs+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
479 W_DrawRelief(scr, d, 2, ofs+(int)knobP,
480 view->size.width-4, (int)knobL, WRRaised);
482 /* after */
483 if ((int)(knobP+knobL) < length)
484 XFillRectangle(scr->display, d, scr->stippleGC,
485 2, ofs+(int)(knobP+knobL),
486 view->size.width-4,
487 length-(int)(knobP+knobL));
490 if (sPtr->flags.arrowsPosition != WSANone) {
491 paintArrow(sPtr, d, 0);
492 paintArrow(sPtr, d, 1);
496 #ifdef DOUBLE_BUFFER
497 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0,
498 view->size.width, view->size.height, 0, 0);
499 XFreePixmap(scr->display, d);
500 #endif
505 static void
506 handleEvents(XEvent *event, void *data)
508 Scroller *sPtr = (Scroller*)data;
510 CHECK_CLASS(data, WC_Scroller);
513 switch (event->type) {
514 case Expose:
515 if (event->xexpose.count==0)
516 paintScroller(sPtr);
517 break;
519 case DestroyNotify:
520 destroyScroller(sPtr);
521 break;
528 * locatePointInScroller-
529 * Return the part of the scroller where the point is located.
531 static WMScrollerPart
532 locatePointInScroller(Scroller *sPtr, int x, int y, int alternate)
534 int width = sPtr->view->size.width;
535 int height = sPtr->view->size.height;
536 int c, p1, p2, p3, p4, p5, p6;
537 int knobL, slotL;
540 /* if there is no knob... */
541 if (sPtr->flags.documentFullyVisible)
542 return WSKnobSlot;
544 if (sPtr->flags.horizontal)
545 c = x;
546 else
547 c = y;
549 /* p1 p2 p3 p4 p5 p6
550 * | | |###########| |#####| | |
551 * | < | > |###########| O |#####| < | > |
552 * | | |###########| |#####| | |
555 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
556 p1 = 18;
557 p2 = 36;
559 if (sPtr->flags.horizontal) {
560 slotL = width - 36;
561 p5 = width;
562 } else {
563 slotL = height - 36;
564 p5 = height;
566 p6 = p5;
567 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
568 if (sPtr->flags.horizontal) {
569 slotL = width - 36;
570 p6 = width - 18;
571 } else {
572 slotL = height - 36;
573 p6 = height - 18;
575 p5 = p6 - 18;
577 p1 = p2 = 0;
578 } else {
579 /* no arrows */
580 p1 = p2 = 0;
582 if (sPtr->flags.horizontal) {
583 slotL = p5 = p6 = width;
584 } else {
585 slotL = p5 = p6 = height;
589 knobL = knobLength(sPtr);
590 p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
591 p4 = p3 + knobL;
593 /* uses a mix of the NS and Win ways of doing scroll page */
594 if (c <= p1)
595 return alternate ? WSDecrementPage : WSDecrementLine;
596 else if (c <= p2)
597 return alternate ? WSIncrementPage : WSIncrementLine;
598 else if (c <= p3)
599 return WSDecrementPage;
600 else if (c <= p4)
601 return WSKnob;
602 else if (c <= p5)
603 return WSIncrementPage;
604 else if (c <= p6)
605 return alternate ? WSDecrementPage : WSDecrementLine;
606 else
607 return alternate ? WSIncrementPage : WSIncrementLine;
612 static void
613 handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
615 WMScrollerPart part;
616 int doAction = 0;
618 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
620 sPtr->flags.hitPart = part;
622 switch (part) {
623 case WSIncrementLine:
624 sPtr->flags.incrDown = 1;
625 doAction = 1;
626 break;
628 case WSIncrementPage:
629 doAction = 1;
630 break;
632 case WSDecrementLine:
633 sPtr->flags.decrDown = 1;
634 doAction = 1;
635 break;
637 case WSDecrementPage:
638 doAction = 1;
639 break;
641 case WSKnob:
642 sPtr->flags.draggingKnob = 1;
643 #ifndef STRICT_NEXT_BEHAVIOUR
644 if (sPtr->flags.horizontal)
645 sPtr->dragPoint = pushX;
646 else
647 sPtr->dragPoint = pushY;
650 int length, knobP;
651 int buttonsLen;
653 if (sPtr->flags.arrowsPosition != WSANone)
654 buttonsLen = 2*(BUTTON_SIZE+1);
655 else
656 buttonsLen = 0;
658 if (sPtr->flags.horizontal)
659 length = sPtr->view->size.width - 4 - buttonsLen;
660 else
661 length = sPtr->view->size.height - 4 - buttonsLen;
663 knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
665 if (sPtr->flags.arrowsPosition == WSAMinEnd)
666 sPtr->dragPoint -= 2 + buttonsLen + knobP;
667 else
668 sPtr->dragPoint -= 2 + knobP;
670 #endif /* STRICT_NEXT_BEHAVIOUR */
671 /* This does not seem necesary here since we don't know yet if the
672 * knob will be dragged later. -Dan
673 handleMotion(sPtr, pushX, pushY); */
674 break;
676 case WSKnobSlot:
677 case WSNoPart:
678 /* dummy */
679 break;
682 if (doAction && sPtr->action) {
683 (*sPtr->action)(sPtr, sPtr->clientData);
685 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
690 static float
691 floatValueForPoint(Scroller *sPtr, int point)
693 float floatValue = 0;
694 float position;
695 int slotOfs, slotLength, knobL;
697 if (sPtr->flags.horizontal)
698 slotLength = sPtr->view->size.width - 4;
699 else
700 slotLength = sPtr->view->size.height - 4;
702 slotOfs = 2;
703 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
704 slotLength -= (BUTTON_SIZE+1)*2;
705 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
706 slotOfs += (BUTTON_SIZE+1)*2;
707 slotLength -= (BUTTON_SIZE+1)*2;
710 knobL = (float)knobLength(sPtr);
711 #ifdef STRICT_NEXT_BEHAVIOUR
712 if (point < slotOfs + knobL/2)
713 position = (float)(slotOfs + knobL/2);
714 else if (point > slotOfs + slotLength - knobL/2)
715 position = (float)(slotOfs + slotLength - knobL/2);
716 else
717 position = (float)point;
719 floatValue = (position-(float)(slotOfs+slotLength/2))
720 /(float)(slotLength-knobL);
721 #else
722 /* Adjust the last point to lie inside the knob slot */
723 if (point < slotOfs)
724 position = (float)slotOfs;
725 else if (point > slotOfs + slotLength)
726 position = (float)(slotOfs + slotLength);
727 else
728 position = (float)point;
730 /* Compute the float value */
731 floatValue = (position-(float)slotOfs) / (float)(slotLength-knobL);
732 #endif
734 assert(!isnan(floatValue));
735 return floatValue;
739 static void
740 handleMotion(Scroller *sPtr, int mouseX, int mouseY)
742 if (sPtr->flags.draggingKnob) {
743 float newFloatValue;
744 int point;
746 if (sPtr->flags.horizontal) {
747 point = mouseX;
748 } else {
749 point = mouseY;
752 #ifndef STRICT_NEXT_BEHAVIOUR
753 point -= sPtr->dragPoint;
754 #endif
756 newFloatValue = floatValueForPoint(sPtr, point);
757 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
758 if (sPtr->action) {
759 (*sPtr->action)(sPtr, sPtr->clientData);
760 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
761 NULL);
763 } else {
764 int part;
766 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
768 sPtr->flags.hitPart = part;
770 if (part == WSIncrementLine && sPtr->flags.decrDown) {
771 sPtr->flags.decrDown = 0;
772 sPtr->flags.incrDown = 1;
773 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
774 sPtr->flags.incrDown = 0;
775 sPtr->flags.decrDown = 1;
776 } else if (part != WSIncrementLine && part != WSDecrementLine) {
777 sPtr->flags.incrDown = 0;
778 sPtr->flags.decrDown = 0;
784 static void
785 autoScroll(void *clientData)
787 Scroller *sPtr = (Scroller*)clientData;
789 if (sPtr->action) {
790 (*sPtr->action)(sPtr, sPtr->clientData);
791 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
793 sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
797 static void
798 handleActionEvents(XEvent *event, void *data)
800 Scroller *sPtr = (Scroller*)data;
801 int id, dd;
804 /* check if we're really dealing with a scroller, as something
805 * might have gone wrong in the event dispatching stuff */
806 CHECK_CLASS(sPtr, WC_Scroller);
808 id = sPtr->flags.incrDown;
809 dd = sPtr->flags.decrDown;
811 switch (event->type) {
812 case EnterNotify:
814 break;
816 case LeaveNotify:
817 if (sPtr->timerID) {
818 WMDeleteTimerHandler(sPtr->timerID);
819 sPtr->timerID = NULL;
821 sPtr->flags.incrDown = 0;
822 sPtr->flags.decrDown = 0;
823 break;
825 case ButtonPress:
826 /* FIXME: change Mod1Mask with something else */
827 if (sPtr->flags.documentFullyVisible)
828 break;
829 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp) {
830 if (event->xbutton.state & ControlMask) {
831 sPtr->flags.hitPart = WSDecrementPage;
832 } else if (event->xbutton.state & ShiftMask) {
833 sPtr->flags.hitPart = WSDecrementLine;
834 } else {
835 sPtr->flags.hitPart = WSDecrementWheel;
837 if (sPtr->action) {
838 (*sPtr->action)(sPtr, sPtr->clientData);
839 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
840 NULL);
842 } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
843 if (event->xbutton.state & ControlMask) {
844 sPtr->flags.hitPart = WSIncrementPage;
845 } else if (event->xbutton.state & ShiftMask) {
846 sPtr->flags.hitPart = WSIncrementLine;
847 } else {
848 sPtr->flags.hitPart = WSIncrementWheel;
850 if (sPtr->action) {
851 (*sPtr->action)(sPtr, sPtr->clientData);
852 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
853 NULL);
855 } else {
856 handlePush(sPtr, event->xbutton.x, event->xbutton.y,
857 (event->xbutton.state & Mod1Mask)
858 ||event->xbutton.button==Button2);
859 /* continue scrolling if pushed on the buttons */
860 if (sPtr->flags.hitPart == WSIncrementLine
861 || sPtr->flags.hitPart == WSDecrementLine) {
862 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY,
863 autoScroll, sPtr);
866 break;
868 case ButtonRelease:
869 if (sPtr->flags.draggingKnob) {
870 if (sPtr->action) {
871 (*sPtr->action)(sPtr, sPtr->clientData);
872 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
873 NULL);
876 if (sPtr->timerID) {
877 WMDeleteTimerHandler(sPtr->timerID);
878 sPtr->timerID = NULL;
880 sPtr->flags.incrDown = 0;
881 sPtr->flags.decrDown = 0;
882 sPtr->flags.draggingKnob = 0;
883 break;
885 case MotionNotify:
886 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
887 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
888 && sPtr->flags.hitPart != WSDecrementLine) {
889 WMDeleteTimerHandler(sPtr->timerID);
890 sPtr->timerID = NULL;
892 break;
894 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
895 paintScroller(sPtr);
900 static void
901 destroyScroller(Scroller *sPtr)
903 /* we don't want autoscroll try to scroll a freed widget */
904 if (sPtr->timerID) {
905 WMDeleteTimerHandler(sPtr->timerID);
908 wfree(sPtr);