Only cache pixmaps for docked icons
[wmaker-crm.git] / WINGs / wscroller.c
blob6afca4804a0b245ab02475debfd9b5fda15634b3
2 #include "WINGsP.h"
4 #include <math.h>
6 /* undefine will disable the autoadjusting of the knob dimple to be
7 * directly below the cursor
8 * DOES NOT WORK */
9 #undef STRICT_NEXT_BEHAVIOUR
11 #define AUTOSCROLL_INITIAL_DELAY 200
13 #define AUTOSCROLL_DELAY 40
15 char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
17 typedef struct W_Scroller {
18 W_Class widgetClass;
19 W_View *view;
21 void *clientData;
22 WMAction *action;
24 float knobProportion;
25 float floatValue;
27 WMHandlerID timerID; /* for continuous scrolling mode */
29 #ifndef STRICT_NEXT_BEHAVIOUR
30 int dragPoint; /* point where the knob is being
31 * dragged */
32 #endif
33 struct {
34 WMScrollArrowPosition arrowsPosition:4;
36 unsigned int horizontal:1;
38 WMScrollerPart hitPart:4;
40 /* */
41 unsigned int documentFullyVisible:1; /* document is fully visible */
43 unsigned int prevSelected:1;
45 unsigned int pushed:1;
47 unsigned int incrDown:1; /* whether increment button is down */
49 unsigned int decrDown:1;
51 unsigned int draggingKnob:1;
53 unsigned int configured:1;
55 unsigned int redrawPending:1;
56 } flags;
57 } Scroller;
59 #define DEFAULT_HEIGHT 60
60 #define DEFAULT_WIDTH SCROLLER_WIDTH
61 #define DEFAULT_ARROWS_POSITION WSAMinEnd
63 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
65 static void destroyScroller(Scroller * sPtr);
66 static void paintScroller(Scroller * sPtr);
68 static void willResizeScroller();
69 static void handleEvents(XEvent * event, void *data);
70 static void handleActionEvents(XEvent * event, void *data);
72 static void handleMotion(Scroller * sPtr, int mouseX, int mouseY);
74 W_ViewDelegate _ScrollerViewDelegate = {
75 NULL,
76 NULL,
77 NULL,
78 NULL,
79 willResizeScroller
82 WMScroller *WMCreateScroller(WMWidget * parent)
84 Scroller *sPtr;
86 sPtr = wmalloc(sizeof(Scroller));
87 sPtr->widgetClass = WC_Scroller;
89 sPtr->view = W_CreateView(W_VIEW(parent));
90 if (!sPtr->view) {
91 wfree(sPtr);
92 return NULL;
94 sPtr->view->self = sPtr;
96 sPtr->view->delegate = &_ScrollerViewDelegate;
98 sPtr->flags.documentFullyVisible = 1;
100 WMCreateEventHandler(sPtr->view, ExposureMask | StructureNotifyMask
101 | ClientMessageMask, handleEvents, sPtr);
103 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
104 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
106 WMCreateEventHandler(sPtr->view, ButtonPressMask | ButtonReleaseMask
107 | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, sPtr);
109 sPtr->flags.hitPart = WSNoPart;
111 sPtr->floatValue = 0.0;
112 sPtr->knobProportion = 1.0;
114 return sPtr;
117 void WMSetScrollerArrowsPosition(WMScroller * sPtr, WMScrollArrowPosition position)
119 sPtr->flags.arrowsPosition = position;
120 if (sPtr->view->flags.realized) {
121 paintScroller(sPtr);
125 static void willResizeScroller(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height)
127 WMScroller *sPtr = (WMScroller *) view->self;
129 if (*width > *height) {
130 sPtr->flags.horizontal = 1;
131 *height = SCROLLER_WIDTH;
132 } else {
133 sPtr->flags.horizontal = 0;
134 *width = SCROLLER_WIDTH;
138 void WMSetScrollerAction(WMScroller * sPtr, WMAction * action, void *clientData)
140 CHECK_CLASS(sPtr, WC_Scroller);
142 sPtr->action = action;
144 sPtr->clientData = clientData;
147 void WMSetScrollerParameters(WMScroller * sPtr, float floatValue, float knobProportion)
149 CHECK_CLASS(sPtr, WC_Scroller);
151 assert(!isnan(floatValue));
153 if (floatValue < 0.0)
154 sPtr->floatValue = 0.0;
155 else if (floatValue > 1.0)
156 sPtr->floatValue = 1.0;
157 else
158 sPtr->floatValue = floatValue;
160 if (knobProportion <= 0.0) {
162 sPtr->knobProportion = 0.0;
163 sPtr->flags.documentFullyVisible = 0;
165 } else if (knobProportion >= 1.0) {
167 sPtr->knobProportion = 1.0;
168 sPtr->flags.documentFullyVisible = 1;
170 } else {
171 sPtr->knobProportion = knobProportion;
172 sPtr->flags.documentFullyVisible = 0;
175 if (sPtr->view->flags.realized)
176 paintScroller(sPtr);
178 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
181 float WMGetScrollerKnobProportion(WMScroller * sPtr)
183 CHECK_CLASS(sPtr, WC_Scroller);
185 return sPtr->knobProportion;
188 float WMGetScrollerValue(WMScroller * sPtr)
190 CHECK_CLASS(sPtr, WC_Scroller);
192 return sPtr->floatValue;
195 WMScrollerPart WMGetScrollerHitPart(WMScroller * sPtr)
197 CHECK_CLASS(sPtr, WC_Scroller);
199 return sPtr->flags.hitPart;
202 static void paintArrow(WMScroller * sPtr, Drawable d, int part)
204 * part- 0 paints the decrement arrow, 1 the increment arrow
207 WMView *view = sPtr->view;
208 WMScreen *scr = view->screen;
209 int ofs;
210 W_Pixmap *arrow;
212 #ifndef DOUBLE_BUFFER
213 GC gc = scr->lightGC;
214 #endif
216 if (part == 0) { /* decrement button */
217 if (sPtr->flags.horizontal) {
218 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
219 ofs = view->size.width - 2 * (BUTTON_SIZE + 1) - 1;
220 } else {
221 ofs = 2;
223 if (sPtr->flags.decrDown)
224 arrow = scr->hiLeftArrow;
225 else
226 arrow = scr->leftArrow;
228 } else {
229 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
230 ofs = view->size.height - 2 * (BUTTON_SIZE + 1) - 1;
231 } else {
232 ofs = 2;
234 if (sPtr->flags.decrDown)
235 arrow = scr->hiUpArrow;
236 else
237 arrow = scr->upArrow;
240 #ifndef DOUBLE_BUFFER
241 if (sPtr->flags.decrDown)
242 gc = WMColorGC(scr->white);
243 #endif
244 } else { /* increment button */
245 if (sPtr->flags.horizontal) {
246 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
247 ofs = view->size.width - BUTTON_SIZE + 1 - 3;
248 } else {
249 ofs = 2 + BUTTON_SIZE + 1;
251 if (sPtr->flags.incrDown)
252 arrow = scr->hiRightArrow;
253 else
254 arrow = scr->rightArrow;
255 } else {
256 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
257 ofs = view->size.height - BUTTON_SIZE + 1 - 3;
258 } else {
259 ofs = 2 + BUTTON_SIZE + 1;
261 if (sPtr->flags.incrDown)
262 arrow = scr->hiDownArrow;
263 else
264 arrow = scr->downArrow;
267 #ifndef DOUBLE_BUFFER
268 if (sPtr->flags.incrDown)
269 gc = scr->whiteGC;
270 #endif
273 if (sPtr->flags.horizontal) {
274 /* paint button */
275 #ifndef DOUBLE_BUFFER
276 XFillRectangle(scr->display, d, gc, ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
277 #else
278 if ((!part && sPtr->flags.decrDown) || (part && sPtr->flags.incrDown))
279 XFillRectangle(scr->display, d, WMColorGC(scr->white),
280 ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
281 #endif /* DOUBLE_BUFFER */
282 W_DrawRelief(scr, d, ofs, 2, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
284 /* paint arrow */
285 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
286 XSetClipOrigin(scr->display, scr->clipGC,
287 ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2);
289 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
290 0, 0, arrow->width, arrow->height,
291 ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2);
293 } else { /* vertical */
295 /* paint button */
296 #ifndef DOUBLE_BUFFER
297 XFillRectangle(scr->display, d, gc, 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
298 #else
299 if ((!part && sPtr->flags.decrDown) || (part && sPtr->flags.incrDown))
300 XFillRectangle(scr->display, d, WMColorGC(scr->white),
301 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
302 #endif /* DOUBLE_BUFFER */
303 W_DrawRelief(scr, d, 2, ofs, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
305 /* paint arrow */
307 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
308 XSetClipOrigin(scr->display, scr->clipGC,
309 2 + (BUTTON_SIZE - arrow->width) / 2, ofs + (BUTTON_SIZE - arrow->height) / 2);
310 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
311 0, 0, arrow->width, arrow->height,
312 2 + (BUTTON_SIZE - arrow->width) / 2, ofs + (BUTTON_SIZE - arrow->height) / 2);
316 static int knobLength(Scroller * sPtr)
318 int tmp, length;
320 if (sPtr->flags.horizontal)
321 length = sPtr->view->size.width - 4;
322 else
323 length = sPtr->view->size.height - 4;
325 if (sPtr->flags.arrowsPosition != WSANone) {
326 length -= 2 * (BUTTON_SIZE + 1);
329 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
330 /* keep minimum size */
331 if (tmp < BUTTON_SIZE)
332 tmp = BUTTON_SIZE;
334 return tmp;
337 static void paintScroller(Scroller * sPtr)
339 WMView *view = sPtr->view;
340 WMScreen *scr = view->screen;
341 #ifdef DOUBLE_BUFFER
342 Pixmap d;
343 #else
344 Drawable d = view->window;
345 #endif
346 int length, ofs;
347 float knobP, knobL;
349 #ifdef DOUBLE_BUFFER
350 d = XCreatePixmap(scr->display, view->window, view->size.width, view->size.height, scr->depth);
351 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0, view->size.width, view->size.height);
352 #endif
354 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0, view->size.width - 1, view->size.height - 1);
355 #ifndef DOUBLE_BUFFER
356 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1, view->size.width - 3, view->size.height - 3);
357 #endif
359 if (sPtr->flags.horizontal)
360 length = view->size.width - 4;
361 else
362 length = view->size.height - 4;
364 if (sPtr->flags.documentFullyVisible) {
365 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2, view->size.width - 4, view->size.height - 4);
366 } else {
367 ofs = 2;
368 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
369 length -= (BUTTON_SIZE + 1) * 2;
370 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
371 ofs += (BUTTON_SIZE + 1) * 2;
372 length -= (BUTTON_SIZE + 1) * 2;
375 knobL = (float)knobLength(sPtr);
377 knobP = sPtr->floatValue * ((float)length - knobL);
379 if (sPtr->flags.horizontal) {
380 /* before */
381 XFillRectangle(scr->display, d, scr->stippleGC, ofs, 2, (int)knobP, view->size.height - 4);
383 /* knob */
384 #ifndef DOUBLE_BUFFER
385 XFillRectangle(scr->display, d, scr->lightGC,
386 ofs + (int)knobP + 2, 2 + 2, (int)knobL - 4, view->size.height - 4 - 4);
387 #endif
388 W_DrawRelief(scr, d, ofs + (int)knobP, 2, (int)knobL, view->size.height - 4, WRRaised);
390 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
391 scr->copyGC, 0, 0,
392 scr->scrollerDimple->width, scr->scrollerDimple->height,
393 ofs + (int)knobP + ((int)knobL - scr->scrollerDimple->width - 1) / 2,
394 (view->size.height - scr->scrollerDimple->height - 1) / 2);
396 /* after */
397 if ((int)(knobP + knobL) < length)
398 XFillRectangle(scr->display, d, scr->stippleGC,
399 ofs + (int)(knobP + knobL), 2,
400 length - (int)(knobP + knobL), view->size.height - 4);
401 } else {
402 /* before */
403 if (knobP > 0.0)
404 XFillRectangle(scr->display, d, scr->stippleGC,
405 2, ofs, view->size.width - 4, (int)knobP);
407 /* knob */
408 #ifndef DOUBLE_BUFFER
409 XFillRectangle(scr->display, d, scr->lightGC,
410 2 + 2, ofs + (int)knobP + 2, view->size.width - 4 - 4, (int)knobL - 4);
411 #endif
412 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
413 scr->copyGC, 0, 0,
414 scr->scrollerDimple->width, scr->scrollerDimple->height,
415 (view->size.width - scr->scrollerDimple->width - 1) / 2,
416 ofs + (int)knobP + ((int)knobL - scr->scrollerDimple->height - 1) / 2);
418 W_DrawRelief(scr, d, 2, ofs + (int)knobP, view->size.width - 4, (int)knobL, WRRaised);
420 /* after */
421 if ((int)(knobP + knobL) < length)
422 XFillRectangle(scr->display, d, scr->stippleGC,
423 2, ofs + (int)(knobP + knobL),
424 view->size.width - 4, length - (int)(knobP + knobL));
427 if (sPtr->flags.arrowsPosition != WSANone) {
428 paintArrow(sPtr, d, 0);
429 paintArrow(sPtr, d, 1);
433 #ifdef DOUBLE_BUFFER
434 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0, view->size.width, view->size.height, 0, 0);
435 XFreePixmap(scr->display, d);
436 #endif
439 static void handleEvents(XEvent * event, void *data)
441 Scroller *sPtr = (Scroller *) data;
443 CHECK_CLASS(data, WC_Scroller);
445 switch (event->type) {
446 case Expose:
447 if (event->xexpose.count == 0)
448 paintScroller(sPtr);
449 break;
451 case DestroyNotify:
452 destroyScroller(sPtr);
453 break;
458 * locatePointInScroller-
459 * Return the part of the scroller where the point is located.
461 static WMScrollerPart locatePointInScroller(Scroller * sPtr, int x, int y, int alternate)
463 int width = sPtr->view->size.width;
464 int height = sPtr->view->size.height;
465 int c, p1, p2, p3, p4, p5, p6;
466 int knobL, slotL;
468 /* if there is no knob... */
469 if (sPtr->flags.documentFullyVisible)
470 return WSKnobSlot;
472 if (sPtr->flags.horizontal)
473 c = x;
474 else
475 c = y;
477 /* p1 p2 p3 p4 p5 p6
478 * | | |###########| |#####| | |
479 * | < | > |###########| O |#####| < | > |
480 * | | |###########| |#####| | |
483 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
484 p1 = 18;
485 p2 = 36;
487 if (sPtr->flags.horizontal) {
488 slotL = width - 36;
489 p5 = width;
490 } else {
491 slotL = height - 36;
492 p5 = height;
494 p6 = p5;
495 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
496 if (sPtr->flags.horizontal) {
497 slotL = width - 36;
498 p6 = width - 18;
499 } else {
500 slotL = height - 36;
501 p6 = height - 18;
503 p5 = p6 - 18;
505 p1 = p2 = 0;
506 } else {
507 /* no arrows */
508 p1 = p2 = 0;
510 if (sPtr->flags.horizontal) {
511 slotL = p5 = p6 = width;
512 } else {
513 slotL = p5 = p6 = height;
517 knobL = knobLength(sPtr);
518 p3 = p2 + (int)((float)(slotL - knobL) * sPtr->floatValue);
519 p4 = p3 + knobL;
521 /* uses a mix of the NS and Win ways of doing scroll page */
522 if (c <= p1)
523 return alternate ? WSDecrementPage : WSDecrementLine;
524 else if (c <= p2)
525 return alternate ? WSIncrementPage : WSIncrementLine;
526 else if (c <= p3)
527 return WSDecrementPage;
528 else if (c <= p4)
529 return WSKnob;
530 else if (c <= p5)
531 return WSIncrementPage;
532 else if (c <= p6)
533 return alternate ? WSDecrementPage : WSDecrementLine;
534 else
535 return alternate ? WSIncrementPage : WSIncrementLine;
538 static void handlePush(Scroller * sPtr, int pushX, int pushY, int alternate)
540 WMScrollerPart part;
541 int doAction = 0;
543 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
545 sPtr->flags.hitPart = part;
547 switch (part) {
548 case WSIncrementLine:
549 sPtr->flags.incrDown = 1;
550 doAction = 1;
551 break;
553 case WSIncrementPage:
554 doAction = 1;
555 break;
557 case WSDecrementLine:
558 sPtr->flags.decrDown = 1;
559 doAction = 1;
560 break;
562 case WSDecrementPage:
563 doAction = 1;
564 break;
566 case WSKnob:
567 sPtr->flags.draggingKnob = 1;
568 #ifndef STRICT_NEXT_BEHAVIOUR
569 if (sPtr->flags.horizontal)
570 sPtr->dragPoint = pushX;
571 else
572 sPtr->dragPoint = pushY;
575 int length, knobP;
576 int buttonsLen;
578 if (sPtr->flags.arrowsPosition != WSANone)
579 buttonsLen = 2 * (BUTTON_SIZE + 1);
580 else
581 buttonsLen = 0;
583 if (sPtr->flags.horizontal)
584 length = sPtr->view->size.width - 4 - buttonsLen;
585 else
586 length = sPtr->view->size.height - 4 - buttonsLen;
588 knobP = (int)(sPtr->floatValue * (float)(length - knobLength(sPtr)));
590 if (sPtr->flags.arrowsPosition == WSAMinEnd)
591 sPtr->dragPoint -= 2 + buttonsLen + knobP;
592 else
593 sPtr->dragPoint -= 2 + knobP;
595 #endif /* STRICT_NEXT_BEHAVIOUR */
596 /* This does not seem necesary here since we don't know yet if the
597 * knob will be dragged later. -Dan
598 handleMotion(sPtr, pushX, pushY); */
599 break;
601 case WSDecrementWheel:
602 case WSIncrementWheel:
603 case WSKnobSlot:
604 case WSNoPart:
605 /* dummy */
606 break;
609 if (doAction && sPtr->action) {
610 (*sPtr->action) (sPtr, sPtr->clientData);
612 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
616 static float floatValueForPoint(Scroller * sPtr, int point)
618 float floatValue = 0;
619 float position;
620 int slotOfs, slotLength, knobL;
622 if (sPtr->flags.horizontal)
623 slotLength = sPtr->view->size.width - 4;
624 else
625 slotLength = sPtr->view->size.height - 4;
627 slotOfs = 2;
628 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
629 slotLength -= (BUTTON_SIZE + 1) * 2;
630 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
631 slotOfs += (BUTTON_SIZE + 1) * 2;
632 slotLength -= (BUTTON_SIZE + 1) * 2;
635 knobL = (float)knobLength(sPtr);
636 #ifdef STRICT_NEXT_BEHAVIOUR
637 if (point < slotOfs + knobL / 2)
638 position = (float)(slotOfs + knobL / 2);
639 else if (point > slotOfs + slotLength - knobL / 2)
640 position = (float)(slotOfs + slotLength - knobL / 2);
641 else
642 position = (float)point;
644 floatValue = (position - (float)(slotOfs + slotLength / 2))
645 / (float)(slotLength - knobL);
646 #else
647 /* Adjust the last point to lie inside the knob slot */
648 if (point < slotOfs)
649 position = (float)slotOfs;
650 else if (point > slotOfs + slotLength)
651 position = (float)(slotOfs + slotLength);
652 else
653 position = (float)point;
655 /* Compute the float value */
656 floatValue = (position - (float)slotOfs) / (float)(slotLength - knobL);
657 #endif
659 assert(!isnan(floatValue));
660 return floatValue;
663 static void handleMotion(Scroller * sPtr, int mouseX, int mouseY)
665 if (sPtr->flags.draggingKnob) {
666 float newFloatValue;
667 int point;
669 if (sPtr->flags.horizontal) {
670 point = mouseX;
671 } else {
672 point = mouseY;
675 #ifndef STRICT_NEXT_BEHAVIOUR
676 point -= sPtr->dragPoint;
677 #endif
679 newFloatValue = floatValueForPoint(sPtr, point);
680 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
681 if (sPtr->action) {
682 (*sPtr->action) (sPtr, sPtr->clientData);
683 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
685 } else {
686 int part;
688 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
690 sPtr->flags.hitPart = part;
692 if (part == WSIncrementLine && sPtr->flags.decrDown) {
693 sPtr->flags.decrDown = 0;
694 sPtr->flags.incrDown = 1;
695 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
696 sPtr->flags.incrDown = 0;
697 sPtr->flags.decrDown = 1;
698 } else if (part != WSIncrementLine && part != WSDecrementLine) {
699 sPtr->flags.incrDown = 0;
700 sPtr->flags.decrDown = 0;
705 static void autoScroll(void *clientData)
707 Scroller *sPtr = (Scroller *) clientData;
709 if (sPtr->action) {
710 (*sPtr->action) (sPtr, sPtr->clientData);
711 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
713 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
716 static void handleActionEvents(XEvent * event, void *data)
718 Scroller *sPtr = (Scroller *) data;
719 int wheelDecrement, wheelIncrement;
720 int id, dd;
722 /* check if we're really dealing with a scroller, as something
723 * might have gone wrong in the event dispatching stuff */
724 CHECK_CLASS(sPtr, WC_Scroller);
726 id = sPtr->flags.incrDown;
727 dd = sPtr->flags.decrDown;
729 switch (event->type) {
730 case EnterNotify:
731 break;
733 case LeaveNotify:
734 if (sPtr->timerID) {
735 WMDeleteTimerHandler(sPtr->timerID);
736 sPtr->timerID = NULL;
738 sPtr->flags.incrDown = 0;
739 sPtr->flags.decrDown = 0;
740 break;
742 case ButtonPress:
743 /* FIXME: change Mod1Mask with something else */
744 if (sPtr->flags.documentFullyVisible)
745 break;
747 if (sPtr->flags.horizontal) {
748 wheelDecrement = WINGsConfiguration.mouseWheelDown;
749 wheelIncrement = WINGsConfiguration.mouseWheelUp;
750 } else {
751 wheelDecrement = WINGsConfiguration.mouseWheelUp;
752 wheelIncrement = WINGsConfiguration.mouseWheelDown;
755 if (event->xbutton.button == wheelDecrement) {
756 if (event->xbutton.state & ControlMask) {
757 sPtr->flags.hitPart = WSDecrementPage;
758 } else if (event->xbutton.state & ShiftMask) {
759 sPtr->flags.hitPart = WSDecrementLine;
760 } else {
761 sPtr->flags.hitPart = WSDecrementWheel;
763 if (sPtr->action) {
764 (*sPtr->action) (sPtr, sPtr->clientData);
765 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
767 } else if (event->xbutton.button == wheelIncrement) {
768 if (event->xbutton.state & ControlMask) {
769 sPtr->flags.hitPart = WSIncrementPage;
770 } else if (event->xbutton.state & ShiftMask) {
771 sPtr->flags.hitPart = WSIncrementLine;
772 } else {
773 sPtr->flags.hitPart = WSIncrementWheel;
775 if (sPtr->action) {
776 (*sPtr->action) (sPtr, sPtr->clientData);
777 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
779 } else {
780 handlePush(sPtr, event->xbutton.x, event->xbutton.y, (event->xbutton.state & Mod1Mask)
781 || event->xbutton.button == Button2);
782 /* continue scrolling if pushed on the buttons */
783 if (sPtr->flags.hitPart == WSIncrementLine || sPtr->flags.hitPart == WSDecrementLine) {
784 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY, autoScroll, sPtr);
787 break;
789 case ButtonRelease:
790 if (sPtr->flags.draggingKnob) {
791 if (sPtr->action) {
792 (*sPtr->action) (sPtr, sPtr->clientData);
793 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
796 if (sPtr->timerID) {
797 WMDeleteTimerHandler(sPtr->timerID);
798 sPtr->timerID = NULL;
800 sPtr->flags.incrDown = 0;
801 sPtr->flags.decrDown = 0;
802 sPtr->flags.draggingKnob = 0;
803 break;
805 case MotionNotify:
806 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
807 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
808 && sPtr->flags.hitPart != WSDecrementLine) {
809 WMDeleteTimerHandler(sPtr->timerID);
810 sPtr->timerID = NULL;
812 break;
814 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
815 paintScroller(sPtr);
818 static void destroyScroller(Scroller * sPtr)
820 /* we don't want autoscroll try to scroll a freed widget */
821 if (sPtr->timerID) {
822 WMDeleteTimerHandler(sPtr->timerID);
825 wfree(sPtr);