another test for cvs notifications
[wmaker-crm.git] / WINGs / wscroller.c
blob263848aa1d274f7b9418590cfad2d1f0b9a4e7fa
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) {
312 /* paint button */
313 #ifndef DOUBLE_BUFFER
314 XFillRectangle(scr->display, d, gc,
315 ofs+1, 2+1, BUTTON_SIZE+1-3, BUTTON_SIZE-3);
316 #else
317 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
318 XFillRectangle(scr->display, d, WMColorGC(scr->white),
319 ofs+1, 2+1, BUTTON_SIZE+1-3, BUTTON_SIZE-3);
320 #endif /* DOUBLE_BUFFER */
321 W_DrawRelief(scr, d, ofs, 2, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
323 /* paint arrow */
324 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
325 XSetClipOrigin(scr->display, scr->clipGC,
326 ofs + (BUTTON_SIZE - arrow->width) / 2,
327 2 + (BUTTON_SIZE - arrow->height) / 2);
329 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
330 0, 0, arrow->width, arrow->height,
331 ofs + (BUTTON_SIZE - arrow->width) / 2,
332 2 + (BUTTON_SIZE - arrow->height) / 2);
334 } else { /* vertical */
336 /* paint button */
337 #ifndef DOUBLE_BUFFER
338 XFillRectangle(scr->display, d, gc,
339 2+1, ofs+1, BUTTON_SIZE-3, BUTTON_SIZE+1-3);
340 #else
341 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
342 XFillRectangle(scr->display, d, WMColorGC(scr->white),
343 2+1, ofs+1, BUTTON_SIZE-3, BUTTON_SIZE+1-3);
344 #endif /* DOUBLE_BUFFER */
345 W_DrawRelief(scr, d, 2, ofs, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
347 /* paint arrow */
349 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
350 XSetClipOrigin(scr->display, scr->clipGC,
351 2 + (BUTTON_SIZE - arrow->width) / 2,
352 ofs + (BUTTON_SIZE - arrow->height) / 2);
353 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
354 0, 0, arrow->width, arrow->height,
355 2 + (BUTTON_SIZE - arrow->width) / 2,
356 ofs + (BUTTON_SIZE - arrow->height) / 2);
361 static int
362 knobLength(Scroller *sPtr)
364 int tmp, length;
367 if (sPtr->flags.horizontal)
368 length = sPtr->view->size.width - 4;
369 else
370 length = sPtr->view->size.height - 4;
372 if (sPtr->flags.arrowsPosition != WSANone) {
373 length -= 2*(BUTTON_SIZE+1);
376 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
377 /* keep minimum size */
378 if (tmp < BUTTON_SIZE)
379 tmp = BUTTON_SIZE;
381 return tmp;
385 static void
386 paintScroller(Scroller *sPtr)
388 WMView *view = sPtr->view;
389 WMScreen *scr = view->screen;
390 #ifdef DOUBLE_BUFFER
391 Pixmap d;
392 #else
393 Drawable d = view->window;
394 #endif
395 int length, ofs;
396 float knobP, knobL;
399 #ifdef DOUBLE_BUFFER
400 d = XCreatePixmap(scr->display, view->window, view->size.width,
401 view->size.height, scr->depth);
402 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0,
403 view->size.width, view->size.height);
404 #endif
406 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0,
407 view->size.width-1, view->size.height-1);
408 #ifndef DOUBLE_BUFFER
409 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1,
410 view->size.width-3, view->size.height-3);
411 #endif
413 if (sPtr->flags.horizontal)
414 length = view->size.width - 4;
415 else
416 length = view->size.height - 4;
418 if (sPtr->flags.documentFullyVisible) {
419 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
420 view->size.width-4, view->size.height-4);
421 } else {
422 ofs = 2;
423 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
424 length -= (BUTTON_SIZE+1)*2;
425 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
426 ofs += (BUTTON_SIZE+1)*2;
427 length -= (BUTTON_SIZE+1)*2;
430 knobL = (float)knobLength(sPtr);
432 knobP = sPtr->floatValue * ((float)length - knobL);
434 if (sPtr->flags.horizontal) {
435 /* before */
436 XFillRectangle(scr->display, d, scr->stippleGC,
437 ofs, 2, (int)knobP, view->size.height-4);
439 /* knob */
440 #ifndef DOUBLE_BUFFER
441 XFillRectangle(scr->display, d, scr->lightGC,
442 ofs+(int)knobP+2, 2+2, (int)knobL-4,
443 view->size.height-4-4);
444 #endif
445 W_DrawRelief(scr, d, ofs+(int)knobP, 2, (int)knobL,
446 view->size.height-4, WRRaised);
448 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
449 scr->copyGC, 0, 0,
450 scr->scrollerDimple->width, scr->scrollerDimple->height,
451 ofs+(int)knobP+((int)knobL-scr->scrollerDimple->width-1)/2,
452 (view->size.height-scr->scrollerDimple->height-1)/2);
454 /* after */
455 if ((int)(knobP+knobL) < length)
456 XFillRectangle(scr->display, d, scr->stippleGC,
457 ofs+(int)(knobP+knobL), 2,
458 length-(int)(knobP+knobL),
459 view->size.height-4);
460 } else {
461 /* before */
462 if (knobP>0.0)
463 XFillRectangle(scr->display, d, scr->stippleGC,
464 2, ofs, view->size.width-4, (int)knobP);
466 /* knob */
467 #ifndef DOUBLE_BUFFER
468 XFillRectangle(scr->display, d, scr->lightGC,
469 2+2, ofs+(int)knobP+2,
470 view->size.width-4-4, (int)knobL-4);
471 #endif
472 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
473 scr->copyGC, 0, 0,
474 scr->scrollerDimple->width, scr->scrollerDimple->height,
475 (view->size.width-scr->scrollerDimple->width-1)/2,
476 ofs+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
478 W_DrawRelief(scr, d, 2, ofs+(int)knobP,
479 view->size.width-4, (int)knobL, WRRaised);
481 /* after */
482 if ((int)(knobP+knobL) < length)
483 XFillRectangle(scr->display, d, scr->stippleGC,
484 2, ofs+(int)(knobP+knobL),
485 view->size.width-4,
486 length-(int)(knobP+knobL));
489 if (sPtr->flags.arrowsPosition != WSANone) {
490 paintArrow(sPtr, d, 0);
491 paintArrow(sPtr, d, 1);
495 #ifdef DOUBLE_BUFFER
496 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0,
497 view->size.width, view->size.height, 0, 0);
498 XFreePixmap(scr->display, d);
499 #endif
504 static void
505 handleEvents(XEvent *event, void *data)
507 Scroller *sPtr = (Scroller*)data;
509 CHECK_CLASS(data, WC_Scroller);
512 switch (event->type) {
513 case Expose:
514 if (event->xexpose.count==0)
515 paintScroller(sPtr);
516 break;
518 case DestroyNotify:
519 destroyScroller(sPtr);
520 break;
527 * locatePointInScroller-
528 * Return the part of the scroller where the point is located.
530 static WMScrollerPart
531 locatePointInScroller(Scroller *sPtr, int x, int y, int alternate)
533 int width = sPtr->view->size.width;
534 int height = sPtr->view->size.height;
535 int c, p1, p2, p3, p4, p5, p6;
536 int knobL, slotL;
539 /* if there is no knob... */
540 if (sPtr->flags.documentFullyVisible)
541 return WSKnobSlot;
543 if (sPtr->flags.horizontal)
544 c = x;
545 else
546 c = y;
548 /* p1 p2 p3 p4 p5 p6
549 * | | |###########| |#####| | |
550 * | < | > |###########| O |#####| < | > |
551 * | | |###########| |#####| | |
554 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
555 p1 = 18;
556 p2 = 36;
558 if (sPtr->flags.horizontal) {
559 slotL = width - 36;
560 p5 = width;
561 } else {
562 slotL = height - 36;
563 p5 = height;
565 p6 = p5;
566 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
567 if (sPtr->flags.horizontal) {
568 slotL = width - 36;
569 p6 = width - 18;
570 } else {
571 slotL = height - 36;
572 p6 = height - 18;
574 p5 = p6 - 18;
576 p1 = p2 = 0;
577 } else {
578 /* no arrows */
579 p1 = p2 = 0;
581 if (sPtr->flags.horizontal) {
582 slotL = p5 = p6 = width;
583 } else {
584 slotL = p5 = p6 = height;
588 knobL = knobLength(sPtr);
589 p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
590 p4 = p3 + knobL;
592 /* uses a mix of the NS and Win ways of doing scroll page */
593 if (c <= p1)
594 return alternate ? WSDecrementPage : WSDecrementLine;
595 else if (c <= p2)
596 return alternate ? WSIncrementPage : WSIncrementLine;
597 else if (c <= p3)
598 return WSDecrementPage;
599 else if (c <= p4)
600 return WSKnob;
601 else if (c <= p5)
602 return WSIncrementPage;
603 else if (c <= p6)
604 return alternate ? WSDecrementPage : WSDecrementLine;
605 else
606 return alternate ? WSIncrementPage : WSIncrementLine;
611 static void
612 handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
614 WMScrollerPart part;
615 int doAction = 0;
617 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
619 sPtr->flags.hitPart = part;
621 switch (part) {
622 case WSIncrementLine:
623 sPtr->flags.incrDown = 1;
624 doAction = 1;
625 break;
627 case WSIncrementPage:
628 doAction = 1;
629 break;
631 case WSDecrementLine:
632 sPtr->flags.decrDown = 1;
633 doAction = 1;
634 break;
636 case WSDecrementPage:
637 doAction = 1;
638 break;
640 case WSKnob:
641 sPtr->flags.draggingKnob = 1;
642 #ifndef STRICT_NEXT_BEHAVIOUR
643 if (sPtr->flags.horizontal)
644 sPtr->dragPoint = pushX;
645 else
646 sPtr->dragPoint = pushY;
649 int length, knobP;
650 int buttonsLen;
652 if (sPtr->flags.arrowsPosition != WSANone)
653 buttonsLen = 2*(BUTTON_SIZE+1);
654 else
655 buttonsLen = 0;
657 if (sPtr->flags.horizontal)
658 length = sPtr->view->size.width - 4 - buttonsLen;
659 else
660 length = sPtr->view->size.height - 4 - buttonsLen;
662 knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
664 if (sPtr->flags.arrowsPosition == WSAMinEnd)
665 sPtr->dragPoint -= 2 + buttonsLen + knobP;
666 else
667 sPtr->dragPoint -= 2 + knobP;
669 #endif /* STRICT_NEXT_BEHAVIOUR */
670 /* This does not seem necesary here since we don't know yet if the
671 * knob will be dragged later. -Dan
672 handleMotion(sPtr, pushX, pushY); */
673 break;
675 case WSKnobSlot:
676 case WSNoPart:
677 /* dummy */
678 break;
681 if (doAction && sPtr->action) {
682 (*sPtr->action)(sPtr, sPtr->clientData);
684 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
689 static float
690 floatValueForPoint(Scroller *sPtr, int point)
692 float floatValue = 0;
693 float position;
694 int slotOfs, slotLength, knobL;
696 if (sPtr->flags.horizontal)
697 slotLength = sPtr->view->size.width - 4;
698 else
699 slotLength = sPtr->view->size.height - 4;
701 slotOfs = 2;
702 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
703 slotLength -= (BUTTON_SIZE+1)*2;
704 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
705 slotOfs += (BUTTON_SIZE+1)*2;
706 slotLength -= (BUTTON_SIZE+1)*2;
709 knobL = (float)knobLength(sPtr);
710 #ifdef STRICT_NEXT_BEHAVIOUR
711 if (point < slotOfs + knobL/2)
712 position = (float)(slotOfs + knobL/2);
713 else if (point > slotOfs + slotLength - knobL/2)
714 position = (float)(slotOfs + slotLength - knobL/2);
715 else
716 position = (float)point;
718 floatValue = (position-(float)(slotOfs+slotLength/2))
719 /(float)(slotLength-knobL);
720 #else
721 /* Adjust the last point to lie inside the knob slot */
722 if (point < slotOfs)
723 position = (float)slotOfs;
724 else if (point > slotOfs + slotLength)
725 position = (float)(slotOfs + slotLength);
726 else
727 position = (float)point;
729 /* Compute the float value */
730 floatValue = (position-(float)slotOfs) / (float)(slotLength-knobL);
731 #endif
733 assert(!isnan(floatValue));
734 return floatValue;
738 static void
739 handleMotion(Scroller *sPtr, int mouseX, int mouseY)
741 if (sPtr->flags.draggingKnob) {
742 float newFloatValue;
743 int point;
745 if (sPtr->flags.horizontal) {
746 point = mouseX;
747 } else {
748 point = mouseY;
751 #ifndef STRICT_NEXT_BEHAVIOUR
752 point -= sPtr->dragPoint;
753 #endif
755 newFloatValue = floatValueForPoint(sPtr, point);
756 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
757 if (sPtr->action) {
758 (*sPtr->action)(sPtr, sPtr->clientData);
759 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
760 NULL);
762 } else {
763 int part;
765 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
767 sPtr->flags.hitPart = part;
769 if (part == WSIncrementLine && sPtr->flags.decrDown) {
770 sPtr->flags.decrDown = 0;
771 sPtr->flags.incrDown = 1;
772 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
773 sPtr->flags.incrDown = 0;
774 sPtr->flags.decrDown = 1;
775 } else if (part != WSIncrementLine && part != WSDecrementLine) {
776 sPtr->flags.incrDown = 0;
777 sPtr->flags.decrDown = 0;
783 static void
784 autoScroll(void *clientData)
786 Scroller *sPtr = (Scroller*)clientData;
788 if (sPtr->action) {
789 (*sPtr->action)(sPtr, sPtr->clientData);
790 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
792 sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
796 static void
797 handleActionEvents(XEvent *event, void *data)
799 Scroller *sPtr = (Scroller*)data;
800 int wheelDecrement, wheelIncrement;
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:
813 break;
815 case LeaveNotify:
816 if (sPtr->timerID) {
817 WMDeleteTimerHandler(sPtr->timerID);
818 sPtr->timerID = NULL;
820 sPtr->flags.incrDown = 0;
821 sPtr->flags.decrDown = 0;
822 break;
824 case ButtonPress:
825 /* FIXME: change Mod1Mask with something else */
826 if (sPtr->flags.documentFullyVisible)
827 break;
829 if (sPtr->flags.horizontal) {
830 wheelDecrement = WINGsConfiguration.mouseWheelDown;
831 wheelIncrement = WINGsConfiguration.mouseWheelUp;
832 } else {
833 wheelDecrement = WINGsConfiguration.mouseWheelUp;
834 wheelIncrement = WINGsConfiguration.mouseWheelDown;
837 if (event->xbutton.button == wheelDecrement) {
838 if (event->xbutton.state & ControlMask) {
839 sPtr->flags.hitPart = WSDecrementPage;
840 } else if (event->xbutton.state & ShiftMask) {
841 sPtr->flags.hitPart = WSDecrementLine;
842 } else {
843 sPtr->flags.hitPart = WSDecrementWheel;
845 if (sPtr->action) {
846 (*sPtr->action)(sPtr, sPtr->clientData);
847 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
848 NULL);
850 } else if (event->xbutton.button == wheelIncrement) {
851 if (event->xbutton.state & ControlMask) {
852 sPtr->flags.hitPart = WSIncrementPage;
853 } else if (event->xbutton.state & ShiftMask) {
854 sPtr->flags.hitPart = WSIncrementLine;
855 } else {
856 sPtr->flags.hitPart = WSIncrementWheel;
858 if (sPtr->action) {
859 (*sPtr->action)(sPtr, sPtr->clientData);
860 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
861 NULL);
863 } else {
864 handlePush(sPtr, event->xbutton.x, event->xbutton.y,
865 (event->xbutton.state & Mod1Mask)
866 ||event->xbutton.button==Button2);
867 /* continue scrolling if pushed on the buttons */
868 if (sPtr->flags.hitPart == WSIncrementLine
869 || sPtr->flags.hitPart == WSDecrementLine) {
870 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY,
871 autoScroll, sPtr);
874 break;
876 case ButtonRelease:
877 if (sPtr->flags.draggingKnob) {
878 if (sPtr->action) {
879 (*sPtr->action)(sPtr, sPtr->clientData);
880 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
881 NULL);
884 if (sPtr->timerID) {
885 WMDeleteTimerHandler(sPtr->timerID);
886 sPtr->timerID = NULL;
888 sPtr->flags.incrDown = 0;
889 sPtr->flags.decrDown = 0;
890 sPtr->flags.draggingKnob = 0;
891 break;
893 case MotionNotify:
894 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
895 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
896 && sPtr->flags.hitPart != WSDecrementLine) {
897 WMDeleteTimerHandler(sPtr->timerID);
898 sPtr->timerID = NULL;
900 break;
902 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
903 paintScroller(sPtr);
908 static void
909 destroyScroller(Scroller *sPtr)
911 /* we don't want autoscroll try to scroll a freed widget */
912 if (sPtr->timerID) {
913 WMDeleteTimerHandler(sPtr->timerID);
916 wfree(sPtr);