Fixed a bug in scroller code related to mouse wheels
[wmaker-crm.git] / WINGs / wscroller.c
blob7ee3f0332666773a0c34a69528a3f93cf1a65326
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 char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
21 typedef struct W_Scroller {
22 W_Class widgetClass;
23 W_View *view;
25 void *clientData;
26 WMAction *action;
28 float knobProportion;
29 float floatValue;
31 WMHandlerID timerID; /* for continuous scrolling mode */
33 #ifndef STRICT_NEXT_BEHAVIOUR
34 int dragPoint; /* point where the knob is being
35 * dragged */
36 #endif
37 struct {
38 WMScrollArrowPosition arrowsPosition:4;
40 unsigned int horizontal:1;
42 WMScrollerPart hitPart:4;
44 /* */
45 unsigned int documentFullyVisible:1; /* document is fully visible */
47 unsigned int prevSelected:1;
49 unsigned int pushed:1;
51 unsigned int incrDown:1; /* whether increment button is down */
53 unsigned int decrDown:1;
55 unsigned int draggingKnob:1;
57 unsigned int configured:1;
59 unsigned int redrawPending:1;
60 } flags;
61 } Scroller;
65 #define DEFAULT_HEIGHT 60
66 #define DEFAULT_WIDTH SCROLLER_WIDTH
67 #define DEFAULT_ARROWS_POSITION WSAMinEnd
71 static void destroyScroller(Scroller *sPtr);
72 static void paintScroller(Scroller *sPtr);
74 static void willResizeScroller();
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);
81 W_ViewDelegate _ScrollerViewDelegate = {
82 NULL,
83 NULL,
84 NULL,
85 NULL,
86 willResizeScroller
92 WMScroller*
93 WMCreateScroller(WMWidget *parent)
95 Scroller *sPtr;
97 sPtr = wmalloc(sizeof(Scroller));
98 memset(sPtr, 0, sizeof(Scroller));
100 sPtr->widgetClass = WC_Scroller;
102 sPtr->view = W_CreateView(W_VIEW(parent));
103 if (!sPtr->view) {
104 wfree(sPtr);
105 return NULL;
107 sPtr->view->self = sPtr;
109 sPtr->view->delegate = &_ScrollerViewDelegate;
111 sPtr->flags.documentFullyVisible = 1;
113 WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask
114 |ClientMessageMask, handleEvents, sPtr);
116 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
117 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
119 WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
120 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
121 handleActionEvents, sPtr);
123 sPtr->flags.hitPart = WSNoPart;
125 return sPtr;
130 void
131 WMSetScrollerArrowsPosition(WMScroller *sPtr, WMScrollArrowPosition position)
133 sPtr->flags.arrowsPosition = position;
134 if (sPtr->view->flags.realized) {
135 paintScroller(sPtr);
140 static void
141 willResizeScroller(W_ViewDelegate *self, WMView *view,
142 unsigned int *width, unsigned int *height)
144 WMScroller *sPtr = (WMScroller*)view->self;
146 if (*width > *height) {
147 sPtr->flags.horizontal = 1;
148 *height = SCROLLER_WIDTH;
149 } else {
150 sPtr->flags.horizontal = 0;
151 *width = SCROLLER_WIDTH;
156 void
157 WMSetScrollerAction(WMScroller *sPtr, WMAction *action, void *clientData)
159 CHECK_CLASS(sPtr, WC_Scroller);
161 sPtr->action = action;
163 sPtr->clientData = clientData;
167 void
168 WMSetScrollerParameters(WMScroller *sPtr, float floatValue,
169 float knobProportion)
171 CHECK_CLASS(sPtr, WC_Scroller);
173 if (floatValue < 0.0)
174 sPtr->floatValue = 0.0;
175 else if (floatValue > 1.0)
176 sPtr->floatValue = 1.0;
177 else
178 sPtr->floatValue = floatValue;
180 if (knobProportion <= 0.0) {
182 sPtr->knobProportion = 0.0;
183 sPtr->flags.documentFullyVisible = 0;
185 } else if (knobProportion >= 1.0) {
187 sPtr->knobProportion = 1.0;
188 sPtr->flags.documentFullyVisible = 1;
190 } else {
191 sPtr->knobProportion = knobProportion;
192 sPtr->flags.documentFullyVisible = 0;
195 if (sPtr->view->flags.realized)
196 paintScroller(sPtr);
200 float
201 WMGetScrollerKnobProportion(WMScroller *sPtr)
203 CHECK_CLASS(sPtr, WC_Scroller);
205 return sPtr->knobProportion;
209 float
210 WMGetScrollerValue(WMScroller *sPtr)
212 CHECK_CLASS(sPtr, WC_Scroller);
214 return sPtr->floatValue;
218 WMScrollerPart
219 WMGetScrollerHitPart(WMScroller *sPtr)
221 CHECK_CLASS(sPtr, WC_Scroller);
223 return sPtr->flags.hitPart;
227 static void
228 paintArrow(WMScroller *sPtr, Drawable d, int part)
230 * part- 0 paints the decrement arrow, 1 the increment arrow
233 WMView *view = sPtr->view;
234 WMScreen *scr = view->screen;
235 int ofs, bsize;
236 W_Pixmap *arrow;
238 #ifndef DOUBLE_BUFFER
239 GC gc = scr->lightGC;
240 #endif
242 bsize = SCROLLER_WIDTH - 4;
245 if (part == 0) { /* decrement button */
246 if (sPtr->flags.horizontal) {
247 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
248 ofs = view->size.width - 2*(bsize+1) - 1;
249 } else {
250 ofs = 2;
252 if (sPtr->flags.decrDown)
253 arrow = scr->hiLeftArrow;
254 else
255 arrow = scr->leftArrow;
257 } else {
258 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
259 ofs = view->size.height - 2*(bsize+1) - 1;
260 } else {
261 ofs = 2;
263 if (sPtr->flags.decrDown)
264 arrow = scr->hiUpArrow;
265 else
266 arrow = scr->upArrow;
269 #ifndef DOUBLE_BUFFER
270 if (sPtr->flags.decrDown)
271 gc = WMColorGC(scr->white);
272 #endif
273 } else { /* increment button */
274 if (sPtr->flags.horizontal) {
275 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
276 ofs = view->size.width - bsize+1 - 3;
277 } else {
278 ofs = 2 + bsize+1;
280 if (sPtr->flags.incrDown)
281 arrow = scr->hiRightArrow;
282 else
283 arrow = scr->rightArrow;
284 } else {
285 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
286 ofs = view->size.height - bsize+1 - 3;
287 } else {
288 ofs = 2 + bsize+1;
290 if (sPtr->flags.incrDown)
291 arrow = scr->hiDownArrow;
292 else
293 arrow = scr->downArrow;
296 #ifndef DOUBLE_BUFFER
297 if (sPtr->flags.incrDown)
298 gc = scr->whiteGC;
299 #endif
303 if (sPtr->flags.horizontal) {
305 /* paint button */
306 #ifndef DOUBLE_BUFFER
307 XFillRectangle(scr->display, d, gc,
308 ofs+1, 2+1, bsize+1-3, bsize-3);
309 #else
310 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
311 XFillRectangle(scr->display, d, WMColorGC(scr->white),
312 ofs+1, 2+1, bsize+1-3, bsize-3);
313 #endif /* DOUBLE_BUFFER */
314 W_DrawRelief(scr, d, ofs, 2, bsize, bsize, WRRaised);
316 /* paint arrow */
317 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
318 XSetClipOrigin(scr->display, scr->clipGC,
319 ofs + (bsize - arrow->width) / 2,
320 2 + (bsize - arrow->height) / 2);
322 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
323 0, 0, arrow->width, arrow->height,
324 ofs + (bsize - arrow->width) / 2,
325 2 + (bsize - arrow->height) / 2);
327 } else { /* vertical */
329 /* paint button */
330 #ifndef DOUBLE_BUFFER
331 XFillRectangle(scr->display, d, gc,
332 2+1, ofs+1, bsize-3, bsize+1-3);
333 #else
334 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
335 XFillRectangle(scr->display, d, WMColorGC(scr->white),
336 2+1, ofs+1, bsize-3, bsize+1-3);
337 #endif /* DOUBLE_BUFFER */
338 W_DrawRelief(scr, d, 2, ofs, bsize, bsize, WRRaised);
340 /* paint arrow */
342 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
343 XSetClipOrigin(scr->display, scr->clipGC,
344 2 + (bsize - arrow->width) / 2,
345 ofs + (bsize - arrow->height) / 2);
346 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
347 0, 0, arrow->width, arrow->height,
348 2 + (bsize - arrow->width) / 2,
349 ofs + (bsize - arrow->height) / 2);
354 static int
355 knobLength(Scroller *sPtr)
357 int tmp, length;
360 if (sPtr->flags.horizontal)
361 length = sPtr->view->size.width - 4;
362 else
363 length = sPtr->view->size.height - 4;
365 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
366 length -= (SCROLLER_WIDTH - 4 + 1)*2;
367 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
368 length -= (SCROLLER_WIDTH - 4 + 1)*2;
371 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
372 /* keep minimum size */
373 if (tmp < SCROLLER_WIDTH-4)
374 tmp = SCROLLER_WIDTH-4;
376 return tmp;
380 static void
381 paintScroller(Scroller *sPtr)
383 WMView *view = sPtr->view;
384 WMScreen *scr = view->screen;
385 #ifdef DOUBLE_BUFFER
386 Pixmap d;
387 #else
388 Drawable d = view->window;
389 #endif
390 int length, ofs;
391 float knobP, knobL;
394 #ifdef DOUBLE_BUFFER
395 d = XCreatePixmap(scr->display, view->window, view->size.width,
396 view->size.height, scr->depth);
397 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0,
398 view->size.width, view->size.height);
399 #endif
401 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0,
402 view->size.width-1, view->size.height-1);
403 #ifndef DOUBLE_BUFFER
404 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1,
405 view->size.width-3, view->size.height-3);
406 #endif
408 if (sPtr->flags.horizontal)
409 length = view->size.width - 4;
410 else
411 length = view->size.height - 4;
413 if (sPtr->flags.documentFullyVisible) {
414 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
415 view->size.width-4, view->size.height-4);
416 } else {
417 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
418 ofs = 0;
419 length -= (SCROLLER_WIDTH - 4 + 1)*2;
420 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
421 ofs = (SCROLLER_WIDTH - 4 + 1)*2;
422 length -= (SCROLLER_WIDTH - 4 + 1)*2;
423 } else {
424 ofs = 0;
427 knobL = (float)knobLength(sPtr);
429 knobP = sPtr->floatValue * ((float)length - knobL);
432 if (sPtr->flags.horizontal) {
433 /* before */
434 XFillRectangle(scr->display, d, scr->stippleGC,
435 ofs+2, 2, (int)knobP, view->size.height-4);
437 /* knob */
438 #ifndef DOUBLE_BUFFER
439 XFillRectangle(scr->display, d, scr->lightGC,
440 ofs+2+(int)knobP+2, 2+2, (int)knobL-4,
441 view->size.height-4-4);
442 #endif
443 W_DrawRelief(scr, d, ofs+2+(int)knobP, 2, (int)knobL,
444 view->size.height-4, WRRaised);
446 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
447 scr->copyGC, 0, 0,
448 scr->scrollerDimple->width, scr->scrollerDimple->height,
449 ofs+2+(int)knobP+((int)knobL-scr->scrollerDimple->width-1)/2,
450 (view->size.height-scr->scrollerDimple->height-1)/2);
452 /* after */
453 if ((int)(knobP+knobL) < length)
454 XFillRectangle(scr->display, d, scr->stippleGC,
455 ofs+2+(int)(knobP+knobL), 2,
456 length-(int)(knobP+knobL),
457 view->size.height-4);
458 } else {
459 /* before */
460 if (knobP>0.0)
461 XFillRectangle(scr->display, d, scr->stippleGC,
462 2, ofs+2, view->size.width-4, (int)knobP);
464 /* knob */
465 #ifndef DOUBLE_BUFFER
466 XFillRectangle(scr->display, d, scr->lightGC,
467 2+2, ofs+2+(int)knobP+2,
468 view->size.width-4-4, (int)knobL-4);
469 #endif
470 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
471 scr->copyGC, 0, 0,
472 scr->scrollerDimple->width, scr->scrollerDimple->height,
473 (view->size.width-scr->scrollerDimple->width-1)/2,
474 ofs+2+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
476 W_DrawRelief(scr, d, 2, ofs+2+(int)knobP,
477 view->size.width-4, (int)knobL, WRRaised);
479 /* after */
480 if ((int)(knobP+knobL) < length)
481 XFillRectangle(scr->display, d, scr->stippleGC,
482 2, ofs+2+(int)(knobP+knobL),
483 view->size.width-4,
484 length-(int)(knobP+knobL));
487 if (sPtr->flags.arrowsPosition != WSANone) {
488 paintArrow(sPtr, d, 0);
489 paintArrow(sPtr, d, 1);
493 #ifdef DOUBLE_BUFFER
494 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0,
495 view->size.width, view->size.height, 0, 0);
496 XFreePixmap(scr->display, d);
497 #endif
502 static void
503 handleEvents(XEvent *event, void *data)
505 Scroller *sPtr = (Scroller*)data;
507 CHECK_CLASS(data, WC_Scroller);
510 switch (event->type) {
511 case Expose:
512 if (event->xexpose.count==0)
513 paintScroller(sPtr);
514 break;
516 case DestroyNotify:
517 destroyScroller(sPtr);
518 break;
525 * locatePointInScroller-
526 * Return the part of the scroller where the point is located.
528 static WMScrollerPart
529 locatePointInScroller(Scroller *sPtr, int x, int y, int alternate)
531 int width = sPtr->view->size.width;
532 int height = sPtr->view->size.height;
533 int c, p1, p2, p3, p4, p5, p6;
534 int knobL, slotL;
537 /* if there is no knob... */
538 if (sPtr->flags.documentFullyVisible)
539 return WSKnobSlot;
541 if (sPtr->flags.horizontal)
542 c = x;
543 else
544 c = y;
546 /* p1 p2 p3 p4 p5 p6
547 * | | |###########| |#####| | |
548 * | < | > |###########| O |#####| < | > |
549 * | | |###########| |#####| | |
552 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
553 p1 = 18;
554 p2 = 36;
556 if (sPtr->flags.horizontal) {
557 slotL = width - 36;
558 p5 = width;
559 } else {
560 slotL = height - 36;
561 p5 = height;
563 p6 = p5;
564 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
565 if (sPtr->flags.horizontal) {
566 slotL = width - 36;
567 p6 = width - 18;
568 } else {
569 slotL = height - 36;
570 p6 = height - 18;
572 p5 = p6 - 18;
574 p1 = p2 = 0;
575 } else {
576 /* no arrows */
577 p1 = p2 = 0;
579 if (sPtr->flags.horizontal) {
580 slotL = p5 = p6 = width;
581 } else {
582 slotL = p5 = p6 = height;
586 knobL = knobLength(sPtr);
587 p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
588 p4 = p3 + knobL;
590 /* uses a mix of the NS and Win ways of doing scroll page */
591 if (c <= p1)
592 return alternate ? WSDecrementPage : WSDecrementLine;
593 else if (c <= p2)
594 return alternate ? WSIncrementPage : WSIncrementLine;
595 else if (c <= p3)
596 return WSDecrementPage;
597 else if (c <= p4)
598 return WSKnob;
599 else if (c <= p5)
600 return WSIncrementPage;
601 else if (c <= p6)
602 return alternate ? WSDecrementPage : WSDecrementLine;
603 else
604 return alternate ? WSIncrementPage : WSIncrementLine;
609 static void
610 handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
612 WMScrollerPart part;
613 int doAction = 0;
615 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
617 sPtr->flags.hitPart = part;
619 switch (part) {
620 case WSIncrementLine:
621 sPtr->flags.incrDown = 1;
622 doAction = 1;
623 break;
625 case WSIncrementPage:
626 doAction = 1;
627 break;
629 case WSDecrementLine:
630 sPtr->flags.decrDown = 1;
631 doAction = 1;
632 break;
634 case WSDecrementPage:
635 doAction = 1;
636 break;
638 case WSKnob:
639 sPtr->flags.draggingKnob = 1;
640 #ifndef STRICT_NEXT_BEHAVIOUR
641 if (sPtr->flags.horizontal)
642 sPtr->dragPoint = pushX;
643 else
644 sPtr->dragPoint = pushY;
647 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
648 int length, knobP;
650 if (sPtr->flags.horizontal)
651 length = sPtr->view->size.width - 4;
652 else
653 length = sPtr->view->size.height - 4;
655 if (!noButtons)
656 length -= 36;
658 knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
660 if (sPtr->flags.arrowsPosition == WSAMinEnd)
661 sPtr->dragPoint -= 2 + (noButtons ? 0 : 36) + knobP;
662 else
663 sPtr->dragPoint -= 2 + knobP;
665 #endif /* STRICT_NEXT_BEHAVIOUR */
666 /* This does not seem necesary here since we don't know yet if the
667 * knob will be dragged later. -Dan
668 handleMotion(sPtr, pushX, pushY); */
669 break;
671 case WSKnobSlot:
672 case WSNoPart:
673 /* dummy */
674 break;
677 if (doAction && sPtr->action) {
678 (*sPtr->action)(sPtr, sPtr->clientData);
680 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
685 static float
686 floatValueForPoint(int slotOfs, int slotLength, int knobLength, int point)
688 float floatValue = 0;
689 float position;
691 #ifdef STRICT_NEXT_BEHAVIOUR
692 if (point < slotOfs + knobLength/2)
693 position = (float)(slotOfs + knobLength/2);
694 else if (point > slotOfs + slotLength - knobLength/2)
695 position = (float)(slotOfs + slotLength - knobLength/2);
696 else
697 position = (float)point;
699 floatValue = (position-(float)(slotOfs+slotLength/2))
700 /(float)(slotLength-knobLength);
701 #else
702 /* Adjust the last point to lie inside the knob slot */
703 if (point < slotOfs)
704 position = (float)slotOfs;
705 else if (point > slotOfs + slotLength)
706 position = (float)(slotOfs + slotLength);
707 else
708 position = (float)point;
710 /* Compute the float value */
711 floatValue = (position-(float)slotOfs) / (float)(slotLength-knobLength);
712 #endif
714 return floatValue;
718 static void
719 handleMotion(Scroller *sPtr, int mouseX, int mouseY)
721 int slotOffset;
722 int slotLength;
723 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
725 if (sPtr->flags.arrowsPosition == WSAMinEnd)
726 slotOffset = 2 + (noButtons ? 0 : 36);
727 else
728 slotOffset = 2;
730 if (sPtr->flags.draggingKnob) {
731 float newFloatValue;
732 #ifdef STRICT_NEXT_BEHAVIOUR
733 if (sPtr->flags.horizontal) {
734 slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
735 newFloatValue = floatValueForPoint(slotOffset, slotLength,
736 (int)(slotLength*sPtr->knobProportion),
737 mouseX);
738 } else {
739 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
740 newFloatValue = floatValueForPoint(slotOffset, slotLength,
741 (int)(slotLength*sPtr->knobProportion),
742 mouseY);
744 #else
745 if (sPtr->flags.horizontal) {
746 slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
747 newFloatValue = floatValueForPoint(slotOffset, slotLength,
748 (int)(slotLength*sPtr->knobProportion),
749 mouseX-sPtr->dragPoint);
750 } else {
751 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
752 newFloatValue = floatValueForPoint(slotOffset, slotLength,
753 (int)(slotLength*sPtr->knobProportion),
754 mouseY-sPtr->dragPoint);
756 #endif /* !STRICT_NEXT_BEHAVIOUR */
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);