1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-01-09 23:34:14 +01:00
Files
wmaker/WINGs/wscroller.c
dan 9aca0d5f6e - Check whether libXft is at least version 2.1.2 else refuse to compile.
- Fixed bug in icon chooser dialog that could cause a segmentation fault
  in some cases (Pascal Hofstee <caelian@gmail.com>)
- Fixed crash in asm code in wrlib, with new versions of gcc.
- Fixed bug in the x86_PseudoColor_32_to_8() function which incorrectly
  used the r, g, b fields in the conversion.
- Fixed x86 ASM code in wrlib to work on 64 bit architectures.
- Fixed the focus flicker seen with some apps (notably gtk2)
  (Alexey Spiridonov <snarkmaster@gmail.com>)
- Fixed all crashing bugs that were generated by wmaker starting with the
  WMState file missing.
- Added NetWM support (a modified version of the patch originaly written
  by Peter Zijlstra <a.p.zijlstra@chello.nl>)
- Applied patch to enhance the Virtual Desktop behaviour, and to integrate
  it with the NetWM code (Peter Zijlstra <a.p.zijlstra@chello.nl>)
- Applied a few xinerama and placement fixes (Peter Zijlstra
    <a.p.zijlstra@chello.nl>)
- Fixed memory leak in dock code.
- Fixed and enhanced the text wrapping in WINGs.
- Fixed the layout of some elements in WPrefs.app
- Added workaround for aplications that don't set the required hints on the
  client leader window, but they set them on normal windows (observer with
  KDE 3.3.0 mainly). This will allow these apps to get an appicon again.
  (they should be fixed still)
- Added workaround for applications that do not set a command with
  XSetCommand(), but instead they set the _NET_WM_PID property. This works
  with operating systems that offer a /proc interface similar to what linux
  has. (This also is to fix problems with KDE 3.3.0 apps, but not only them).
- Fixed bug with autostart and exit scripts not being executed if user
  GNUstep path was different from ~/GNUstep (when setting GNUSTEP_USER_ROOT)
- Added utf8 support in WINGs (removed old X core font code)
- Added utility to convert old font names to new font names in style files
2004-10-12 01:34:32 +00:00

919 lines
22 KiB
C

#include "WINGsP.h"
#include <math.h>
/* undefine will disable the autoadjusting of the knob dimple to be
* directly below the cursor
* DOES NOT WORK */
#undef STRICT_NEXT_BEHAVIOUR
#define AUTOSCROLL_INITIAL_DELAY 200
#define AUTOSCROLL_DELAY 40
char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
typedef struct W_Scroller {
W_Class widgetClass;
W_View *view;
void *clientData;
WMAction *action;
float knobProportion;
float floatValue;
WMHandlerID timerID; /* for continuous scrolling mode */
#ifndef STRICT_NEXT_BEHAVIOUR
int dragPoint; /* point where the knob is being
* dragged */
#endif
struct {
WMScrollArrowPosition arrowsPosition:4;
unsigned int horizontal:1;
WMScrollerPart hitPart:4;
/* */
unsigned int documentFullyVisible:1; /* document is fully visible */
unsigned int prevSelected:1;
unsigned int pushed:1;
unsigned int incrDown:1; /* whether increment button is down */
unsigned int decrDown:1;
unsigned int draggingKnob:1;
unsigned int configured:1;
unsigned int redrawPending:1;
} flags;
} Scroller;
#define DEFAULT_HEIGHT 60
#define DEFAULT_WIDTH SCROLLER_WIDTH
#define DEFAULT_ARROWS_POSITION WSAMinEnd
#define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
static void destroyScroller(Scroller *sPtr);
static void paintScroller(Scroller *sPtr);
static void willResizeScroller();
static void handleEvents(XEvent *event, void *data);
static void handleActionEvents(XEvent *event, void *data);
static void handleMotion(Scroller *sPtr, int mouseX, int mouseY);
W_ViewDelegate _ScrollerViewDelegate = {
NULL,
NULL,
NULL,
NULL,
willResizeScroller
};
WMScroller*
WMCreateScroller(WMWidget *parent)
{
Scroller *sPtr;
sPtr = wmalloc(sizeof(Scroller));
memset(sPtr, 0, sizeof(Scroller));
sPtr->widgetClass = WC_Scroller;
sPtr->view = W_CreateView(W_VIEW(parent));
if (!sPtr->view) {
wfree(sPtr);
return NULL;
}
sPtr->view->self = sPtr;
sPtr->view->delegate = &_ScrollerViewDelegate;
sPtr->flags.documentFullyVisible = 1;
WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask
|ClientMessageMask, handleEvents, sPtr);
W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
|EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
handleActionEvents, sPtr);
sPtr->flags.hitPart = WSNoPart;
sPtr->floatValue = 0.0;
sPtr->knobProportion = 1.0;
return sPtr;
}
void
WMSetScrollerArrowsPosition(WMScroller *sPtr, WMScrollArrowPosition position)
{
sPtr->flags.arrowsPosition = position;
if (sPtr->view->flags.realized) {
paintScroller(sPtr);
}
}
static void
willResizeScroller(W_ViewDelegate *self, WMView *view,
unsigned int *width, unsigned int *height)
{
WMScroller *sPtr = (WMScroller*)view->self;
if (*width > *height) {
sPtr->flags.horizontal = 1;
*height = SCROLLER_WIDTH;
} else {
sPtr->flags.horizontal = 0;
*width = SCROLLER_WIDTH;
}
}
void
WMSetScrollerAction(WMScroller *sPtr, WMAction *action, void *clientData)
{
CHECK_CLASS(sPtr, WC_Scroller);
sPtr->action = action;
sPtr->clientData = clientData;
}
void
WMSetScrollerParameters(WMScroller *sPtr, float floatValue,
float knobProportion)
{
CHECK_CLASS(sPtr, WC_Scroller);
assert(!isnan(floatValue));
if (floatValue < 0.0)
sPtr->floatValue = 0.0;
else if (floatValue > 1.0)
sPtr->floatValue = 1.0;
else
sPtr->floatValue = floatValue;
if (knobProportion <= 0.0) {
sPtr->knobProportion = 0.0;
sPtr->flags.documentFullyVisible = 0;
} else if (knobProportion >= 1.0) {
sPtr->knobProportion = 1.0;
sPtr->flags.documentFullyVisible = 1;
} else {
sPtr->knobProportion = knobProportion;
sPtr->flags.documentFullyVisible = 0;
}
if (sPtr->view->flags.realized)
paintScroller(sPtr);
/* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);*/
}
float
WMGetScrollerKnobProportion(WMScroller *sPtr)
{
CHECK_CLASS(sPtr, WC_Scroller);
return sPtr->knobProportion;
}
float
WMGetScrollerValue(WMScroller *sPtr)
{
CHECK_CLASS(sPtr, WC_Scroller);
return sPtr->floatValue;
}
WMScrollerPart
WMGetScrollerHitPart(WMScroller *sPtr)
{
CHECK_CLASS(sPtr, WC_Scroller);
return sPtr->flags.hitPart;
}
static void
paintArrow(WMScroller *sPtr, Drawable d, int part)
/*
* part- 0 paints the decrement arrow, 1 the increment arrow
*/
{
WMView *view = sPtr->view;
WMScreen *scr = view->screen;
int ofs;
W_Pixmap *arrow;
#ifndef DOUBLE_BUFFER
GC gc = scr->lightGC;
#endif
if (part == 0) { /* decrement button */
if (sPtr->flags.horizontal) {
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
ofs = view->size.width - 2*(BUTTON_SIZE+1) - 1;
} else {
ofs = 2;
}
if (sPtr->flags.decrDown)
arrow = scr->hiLeftArrow;
else
arrow = scr->leftArrow;
} else {
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
ofs = view->size.height - 2*(BUTTON_SIZE+1) - 1;
} else {
ofs = 2;
}
if (sPtr->flags.decrDown)
arrow = scr->hiUpArrow;
else
arrow = scr->upArrow;
}
#ifndef DOUBLE_BUFFER
if (sPtr->flags.decrDown)
gc = WMColorGC(scr->white);
#endif
} else { /* increment button */
if (sPtr->flags.horizontal) {
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
ofs = view->size.width - BUTTON_SIZE+1 - 3;
} else {
ofs = 2 + BUTTON_SIZE+1;
}
if (sPtr->flags.incrDown)
arrow = scr->hiRightArrow;
else
arrow = scr->rightArrow;
} else {
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
ofs = view->size.height - BUTTON_SIZE+1 - 3;
} else {
ofs = 2 + BUTTON_SIZE+1;
}
if (sPtr->flags.incrDown)
arrow = scr->hiDownArrow;
else
arrow = scr->downArrow;
}
#ifndef DOUBLE_BUFFER
if (sPtr->flags.incrDown)
gc = scr->whiteGC;
#endif
}
if (sPtr->flags.horizontal) {
/* paint button */
#ifndef DOUBLE_BUFFER
XFillRectangle(scr->display, d, gc,
ofs+1, 2+1, BUTTON_SIZE+1-3, BUTTON_SIZE-3);
#else
if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
XFillRectangle(scr->display, d, WMColorGC(scr->white),
ofs+1, 2+1, BUTTON_SIZE+1-3, BUTTON_SIZE-3);
#endif /* DOUBLE_BUFFER */
W_DrawRelief(scr, d, ofs, 2, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
/* paint arrow */
XSetClipMask(scr->display, scr->clipGC, arrow->mask);
XSetClipOrigin(scr->display, scr->clipGC,
ofs + (BUTTON_SIZE - arrow->width) / 2,
2 + (BUTTON_SIZE - arrow->height) / 2);
XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
0, 0, arrow->width, arrow->height,
ofs + (BUTTON_SIZE - arrow->width) / 2,
2 + (BUTTON_SIZE - arrow->height) / 2);
} else { /* vertical */
/* paint button */
#ifndef DOUBLE_BUFFER
XFillRectangle(scr->display, d, gc,
2+1, ofs+1, BUTTON_SIZE-3, BUTTON_SIZE+1-3);
#else
if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
XFillRectangle(scr->display, d, WMColorGC(scr->white),
2+1, ofs+1, BUTTON_SIZE-3, BUTTON_SIZE+1-3);
#endif /* DOUBLE_BUFFER */
W_DrawRelief(scr, d, 2, ofs, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
/* paint arrow */
XSetClipMask(scr->display, scr->clipGC, arrow->mask);
XSetClipOrigin(scr->display, scr->clipGC,
2 + (BUTTON_SIZE - arrow->width) / 2,
ofs + (BUTTON_SIZE - arrow->height) / 2);
XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
0, 0, arrow->width, arrow->height,
2 + (BUTTON_SIZE - arrow->width) / 2,
ofs + (BUTTON_SIZE - arrow->height) / 2);
}
}
static int
knobLength(Scroller *sPtr)
{
int tmp, length;
if (sPtr->flags.horizontal)
length = sPtr->view->size.width - 4;
else
length = sPtr->view->size.height - 4;
if (sPtr->flags.arrowsPosition != WSANone) {
length -= 2*(BUTTON_SIZE+1);
}
tmp = (int)((float)length * sPtr->knobProportion + 0.5);
/* keep minimum size */
if (tmp < BUTTON_SIZE)
tmp = BUTTON_SIZE;
return tmp;
}
static void
paintScroller(Scroller *sPtr)
{
WMView *view = sPtr->view;
WMScreen *scr = view->screen;
#ifdef DOUBLE_BUFFER
Pixmap d;
#else
Drawable d = view->window;
#endif
int length, ofs;
float knobP, knobL;
#ifdef DOUBLE_BUFFER
d = XCreatePixmap(scr->display, view->window, view->size.width,
view->size.height, scr->depth);
XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0,
view->size.width, view->size.height);
#endif
XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0,
view->size.width-1, view->size.height-1);
#ifndef DOUBLE_BUFFER
XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1,
view->size.width-3, view->size.height-3);
#endif
if (sPtr->flags.horizontal)
length = view->size.width - 4;
else
length = view->size.height - 4;
if (sPtr->flags.documentFullyVisible) {
XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
view->size.width-4, view->size.height-4);
} else {
ofs = 2;
if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
length -= (BUTTON_SIZE+1)*2;
} else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
ofs += (BUTTON_SIZE+1)*2;
length -= (BUTTON_SIZE+1)*2;
}
knobL = (float)knobLength(sPtr);
knobP = sPtr->floatValue * ((float)length - knobL);
if (sPtr->flags.horizontal) {
/* before */
XFillRectangle(scr->display, d, scr->stippleGC,
ofs, 2, (int)knobP, view->size.height-4);
/* knob */
#ifndef DOUBLE_BUFFER
XFillRectangle(scr->display, d, scr->lightGC,
ofs+(int)knobP+2, 2+2, (int)knobL-4,
view->size.height-4-4);
#endif
W_DrawRelief(scr, d, ofs+(int)knobP, 2, (int)knobL,
view->size.height-4, WRRaised);
XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
scr->copyGC, 0, 0,
scr->scrollerDimple->width, scr->scrollerDimple->height,
ofs+(int)knobP+((int)knobL-scr->scrollerDimple->width-1)/2,
(view->size.height-scr->scrollerDimple->height-1)/2);
/* after */
if ((int)(knobP+knobL) < length)
XFillRectangle(scr->display, d, scr->stippleGC,
ofs+(int)(knobP+knobL), 2,
length-(int)(knobP+knobL),
view->size.height-4);
} else {
/* before */
if (knobP>0.0)
XFillRectangle(scr->display, d, scr->stippleGC,
2, ofs, view->size.width-4, (int)knobP);
/* knob */
#ifndef DOUBLE_BUFFER
XFillRectangle(scr->display, d, scr->lightGC,
2+2, ofs+(int)knobP+2,
view->size.width-4-4, (int)knobL-4);
#endif
XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
scr->copyGC, 0, 0,
scr->scrollerDimple->width, scr->scrollerDimple->height,
(view->size.width-scr->scrollerDimple->width-1)/2,
ofs+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
W_DrawRelief(scr, d, 2, ofs+(int)knobP,
view->size.width-4, (int)knobL, WRRaised);
/* after */
if ((int)(knobP+knobL) < length)
XFillRectangle(scr->display, d, scr->stippleGC,
2, ofs+(int)(knobP+knobL),
view->size.width-4,
length-(int)(knobP+knobL));
}
if (sPtr->flags.arrowsPosition != WSANone) {
paintArrow(sPtr, d, 0);
paintArrow(sPtr, d, 1);
}
}
#ifdef DOUBLE_BUFFER
XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0,
view->size.width, view->size.height, 0, 0);
XFreePixmap(scr->display, d);
#endif
}
static void
handleEvents(XEvent *event, void *data)
{
Scroller *sPtr = (Scroller*)data;
CHECK_CLASS(data, WC_Scroller);
switch (event->type) {
case Expose:
if (event->xexpose.count==0)
paintScroller(sPtr);
break;
case DestroyNotify:
destroyScroller(sPtr);
break;
}
}
/*
* locatePointInScroller-
* Return the part of the scroller where the point is located.
*/
static WMScrollerPart
locatePointInScroller(Scroller *sPtr, int x, int y, int alternate)
{
int width = sPtr->view->size.width;
int height = sPtr->view->size.height;
int c, p1, p2, p3, p4, p5, p6;
int knobL, slotL;
/* if there is no knob... */
if (sPtr->flags.documentFullyVisible)
return WSKnobSlot;
if (sPtr->flags.horizontal)
c = x;
else
c = y;
/* p1 p2 p3 p4 p5 p6
* | | |###########| |#####| | |
* | < | > |###########| O |#####| < | > |
* | | |###########| |#####| | |
*/
if (sPtr->flags.arrowsPosition == WSAMinEnd) {
p1 = 18;
p2 = 36;
if (sPtr->flags.horizontal) {
slotL = width - 36;
p5 = width;
} else {
slotL = height - 36;
p5 = height;
}
p6 = p5;
} else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
if (sPtr->flags.horizontal) {
slotL = width - 36;
p6 = width - 18;
} else {
slotL = height - 36;
p6 = height - 18;
}
p5 = p6 - 18;
p1 = p2 = 0;
} else {
/* no arrows */
p1 = p2 = 0;
if (sPtr->flags.horizontal) {
slotL = p5 = p6 = width;
} else {
slotL = p5 = p6 = height;
}
}
knobL = knobLength(sPtr);
p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
p4 = p3 + knobL;
/* uses a mix of the NS and Win ways of doing scroll page */
if (c <= p1)
return alternate ? WSDecrementPage : WSDecrementLine;
else if (c <= p2)
return alternate ? WSIncrementPage : WSIncrementLine;
else if (c <= p3)
return WSDecrementPage;
else if (c <= p4)
return WSKnob;
else if (c <= p5)
return WSIncrementPage;
else if (c <= p6)
return alternate ? WSDecrementPage : WSDecrementLine;
else
return alternate ? WSIncrementPage : WSIncrementLine;
}
static void
handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
{
WMScrollerPart part;
int doAction = 0;
part = locatePointInScroller(sPtr, pushX, pushY, alternate);
sPtr->flags.hitPart = part;
switch (part) {
case WSIncrementLine:
sPtr->flags.incrDown = 1;
doAction = 1;
break;
case WSIncrementPage:
doAction = 1;
break;
case WSDecrementLine:
sPtr->flags.decrDown = 1;
doAction = 1;
break;
case WSDecrementPage:
doAction = 1;
break;
case WSKnob:
sPtr->flags.draggingKnob = 1;
#ifndef STRICT_NEXT_BEHAVIOUR
if (sPtr->flags.horizontal)
sPtr->dragPoint = pushX;
else
sPtr->dragPoint = pushY;
{
int length, knobP;
int buttonsLen;
if (sPtr->flags.arrowsPosition != WSANone)
buttonsLen = 2*(BUTTON_SIZE+1);
else
buttonsLen = 0;
if (sPtr->flags.horizontal)
length = sPtr->view->size.width - 4 - buttonsLen;
else
length = sPtr->view->size.height - 4 - buttonsLen;
knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
if (sPtr->flags.arrowsPosition == WSAMinEnd)
sPtr->dragPoint -= 2 + buttonsLen + knobP;
else
sPtr->dragPoint -= 2 + knobP;
}
#endif /* STRICT_NEXT_BEHAVIOUR */
/* This does not seem necesary here since we don't know yet if the
* knob will be dragged later. -Dan
handleMotion(sPtr, pushX, pushY); */
break;
case WSKnobSlot:
case WSNoPart:
/* dummy */
break;
}
if (doAction && sPtr->action) {
(*sPtr->action)(sPtr, sPtr->clientData);
WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
}
}
static float
floatValueForPoint(Scroller *sPtr, int point)
{
float floatValue = 0;
float position;
int slotOfs, slotLength, knobL;
if (sPtr->flags.horizontal)
slotLength = sPtr->view->size.width - 4;
else
slotLength = sPtr->view->size.height - 4;
slotOfs = 2;
if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
slotLength -= (BUTTON_SIZE+1)*2;
} else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
slotOfs += (BUTTON_SIZE+1)*2;
slotLength -= (BUTTON_SIZE+1)*2;
}
knobL = (float)knobLength(sPtr);
#ifdef STRICT_NEXT_BEHAVIOUR
if (point < slotOfs + knobL/2)
position = (float)(slotOfs + knobL/2);
else if (point > slotOfs + slotLength - knobL/2)
position = (float)(slotOfs + slotLength - knobL/2);
else
position = (float)point;
floatValue = (position-(float)(slotOfs+slotLength/2))
/(float)(slotLength-knobL);
#else
/* Adjust the last point to lie inside the knob slot */
if (point < slotOfs)
position = (float)slotOfs;
else if (point > slotOfs + slotLength)
position = (float)(slotOfs + slotLength);
else
position = (float)point;
/* Compute the float value */
floatValue = (position-(float)slotOfs) / (float)(slotLength-knobL);
#endif
assert(!isnan(floatValue));
return floatValue;
}
static void
handleMotion(Scroller *sPtr, int mouseX, int mouseY)
{
if (sPtr->flags.draggingKnob) {
float newFloatValue;
int point;
if (sPtr->flags.horizontal) {
point = mouseX;
} else {
point = mouseY;
}
#ifndef STRICT_NEXT_BEHAVIOUR
point -= sPtr->dragPoint;
#endif
newFloatValue = floatValueForPoint(sPtr, point);
WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
if (sPtr->action) {
(*sPtr->action)(sPtr, sPtr->clientData);
WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
NULL);
}
} else {
int part;
part = locatePointInScroller(sPtr, mouseX, mouseY, False);
sPtr->flags.hitPart = part;
if (part == WSIncrementLine && sPtr->flags.decrDown) {
sPtr->flags.decrDown = 0;
sPtr->flags.incrDown = 1;
} else if (part == WSDecrementLine && sPtr->flags.incrDown) {
sPtr->flags.incrDown = 0;
sPtr->flags.decrDown = 1;
} else if (part != WSIncrementLine && part != WSDecrementLine) {
sPtr->flags.incrDown = 0;
sPtr->flags.decrDown = 0;
}
}
}
static void
autoScroll(void *clientData)
{
Scroller *sPtr = (Scroller*)clientData;
if (sPtr->action) {
(*sPtr->action)(sPtr, sPtr->clientData);
WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
}
sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
}
static void
handleActionEvents(XEvent *event, void *data)
{
Scroller *sPtr = (Scroller*)data;
int wheelDecrement, wheelIncrement;
int id, dd;
/* check if we're really dealing with a scroller, as something
* might have gone wrong in the event dispatching stuff */
CHECK_CLASS(sPtr, WC_Scroller);
id = sPtr->flags.incrDown;
dd = sPtr->flags.decrDown;
switch (event->type) {
case EnterNotify:
break;
case LeaveNotify:
if (sPtr->timerID) {
WMDeleteTimerHandler(sPtr->timerID);
sPtr->timerID = NULL;
}
sPtr->flags.incrDown = 0;
sPtr->flags.decrDown = 0;
break;
case ButtonPress:
/* FIXME: change Mod1Mask with something else */
if (sPtr->flags.documentFullyVisible)
break;
if (sPtr->flags.horizontal) {
wheelDecrement = WINGsConfiguration.mouseWheelDown;
wheelIncrement = WINGsConfiguration.mouseWheelUp;
} else {
wheelDecrement = WINGsConfiguration.mouseWheelUp;
wheelIncrement = WINGsConfiguration.mouseWheelDown;
}
if (event->xbutton.button == wheelDecrement) {
if (event->xbutton.state & ControlMask) {
sPtr->flags.hitPart = WSDecrementPage;
} else if (event->xbutton.state & ShiftMask) {
sPtr->flags.hitPart = WSDecrementLine;
} else {
sPtr->flags.hitPart = WSDecrementWheel;
}
if (sPtr->action) {
(*sPtr->action)(sPtr, sPtr->clientData);
WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
NULL);
}
} else if (event->xbutton.button == wheelIncrement) {
if (event->xbutton.state & ControlMask) {
sPtr->flags.hitPart = WSIncrementPage;
} else if (event->xbutton.state & ShiftMask) {
sPtr->flags.hitPart = WSIncrementLine;
} else {
sPtr->flags.hitPart = WSIncrementWheel;
}
if (sPtr->action) {
(*sPtr->action)(sPtr, sPtr->clientData);
WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
NULL);
}
} else {
handlePush(sPtr, event->xbutton.x, event->xbutton.y,
(event->xbutton.state & Mod1Mask)
||event->xbutton.button==Button2);
/* continue scrolling if pushed on the buttons */
if (sPtr->flags.hitPart == WSIncrementLine
|| sPtr->flags.hitPart == WSDecrementLine) {
sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY,
autoScroll, sPtr);
}
}
break;
case ButtonRelease:
if (sPtr->flags.draggingKnob) {
if (sPtr->action) {
(*sPtr->action)(sPtr, sPtr->clientData);
WMPostNotificationName(WMScrollerDidScrollNotification, sPtr,
NULL);
}
}
if (sPtr->timerID) {
WMDeleteTimerHandler(sPtr->timerID);
sPtr->timerID = NULL;
}
sPtr->flags.incrDown = 0;
sPtr->flags.decrDown = 0;
sPtr->flags.draggingKnob = 0;
break;
case MotionNotify:
handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
&& sPtr->flags.hitPart != WSDecrementLine) {
WMDeleteTimerHandler(sPtr->timerID);
sPtr->timerID = NULL;
}
break;
}
if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
paintScroller(sPtr);
}
static void
destroyScroller(Scroller *sPtr)
{
/* we don't want autoscroll try to scroll a freed widget */
if (sPtr->timerID) {
WMDeleteTimerHandler(sPtr->timerID);
}
wfree(sPtr);
}