added WINDOWS_MENU to rootmenu
[wmaker-crm.git] / WINGs / wscroller.c
blobd54e7dac95ff3aed702867db5a5793a2d97ce59b
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);
198 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);*/
202 float
203 WMGetScrollerKnobProportion(WMScroller *sPtr)
205 CHECK_CLASS(sPtr, WC_Scroller);
207 return sPtr->knobProportion;
211 float
212 WMGetScrollerValue(WMScroller *sPtr)
214 CHECK_CLASS(sPtr, WC_Scroller);
216 return sPtr->floatValue;
220 WMScrollerPart
221 WMGetScrollerHitPart(WMScroller *sPtr)
223 CHECK_CLASS(sPtr, WC_Scroller);
225 return sPtr->flags.hitPart;
229 static void
230 paintArrow(WMScroller *sPtr, Drawable d, int part)
232 * part- 0 paints the decrement arrow, 1 the increment arrow
235 WMView *view = sPtr->view;
236 WMScreen *scr = view->screen;
237 int ofs, bsize;
238 W_Pixmap *arrow;
240 #ifndef DOUBLE_BUFFER
241 GC gc = scr->lightGC;
242 #endif
244 bsize = SCROLLER_WIDTH - 4;
247 if (part == 0) { /* decrement button */
248 if (sPtr->flags.horizontal) {
249 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
250 ofs = view->size.width - 2*(bsize+1) - 1;
251 } else {
252 ofs = 2;
254 if (sPtr->flags.decrDown)
255 arrow = scr->hiLeftArrow;
256 else
257 arrow = scr->leftArrow;
259 } else {
260 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
261 ofs = view->size.height - 2*(bsize+1) - 1;
262 } else {
263 ofs = 2;
265 if (sPtr->flags.decrDown)
266 arrow = scr->hiUpArrow;
267 else
268 arrow = scr->upArrow;
271 #ifndef DOUBLE_BUFFER
272 if (sPtr->flags.decrDown)
273 gc = WMColorGC(scr->white);
274 #endif
275 } else { /* increment button */
276 if (sPtr->flags.horizontal) {
277 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
278 ofs = view->size.width - bsize+1 - 3;
279 } else {
280 ofs = 2 + bsize+1;
282 if (sPtr->flags.incrDown)
283 arrow = scr->hiRightArrow;
284 else
285 arrow = scr->rightArrow;
286 } else {
287 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
288 ofs = view->size.height - bsize+1 - 3;
289 } else {
290 ofs = 2 + bsize+1;
292 if (sPtr->flags.incrDown)
293 arrow = scr->hiDownArrow;
294 else
295 arrow = scr->downArrow;
298 #ifndef DOUBLE_BUFFER
299 if (sPtr->flags.incrDown)
300 gc = scr->whiteGC;
301 #endif
305 if (sPtr->flags.horizontal) {
307 /* paint button */
308 #ifndef DOUBLE_BUFFER
309 XFillRectangle(scr->display, d, gc,
310 ofs+1, 2+1, bsize+1-3, bsize-3);
311 #else
312 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
313 XFillRectangle(scr->display, d, WMColorGC(scr->white),
314 ofs+1, 2+1, bsize+1-3, bsize-3);
315 #endif /* DOUBLE_BUFFER */
316 W_DrawRelief(scr, d, ofs, 2, bsize, bsize, WRRaised);
318 /* paint arrow */
319 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
320 XSetClipOrigin(scr->display, scr->clipGC,
321 ofs + (bsize - arrow->width) / 2,
322 2 + (bsize - arrow->height) / 2);
324 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
325 0, 0, arrow->width, arrow->height,
326 ofs + (bsize - arrow->width) / 2,
327 2 + (bsize - arrow->height) / 2);
329 } else { /* vertical */
331 /* paint button */
332 #ifndef DOUBLE_BUFFER
333 XFillRectangle(scr->display, d, gc,
334 2+1, ofs+1, bsize-3, bsize+1-3);
335 #else
336 if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
337 XFillRectangle(scr->display, d, WMColorGC(scr->white),
338 2+1, ofs+1, bsize-3, bsize+1-3);
339 #endif /* DOUBLE_BUFFER */
340 W_DrawRelief(scr, d, 2, ofs, bsize, bsize, WRRaised);
342 /* paint arrow */
344 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
345 XSetClipOrigin(scr->display, scr->clipGC,
346 2 + (bsize - arrow->width) / 2,
347 ofs + (bsize - arrow->height) / 2);
348 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
349 0, 0, arrow->width, arrow->height,
350 2 + (bsize - arrow->width) / 2,
351 ofs + (bsize - arrow->height) / 2);
356 static int
357 knobLength(Scroller *sPtr)
359 int tmp, length;
362 if (sPtr->flags.horizontal)
363 length = sPtr->view->size.width - 4;
364 else
365 length = sPtr->view->size.height - 4;
367 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
368 length -= (SCROLLER_WIDTH - 4 + 1)*2;
369 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
370 length -= (SCROLLER_WIDTH - 4 + 1)*2;
373 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
374 /* keep minimum size */
375 if (tmp < SCROLLER_WIDTH-4)
376 tmp = SCROLLER_WIDTH-4;
378 return tmp;
382 static void
383 paintScroller(Scroller *sPtr)
385 WMView *view = sPtr->view;
386 WMScreen *scr = view->screen;
387 #ifdef DOUBLE_BUFFER
388 Pixmap d;
389 #else
390 Drawable d = view->window;
391 #endif
392 int length, ofs;
393 float knobP, knobL;
396 #ifdef DOUBLE_BUFFER
397 d = XCreatePixmap(scr->display, view->window, view->size.width,
398 view->size.height, scr->depth);
399 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0,
400 view->size.width, view->size.height);
401 #endif
403 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0,
404 view->size.width-1, view->size.height-1);
405 #ifndef DOUBLE_BUFFER
406 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1,
407 view->size.width-3, view->size.height-3);
408 #endif
410 if (sPtr->flags.horizontal)
411 length = view->size.width - 4;
412 else
413 length = view->size.height - 4;
415 if (sPtr->flags.documentFullyVisible) {
416 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
417 view->size.width-4, view->size.height-4);
418 } else {
419 if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
420 ofs = 0;
421 length -= (SCROLLER_WIDTH - 4 + 1)*2;
422 } else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
423 ofs = (SCROLLER_WIDTH - 4 + 1)*2;
424 length -= (SCROLLER_WIDTH - 4 + 1)*2;
425 } else {
426 ofs = 0;
429 knobL = (float)knobLength(sPtr);
431 knobP = sPtr->floatValue * ((float)length - knobL);
434 if (sPtr->flags.horizontal) {
435 /* before */
436 XFillRectangle(scr->display, d, scr->stippleGC,
437 ofs+2, 2, (int)knobP, view->size.height-4);
439 /* knob */
440 #ifndef DOUBLE_BUFFER
441 XFillRectangle(scr->display, d, scr->lightGC,
442 ofs+2+(int)knobP+2, 2+2, (int)knobL-4,
443 view->size.height-4-4);
444 #endif
445 W_DrawRelief(scr, d, ofs+2+(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+2+(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+2+(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+2, view->size.width-4, (int)knobP);
466 /* knob */
467 #ifndef DOUBLE_BUFFER
468 XFillRectangle(scr->display, d, scr->lightGC,
469 2+2, ofs+2+(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+2+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
478 W_DrawRelief(scr, d, 2, ofs+2+(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+2+(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 noButtons = (sPtr->flags.arrowsPosition == WSANone);
650 int length, knobP;
652 if (sPtr->flags.horizontal)
653 length = sPtr->view->size.width - 4;
654 else
655 length = sPtr->view->size.height - 4;
657 if (!noButtons)
658 length -= 36;
660 knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
662 if (sPtr->flags.arrowsPosition == WSAMinEnd)
663 sPtr->dragPoint -= 2 + (noButtons ? 0 : 36) + knobP;
664 else
665 sPtr->dragPoint -= 2 + knobP;
667 #endif /* STRICT_NEXT_BEHAVIOUR */
668 /* This does not seem necesary here since we don't know yet if the
669 * knob will be dragged later. -Dan
670 handleMotion(sPtr, pushX, pushY); */
671 break;
673 case WSKnobSlot:
674 case WSNoPart:
675 /* dummy */
676 break;
679 if (doAction && sPtr->action) {
680 (*sPtr->action)(sPtr, sPtr->clientData);
682 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
687 static float
688 floatValueForPoint(int slotOfs, int slotLength, int knobLength, int point)
690 float floatValue = 0;
691 float position;
693 #ifdef STRICT_NEXT_BEHAVIOUR
694 if (point < slotOfs + knobLength/2)
695 position = (float)(slotOfs + knobLength/2);
696 else if (point > slotOfs + slotLength - knobLength/2)
697 position = (float)(slotOfs + slotLength - knobLength/2);
698 else
699 position = (float)point;
701 floatValue = (position-(float)(slotOfs+slotLength/2))
702 /(float)(slotLength-knobLength);
703 #else
704 /* Adjust the last point to lie inside the knob slot */
705 if (point < slotOfs)
706 position = (float)slotOfs;
707 else if (point > slotOfs + slotLength)
708 position = (float)(slotOfs + slotLength);
709 else
710 position = (float)point;
712 /* Compute the float value */
713 floatValue = (position-(float)slotOfs) / (float)(slotLength-knobLength);
714 #endif
716 return floatValue;
720 static void
721 handleMotion(Scroller *sPtr, int mouseX, int mouseY)
723 int slotOffset;
724 int slotLength;
725 int noButtons = (sPtr->flags.arrowsPosition == WSANone);
727 if (sPtr->flags.arrowsPosition == WSAMinEnd)
728 slotOffset = 2 + (noButtons ? 0 : 36);
729 else
730 slotOffset = 2;
732 if (sPtr->flags.draggingKnob) {
733 float newFloatValue;
734 #ifdef STRICT_NEXT_BEHAVIOUR
735 if (sPtr->flags.horizontal) {
736 slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
737 newFloatValue = floatValueForPoint(slotOffset, slotLength,
738 (int)(slotLength*sPtr->knobProportion),
739 mouseX);
740 } else {
741 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
742 newFloatValue = floatValueForPoint(slotOffset, slotLength,
743 (int)(slotLength*sPtr->knobProportion),
744 mouseY);
746 #else
747 if (sPtr->flags.horizontal) {
748 slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
749 newFloatValue = floatValueForPoint(slotOffset, slotLength,
750 (int)(slotLength*sPtr->knobProportion),
751 mouseX-sPtr->dragPoint);
752 } else {
753 slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
754 newFloatValue = floatValueForPoint(slotOffset, slotLength,
755 (int)(slotLength*sPtr->knobProportion),
756 mouseY-sPtr->dragPoint);
758 #endif /* !STRICT_NEXT_BEHAVIOUR */
759 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
760 if (sPtr->action) {
761 (*sPtr->action)(sPtr, sPtr->clientData);
762 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
763 NULL);
765 } else {
766 int part;
768 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
770 sPtr->flags.hitPart = part;
772 if (part == WSIncrementLine && sPtr->flags.decrDown) {
773 sPtr->flags.decrDown = 0;
774 sPtr->flags.incrDown = 1;
775 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
776 sPtr->flags.incrDown = 0;
777 sPtr->flags.decrDown = 1;
778 } else if (part != WSIncrementLine && part != WSDecrementLine) {
779 sPtr->flags.incrDown = 0;
780 sPtr->flags.decrDown = 0;
786 static void
787 autoScroll(void *clientData)
789 Scroller *sPtr = (Scroller*)clientData;
791 if (sPtr->action) {
792 (*sPtr->action)(sPtr, sPtr->clientData);
793 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
795 sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
799 static void
800 handleActionEvents(XEvent *event, void *data)
802 Scroller *sPtr = (Scroller*)data;
803 int id, dd;
806 /* check if we're really dealing with a scroller, as something
807 * might have gone wrong in the event dispatching stuff */
808 CHECK_CLASS(sPtr, WC_Scroller);
810 id = sPtr->flags.incrDown;
811 dd = sPtr->flags.decrDown;
813 switch (event->type) {
814 case EnterNotify:
816 break;
818 case LeaveNotify:
819 if (sPtr->timerID) {
820 WMDeleteTimerHandler(sPtr->timerID);
821 sPtr->timerID = NULL;
823 sPtr->flags.incrDown = 0;
824 sPtr->flags.decrDown = 0;
825 break;
827 case ButtonPress:
828 /* FIXME: change Mod1Mask with something else */
829 if (sPtr->flags.documentFullyVisible)
830 break;
831 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp) {
832 if (event->xbutton.state & ControlMask) {
833 sPtr->flags.hitPart = WSDecrementPage;
834 } else if (event->xbutton.state & ShiftMask) {
835 sPtr->flags.hitPart = WSDecrementLine;
836 } else {
837 sPtr->flags.hitPart = WSDecrementWheel;
839 if (sPtr->action) {
840 (*sPtr->action)(sPtr, sPtr->clientData);
841 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
842 NULL);
844 } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
845 if (event->xbutton.state & ControlMask) {
846 sPtr->flags.hitPart = WSIncrementPage;
847 } else if (event->xbutton.state & ShiftMask) {
848 sPtr->flags.hitPart = WSIncrementLine;
849 } else {
850 sPtr->flags.hitPart = WSIncrementWheel;
852 if (sPtr->action) {
853 (*sPtr->action)(sPtr, sPtr->clientData);
854 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
855 NULL);
857 } else {
858 handlePush(sPtr, event->xbutton.x, event->xbutton.y,
859 (event->xbutton.state & Mod1Mask)
860 ||event->xbutton.button==Button2);
861 /* continue scrolling if pushed on the buttons */
862 if (sPtr->flags.hitPart == WSIncrementLine
863 || sPtr->flags.hitPart == WSDecrementLine) {
864 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY,
865 autoScroll, sPtr);
868 break;
870 case ButtonRelease:
871 if (sPtr->flags.draggingKnob) {
872 if (sPtr->action) {
873 (*sPtr->action)(sPtr, sPtr->clientData);
874 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
875 NULL);
878 if (sPtr->timerID) {
879 WMDeleteTimerHandler(sPtr->timerID);
880 sPtr->timerID = NULL;
882 sPtr->flags.incrDown = 0;
883 sPtr->flags.decrDown = 0;
884 sPtr->flags.draggingKnob = 0;
885 break;
887 case MotionNotify:
888 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
889 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
890 && sPtr->flags.hitPart != WSDecrementLine) {
891 WMDeleteTimerHandler(sPtr->timerID);
892 sPtr->timerID = NULL;
894 break;
896 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
897 paintScroller(sPtr);
902 static void
903 destroyScroller(Scroller *sPtr)
905 /* we don't want autoscroll try to scroll a freed widget */
906 if (sPtr->timerID) {
907 WMDeleteTimerHandler(sPtr->timerID);
910 wfree(sPtr);