Icon creation in only one function
[wmaker-crm.git] / WINGs / wscroller.c
blob671bb229bc9b173689e08784e1fd20a99f6f3263
2 /*
3 * Until FreeBSD gets their act together;
4 * http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
5 */
6 #if defined( FREEBSD )
7 # undef _XOPEN_SOURCE
8 #endif
10 #include "WINGsP.h"
12 #include <math.h>
14 /* undefine will disable the autoadjusting of the knob dimple to be
15 * directly below the cursor
16 * DOES NOT WORK */
17 #undef STRICT_NEXT_BEHAVIOUR
19 #define AUTOSCROLL_INITIAL_DELAY 200
21 #define AUTOSCROLL_DELAY 40
23 char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
25 typedef struct W_Scroller {
26 W_Class widgetClass;
27 W_View *view;
29 void *clientData;
30 WMAction *action;
32 float knobProportion;
33 float floatValue;
35 WMHandlerID timerID; /* for continuous scrolling mode */
37 #ifndef STRICT_NEXT_BEHAVIOUR
38 int dragPoint; /* point where the knob is being
39 * dragged */
40 #endif
41 struct {
42 WMScrollArrowPosition arrowsPosition:4;
44 unsigned int horizontal:1;
46 WMScrollerPart hitPart:4;
48 /* */
49 unsigned int documentFullyVisible:1; /* document is fully visible */
51 unsigned int prevSelected:1;
53 unsigned int pushed:1;
55 unsigned int incrDown:1; /* whether increment button is down */
57 unsigned int decrDown:1;
59 unsigned int draggingKnob:1;
61 unsigned int configured:1;
63 unsigned int redrawPending:1;
64 } flags;
65 } Scroller;
67 #define DEFAULT_HEIGHT 60
68 #define DEFAULT_WIDTH SCROLLER_WIDTH
69 #define DEFAULT_ARROWS_POSITION WSAMinEnd
71 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
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);
82 W_ViewDelegate _ScrollerViewDelegate = {
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 willResizeScroller
90 WMScroller *WMCreateScroller(WMWidget * parent)
92 Scroller *sPtr;
94 sPtr = wmalloc(sizeof(Scroller));
95 sPtr->widgetClass = WC_Scroller;
97 sPtr->view = W_CreateView(W_VIEW(parent));
98 if (!sPtr->view) {
99 wfree(sPtr);
100 return NULL;
102 sPtr->view->self = sPtr;
104 sPtr->view->delegate = &_ScrollerViewDelegate;
106 sPtr->flags.documentFullyVisible = 1;
108 WMCreateEventHandler(sPtr->view, ExposureMask | StructureNotifyMask
109 | ClientMessageMask, handleEvents, sPtr);
111 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
112 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
114 WMCreateEventHandler(sPtr->view, ButtonPressMask | ButtonReleaseMask
115 | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, sPtr);
117 sPtr->flags.hitPart = WSNoPart;
119 sPtr->floatValue = 0.0;
120 sPtr->knobProportion = 1.0;
122 return sPtr;
125 void WMSetScrollerArrowsPosition(WMScroller * sPtr, WMScrollArrowPosition position)
127 sPtr->flags.arrowsPosition = position;
128 if (sPtr->view->flags.realized) {
129 paintScroller(sPtr);
133 static void willResizeScroller(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height)
135 WMScroller *sPtr = (WMScroller *) view->self;
137 if (*width > *height) {
138 sPtr->flags.horizontal = 1;
139 *height = SCROLLER_WIDTH;
140 } else {
141 sPtr->flags.horizontal = 0;
142 *width = SCROLLER_WIDTH;
146 void WMSetScrollerAction(WMScroller * sPtr, WMAction * action, void *clientData)
148 CHECK_CLASS(sPtr, WC_Scroller);
150 sPtr->action = action;
152 sPtr->clientData = clientData;
155 void WMSetScrollerParameters(WMScroller * sPtr, float floatValue, float knobProportion)
157 CHECK_CLASS(sPtr, WC_Scroller);
159 assert(!isnan(floatValue));
161 if (floatValue < 0.0)
162 sPtr->floatValue = 0.0;
163 else if (floatValue > 1.0)
164 sPtr->floatValue = 1.0;
165 else
166 sPtr->floatValue = floatValue;
168 if (knobProportion <= 0.0) {
170 sPtr->knobProportion = 0.0;
171 sPtr->flags.documentFullyVisible = 0;
173 } else if (knobProportion >= 1.0) {
175 sPtr->knobProportion = 1.0;
176 sPtr->flags.documentFullyVisible = 1;
178 } else {
179 sPtr->knobProportion = knobProportion;
180 sPtr->flags.documentFullyVisible = 0;
183 if (sPtr->view->flags.realized)
184 paintScroller(sPtr);
186 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
189 float WMGetScrollerKnobProportion(WMScroller * sPtr)
191 CHECK_CLASS(sPtr, WC_Scroller);
193 return sPtr->knobProportion;
196 float WMGetScrollerValue(WMScroller * sPtr)
198 CHECK_CLASS(sPtr, WC_Scroller);
200 return sPtr->floatValue;
203 WMScrollerPart WMGetScrollerHitPart(WMScroller * sPtr)
205 CHECK_CLASS(sPtr, WC_Scroller);
207 return sPtr->flags.hitPart;
210 static void paintArrow(WMScroller * sPtr, Drawable d, int part)
212 * part- 0 paints the decrement arrow, 1 the increment arrow
215 WMView *view = sPtr->view;
216 WMScreen *scr = view->screen;
217 int ofs;
218 W_Pixmap *arrow;
220 #ifndef DOUBLE_BUFFER
221 GC gc = scr->lightGC;
222 #endif
224 if (part == 0) { /* decrement button */
225 if (sPtr->flags.horizontal) {
226 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
227 ofs = view->size.width - 2 * (BUTTON_SIZE + 1) - 1;
228 } else {
229 ofs = 2;
231 if (sPtr->flags.decrDown)
232 arrow = scr->hiLeftArrow;
233 else
234 arrow = scr->leftArrow;
236 } else {
237 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
238 ofs = view->size.height - 2 * (BUTTON_SIZE + 1) - 1;
239 } else {
240 ofs = 2;
242 if (sPtr->flags.decrDown)
243 arrow = scr->hiUpArrow;
244 else
245 arrow = scr->upArrow;
248 #ifndef DOUBLE_BUFFER
249 if (sPtr->flags.decrDown)
250 gc = WMColorGC(scr->white);
251 #endif
252 } else { /* increment button */
253 if (sPtr->flags.horizontal) {
254 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
255 ofs = view->size.width - BUTTON_SIZE + 1 - 3;
256 } else {
257 ofs = 2 + BUTTON_SIZE + 1;
259 if (sPtr->flags.incrDown)
260 arrow = scr->hiRightArrow;
261 else
262 arrow = scr->rightArrow;
263 } else {
264 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
265 ofs = view->size.height - BUTTON_SIZE + 1 - 3;
266 } else {
267 ofs = 2 + BUTTON_SIZE + 1;
269 if (sPtr->flags.incrDown)
270 arrow = scr->hiDownArrow;
271 else
272 arrow = scr->downArrow;
275 #ifndef DOUBLE_BUFFER
276 if (sPtr->flags.incrDown)
277 gc = scr->whiteGC;
278 #endif
281 if (sPtr->flags.horizontal) {
282 /* paint button */
283 #ifndef DOUBLE_BUFFER
284 XFillRectangle(scr->display, d, gc, ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
285 #else
286 if ((!part && sPtr->flags.decrDown) || (part && sPtr->flags.incrDown))
287 XFillRectangle(scr->display, d, WMColorGC(scr->white),
288 ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
289 #endif /* DOUBLE_BUFFER */
290 W_DrawRelief(scr, d, ofs, 2, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
292 /* paint arrow */
293 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
294 XSetClipOrigin(scr->display, scr->clipGC,
295 ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2);
297 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
298 0, 0, arrow->width, arrow->height,
299 ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2);
301 } else { /* vertical */
303 /* paint button */
304 #ifndef DOUBLE_BUFFER
305 XFillRectangle(scr->display, d, gc, 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
306 #else
307 if ((!part && sPtr->flags.decrDown) || (part && sPtr->flags.incrDown))
308 XFillRectangle(scr->display, d, WMColorGC(scr->white),
309 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
310 #endif /* DOUBLE_BUFFER */
311 W_DrawRelief(scr, d, 2, ofs, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
313 /* paint arrow */
315 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
316 XSetClipOrigin(scr->display, scr->clipGC,
317 2 + (BUTTON_SIZE - arrow->width) / 2, ofs + (BUTTON_SIZE - arrow->height) / 2);
318 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
319 0, 0, arrow->width, arrow->height,
320 2 + (BUTTON_SIZE - arrow->width) / 2, ofs + (BUTTON_SIZE - arrow->height) / 2);
324 static int knobLength(Scroller * sPtr)
326 int tmp, length;
328 if (sPtr->flags.horizontal)
329 length = sPtr->view->size.width - 4;
330 else
331 length = sPtr->view->size.height - 4;
333 if (sPtr->flags.arrowsPosition != WSANone) {
334 length -= 2 * (BUTTON_SIZE + 1);
337 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
338 /* keep minimum size */
339 if (tmp < BUTTON_SIZE)
340 tmp = BUTTON_SIZE;
342 return tmp;
345 static void paintScroller(Scroller * sPtr)
347 WMView *view = sPtr->view;
348 WMScreen *scr = view->screen;
349 #ifdef DOUBLE_BUFFER
350 Pixmap d;
351 #else
352 Drawable d = view->window;
353 #endif
354 int length, ofs;
355 float knobP, knobL;
357 #ifdef DOUBLE_BUFFER
358 d = XCreatePixmap(scr->display, view->window, view->size.width, view->size.height, scr->depth);
359 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0, view->size.width, view->size.height);
360 #endif
362 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0, view->size.width - 1, view->size.height - 1);
363 #ifndef DOUBLE_BUFFER
364 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1, view->size.width - 3, view->size.height - 3);
365 #endif
367 if (sPtr->flags.horizontal)
368 length = view->size.width - 4;
369 else
370 length = view->size.height - 4;
372 if (sPtr->flags.documentFullyVisible) {
373 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2, view->size.width - 4, view->size.height - 4);
374 } else {
375 ofs = 2;
376 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
377 length -= (BUTTON_SIZE + 1) * 2;
378 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
379 ofs += (BUTTON_SIZE + 1) * 2;
380 length -= (BUTTON_SIZE + 1) * 2;
383 knobL = (float)knobLength(sPtr);
385 knobP = sPtr->floatValue * ((float)length - knobL);
387 if (sPtr->flags.horizontal) {
388 /* before */
389 XFillRectangle(scr->display, d, scr->stippleGC, ofs, 2, (int)knobP, view->size.height - 4);
391 /* knob */
392 #ifndef DOUBLE_BUFFER
393 XFillRectangle(scr->display, d, scr->lightGC,
394 ofs + (int)knobP + 2, 2 + 2, (int)knobL - 4, view->size.height - 4 - 4);
395 #endif
396 W_DrawRelief(scr, d, ofs + (int)knobP, 2, (int)knobL, view->size.height - 4, WRRaised);
398 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
399 scr->copyGC, 0, 0,
400 scr->scrollerDimple->width, scr->scrollerDimple->height,
401 ofs + (int)knobP + ((int)knobL - scr->scrollerDimple->width - 1) / 2,
402 (view->size.height - scr->scrollerDimple->height - 1) / 2);
404 /* after */
405 if ((int)(knobP + knobL) < length)
406 XFillRectangle(scr->display, d, scr->stippleGC,
407 ofs + (int)(knobP + knobL), 2,
408 length - (int)(knobP + knobL), view->size.height - 4);
409 } else {
410 /* before */
411 if (knobP > 0.0)
412 XFillRectangle(scr->display, d, scr->stippleGC,
413 2, ofs, view->size.width - 4, (int)knobP);
415 /* knob */
416 #ifndef DOUBLE_BUFFER
417 XFillRectangle(scr->display, d, scr->lightGC,
418 2 + 2, ofs + (int)knobP + 2, view->size.width - 4 - 4, (int)knobL - 4);
419 #endif
420 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
421 scr->copyGC, 0, 0,
422 scr->scrollerDimple->width, scr->scrollerDimple->height,
423 (view->size.width - scr->scrollerDimple->width - 1) / 2,
424 ofs + (int)knobP + ((int)knobL - scr->scrollerDimple->height - 1) / 2);
426 W_DrawRelief(scr, d, 2, ofs + (int)knobP, view->size.width - 4, (int)knobL, WRRaised);
428 /* after */
429 if ((int)(knobP + knobL) < length)
430 XFillRectangle(scr->display, d, scr->stippleGC,
431 2, ofs + (int)(knobP + knobL),
432 view->size.width - 4, length - (int)(knobP + knobL));
435 if (sPtr->flags.arrowsPosition != WSANone) {
436 paintArrow(sPtr, d, 0);
437 paintArrow(sPtr, d, 1);
441 #ifdef DOUBLE_BUFFER
442 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0, view->size.width, view->size.height, 0, 0);
443 XFreePixmap(scr->display, d);
444 #endif
447 static void handleEvents(XEvent * event, void *data)
449 Scroller *sPtr = (Scroller *) data;
451 CHECK_CLASS(data, WC_Scroller);
453 switch (event->type) {
454 case Expose:
455 if (event->xexpose.count == 0)
456 paintScroller(sPtr);
457 break;
459 case DestroyNotify:
460 destroyScroller(sPtr);
461 break;
466 * locatePointInScroller-
467 * Return the part of the scroller where the point is located.
469 static WMScrollerPart locatePointInScroller(Scroller * sPtr, int x, int y, int alternate)
471 int width = sPtr->view->size.width;
472 int height = sPtr->view->size.height;
473 int c, p1, p2, p3, p4, p5, p6;
474 int knobL, slotL;
476 /* if there is no knob... */
477 if (sPtr->flags.documentFullyVisible)
478 return WSKnobSlot;
480 if (sPtr->flags.horizontal)
481 c = x;
482 else
483 c = y;
485 /* p1 p2 p3 p4 p5 p6
486 * | | |###########| |#####| | |
487 * | < | > |###########| O |#####| < | > |
488 * | | |###########| |#####| | |
491 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
492 p1 = 18;
493 p2 = 36;
495 if (sPtr->flags.horizontal) {
496 slotL = width - 36;
497 p5 = width;
498 } else {
499 slotL = height - 36;
500 p5 = height;
502 p6 = p5;
503 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
504 if (sPtr->flags.horizontal) {
505 slotL = width - 36;
506 p6 = width - 18;
507 } else {
508 slotL = height - 36;
509 p6 = height - 18;
511 p5 = p6 - 18;
513 p1 = p2 = 0;
514 } else {
515 /* no arrows */
516 p1 = p2 = 0;
518 if (sPtr->flags.horizontal) {
519 slotL = p5 = p6 = width;
520 } else {
521 slotL = p5 = p6 = height;
525 knobL = knobLength(sPtr);
526 p3 = p2 + (int)((float)(slotL - knobL) * sPtr->floatValue);
527 p4 = p3 + knobL;
529 /* uses a mix of the NS and Win ways of doing scroll page */
530 if (c <= p1)
531 return alternate ? WSDecrementPage : WSDecrementLine;
532 else if (c <= p2)
533 return alternate ? WSIncrementPage : WSIncrementLine;
534 else if (c <= p3)
535 return WSDecrementPage;
536 else if (c <= p4)
537 return WSKnob;
538 else if (c <= p5)
539 return WSIncrementPage;
540 else if (c <= p6)
541 return alternate ? WSDecrementPage : WSDecrementLine;
542 else
543 return alternate ? WSIncrementPage : WSIncrementLine;
546 static void handlePush(Scroller * sPtr, int pushX, int pushY, int alternate)
548 WMScrollerPart part;
549 int doAction = 0;
551 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
553 sPtr->flags.hitPart = part;
555 switch (part) {
556 case WSIncrementLine:
557 sPtr->flags.incrDown = 1;
558 doAction = 1;
559 break;
561 case WSIncrementPage:
562 doAction = 1;
563 break;
565 case WSDecrementLine:
566 sPtr->flags.decrDown = 1;
567 doAction = 1;
568 break;
570 case WSDecrementPage:
571 doAction = 1;
572 break;
574 case WSKnob:
575 sPtr->flags.draggingKnob = 1;
576 #ifndef STRICT_NEXT_BEHAVIOUR
577 if (sPtr->flags.horizontal)
578 sPtr->dragPoint = pushX;
579 else
580 sPtr->dragPoint = pushY;
583 int length, knobP;
584 int buttonsLen;
586 if (sPtr->flags.arrowsPosition != WSANone)
587 buttonsLen = 2 * (BUTTON_SIZE + 1);
588 else
589 buttonsLen = 0;
591 if (sPtr->flags.horizontal)
592 length = sPtr->view->size.width - 4 - buttonsLen;
593 else
594 length = sPtr->view->size.height - 4 - buttonsLen;
596 knobP = (int)(sPtr->floatValue * (float)(length - knobLength(sPtr)));
598 if (sPtr->flags.arrowsPosition == WSAMinEnd)
599 sPtr->dragPoint -= 2 + buttonsLen + knobP;
600 else
601 sPtr->dragPoint -= 2 + knobP;
603 #endif /* STRICT_NEXT_BEHAVIOUR */
604 /* This does not seem necesary here since we don't know yet if the
605 * knob will be dragged later. -Dan
606 handleMotion(sPtr, pushX, pushY); */
607 break;
609 case WSDecrementWheel:
610 case WSIncrementWheel:
611 case WSKnobSlot:
612 case WSNoPart:
613 /* dummy */
614 break;
617 if (doAction && sPtr->action) {
618 (*sPtr->action) (sPtr, sPtr->clientData);
620 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
624 static float floatValueForPoint(Scroller * sPtr, int point)
626 float floatValue = 0;
627 float position;
628 int slotOfs, slotLength, knobL;
630 if (sPtr->flags.horizontal)
631 slotLength = sPtr->view->size.width - 4;
632 else
633 slotLength = sPtr->view->size.height - 4;
635 slotOfs = 2;
636 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
637 slotLength -= (BUTTON_SIZE + 1) * 2;
638 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
639 slotOfs += (BUTTON_SIZE + 1) * 2;
640 slotLength -= (BUTTON_SIZE + 1) * 2;
643 knobL = (float)knobLength(sPtr);
644 #ifdef STRICT_NEXT_BEHAVIOUR
645 if (point < slotOfs + knobL / 2)
646 position = (float)(slotOfs + knobL / 2);
647 else if (point > slotOfs + slotLength - knobL / 2)
648 position = (float)(slotOfs + slotLength - knobL / 2);
649 else
650 position = (float)point;
652 floatValue = (position - (float)(slotOfs + slotLength / 2))
653 / (float)(slotLength - knobL);
654 #else
655 /* Adjust the last point to lie inside the knob slot */
656 if (point < slotOfs)
657 position = (float)slotOfs;
658 else if (point > slotOfs + slotLength)
659 position = (float)(slotOfs + slotLength);
660 else
661 position = (float)point;
663 /* Compute the float value */
664 floatValue = (position - (float)slotOfs) / (float)(slotLength - knobL);
665 #endif
667 assert(!isnan(floatValue));
668 return floatValue;
671 static void handleMotion(Scroller * sPtr, int mouseX, int mouseY)
673 if (sPtr->flags.draggingKnob) {
674 float newFloatValue;
675 int point;
677 if (sPtr->flags.horizontal) {
678 point = mouseX;
679 } else {
680 point = mouseY;
683 #ifndef STRICT_NEXT_BEHAVIOUR
684 point -= sPtr->dragPoint;
685 #endif
687 newFloatValue = floatValueForPoint(sPtr, point);
688 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
689 if (sPtr->action) {
690 (*sPtr->action) (sPtr, sPtr->clientData);
691 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
693 } else {
694 int part;
696 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
698 sPtr->flags.hitPart = part;
700 if (part == WSIncrementLine && sPtr->flags.decrDown) {
701 sPtr->flags.decrDown = 0;
702 sPtr->flags.incrDown = 1;
703 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
704 sPtr->flags.incrDown = 0;
705 sPtr->flags.decrDown = 1;
706 } else if (part != WSIncrementLine && part != WSDecrementLine) {
707 sPtr->flags.incrDown = 0;
708 sPtr->flags.decrDown = 0;
713 static void autoScroll(void *clientData)
715 Scroller *sPtr = (Scroller *) clientData;
717 if (sPtr->action) {
718 (*sPtr->action) (sPtr, sPtr->clientData);
719 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
721 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
724 static void handleActionEvents(XEvent * event, void *data)
726 Scroller *sPtr = (Scroller *) data;
727 int wheelDecrement, wheelIncrement;
728 int id, dd;
730 /* check if we're really dealing with a scroller, as something
731 * might have gone wrong in the event dispatching stuff */
732 CHECK_CLASS(sPtr, WC_Scroller);
734 id = sPtr->flags.incrDown;
735 dd = sPtr->flags.decrDown;
737 switch (event->type) {
738 case EnterNotify:
739 break;
741 case LeaveNotify:
742 if (sPtr->timerID) {
743 WMDeleteTimerHandler(sPtr->timerID);
744 sPtr->timerID = NULL;
746 sPtr->flags.incrDown = 0;
747 sPtr->flags.decrDown = 0;
748 break;
750 case ButtonPress:
751 /* FIXME: change Mod1Mask with something else */
752 if (sPtr->flags.documentFullyVisible)
753 break;
755 if (sPtr->flags.horizontal) {
756 wheelDecrement = WINGsConfiguration.mouseWheelDown;
757 wheelIncrement = WINGsConfiguration.mouseWheelUp;
758 } else {
759 wheelDecrement = WINGsConfiguration.mouseWheelUp;
760 wheelIncrement = WINGsConfiguration.mouseWheelDown;
763 if (event->xbutton.button == wheelDecrement) {
764 if (event->xbutton.state & ControlMask) {
765 sPtr->flags.hitPart = WSDecrementPage;
766 } else if (event->xbutton.state & ShiftMask) {
767 sPtr->flags.hitPart = WSDecrementLine;
768 } else {
769 sPtr->flags.hitPart = WSDecrementWheel;
771 if (sPtr->action) {
772 (*sPtr->action) (sPtr, sPtr->clientData);
773 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
775 } else if (event->xbutton.button == wheelIncrement) {
776 if (event->xbutton.state & ControlMask) {
777 sPtr->flags.hitPart = WSIncrementPage;
778 } else if (event->xbutton.state & ShiftMask) {
779 sPtr->flags.hitPart = WSIncrementLine;
780 } else {
781 sPtr->flags.hitPart = WSIncrementWheel;
783 if (sPtr->action) {
784 (*sPtr->action) (sPtr, sPtr->clientData);
785 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
787 } else {
788 handlePush(sPtr, event->xbutton.x, event->xbutton.y, (event->xbutton.state & Mod1Mask)
789 || event->xbutton.button == Button2);
790 /* continue scrolling if pushed on the buttons */
791 if (sPtr->flags.hitPart == WSIncrementLine || sPtr->flags.hitPart == WSDecrementLine) {
792 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY, autoScroll, sPtr);
795 break;
797 case ButtonRelease:
798 if (sPtr->flags.draggingKnob) {
799 if (sPtr->action) {
800 (*sPtr->action) (sPtr, sPtr->clientData);
801 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
804 if (sPtr->timerID) {
805 WMDeleteTimerHandler(sPtr->timerID);
806 sPtr->timerID = NULL;
808 sPtr->flags.incrDown = 0;
809 sPtr->flags.decrDown = 0;
810 sPtr->flags.draggingKnob = 0;
811 break;
813 case MotionNotify:
814 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
815 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
816 && sPtr->flags.hitPart != WSDecrementLine) {
817 WMDeleteTimerHandler(sPtr->timerID);
818 sPtr->timerID = NULL;
820 break;
822 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
823 paintScroller(sPtr);
826 static void destroyScroller(Scroller * sPtr)
828 /* we don't want autoscroll try to scroll a freed widget */
829 if (sPtr->timerID) {
830 WMDeleteTimerHandler(sPtr->timerID);
833 wfree(sPtr);