- put back wmksize(), wmkrange() and wmkpoint() as functions instead of macros
[wmaker-crm.git] / WINGs / wscroller.c
blobd8eacd613b86a545c140bbe2733390f59ccca208
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
73 static void destroyScroller(Scroller *sPtr);
74 static void paintScroller(Scroller *sPtr);
76 static void willResizeScroller();
77 static void handleEvents(XEvent *event, void *data);
78 static void handleActionEvents(XEvent *event, void *data);
80 static void handleMotion(Scroller *sPtr, int mouseX, int mouseY);
83 W_ViewDelegate _ScrollerViewDelegate = {
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 willResizeScroller
94 WMScroller*
95 WMCreateScroller(WMWidget *parent)
97 Scroller *sPtr;
99 sPtr = wmalloc(sizeof(Scroller));
100 memset(sPtr, 0, sizeof(Scroller));
102 sPtr->widgetClass = WC_Scroller;
104 sPtr->view = W_CreateView(W_VIEW(parent));
105 if (!sPtr->view) {
106 wfree(sPtr);
107 return NULL;
109 sPtr->view->self = sPtr;
111 sPtr->view->delegate = &_ScrollerViewDelegate;
113 sPtr->flags.documentFullyVisible = 1;
115 WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask
116 |ClientMessageMask, handleEvents, sPtr);
118 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
119 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
121 WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
122 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
123 handleActionEvents, sPtr);
125 sPtr->flags.hitPart = WSNoPart;
127 sPtr->floatValue = 0.0;
128 sPtr->knobProportion = 1.0;
130 return sPtr;
135 void
136 WMSetScrollerArrowsPosition(WMScroller *sPtr, WMScrollArrowPosition position)
138 sPtr->flags.arrowsPosition = position;
139 if (sPtr->view->flags.realized) {
140 paintScroller(sPtr);
145 static void
146 willResizeScroller(W_ViewDelegate *self, WMView *view,
147 unsigned int *width, unsigned int *height)
149 WMScroller *sPtr = (WMScroller*)view->self;
151 if (*width > *height) {
152 sPtr->flags.horizontal = 1;
153 *height = SCROLLER_WIDTH;
154 } else {
155 sPtr->flags.horizontal = 0;
156 *width = SCROLLER_WIDTH;
161 void
162 WMSetScrollerAction(WMScroller *sPtr, WMAction *action, void *clientData)
164 CHECK_CLASS(sPtr, WC_Scroller);
166 sPtr->action = action;
168 sPtr->clientData = clientData;
172 void
173 WMSetScrollerParameters(WMScroller *sPtr, float floatValue,
174 float knobProportion)
176 CHECK_CLASS(sPtr, WC_Scroller);
178 assert(!isnan(floatValue));
180 if (floatValue < 0.0)
181 sPtr->floatValue = 0.0;
182 else if (floatValue > 1.0)
183 sPtr->floatValue = 1.0;
184 else
185 sPtr->floatValue = floatValue;
187 if (knobProportion <= 0.0) {
189 sPtr->knobProportion = 0.0;
190 sPtr->flags.documentFullyVisible = 0;
192 } else if (knobProportion >= 1.0) {
194 sPtr->knobProportion = 1.0;
195 sPtr->flags.documentFullyVisible = 1;
197 } else {
198 sPtr->knobProportion = knobProportion;
199 sPtr->flags.documentFullyVisible = 0;
202 if (sPtr->view->flags.realized)
203 paintScroller(sPtr);
205 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);*/
209 float
210 WMGetScrollerKnobProportion(WMScroller *sPtr)
212 CHECK_CLASS(sPtr, WC_Scroller);
214 return sPtr->knobProportion;
218 float
219 WMGetScrollerValue(WMScroller *sPtr)
221 CHECK_CLASS(sPtr, WC_Scroller);
223 return sPtr->floatValue;
227 WMScrollerPart
228 WMGetScrollerHitPart(WMScroller *sPtr)
230 CHECK_CLASS(sPtr, WC_Scroller);
232 return sPtr->flags.hitPart;
236 static void
237 paintArrow(WMScroller *sPtr, Drawable d, int part)
239 * part- 0 paints the decrement arrow, 1 the increment arrow
242 WMView *view = sPtr->view;
243 WMScreen *scr = view->screen;
244 int ofs, bsize;
245 W_Pixmap *arrow;
247 #ifndef DOUBLE_BUFFER
248 GC gc = scr->lightGC;
249 #endif
251 bsize = SCROLLER_WIDTH - 4;
254 if (part == 0) { /* decrement button */
255 if (sPtr->flags.horizontal) {
256 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
257 ofs = view->size.width - 2*(bsize+1) - 1;
258 } else {
259 ofs = 2;
261 if (sPtr->flags.decrDown)
262 arrow = scr->hiLeftArrow;
263 else
264 arrow = scr->leftArrow;
266 } else {
267 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
268 ofs = view->size.height - 2*(bsize+1) - 1;
269 } else {
270 ofs = 2;
272 if (sPtr->flags.decrDown)
273 arrow = scr->hiUpArrow;
274 else
275 arrow = scr->upArrow;
278 #ifndef DOUBLE_BUFFER
279 if (sPtr->flags.decrDown)
280 gc = WMColorGC(scr->white);
281 #endif
282 } else { /* increment button */
283 if (sPtr->flags.horizontal) {
284 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
285 ofs = view->size.width - bsize+1 - 3;
286 } else {
287 ofs = 2 + bsize+1;
289 if (sPtr->flags.incrDown)
290 arrow = scr->hiRightArrow;
291 else
292 arrow = scr->rightArrow;
293 } else {
294 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
295 ofs = view->size.height - bsize+1 - 3;
296 } else {
297 ofs = 2 + bsize+1;
299 if (sPtr->flags.incrDown)
300 arrow = scr->hiDownArrow;
301 else
302 arrow = scr->downArrow;
305 #ifndef DOUBLE_BUFFER
306 if (sPtr->flags.incrDown)
307 gc = scr->whiteGC;
308 #endif
312 if (sPtr->flags.horizontal) {
314 /* paint button */
315 #ifndef DOUBLE_BUFFER
316 XFillRectangle(scr->display, d, gc,
317 ofs+1, 2+1, bsize+1-3, bsize-3);
318 #else
319 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
320 XFillRectangle(scr->display, d, WMColorGC(scr->white),
321 ofs+1, 2+1, bsize+1-3, bsize-3);
322 #endif /* DOUBLE_BUFFER */
323 W_DrawRelief(scr, d, ofs, 2, bsize, bsize, WRRaised);
325 /* paint arrow */
326 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
327 XSetClipOrigin(scr->display, scr->clipGC,
328 ofs + (bsize - arrow->width) / 2,
329 2 + (bsize - arrow->height) / 2);
331 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
332 0, 0, arrow->width, arrow->height,
333 ofs + (bsize - arrow->width) / 2,
334 2 + (bsize - arrow->height) / 2);
336 } else { /* vertical */
338 /* paint button */
339 #ifndef DOUBLE_BUFFER
340 XFillRectangle(scr->display, d, gc,
341 2+1, ofs+1, bsize-3, bsize+1-3);
342 #else
343 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
344 XFillRectangle(scr->display, d, WMColorGC(scr->white),
345 2+1, ofs+1, bsize-3, bsize+1-3);
346 #endif /* DOUBLE_BUFFER */
347 W_DrawRelief(scr, d, 2, ofs, bsize, bsize, WRRaised);
349 /* paint arrow */
351 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
352 XSetClipOrigin(scr->display, scr->clipGC,
353 2 + (bsize - arrow->width) / 2,
354 ofs + (bsize - arrow->height) / 2);
355 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
356 0, 0, arrow->width, arrow->height,
357 2 + (bsize - arrow->width) / 2,
358 ofs + (bsize - arrow->height) / 2);
363 static int
364 knobLength(Scroller *sPtr)
366 int tmp, length;
369 if (sPtr->flags.horizontal)
370 length = sPtr->view->size.width - 4;
371 else
372 length = sPtr->view->size.height - 4;
374 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
375 length -= (SCROLLER_WIDTH - 4 + 1)*2;
376 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
377 length -= (SCROLLER_WIDTH - 4 + 1)*2;
380 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
381 /* keep minimum size */
382 if (tmp < SCROLLER_WIDTH-4)
383 tmp = SCROLLER_WIDTH-4;
385 return tmp;
389 static void
390 paintScroller(Scroller *sPtr)
392 WMView *view = sPtr->view;
393 WMScreen *scr = view->screen;
394 #ifdef DOUBLE_BUFFER
395 Pixmap d;
396 #else
397 Drawable d = view->window;
398 #endif
399 int length, ofs;
400 float knobP, knobL;
403 #ifdef DOUBLE_BUFFER
404 d = XCreatePixmap(scr->display, view->window, view->size.width,
405 view->size.height, scr->depth);
406 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0,
407 view->size.width, view->size.height);
408 #endif
410 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0,
411 view->size.width-1, view->size.height-1);
412 #ifndef DOUBLE_BUFFER
413 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1,
414 view->size.width-3, view->size.height-3);
415 #endif
417 if (sPtr->flags.horizontal)
418 length = view->size.width - 4;
419 else
420 length = view->size.height - 4;
422 if (sPtr->flags.documentFullyVisible) {
423 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
424 view->size.width-4, view->size.height-4);
425 } else {
426 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
427 ofs = 0;
428 length -= (SCROLLER_WIDTH - 4 + 1)*2;
429 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
430 ofs = (SCROLLER_WIDTH - 4 + 1)*2;
431 length -= (SCROLLER_WIDTH - 4 + 1)*2;
432 } else {
433 ofs = 0;
436 knobL = (float)knobLength(sPtr);
438 knobP = sPtr->floatValue * ((float)length - knobL);
440 if (sPtr->flags.horizontal) {
441 /* before */
442 XFillRectangle(scr->display, d, scr->stippleGC,
443 ofs+2, 2, (int)knobP, view->size.height-4);
445 /* knob */
446 #ifndef DOUBLE_BUFFER
447 XFillRectangle(scr->display, d, scr->lightGC,
448 ofs+2+(int)knobP+2, 2+2, (int)knobL-4,
449 view->size.height-4-4);
450 #endif
451 W_DrawRelief(scr, d, ofs+2+(int)knobP, 2, (int)knobL,
452 view->size.height-4, WRRaised);
454 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
455 scr->copyGC, 0, 0,
456 scr->scrollerDimple->width, scr->scrollerDimple->height,
457 ofs+2+(int)knobP+((int)knobL-scr->scrollerDimple->width-1)/2,
458 (view->size.height-scr->scrollerDimple->height-1)/2);
460 /* after */
461 if ((int)(knobP+knobL) < length)
462 XFillRectangle(scr->display, d, scr->stippleGC,
463 ofs+2+(int)(knobP+knobL), 2,
464 length-(int)(knobP+knobL),
465 view->size.height-4);
466 } else {
467 /* before */
468 if (knobP>0.0)
469 XFillRectangle(scr->display, d, scr->stippleGC,
470 2, ofs+2, view->size.width-4, (int)knobP);
472 /* knob */
473 #ifndef DOUBLE_BUFFER
474 XFillRectangle(scr->display, d, scr->lightGC,
475 2+2, ofs+2+(int)knobP+2,
476 view->size.width-4-4, (int)knobL-4);
477 #endif
478 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
479 scr->copyGC, 0, 0,
480 scr->scrollerDimple->width, scr->scrollerDimple->height,
481 (view->size.width-scr->scrollerDimple->width-1)/2,
482 ofs+2+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
484 W_DrawRelief(scr, d, 2, ofs+2+(int)knobP,
485 view->size.width-4, (int)knobL, WRRaised);
487 /* after */
488 if ((int)(knobP+knobL) < length)
489 XFillRectangle(scr->display, d, scr->stippleGC,
490 2, ofs+2+(int)(knobP+knobL),
491 view->size.width-4,
492 length-(int)(knobP+knobL));
495 if (sPtr->flags.arrowsPosition != WSANone) {
496 paintArrow(sPtr, d, 0);
497 paintArrow(sPtr, d, 1);
501 #ifdef DOUBLE_BUFFER
502 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0,
503 view->size.width, view->size.height, 0, 0);
504 XFreePixmap(scr->display, d);
505 #endif
510 static void
511 handleEvents(XEvent *event, void *data)
513 Scroller *sPtr = (Scroller*)data;
515 CHECK_CLASS(data, WC_Scroller);
518 switch (event->type) {
519 case Expose:
520 if (event->xexpose.count==0)
521 paintScroller(sPtr);
522 break;
524 case DestroyNotify:
525 destroyScroller(sPtr);
526 break;
533 * locatePointInScroller-
534 * Return the part of the scroller where the point is located.
536 static WMScrollerPart
537 locatePointInScroller(Scroller *sPtr, int x, int y, int alternate)
539 int width = sPtr->view->size.width;
540 int height = sPtr->view->size.height;
541 int c, p1, p2, p3, p4, p5, p6;
542 int knobL, slotL;
545 /* if there is no knob... */
546 if (sPtr->flags.documentFullyVisible)
547 return WSKnobSlot;
549 if (sPtr->flags.horizontal)
550 c = x;
551 else
552 c = y;
554 /* p1 p2 p3 p4 p5 p6
555 * | | |###########| |#####| | |
556 * | < | > |###########| O |#####| < | > |
557 * | | |###########| |#####| | |
560 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
561 p1 = 18;
562 p2 = 36;
564 if (sPtr->flags.horizontal) {
565 slotL = width - 36;
566 p5 = width;
567 } else {
568 slotL = height - 36;
569 p5 = height;
571 p6 = p5;
572 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
573 if (sPtr->flags.horizontal) {
574 slotL = width - 36;
575 p6 = width - 18;
576 } else {
577 slotL = height - 36;
578 p6 = height - 18;
580 p5 = p6 - 18;
582 p1 = p2 = 0;
583 } else {
584 /* no arrows */
585 p1 = p2 = 0;
587 if (sPtr->flags.horizontal) {
588 slotL = p5 = p6 = width;
589 } else {
590 slotL = p5 = p6 = height;
594 knobL = knobLength(sPtr);
595 p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
596 p4 = p3 + knobL;
598 /* uses a mix of the NS and Win ways of doing scroll page */
599 if (c <= p1)
600 return alternate ? WSDecrementPage : WSDecrementLine;
601 else if (c <= p2)
602 return alternate ? WSIncrementPage : WSIncrementLine;
603 else if (c <= p3)
604 return WSDecrementPage;
605 else if (c <= p4)
606 return WSKnob;
607 else if (c <= p5)
608 return WSIncrementPage;
609 else if (c <= p6)
610 return alternate ? WSDecrementPage : WSDecrementLine;
611 else
612 return alternate ? WSIncrementPage : WSIncrementLine;
617 static void
618 handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
620 WMScrollerPart part;
621 int doAction = 0;
623 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
625 sPtr->flags.hitPart = part;
627 switch (part) {
628 case WSIncrementLine:
629 sPtr->flags.incrDown = 1;
630 doAction = 1;
631 break;
633 case WSIncrementPage:
634 doAction = 1;
635 break;
637 case WSDecrementLine:
638 sPtr->flags.decrDown = 1;
639 doAction = 1;
640 break;
642 case WSDecrementPage:
643 doAction = 1;
644 break;
646 case WSKnob:
647 sPtr->flags.draggingKnob = 1;
648 #ifndef STRICT_NEXT_BEHAVIOUR
649 if (sPtr->flags.horizontal)
650 sPtr->dragPoint = pushX;
651 else
652 sPtr->dragPoint = pushY;
655 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
656 int length, knobP;
658 if (sPtr->flags.horizontal)
659 length = sPtr->view->size.width - 4;
660 else
661 length = sPtr->view->size.height - 4;
663 if (!noButtons)
664 length -= 36;
666 knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
668 if (sPtr->flags.arrowsPosition == WSAMinEnd)
669 sPtr->dragPoint -= 2 + (noButtons ? 0 : 36) + knobP;
670 else
671 sPtr->dragPoint -= 2 + knobP;
673 #endif /* STRICT_NEXT_BEHAVIOUR */
674 /* This does not seem necesary here since we don't know yet if the
675 * knob will be dragged later. -Dan
676 handleMotion(sPtr, pushX, pushY); */
677 break;
679 case WSKnobSlot:
680 case WSNoPart:
681 /* dummy */
682 break;
685 if (doAction && sPtr->action) {
686 (*sPtr->action)(sPtr, sPtr->clientData);
688 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
693 static float
694 floatValueForPoint(int slotOfs, int slotLength, int knobLength, int point)
696 float floatValue = 0;
697 float position;
699 #ifdef STRICT_NEXT_BEHAVIOUR
700 if (point < slotOfs + knobLength/2)
701 position = (float)(slotOfs + knobLength/2);
702 else if (point > slotOfs + slotLength - knobLength/2)
703 position = (float)(slotOfs + slotLength - knobLength/2);
704 else
705 position = (float)point;
707 floatValue = (position-(float)(slotOfs+slotLength/2))
708 /(float)(slotLength-knobLength);
709 #else
710 /* Adjust the last point to lie inside the knob slot */
711 if (point < slotOfs)
712 position = (float)slotOfs;
713 else if (point > slotOfs + slotLength)
714 position = (float)(slotOfs + slotLength);
715 else
716 position = (float)point;
718 /* Compute the float value */
719 floatValue = (position-(float)slotOfs) / (float)(slotLength-knobLength);
720 #endif
722 assert(!isnan(floatValue));
723 return floatValue;
727 static void
728 handleMotion(Scroller *sPtr, int mouseX, int mouseY)
730 int slotOffset;
731 int slotLength;
732 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
734 if (sPtr->flags.arrowsPosition == WSAMinEnd)
735 slotOffset = 2 + (noButtons ? 0 : 36);
736 else
737 slotOffset = 2;
739 if (sPtr->flags.draggingKnob) {
740 float newFloatValue;
741 #ifdef STRICT_NEXT_BEHAVIOUR
742 if (sPtr->flags.horizontal) {
743 slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
744 newFloatValue = floatValueForPoint(slotOffset, slotLength,
745 (int)(slotLength*sPtr->knobProportion),
746 mouseX);
747 } else {
748 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
749 newFloatValue = floatValueForPoint(slotOffset, slotLength,
750 (int)(slotLength*sPtr->knobProportion),
751 mouseY);
753 #else
754 if (sPtr->flags.horizontal) {
755 slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
756 newFloatValue = floatValueForPoint(slotOffset, slotLength,
757 (int)(slotLength*sPtr->knobProportion),
758 mouseX-sPtr->dragPoint);
759 } else {
760 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
761 newFloatValue = floatValueForPoint(slotOffset, slotLength,
762 (int)(slotLength*sPtr->knobProportion),
763 mouseY-sPtr->dragPoint);
765 #endif /* !STRICT_NEXT_BEHAVIOUR */
766 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
767 if (sPtr->action) {
768 (*sPtr->action)(sPtr, sPtr->clientData);
769 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
770 NULL);
772 } else {
773 int part;
775 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
777 sPtr->flags.hitPart = part;
779 if (part == WSIncrementLine && sPtr->flags.decrDown) {
780 sPtr->flags.decrDown = 0;
781 sPtr->flags.incrDown = 1;
782 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
783 sPtr->flags.incrDown = 0;
784 sPtr->flags.decrDown = 1;
785 } else if (part != WSIncrementLine && part != WSDecrementLine) {
786 sPtr->flags.incrDown = 0;
787 sPtr->flags.decrDown = 0;
793 static void
794 autoScroll(void *clientData)
796 Scroller *sPtr = (Scroller*)clientData;
798 if (sPtr->action) {
799 (*sPtr->action)(sPtr, sPtr->clientData);
800 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
802 sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
806 static void
807 handleActionEvents(XEvent *event, void *data)
809 Scroller *sPtr = (Scroller*)data;
810 int id, dd;
813 /* check if we're really dealing with a scroller, as something
814 * might have gone wrong in the event dispatching stuff */
815 CHECK_CLASS(sPtr, WC_Scroller);
817 id = sPtr->flags.incrDown;
818 dd = sPtr->flags.decrDown;
820 switch (event->type) {
821 case EnterNotify:
823 break;
825 case LeaveNotify:
826 if (sPtr->timerID) {
827 WMDeleteTimerHandler(sPtr->timerID);
828 sPtr->timerID = NULL;
830 sPtr->flags.incrDown = 0;
831 sPtr->flags.decrDown = 0;
832 break;
834 case ButtonPress:
835 /* FIXME: change Mod1Mask with something else */
836 if (sPtr->flags.documentFullyVisible)
837 break;
838 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp) {
839 if (event->xbutton.state & ControlMask) {
840 sPtr->flags.hitPart = WSDecrementPage;
841 } else if (event->xbutton.state & ShiftMask) {
842 sPtr->flags.hitPart = WSDecrementLine;
843 } else {
844 sPtr->flags.hitPart = WSDecrementWheel;
846 if (sPtr->action) {
847 (*sPtr->action)(sPtr, sPtr->clientData);
848 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
849 NULL);
851 } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
852 if (event->xbutton.state & ControlMask) {
853 sPtr->flags.hitPart = WSIncrementPage;
854 } else if (event->xbutton.state & ShiftMask) {
855 sPtr->flags.hitPart = WSIncrementLine;
856 } else {
857 sPtr->flags.hitPart = WSIncrementWheel;
859 if (sPtr->action) {
860 (*sPtr->action)(sPtr, sPtr->clientData);
861 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
862 NULL);
864 } else {
865 handlePush(sPtr, event->xbutton.x, event->xbutton.y,
866 (event->xbutton.state & Mod1Mask)
867 ||event->xbutton.button==Button2);
868 /* continue scrolling if pushed on the buttons */
869 if (sPtr->flags.hitPart == WSIncrementLine
870 || sPtr->flags.hitPart == WSDecrementLine) {
871 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY,
872 autoScroll, sPtr);
875 break;
877 case ButtonRelease:
878 if (sPtr->flags.draggingKnob) {
879 if (sPtr->action) {
880 (*sPtr->action)(sPtr, sPtr->clientData);
881 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
882 NULL);
885 if (sPtr->timerID) {
886 WMDeleteTimerHandler(sPtr->timerID);
887 sPtr->timerID = NULL;
889 sPtr->flags.incrDown = 0;
890 sPtr->flags.decrDown = 0;
891 sPtr->flags.draggingKnob = 0;
892 break;
894 case MotionNotify:
895 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
896 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
897 && sPtr->flags.hitPart != WSDecrementLine) {
898 WMDeleteTimerHandler(sPtr->timerID);
899 sPtr->timerID = NULL;
901 break;
903 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
904 paintScroller(sPtr);
909 static void
910 destroyScroller(Scroller *sPtr)
912 /* we don't want autoscroll try to scroll a freed widget */
913 if (sPtr->timerID) {
914 WMDeleteTimerHandler(sPtr->timerID);
917 wfree(sPtr);