--- X11R6.8.1/xc/programs/Xserver/hw/xfree86/input/wacom/xf86Wacom.c 2004-11-18 17:38:02.000000000 -0800 +++ xf86Wacom.c 2004-11-23 14:59:11.000000000 -0800 @@ -2,6 +2,7 @@ /* $XConsortium: xf86Wacom.c /main/20 1996/10/27 11:05:20 kaleb $ */ /* * Copyright 1995-2001 by Frederic Lepied, France. + * Copyright 2002-2004 by Ping Cheng. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -45,7 +46,7 @@ * */ -static const char identification[] = "$Identification: 42 $"; +static const char identification[] = "$Identification: 43 $"; #include @@ -53,7 +54,7 @@ #include #include -/* 2.4.6 module support */ +/* 2.6 module support */ #ifndef EV_MSC #define EV_MSC 0x04 #endif @@ -209,14 +210,18 @@ static Bool isdv4Init(LocalDevicePtr); static void isdv4InitISDV4(WacomCommonPtr common, int fd, const char* id, float version); +static int isdv4GetRanges(WacomCommonPtr common, int fd); +static int isdv4StartTablet(WacomCommonPtr common, int fd); static int isdv4Parse(WacomCommonPtr common, const unsigned char* data); static int xf86WcmFilterCoord(WacomCommonPtr common, WacomChannelPtr pChannel, WacomDeviceStatePtr ds); static int xf86WcmFilterIntuos(WacomCommonPtr common, WacomChannelPtr pChannel, WacomDeviceStatePtr ds); +static int xf86WcmHysteresisFilter(WacomCommonPtr common, WacomChannelPtr pChannel, + WacomDeviceStatePtr ds); -static void xf86WcmSendEvents(LocalDevicePtr local, const WacomDeviceState* ds); +static void xf86WcmSendEvents(LocalDevicePtr local, const WacomDeviceState* ds, unsigned int c); static Bool xf86WcmDevConvert(LocalDevicePtr local, int first, int num, int v0, int v1, int v2, int v3, int v4, int v5, int *x, int *y); static Bool xf86WcmDevReverseConvert(LocalDevicePtr local, int x, int y, @@ -271,20 +276,23 @@ /****************************************************************************** * WacomDeviceRec flags *****************************************************************************/ -#define DEVICE_ID(flags) ((flags) & 0x07) +#define DEVICE_ID(flags) ((flags) & 0x0f) #define STYLUS_ID 1 #define CURSOR_ID 2 #define ERASER_ID 4 -#define ABSOLUTE_FLAG 8 -#define KEEP_SHAPE_FLAG 16 -#define BAUD_19200_FLAG 32 -#define BETA_FLAG 64 +#define PAD_ID 8 +#define ABSOLUTE_FLAG 16 +#define KEEP_SHAPE_FLAG 32 +#define BAUD_19200_FLAG 64 #define BUTTONS_ONLY_FLAG 128 +#define TPCBUTTONS_FLAG 256 +#define TPCBUTTONONE_FLAG 512 #define IsCursor(priv) (DEVICE_ID((priv)->flags) == CURSOR_ID) #define IsStylus(priv) (DEVICE_ID((priv)->flags) == STYLUS_ID) #define IsEraser(priv) (DEVICE_ID((priv)->flags) == ERASER_ID) +#define IsPad(priv) (DEVICE_ID((priv)->flags) == PAD_ID) #define MAX_SAMPLES 4 @@ -330,6 +338,7 @@ #define XI_STYLUS "STYLUS" /* X device name for the stylus */ #define XI_CURSOR "CURSOR" /* X device name for the cursor */ #define XI_ERASER "ERASER" /* X device name for the eraser */ +#define XI_PAD "PAD" /* X device name for the I3 Pad */ #define MAX_VALUE 100 /* number of positions */ #define MAXTRY 3 /* max number of try to receive magic number */ #define MAX_COORD_RES 1270.0 /* Resolution of the returned MaxX and MaxY */ @@ -341,6 +350,9 @@ #define WC_CONFIG "~R\r" /* request a configuration string */ #define WC_COORD "~C\r" /* request max coordinates */ #define WC_MODEL "~#\r" /* request model and ROM version */ +#define WC_ISDV4_QUERY "*" /* ISDV4 query command */ +#define WC_ISDV4_STOP "0" /* ISDV4 stop command */ +#define WC_ISDV4_SAMPLING "1" /* ISDV4 sampling command */ #define WC_MULTI "MU1\r" /* multi mode input */ #define WC_UPPER_ORIGIN "OC1\r" /* origin in upper left */ @@ -398,6 +410,8 @@ int pressure; int tiltx; int tilty; + int stripx; + int stripy; int rotation; int abswheel; int relwheel; @@ -459,6 +473,8 @@ int oldTiltY; /* previous tilt in y direction */ int oldWheel; /* previous wheel value */ int oldRot; /* previous rotation value */ + int oldStripX; /* previous left strip value */ + int oldStripY; /* previous right strip value */ int oldThrottle; /* previous throttle value */ int oldButtons; /* previous buttons state */ int oldProximity; /* previous proximity */ @@ -466,11 +482,9 @@ int accel; /* relative mode acceleration */ int numScreen; /* number of configured screens */ int currentScreen; /* current screen in display */ - double dscaleX; /* scale in X for dual screens */ - double dscaleY; /* scale in Y for dual screens */ - int doffsetX; /* offset in X for dual screens */ - int doffsetY; /* offset in Y for dual screens */ tvMode twinview; /* using twinview mode of gfx card */ + int tvoffsetX; /* X edge offset for TwinView setup */ + int tvoffsetY; /* Y edge offset for TwinView setup */ int tvResolution[4];/* twinview screens' resultion */ int throttleStart; /* time in ticks for last wheel movement */ int throttleLimit; /* time in ticks for next wheel movement */ @@ -508,7 +522,10 @@ WacomDeviceClassPtr wcmDevCls; /* device class functions */ WacomModelPtr wcmModel; /* model-specific functions */ + char *wcmEraserID; /* eraser associated with the stylus */ int wcmGimp; /* support Gimp on Xinerama Enabled multi-monitor desktop */ + int wcmMMonitor; /* disable/enable moving across screens in multi-monitor desktop */ + int wcmTPCButton; /* set Tablet PC button on/off */ int bufpos; /* position with buffer */ unsigned char buffer[BUFFER_SIZE]; /* data read from device */ @@ -680,6 +697,8 @@ #define XWACOM_PARAM_FILEMODEL 100 #define XWACOM_PARAM_FILEOPTION 101 #define XWACOM_PARAM_GIMP 102 +#define XWACOM_PARAM_MMT 103 +#define XWACOM_PARAM_TPCBUTTON 104 WacomModule gWacomModule = { @@ -867,6 +886,21 @@ xf86WcmFilterIntuos, /* input filtering recommended */ }; +static WacomModel usbIntuos3 = +{ + "USB Intuos3", + usbInitProtocol5, + NULL, /* resolution not queried */ + usbGetRanges, + NULL, /* reset not supported */ + NULL, /* tilt automatically enabled */ + NULL, /* suppress implemented in software */ + NULL, /* link speed unsupported */ + NULL, /* start not supported */ + usbParse, + xf86WcmFilterIntuos, /* input filtering recommended */ +}; + static WacomModel usbVolito = { "USB Volito", @@ -952,8 +986,8 @@ case 0x12: /* Graphire2 5x7 */ model = &usbGraphire2; break; - case 0x13: /* Graphire2 4x5 */ - case 0x14: /* Graphire2 6x8 */ + case 0x13: /* Graphire3 4x5 */ + case 0x14: /* Graphire3 6x8 */ model = &usbGraphire3; break; case 0x20: /* Intuos 4x5 */ @@ -984,6 +1018,11 @@ case 0x60: /* Volito */ model = &usbVolito; break; + + case 0xB0: /* Intuos3 4x5 */ + case 0xB1: /* Intuos3 6x8 */ + case 0xB2: /* Intuos3 9x12 */ + model = &usbIntuos3; break; } } @@ -996,9 +1035,17 @@ float version) { DBG(2, ErrorF("detected a protocol 5 model (%s)\n",id)); - common->wcmResolX = common->wcmResolY = 2540; + if ( strstr(id, "Intuos3") ) + { + common->wcmChannelCnt = 1; + common->wcmResolX = common->wcmResolY = 5080; + } + else + { + common->wcmChannelCnt = 2; + common->wcmResolX = common->wcmResolY = 2540; + } common->wcmProtocolLevel = 5; - common->wcmChannelCnt = 2; common->wcmPktLength = sizeof(struct input_event); } @@ -1043,6 +1090,10 @@ return !Success; } common->wcmMaxX = nValues[2]; + if (common->wcmMaxX <= 0) { + ErrorF("WACOM: xmax value is wrong.\n"); + return !Success; + } } /* max y */ @@ -1052,6 +1103,10 @@ return !Success; } common->wcmMaxY = nValues[2]; + if (common->wcmMaxY <= 0) { + ErrorF("WACOM: ymax value is wrong.\n"); + return !Success; + } } /* max z cannot be configured */ @@ -1060,6 +1115,14 @@ return !Success; } common->wcmMaxZ = nValues[2]; + if (common->wcmMaxZ <= 0) { + ErrorF("WACOM: press max value is wrong.\n"); + return !Success; + } + } + else { + ErrorF("WACOM: unable to ioctl max values.\n"); + return !Success; } return Success; @@ -1092,11 +1155,12 @@ /* save it for later */ common->wcmEvents[common->wcmEventCnt++] = *event; - /* packet terminated by MSC_SERIAL on kernel 2.4 and SYN_REPORT on kernel 2.5 */ + /* packet terminated by MSC_SERIAL on kernel 2.4 and SYN_REPORT on kernel 2.6 */ if ((event->type != EV_MSC) || (event->code != MSC_SERIAL)) { #ifdef EV_SYN /* none serial number tools fall here */ - if ((event->type == EV_SYN) && (event->code == SYN_REPORT)) { + if ((event->type == EV_SYN) && (event->code == SYN_REPORT) + && (common->wcmChannelCnt == 1)) { usbParseChannel(common,0,0); common->wcmEventCnt = 0; } @@ -1107,9 +1171,29 @@ serial = event->value; channel = -1; - /* one channel only? must be it. */ - if (common->wcmChannelCnt == 1) channel = 0; + /* one channel only? */ + if (common->wcmChannelCnt == 1) { + /* Intuos3 Pad */ + if (serial == 0xffffffff) { + channel = 1; + (&common->wcmChannel[channel].work)->device_type = PAD_ID; + (&common->wcmChannel[channel].work)->proximity = 1; + } + else { /* must be it. */ + channel = 0; + if (common->wcmChannel[0].work.proximity == 0) { + memset(&common->wcmChannel[0],0,sizeof(WacomChannel)); + } + } + } else { /* otherwise, find the channel */ + /* clear out channels */ + for (i=0; iwcmChannelCnt; ++i) { + if (common->wcmChannel[i].work.proximity == 0) { + memset(&common->wcmChannel[i],0,sizeof(WacomChannel)); + } + } + /* find existing channel */ for (i=0; iwcmChannelCnt; ++i) { if (common->wcmChannel[i].work.serial_num == serial) { @@ -1122,9 +1206,9 @@ if (channel < 0) { for (i=0; iwcmChannelCnt; ++i) { if (common->wcmChannel[i].work.proximity == 0) { - /* clear out channel */ - memset(&common->wcmChannel[i],0, sizeof(WacomChannel)); channel = i; + /* the in-prox event was missing */ + common->wcmChannel[i].work.proximity = 1; break; } } @@ -1145,13 +1229,14 @@ static void usbParseChannel(WacomCommonPtr common, int channel, int serial) { - int i; + int i, shift; WacomDeviceState* ds; struct input_event* event; # define MOD_BUTTONS(bit, value) do { \ + shift = 1<buttons = (((value) != 0) ? \ - (ds->buttons | (bit)) : (ds->buttons & ~(bit))); \ + (ds->buttons | (shift)) : (ds->buttons & ~(shift))); \ } while (0) /* all USB data operates from previous context except relative values*/ @@ -1173,17 +1258,18 @@ ds->x = event->value; else if (event->code == ABS_Y) ds->y = event->value; + else if (event->code == ABS_RX) + ds->stripx = event->value; + else if (event->code == ABS_RY) + ds->stripy = event->value; else if (event->code == ABS_RZ) ds->rotation = event->value; else if (event->code == ABS_TILT_X) ds->tiltx = event->value - 64; else if (event->code == ABS_TILT_Y) ds->tilty = event->value - 64; - else if (event->code == ABS_PRESSURE) { + else if (event->code == ABS_PRESSURE) ds->pressure = event->value; - MOD_BUTTONS (1, event->value > common->wcmThreshold ? 1 : 0); - /* pressure button should be downstream */ - } else if (event->code == ABS_DISTANCE) ds->distance = event->value; else if (event->code == ABS_WHEEL) @@ -1211,18 +1297,38 @@ DBG(6, ErrorF("USB mouse detected %x\n", event->code)); ds->device_type = CURSOR_ID; ds->proximity = (event->value != 0); + } else if (event->code == BTN_TOOL_FINGER) { + DBG(6, ErrorF("USB Intuos3 Pad detected %x\n", event->code)); + ds->device_type = PAD_ID; + ds->proximity = (event->value != 0); } else if (event->code == BTN_TOUCH) { /* we use the pressure to determine the button 1 for now */ } else if ((event->code == BTN_STYLUS) || (event->code == BTN_MIDDLE)) { - MOD_BUTTONS (2, event->value); + MOD_BUTTONS (1, event->value); } else if ((event->code == BTN_STYLUS2) || (event->code == BTN_RIGHT)) { - MOD_BUTTONS (4, event->value); + MOD_BUTTONS (2, event->value); } else if (event->code == BTN_LEFT) - MOD_BUTTONS (1, event->value); + MOD_BUTTONS (0, event->value); else if (event->code == BTN_SIDE) - MOD_BUTTONS (8, event->value); + MOD_BUTTONS (3, event->value); else if (event->code == BTN_EXTRA) - MOD_BUTTONS (16, event->value); + MOD_BUTTONS (4, event->value); + else if (event->code == BTN_0) + MOD_BUTTONS (8, event->value); + else if (event->code == BTN_1) + MOD_BUTTONS (9, event->value); + else if (event->code == BTN_2) + MOD_BUTTONS (10, event->value); + else if (event->code == BTN_3) + MOD_BUTTONS (11, event->value); + else if (event->code == BTN_4) + MOD_BUTTONS (12, event->value); + else if (event->code == BTN_5) + MOD_BUTTONS (13, event->value); + else if (event->code == BTN_6) + MOD_BUTTONS (14, event->value); + else if (event->code == BTN_7) + MOD_BUTTONS (15, event->value); } } /* next event */ @@ -2232,14 +2338,14 @@ "General ISDV4", isdv4InitISDV4, NULL, /* resolution not queried */ - NULL, /* ranges not queried */ + isdv4GetRanges, /* query ranges */ NULL, /* reset not supported */ NULL, /* tilt automatically enabled */ NULL, /* suppress implemented in software */ NULL, /* link speed unsupported */ - NULL, /* start not supported */ + isdv4StartTablet, /* start tablet */ isdv4Parse, - xf86WcmFilterCoord, /* input filtering */ + xf86WcmHysteresisFilter, /* input filtering */ }; /***************************************************************************** @@ -2267,11 +2373,11 @@ DBG(1, ErrorF("resetting tablet\n")); - /* Set the speed of the serial link to 38400 */ - if (xf86WcmSetSerialSpeed(local->fd, 38400) < 0) return !Success; + /* Set the speed of the serial link to 19200 */ + if (xf86WcmSetSerialSpeed(local->fd, 19200) < 0) return !Success; - /* Send reset to the tablet */ - SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD))); + /* Send stop command to the tablet */ + SYSCALL(err = xf86WcmWrite(local->fd, WC_ISDV4_STOP, strlen(WC_ISDV4_STOP))); if (err == -1) { ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno)); return !Success; @@ -2280,68 +2386,103 @@ /* Wait 250 mSecs */ if (xf86WcmWait(250)) return !Success; - /* Send reset to the tablet */ - SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET))); - if (err == -1) { - ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno)); - return !Success; + return xf86WcmInitTablet(common,&isdv4General,local->fd,"ISDV4", common->wcmVersion); +} + +/***************************************************************************** + * isdv4InitISDV4 -- Setup the device + ****************************************************************************/ + +static void isdv4InitISDV4(WacomCommonPtr common, int fd, + const char* id, float version) +{ + int temp; + DBG(2, ErrorF("initializing as ISDV4 model\n")); + + /* set parameters */ + common->wcmProtocolLevel = 4; + common->wcmResolX = 2540; /* X resolution in points/inch */ + common->wcmResolY = 2540; /* Y resolution in points/inch */ + common->wcmPktLength = 9; /* length of a packet */ + common->wcmTPCButton = 1; /* Tablet PC buttons on by default */ + + if (common->wcmRotate==ROTATE_CW || common->wcmRotate==ROTATE_CCW) { + temp = common->wcmMaxX; + common->wcmMaxX = common->wcmMaxY; + common->wcmMaxY = temp; } +} - /* Wait 75 mSecs */ - if (xf86WcmWait(75)) return !Success; +static int isdv4GetRanges(WacomCommonPtr common, int fd) +{ + char data[BUFFER_SIZE]; + int maxtry = MAXTRY, nr; - /* Set the speed of the serial link to 19200 */ - if (xf86WcmSetSerialSpeed(local->fd, 19200) < 0) return !Success; + DBG(2, ErrorF("getting ISDV4 Ranges\n")); + /* Send query command to the tablet */ + do { + SYSCALL(nr = xf86WcmWrite(fd, WC_ISDV4_QUERY, strlen(WC_ISDV4_QUERY))); + if ((nr == -1) && (errno != EAGAIN)) { + ErrorF("Wacom xf86WcmWrite error : %s", strerror(errno)); + return !Success; + } + maxtry--; + } while ((nr == -1) && maxtry); - /* Send reset to the tablet */ - SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD))); - if (err == -1) { - ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno)); + if (maxtry == 0) { + ErrorF("Wacom unable to xf86WcmWrite request query command " + "after %d tries\n", MAXTRY); return !Success; } - /* Wait 250 mSecs */ - if (xf86WcmWait(250)) return !Success; + /* Read the control data */ + maxtry = MAXTRY; + do { + if ((nr = xf86WcmWaitForTablet(fd)) > 0) { + SYSCALL(nr = xf86WcmRead(fd, data, 11)); + if ((nr == -1) && (errno != EAGAIN)) { + ErrorF("Wacom xf86WcmRead error : %s\n", strerror(errno)); + return !Success; + } + } + maxtry--; + } while ( nr <= 0 && maxtry ); - /* Send reset to the tablet */ - SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET))); - if (err == -1) { - ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno)); + if (maxtry == 0 && nr <= 0 ) { + ErrorF("Wacom unable to read ISDV4 control data " + "after %d tries\n", MAXTRY); return !Success; } - /* Wait 75 mSecs */ - if (xf86WcmWait(75)) return !Success; - - xf86WcmFlushTablet(local->fd); + /* Control data bit check */ + if ( !(data[0] & 0x40) ) { + ErrorF("Wacom Query ISDV4 error magic error \n"); + return !Success; + } + + common->wcmMaxZ = ( data[5] | ((data[6] & 0x07) << 7) ); + common->wcmMaxX = ( (data[1] << 9) | (data[2] << 2) + | ( (data[6] & 0x60) >> 5) ); + common->wcmMaxY = ( (data[3] << 9) | (data[4] << 2 ) + | ( (data[6] & 0x18) >> 3) ); + common->wcmVersion = ( data[10] | (data[9] << 7) ); - DBG(2, ErrorF("not reading model -- Wacom TabletPC ISD V4\n")); - return xf86WcmInitTablet(common,&isdv4General,local->fd,"unknown",0.0); + return Success; } -/***************************************************************************** - * isdv4InitISDV4 -- Setup the device - ****************************************************************************/ - -static void isdv4InitISDV4(WacomCommonPtr common, int fd, - const char* id, float version) +static int isdv4StartTablet(WacomCommonPtr common, int fd) { - DBG(2, ErrorF("initializing as ISDV4 model\n")); + int err; - /* set parameters */ - common->wcmProtocolLevel = 0; - common->wcmMaxZ = 255; /* max Z value (pressure)*/ - common->wcmResolX = 2570; /* X resolution in points/inch */ - common->wcmResolY = 2570; /* Y resolution in points/inch */ - common->wcmPktLength = 9; /* length of a packet */ + /* Tell the tablet to start sending coordinates */ + SYSCALL(err = xf86WcmWrite(fd, WC_ISDV4_SAMPLING, (strlen(WC_ISDV4_SAMPLING)))); - if (common->wcmRotate==ROTATE_NONE) { - common->wcmMaxX = 21136; - common->wcmMaxY = 15900; - } else if (common->wcmRotate==ROTATE_CW || common->wcmRotate==ROTATE_CCW) { - common->wcmMaxX = 15900; - common->wcmMaxY = 21136; + if (err == -1) { + ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno)); + return !Success; } + + return Success; } static int isdv4Parse(WacomCommonPtr common, const unsigned char* data) @@ -2350,7 +2491,12 @@ WacomDeviceState* ds; int n, cur_type, tmp_coord; - if ((n = xf86WcmSerialValidate(common,data)) > 0) return n; + if ((n = xf86WcmSerialValidate(common,data)) > 0) + return n; + else { + /* Coordinate data bit check */ + if (data[0] & 0x40) return common->wcmPktLength; + } /* pick up where we left off, minus relative values */ ds = &common->wcmChannel[0].work; @@ -2376,33 +2522,13 @@ } /* pressure */ - ds->pressure = ((data[6] & 0x01) << 7) | (data[5] & 0x7F); - - /* button order is slightly amiss so that styluses with only - * one side button have buttons 1 and 3 */ - - /* report touch as button 1 */ - ds->buttons = (data[0] & 0x01) ? 1 : 0 ; - - /* report side switch as button 3 */ - ds->buttons |= (data[0] & 0x02) ? 0x04 : 0 ; + ds->pressure = ((data[6] & 0x07) << 7) | data[5]; - /* report as button 2 (subject eraser check below) */ - ds->buttons |= (data[0] & 0x04) ? 0x02 : 0 ; - - /* the bit used for button 2 is also used to ID the - * eraser. If the tool comes into proximity with this bit - * set, it is assumed to be the eraser. If the tool was - * previously in proximity, it is assumed to be the button. - * The mistaken identity case is handled with proximity below. */ + /* button */ + ds->buttons = (data[0] & 0x07) ; /* check which device we have */ - cur_type = (data[0] & 0x04) ? ERASER_ID : STYLUS_ID; - - /* If there's no eraser configured, let's not even try to - * report an eraser (handy for making button 2 action more - * definite) */ - if ( common->wcmNumDevices == 1 && cur_type == ERASER_ID ) cur_type = STYLUS_ID; + cur_type = (ds->buttons & 4) ? ERASER_ID : STYLUS_ID; /* first time into prox */ if (!last->proximity && ds->proximity) ds->device_type = cur_type; @@ -2617,13 +2743,13 @@ static void filterIntuosStylus(WacomFilterStatePtr state, WacomDeviceStatePtr ds) { - if (!state->npoints) { + if (state->npoints < 3) { + state->x[state->npoints] = ds->x; + state->y[state->npoints] = ds->y; + state->tiltx[state->npoints] = ds->tiltx; + state->tilty[state->npoints] = ds->tilty; ++state->npoints; - DBG(2,ErrorF("filterIntuosStylus: first sample NO_FILTER\n")); - state->x[0] = state->x[1] = state->x[2] = ds->x; - state->y[0] = state->y[1] = state->y[2] = ds->y; - state->tiltx[0] = state->tiltx[1] = state->tiltx[2] = ds->tiltx; - state->tilty[0] = state->tilty[1] = state->tilty[2] = ds->tilty; + DBG(11,ErrorF("filterIntuosStylus: first %d sample(s) NO_FILTER\n",state->npoints)); return; } @@ -2672,10 +2798,6 @@ x1/100.0, y1/100.0, /* control point 2 */ 1.0, 1.0); /* top right */ - for (i=0; i<=FILTER_PRESSURE_RES; i+=128) - DBG(6, ErrorF("PRESSCURVE: %d=%d (%d)\n",i,pDev->pPressCurve[i], - pDev->pPressCurve[i] - i)); - pDev->nPressCtrl[0] = x0; pDev->nPressCtrl[1] = y0; pDev->nPressCtrl[2] = x1; @@ -2698,11 +2820,11 @@ x = pChannel->rawFilter.x; y = pChannel->rawFilter.y; - if (!pChannel->rawFilter.npoints) { + if (pChannel->rawFilter.npoints<3) { + x[pChannel->rawFilter.npoints] = ds->x; + y[pChannel->rawFilter.npoints] = ds->y; ++pChannel->rawFilter.npoints; - DBG(2,ErrorF("xf86WcmFilterCoord: first sample NO_FILTER\n")); - x[0] = x[1] = x[2] = ds->x; - y[0] = y[1] = y[2] = ds->y; + DBG(11,ErrorF("xf86WcmFilterCoord: first %d sample NO_FILTER\n",pChannel->rawFilter.npoints)); return 0; } @@ -2731,7 +2853,7 @@ } /***************************************************************************** - * xf86WcmFilterCoord -- provide error correction to Intuos and Intuos2 + * xf86WcmFilterIntuos -- provide error correction to Intuos and Intuos2 ****************************************************************************/ static int xf86WcmFilterIntuos(WacomCommonPtr common, WacomChannelPtr pChannel, @@ -2748,7 +2870,24 @@ return 0; /* lookin' good */ } +/***************************************************************************** + * xf86WcmHysteresisFilter -- provide noise correction to protocol IV transducers + ****************************************************************************/ +static int xf86WcmHysteresisFilter(WacomCommonPtr common, WacomChannelPtr pChannel, + WacomDeviceStatePtr ds) +{ + WacomDeviceState* pLast; + pLast = &pChannel->valid.state; + + if (abs(ds->x - pLast->x) < 4) + ds->x = pLast->x; + + if (abs(ds->y - pLast->y) < 4) + ds->y = pLast->y; + + return 0; +} /* *************************************************************************** @@ -2791,57 +2930,51 @@ } #endif if (priv->twinview != TV_NONE && (priv->flags & ABSOLUTE_FLAG)) { - v0 -= priv->topX; - v1 -= priv->topY; + v0 -= priv->topX - priv->tvoffsetX; + v1 -= priv->topY - priv->tvoffsetY; if (priv->twinview == TV_LEFT_RIGHT) { - if (v0 > priv->bottomX) + if (v0 > priv->bottomX - priv->tvoffsetX) { - v0 -= priv->bottomX; - priv->currentScreen = 1; - if (priv->screen_no == 0) { - priv->currentScreen = 0; - } - } else { - priv->currentScreen = 0; - if (priv->screen_no == 1) { - priv->currentScreen = 1; + if (priv->currentScreen == 0) + v0 = priv->bottomX - priv->tvoffsetX; + else { + v0 -= priv->bottomX - priv->topX - 2*priv->tvoffsetX; + if (v0 > priv->bottomX - priv->tvoffsetX) + v0 = 2*(priv->bottomX - priv->tvoffsetX) - v0; } } if (priv->currentScreen == 1) { *x = priv->tvResolution[0] + priv->tvResolution[2] - * v0 / (priv->bottomX - priv->topX); + * v0 / (priv->bottomX - priv->topX - 2*priv->tvoffsetX); *y = v1 * priv->tvResolution[3] / - (priv->bottomY - priv->topY) + 0.5; + (priv->bottomY - priv->topY - 2*priv->tvoffsetY) + 0.5; } else { *x = priv->tvResolution[0] * v0 / - (priv->bottomX - priv->topX); + (priv->bottomX - priv->topX - 2*priv->tvoffsetX); *y = v1 * priv->tvResolution[1] / - (priv->bottomY - priv->topY) + 0.5; + (priv->bottomY - priv->topY - 2*priv->tvoffsetY) + 0.5; } } if (priv->twinview == TV_ABOVE_BELOW) { - if (v1 > priv->bottomY) { - v1 -= priv->bottomY; - priv->currentScreen = 1; - if (priv->screen_no == 0) { - priv->currentScreen = 0; - } - } else { - priv->currentScreen = 0; - if (priv->screen_no == 1) { - priv->currentScreen = 1; + if (v1 > priv->bottomY - priv->tvoffsetY) { + if (priv->currentScreen == 0) + v1 = priv->bottomY - priv->tvoffsetY; + else { + v1 -= priv->bottomY - priv->topY - 2*priv->tvoffsetY; + if (v1 > priv->bottomY - priv->tvoffsetY) + v1 = 2*(priv->bottomY - priv->tvoffsetY) - v1; } } if (priv->currentScreen == 1) { *x = v0 * priv->tvResolution[2] / - (priv->bottomX - priv->topX) + 0.5; + (priv->bottomX - priv->topX - 2*priv->tvoffsetX) + 0.5; *y = priv->tvResolution[1] + priv->tvResolution[3] * v1 - / (priv->bottomY - priv->topY); + / (priv->bottomY - priv->topY - 2*priv->tvoffsetY); } else { *x = v0 * priv->tvResolution[0] / - (priv->bottomX - priv->topX) + 0.5; + (priv->bottomX - priv->topX - 2*priv->tvoffsetX) + 0.5; *y = priv->tvResolution[1] * v1 / - (priv->bottomY - priv->topY); + (priv->bottomY - priv->topY - 2*priv->tvoffsetY); } } } else { @@ -2874,7 +3007,7 @@ #ifdef PANORAMIX if (!noPanoramiXExtension && (priv->flags & ABSOLUTE_FLAG) && - priv->common->wcmGimp) { + priv->common->wcmGimp && priv->common->wcmMMonitor) { int i, totalWidth, leftPadding = 0; for (i = 0; i < priv->currentScreen; i++) leftPadding += screenInfo.screens[i]->width; @@ -2886,57 +3019,41 @@ #endif if (priv->twinview != TV_NONE && (priv->flags & ABSOLUTE_FLAG)) { if (priv->twinview == TV_LEFT_RIGHT) { - if (x > priv->tvResolution[0]) { + if (x > priv->tvResolution[0]) x -= priv->tvResolution[0]; - priv->currentScreen = 1; - if (priv->screen_no == 0) { - priv->currentScreen = 0; - } - } else { - priv->currentScreen = 0; - if (priv->screen_no == 1) { - priv->currentScreen = 1; - } - } if (priv->currentScreen == 1) { - valuators[0] = x * (priv->bottomX - priv->topX) - / priv->tvResolution[2] + priv->bottomX - priv->topX + 0.5; - valuators[1] = y * (priv->bottomY - priv->topY) / - priv->tvResolution[3] + 0.5; - } else { - valuators[0] = x * (priv->bottomX - priv->topX) - / priv->tvResolution[0] + 0.5; - valuators[1] = y * (priv->bottomY - priv->topY) / - priv->tvResolution[1] + 0.5; + valuators[0] = x * (priv->bottomX - priv->topX - 2*priv->tvoffsetX) + / priv->tvResolution[2] + (priv->bottomX - priv->topX - + 2*priv->tvoffsetX) +0.5; + valuators[1] = y * (priv->bottomY - priv->topY - 2*priv->tvoffsetY) / + priv->tvResolution[3] + 0.5; + } + else { + valuators[0] = x * (priv->bottomX - priv->topX - 2*priv->tvoffsetX) + / priv->tvResolution[0] + 0.5; + valuators[1] = y * (priv->bottomY - priv->topY - 2*priv->tvoffsetY) / + priv->tvResolution[1] + 0.5; } } if (priv->twinview == TV_ABOVE_BELOW) { - if (y > priv->tvResolution[1]) { + if (y > priv->tvResolution[1]) y -= priv->tvResolution[1]; - priv->currentScreen = 1; - if (priv->screen_no == 0) { - priv->currentScreen = 0; - } - } else { - priv->currentScreen = 0; - if (priv->screen_no == 1) { - priv->currentScreen = 1; - } - } if (priv->currentScreen == 1) { - valuators[0] = x * (priv->bottomX - priv->topX) / + valuators[0] = x * (priv->bottomX - priv->topX - 2*priv->tvoffsetX) / priv->tvResolution[2] + 0.5; - valuators[1] = y *(priv->bottomY - priv->topY) / - priv->tvResolution[3] + priv->bottomY - priv->topY + 0.5; - } else { - valuators[0] = x * (priv->bottomX - priv->topX) / + valuators[1] = y *(priv->bottomY - priv->topY - 2*priv->tvoffsetY) + / priv->tvResolution[3] + + priv->bottomY - priv->topY - 2*priv->tvoffsetY + 0.5; + } + else { + valuators[0] = x * (priv->bottomX - priv->topX - 2*priv->tvoffsetX) / priv->tvResolution[0] + 0.5; - valuators[1] = y *(priv->bottomY - priv->topY) / - priv->tvResolution[1] + 0.5; + valuators[1] = y *(priv->bottomY - priv->topY - 2*priv->tvoffsetY) + / priv->tvResolution[1] + 0.5; } } - valuators[0] += priv->topX; - valuators[1] += priv->topY; + valuators[0] += priv->topX + priv->tvoffsetX; + valuators[1] += priv->topY + priv->tvoffsetY; } DBG(6, ErrorF("Wacom converted x=%d y=%d to v0=%d v1=%d\n", x, y, valuators[0], valuators[1])); @@ -2961,19 +3078,44 @@ int *v1) { WacomDevicePtr priv = (WacomDevicePtr) local->private; - int screenToSet = miPointerCurrentScreen()->myNum; - int i; - int x, y; + int screenToSet = 0; + int i, x, y; int totalWidth = 0, maxHeight = 0, leftPadding = 0; - double sizeX = priv->bottomX - priv->topX; - double sizeY = priv->bottomY - priv->topY; + double sizeX = priv->bottomX - priv->topX - 2*priv->tvoffsetX; + double sizeY = priv->bottomY - priv->topY - 2*priv->tvoffsetY; /* set factorX and factorY for single screen setup since * Top X Y and Bottom X Y can be changed while driver is running */ - if (screenInfo.numScreens == 1) { - priv->factorX = screenInfo.screens[0]->width / sizeX; - priv->factorY = screenInfo.screens[0]->height / sizeY; + if (screenInfo.numScreens == 1 || !priv->common->wcmMMonitor) { + if (priv->twinview != TV_NONE && (priv->flags & ABSOLUTE_FLAG)) { + if (priv->screen_no == -1) { + if (priv->twinview == TV_LEFT_RIGHT) { + if (*v0 > priv->bottomX - priv->tvoffsetX && *v0 <= priv->bottomX) + priv->currentScreen = 1; + if (*v0 > priv->topX && *v0 <= priv->topX + priv->tvoffsetX) + priv->currentScreen = 0; + } + if (priv->twinview == TV_ABOVE_BELOW) { + if (*v1 > priv->bottomY - priv->tvoffsetY && *v1 <= priv->bottomY) + priv->currentScreen = 1; + if (*v1 > priv->topY && *v1 <= priv->topY + priv->tvoffsetY) + priv->currentScreen = 0; + } + } + else + priv->currentScreen = priv->screen_no; + priv->factorX = priv->tvResolution[2*priv->currentScreen] / sizeX; + priv->factorY = priv->tvResolution[2*priv->currentScreen+1] / sizeY; + } + else + { + /* tool on the tablet when driver starts */ + if (miPointerCurrentScreen()) + priv->currentScreen = miPointerCurrentScreen()->myNum; + priv->factorX = screenInfo.screens[priv->currentScreen]->width / sizeX; + priv->factorY = screenInfo.screens[priv->currentScreen]->height / sizeY; + } return; } @@ -3044,6 +3186,67 @@ priv->currentScreen, screenToSet)); priv->currentScreen = screenToSet; } + +/***************************************************************************** + * sendAButton -- + * Send one button event, called by xf86WcmSendButtons + ****************************************************************************/ + +static void sendAButton(LocalDevicePtr local, int button, int mask, + int rx, int ry, int rz, int rtx, int rty, int rrot, + int rth, int rwheel) +{ + WacomDevicePtr priv = (WacomDevicePtr) local->private; + int is_absolute = priv->flags & ABSOLUTE_FLAG, nbutton; + + /* translate into Left Double Click */ + if (button == 17) { + nbutton = 1; + if ( mask ) { + /* Left button down */ + if (IsCursor(priv)) + xf86PostButtonEvent(local->dev, is_absolute, nbutton, + 1, 0, 6, rx, ry, rz, rrot, rth, rwheel); + else + xf86PostButtonEvent(local->dev, is_absolute, nbutton, + 1, 0, 6, rx, ry, rz, rtx, rty, rwheel); + /* Left button up */ + if (IsCursor(priv)) + xf86PostButtonEvent(local->dev, is_absolute, nbutton, + 0, 0, 6, rx, ry, rz, rrot, rth, rwheel); + else + xf86PostButtonEvent(local->dev, is_absolute, nbutton, + 0, 0, 6, rx, ry, rz, rtx, rty, rwheel); + } + + /* Left button down/up upon mask is 1/0 */ + if (IsCursor(priv)) + xf86PostButtonEvent(local->dev, is_absolute, nbutton, + mask != 0, 0, 6, rx, ry, rz, rrot, rth, rwheel); + else + xf86PostButtonEvent(local->dev, is_absolute, nbutton, + mask != 0, 0, 6, rx, ry, rz, rtx, rty, rwheel); + } + /* switch absolute or relative (Mode Toggle) */ + if ( button == 19 && mask ) { + if (is_absolute) { + priv->flags &= ~ABSOLUTE_FLAG; + xf86ReplaceStrOption(local->options, "Mode", "Relative"); + } + else { + priv->flags |= ABSOLUTE_FLAG; + xf86ReplaceStrOption(local->options, "Mode", "Absolute"); + } + } + if (button < 17) { + if (IsCursor(priv)) + xf86PostButtonEvent(local->dev, is_absolute, button, + mask != 0, 0, 6, rx, ry, rz, rrot, rth, rwheel); + else + xf86PostButtonEvent(local->dev, is_absolute, button, + mask != 0, 0, 6, rx, ry, rz, rtx, rty, rwheel); + } +} /* *************************************************************************** @@ -3067,54 +3270,89 @@ int rwheel) { - int button, newb; + int button, mask, bsent = 0; WacomDevicePtr priv = (WacomDevicePtr) local->private; + WacomCommonPtr common = priv->common; - for (button=1; button<=16; button++) { - int mask = 1 << (button-1); - - if ((mask & priv->oldButtons) != (mask & buttons)) { - DBG(4, ErrorF("xf86WcmSendButtons button=%d state=%d, for %s\n", - button, (buttons & mask) != 0, local->name)); - /* set to the configured buttons */ - newb = button; - if (priv->button[button-1] != button) - newb = priv->button[button-1]; + /* Tablet PC buttons. */ + if ( common->wcmTPCButton && !IsCursor(priv) && !IsPad(priv) ) { + if ( buttons & 1 ) { + if ( !(priv->flags & TPCBUTTONS_FLAG) ) { + priv->flags |= TPCBUTTONS_FLAG; + + bsent = 0; + + /* send all pressed buttons down */ + for (button=2; button<=16; button++) { + mask = 1 << (button-1); + if ( buttons & mask ) { + bsent = 1; + /* set to the configured button */ + sendAButton(local, priv->button[button-1], 1, rx, ry, + rz, rtx, rty, rrot, rth, rwheel); + } + } + + /* only send button one when nothing else was sent + * There is a bug in XFree86 for combined left click and + * other button. It'll lost left up when releases. + * This should be removed if XFree86 fixes the problem. + */ + if ( !bsent && (buttons & 1) ) { + priv->flags |= TPCBUTTONONE_FLAG; + sendAButton(local, priv->button[0], 1, rx, ry, + rz, rtx, rty, rrot, rth, rwheel); + } + } + else { + bsent = 0; + for (button=2; button<=16; button++) { + mask = 1 << (button-1); + if ((mask & priv->oldButtons) != (mask & buttons)) { + /* Send button one up before any button down is sent. + * There is a bug in XFree86 for combined left click and + * other button. It'll lost left up when releases. + * This should be removed if XFree86 fixes the problem. + */ + if (priv->flags & TPCBUTTONONE_FLAG && !bsent) { + priv->flags &= ~TPCBUTTONONE_FLAG; + sendAButton(local, 1, 0, rx, ry, rz, rtx, rty, rrot, rth, rwheel); + bsent = 1; + } + /* set to the configured buttons */ + sendAButton(local, priv->button[button-1], mask & buttons, + rx, ry, rz, rtx, rty, rrot, rth, rwheel); + } + } + } + } + else if ( priv->flags & TPCBUTTONS_FLAG ) { + priv->flags &= ~TPCBUTTONS_FLAG; - /* translate into Left Double Click */ - if (newb == 17) - { - newb = 1; - if (buttons & mask) - { - /* Left button down */ - if (IsCursor(priv)) - xf86PostButtonEvent(local->dev, - (priv->flags & ABSOLUTE_FLAG), newb, 1, - 0, 6, rx, ry, rz, rrot, rth, rwheel); - else - xf86PostButtonEvent(local->dev, - (priv->flags & ABSOLUTE_FLAG), newb, 1, - 0, 6, rx, ry, rz, rtx, rty, rwheel); - /* Left button up */ - if (IsCursor(priv)) - xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG), - newb, 0, 0, 6, rx, ry, rz, rrot, rth, rwheel); - else - xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG), - newb, 0, 0, 6, rx, ry, rz, rtx, rty, rwheel); + /* send all pressed buttons up */ + for (button=2; button<=16; button++) { + mask = 1 << (button-1); + if ((mask & priv->oldButtons) != (mask & buttons) || (mask & buttons) ) { + /* set to the configured button */ + sendAButton(local, priv->button[button-1], 0, rx, ry, + rz, rtx, rty, rrot, rth, rwheel); } } - if (newb <= 17) - { - if (IsCursor(priv)) - xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG), - newb, (buttons & mask) != 0, - 0, 6, rx, ry, rz, rrot, rth, rwheel); - else - xf86PostButtonEvent(local->dev, (priv->flags & ABSOLUTE_FLAG), - newb, (buttons & mask) != 0, - 0, 6, rx, ry, rz, rtx, rty, rwheel); + /* This is also part of the workaround of the XFree86 bug mentioned above + */ + if (priv->flags & TPCBUTTONONE_FLAG) { + priv->flags &= ~TPCBUTTONONE_FLAG; + sendAButton(local, 1, 0, rx, ry, rz, rtx, rty, rrot, rth, rwheel); + } + } + } + else { /* normal buttons */ + for (button=1; button<=16; button++) { + mask = 1 << (button-1); + if ((mask & priv->oldButtons) != (mask & buttons)) { + /* set to the configured button */ + sendAButton(local, priv->button[button-1], mask & buttons, rx, ry, + rz, rtx, rty, rrot, rth, rwheel); } } } @@ -3130,7 +3368,8 @@ */ static void xf86WcmSendEvents(LocalDevicePtr local, - const WacomDeviceState *ds) + const WacomDeviceState *ds, + unsigned int channel) { int type = ds->device_type; int is_button = !!(ds->buttons); @@ -3146,18 +3385,24 @@ int wheel = ds->abswheel; WacomDevicePtr priv = (WacomDevicePtr) local->private; WacomCommonPtr common = priv->common; - int rx, ry, rz, rtx, rty, rrot, rth, rw; - int is_core_pointer, is_absolute; + int rx, ry, rz, rtx, rty, rrot, rth, rw, no_jitter; + double param, relacc; + int is_core_pointer, is_absolute, doffsetX=0, doffsetY=0; int aboveBelowSwitch = (priv->twinview == TV_ABOVE_BELOW) ? ((y < priv->topY) ? -1 : ((priv->bottomY < y) ? 1 : 0)) : 0; int leftRightSwitch = (priv->twinview == TV_LEFT_RIGHT) ? ((x < priv->topX) ? -1 : ((priv->bottomX < x) ? 1 : 0)) : 0; + /* use tx and ty to report stripx and stripy */ + if (type == PAD_ID) { + tx = ds->stripx; + ty = ds->stripy; + } + DBG(7, ErrorF("[%s] prox=%s\tx=%d\ty=%d\tz=%d\tbutton=%s\tbuttons=%d\ttx=%d ty=%d\twl=%d rot=%d th=%d\n", - (type == STYLUS_ID) ? "stylus" : (type == CURSOR_ID) ? "cursor" : "eraser", - is_proximity ? "true" : "false", - x, y, z, - is_button ? "true" : "false", buttons, + (type == STYLUS_ID) ? "stylus" : (type == CURSOR_ID) ? "cursor" : + (type == ERASER_ID) ? "eraser" : "pad", is_proximity ? "true" : "false", + x, y, z, is_button ? "true" : "false", buttons, tx, ty, wheel, rot, throttle)); is_absolute = (priv->flags & ABSOLUTE_FLAG); @@ -3168,25 +3413,25 @@ switch ( leftRightSwitch ) { case -1: - priv->doffsetX = 0; + doffsetX = 0; break; case 1: - priv->doffsetX = priv->bottomX - priv->topX; + doffsetX = priv->bottomX - priv->topX - 2*priv->tvoffsetX; break; } switch ( aboveBelowSwitch ) { case -1: - priv->doffsetY = 0; + doffsetY = 0; break; case 1: - priv->doffsetY = priv->bottomY - priv->topY; + doffsetY = priv->bottomY - priv->topY - 2*priv->tvoffsetY; break; } } - x += priv->doffsetX; - y += priv->doffsetY; + x += doffsetX; + y += doffsetY; /* sets rx and ry according to the mode */ if (is_absolute) { @@ -3220,27 +3465,32 @@ rx = 0; ry = 0; } - if (priv->speed != DEFAULT_SPEED ) { - /* don't apply acceleration for fairly small - * increments (but larger than speed setting). - */ - int no_jitter = priv->speed * 3; - double param = priv->speed; - double relacc = (MAX_ACCEL-priv->accel)*(MAX_ACCEL-priv->accel); - if (ABS(rx) > no_jitter) - { + /* don't apply acceleration for fairly small + * increments (but larger than speed setting). + */ + no_jitter = priv->speed * 3; + relacc = (MAX_ACCEL-priv->accel)*(MAX_ACCEL-priv->accel); + if (ABS(rx) > no_jitter) { + param = priv->speed; + + /* apply acceleration only when priv->speed > DEFAULT_SPEED */ + if (priv->speed > DEFAULT_SPEED ) { + param += priv->accel > 0 ? abs(rx)/relacc : 0; /* don't apply acceleration when too fast. */ - param += priv->accel > 0 ? rx/relacc : 0; - if (param > 20.00) - rx *= param; + if (param < 20.00) rx *= param; } - if (ABS(ry) > no_jitter) - { - param += priv->accel > 0 ? ry/relacc : 0; - if (param > 20.00) - ry *= param; + } + if (ABS(ry) > no_jitter) { + param = priv->speed; + + /* apply acceleration only when priv->speed > DEFAULT_SPEED */ + if (priv->speed > DEFAULT_SPEED ) { + param += priv->accel > 0 ? abs(ry)/relacc : 0; + /* don't apply acceleration when too fast. */ + if (param < 20.00) ry *= param; } } + rz = z - priv->oldZ; rtx = tx - priv->oldTiltX; rty = ty - priv->oldTiltY; @@ -3251,7 +3501,8 @@ /* for multiple monitor support, we need to set the proper * screen and modify the axes before posting events */ - xf86WcmSetScreen(local, &rx, &ry); + if( !(priv->flags & BUTTONS_ONLY_FLAG) || !channel ) + xf86WcmSetScreen(local, &rx, &ry); /* coordinates are ready we can send events */ if (is_proximity) { @@ -3263,7 +3514,7 @@ xf86PostProximityEvent(local->dev, 1, 0, 6, rx, ry, rz, rtx, rty, rw); } - if(!(priv->flags & BUTTONS_ONLY_FLAG)) { + if(!(priv->flags & BUTTONS_ONLY_FLAG) || !channel) { if (IsCursor(priv)) xf86PostMotionEvent(local->dev, is_absolute, 0, 6, rx, ry, rz, rrot, rth, rw); else @@ -3339,6 +3590,8 @@ priv->oldZ = z; priv->oldTiltX = tx; priv->oldTiltY = ty; + priv->oldStripX = ds->stripx; + priv->oldStripY = ds->stripy; priv->oldRot = rot; priv->oldThrottle = throttle; } @@ -3361,10 +3614,14 @@ if (ds1->proximity != ds2->proximity) return 0; if (ABS(ds1->x - ds2->x) > suppress) return 0; if (ABS(ds1->y - ds2->y) > suppress) return 0; + if (ABS(ds1->tiltx - ds2->tiltx) > suppress) return 0; + if (ABS(ds1->tilty - ds2->tilty) > suppress) return 0; + if (ABS(ds1->stripx - ds2->stripx) > suppress) return 0; + if (ABS(ds1->stripy - ds2->stripy) > suppress) return 0; if (ABS(ds1->pressure - ds2->pressure) > suppress) return 0; if (ABS(ds1->throttle - ds2->throttle) > suppress) return 0; - if ((1800 + ds1->rotation - ds2->rotation) % 1800 > suppress && - (1800 + ds2->rotation - ds1->rotation) % 1800 > suppress) return 0; + if (ABS(ds1->rotation - ds2->rotation) > suppress || + (1800 - ABS(ds2->rotation - ds1->rotation)) > suppress) return 0; if (ABS(ds1->abswheel - ds2->abswheel) > suppress || (ds2->relwheel) != 0) return 0; return 1; @@ -3637,7 +3894,7 @@ } static void commonDispatchDevice(WacomCommonPtr common, - const WacomChannelPtr pChannel) + int channel, const WacomChannelPtr pChannel) { int id, idx; WacomDevicePtr priv; @@ -3648,6 +3905,20 @@ DBG(10, ErrorF("commonDispatchEvents\n")); + if (!ds->device_type) { + /* defaults to cursor if tool is on the tablet when X starts */ + ds->device_type = CURSOR_ID; + ds->proximity = 1; + if (ds->serial_num) + for (idx=0; idxwcmNumDevices; idx++) { + priv = common->wcmDevices[idx]->private; + if (ds->serial_num == priv->serial) { + ds->device_type = DEVICE_ID(priv->flags); + break; + } + } + } + /* Find the device the current events are meant for */ for (idx=0; idxwcmNumDevices; idx++) { @@ -3680,7 +3951,7 @@ if (pLastDev && (pLastDev != pDev) && (pLast->serial_num == ds->serial_num)) { pLast->proximity = 0; - xf86WcmSendEvents(pLastDev, pLast); + xf86WcmSendEvents(pLastDev, pLast, channel); } /* if a device matched criteria, handle filtering per device @@ -3709,7 +3980,7 @@ int sampleTime, ticks; /* get the sample time */ - sampleTime = GetTimeInMillis(); + sampleTime = (int)GetTimeInMillis(); ticks = ThrottleToRate(ds->throttle); @@ -3746,13 +4017,13 @@ * This only applies to USB protocol V tablets * which aimed at improving relative movement support. */ - if (ds->distance > 112 && !(priv->flags & ABSOLUTE_FLAG)) + if (filtered.distance > 112 && !(priv->flags & ABSOLUTE_FLAG) && !channel) { ds->proximity = 0; filtered.proximity = 0; } - xf86WcmSendEvents(pDev, &filtered); + xf86WcmSendEvents(pDev, &filtered, channel); } /* otherwise, if no device matched... */ @@ -3778,6 +4049,13 @@ WacomDeviceState ds; WacomChannelPtr pChannel; + /* tool on the tablet when driver starts */ + if (!miPointerCurrentScreen()) { + DBG(6, ErrorF("xf86WcmEvent: Wacom driver can not get Current Screen ID\n")); + DBG(6, ErrorF("Please remove Wacom tool from the tablet.\n")); + return; + } + /* sanity check the channel */ if (channel >= MAX_CHANNELS) return; @@ -3790,7 +4068,7 @@ ds = *pState; /* timestamp the state for velocity and acceleration analysis */ - ds.sample = GetTimeInMillis(); + ds.sample = (int)GetTimeInMillis(); DBG(10, ErrorF("xf86WcmEvent: c=%d i=%d t=%d s=0x%X x=%d y=%d b=0x%X " "p=%d rz=%d tx=%d ty=%d aw=%d rw=%d t=%d df=%d px=%d st=%d\n", @@ -3803,6 +4081,15 @@ ds.tilty, ds.abswheel, ds.relwheel, ds.throttle, ds.discard_first, ds.proximity, ds.sample)); + /* Discard the first 2 USB packages due to events delay */ + if ( (pChannel->nSamples < 2) && (common->wcmDevCls == &gWacomUSBDevice) ) { + /* store channel device state for later use */ + memmove(pChannel->valid.states + 1, pChannel->valid.states, + sizeof(WacomDeviceState) * (MAX_SAMPLES - 1)); + ++pChannel->nSamples; + return; /* discard */ + } + /* Filter raw data, fix hardware defects, perform error correction */ if (RAW_FILTERING(common) && common->wcmModel->FilterRaw) { @@ -3815,7 +4102,7 @@ } /* Discard unwanted data */ - if (xf86WcmSuppress(common->wcmSuppress, pLast, &ds)) + if (xf86WcmSuppress(common->wcmSuppress, pLast, &ds) && pChannel->rawFilter.npoints == 4) { DBG(10, ErrorF("Suppressing data according to filter\n")); @@ -3845,9 +4132,9 @@ memmove(pChannel->valid.states + 1, pChannel->valid.states, sizeof(WacomDeviceState) * (MAX_SAMPLES - 1)); pChannel->valid.state = ds; /*save last raw sample */ - if (pChannel->nSamples < 4) ++pChannel->nSamples; + if (pChannel->rawFilter.npoints < 4) ++pChannel->nSamples; - commonDispatchDevice(common,pChannel); + commonDispatchDevice(common,channel,pChannel); resetSampleCounter(pChannel); } @@ -3938,8 +4225,9 @@ WacomDevicePtr priv = (WacomDevicePtr)PRIVATE(pWcm); WacomCommonPtr common = priv->common; double screenRatio, tabletRatio; - int totalWidth = 0, maxHeight = 0; - + int totalWidth = 0, maxHeight = 0, tabletSize = 0; + char m1[32], m2[32]; + if (local->fd < 0) { if (!xf86WcmInitDevice(local) || (local->fd < 0)) { @@ -3950,23 +4238,10 @@ if (priv->factorX == 0.0) { - if (priv->twinview != TV_NONE && priv->bottomX == 0 && - priv->bottomY == 0 && priv->topX == 0 && priv->topY == 0) + if (priv->twinview != TV_NONE && priv->screen_no == -1) { - if (IsCursor(priv)) - { - /* for absolute cursor */ - priv->topX = 80; - priv->topY = 80; - } - else - { - /* for absolute stylus and eraser */ - priv->topX = 50; - priv->topY = 50; - } - priv->bottomX = common->wcmMaxX - priv->topX; - priv->bottomY = common->wcmMaxY - priv->topY; + priv->tvoffsetX = 60; + priv->tvoffsetY = 60; } if (priv->bottomX == 0) priv->bottomX = common->wcmMaxX; @@ -4067,36 +4342,52 @@ } /* x and y axes */ - InitValuatorAxisStruct(pWcm, 0, 0, - ((priv->bottomX - priv->topX) * priv->dscaleX), /* max val */ + if (priv->twinview == TV_LEFT_RIGHT) + tabletSize = 2*(priv->bottomX - priv->topX - 2*priv->tvoffsetX); + else + tabletSize = priv->bottomX - priv->topX; + + InitValuatorAxisStruct(pWcm, 0, 0, tabletSize, /* max val */ mils(common->wcmResolX), /* tablet resolution */ 0, mils(common->wcmResolX)); /* max_res */ - InitValuatorAxisStruct(pWcm, 1, 0, - ((priv->bottomY - priv->topY) * priv->dscaleY), /* max val */ + if (priv->twinview == TV_ABOVE_BELOW) + tabletSize = 2*(priv->bottomY - priv->topY - 2*priv->tvoffsetY); + else + tabletSize = priv->bottomY - priv->topY; + + InitValuatorAxisStruct(pWcm, 1, 0, tabletSize, /* max val */ mils(common->wcmResolY), /* tablet resolution */ 0, mils(common->wcmResolY)); /* max_res */ /* pressure */ InitValuatorAxisStruct(pWcm, 2, 0, common->wcmMaxZ, 1, 1, 1); - if (IsCursor(priv)) - { + if (IsCursor(priv)) { /* z-rot and throttle */ InitValuatorAxisStruct(pWcm, 3, -900, 899, 1, 1, 1); InitValuatorAxisStruct(pWcm, 4, -1023, 1023, 1, 1, 1); } - else - { + else if (IsPad(priv)) { + /* strip-x and strip-y */ + InitValuatorAxisStruct(pWcm, 3, 0, 4097, 1, 1, 1); + InitValuatorAxisStruct(pWcm, 4, 0, 4097, 1, 1, 1); + } + else { /* tilt-x and tilt-y */ InitValuatorAxisStruct(pWcm, 3, -64, 63, 1, 1, 1); InitValuatorAxisStruct(pWcm, 4, -64, 63, 1, 1, 1); } - /* wheel */ - InitValuatorAxisStruct(pWcm, 5, 0, 1023, 1, 1, 1); - - return (local->fd != -1); + sscanf((char*)(common->wcmModel)->name, "%s %s", m1, m2); + if (strstr(m2, "Intuos3") && IsStylus(priv)) + /* Intuos3 Marker Pen rotation */ + InitValuatorAxisStruct(pWcm, 5, -900, 899, 1, 1, 1); + else + /* absulate wheel */ + InitValuatorAxisStruct(pWcm, 5, 0, 1023, 1, 1, 1); + + return TRUE; } /* @@ -4260,40 +4551,45 @@ priv->bottomY = xf86SetIntOption(local->options, "BottomY", 0); break; case XWACOM_PARAM_BUTTON1: - if ((value < 0) || (value > 18)) return BadValue; + if ((value < 0) || (value > 19)) return BadValue; xf86ReplaceIntOption(local->options,"Button1",value); priv->button[0] = xf86SetIntOption(local->options,"Button1",1); break; case XWACOM_PARAM_BUTTON2: - if ((value < 0) || (value > 18)) return BadValue; + if ((value < 0) || (value > 19)) return BadValue; xf86ReplaceIntOption(local->options, "Button2", value); priv->button[1] = xf86SetIntOption(local->options,"Button2",2); break; case XWACOM_PARAM_BUTTON3: - if ((value < 0) || (value > 18)) return BadValue; + if ((value < 0) || (value > 19)) return BadValue; xf86ReplaceIntOption(local->options, "Button3", value); priv->button[2] = xf86SetIntOption(local->options,"Button3",3); break; case XWACOM_PARAM_BUTTON4: - if ((value < 0) || (value > 18)) return BadValue; + if ((value < 0) || (value > 19)) return BadValue; xf86ReplaceIntOption(local->options, "Button4", value); priv->button[3] = xf86SetIntOption(local->options,"Button4",4); break; case XWACOM_PARAM_BUTTON5: - if ((value < 0) || (value > 18)) return BadValue; + if ((value < 0) || (value > 19)) return BadValue; xf86ReplaceIntOption(local->options, "Button5", value); priv->button[4] = xf86SetIntOption(local->options,"Button5",5); break; case XWACOM_PARAM_DEBUGLEVEL: - if ((value < 0) || (value > 100)) return BadValue; + if ((value < 1) || (value > 100)) return BadValue; xf86ReplaceIntOption(local->options, "DebugLevel", value); gWacomModule.debugLevel = value; break; case XWACOM_PARAM_RAWFILTER: if ((value < 0) || (value > 1)) return BadValue; - xf86ReplaceIntOption(local->options, "RawFilter", value); - if (value) priv->common->wcmFlags |= RAW_FILTERING_FLAG; - else priv->common->wcmFlags &= ~(RAW_FILTERING_FLAG); + if (value) { + priv->common->wcmFlags |= RAW_FILTERING_FLAG; + xf86ReplaceStrOption(local->options, "RawFilter", "On"); + } + else { + priv->common->wcmFlags &= ~(RAW_FILTERING_FLAG); + xf86ReplaceStrOption(local->options, "RawFilter", "Off"); + } break; case XWACOM_PARAM_PRESSCURVE: { char chBuf[64]; @@ -4303,7 +4599,7 @@ int y1 = value & 0xFF; if ((x0 > 100) || (y0 > 100) || (x1 > 100) || (y1 > 100)) return BadValue; - snprintf(chBuf,sizeof(chBuf),"%d %d %d %d",x0,y0,x1,y1); + snprintf(chBuf,sizeof(chBuf),"%d,%d,%d,%d",x0,y0,x1,y1); xf86ReplaceStrOption(local->options, "PressCurve",chBuf); xf86WcmSetPressureCurve(priv,x0,y0,x1,y1); break; @@ -4319,19 +4615,19 @@ } break; case XWACOM_PARAM_SPEEDLEVEL: - if ((value < 0) || (value > 10)) return BadValue; - if (value > 5) priv->speed = 2.00*((double)value - 5.00); - else priv->speed = ((double)value + 1.00) / 6.00; + if ((value < 1) || (value > 11)) return BadValue; + if (value > 6) priv->speed = 2.00*((double)value - 6.00); + else priv->speed = ((double)value) / 6.00; sprintf(st, "%.3f", priv->speed); xf86AddNewOption(local->options, "Speed", st); break; case XWACOM_PARAM_ACCEL: - if ((value < 0) || (value > MAX_ACCEL-1)) return BadValue; - priv->accel = value; + if ((value < 1) || (value > MAX_ACCEL)) return BadValue; + priv->accel = value-1; xf86ReplaceIntOption(local->options, "Accel", priv->accel); break; case XWACOM_PARAM_CLICKFORCE: - if ((value < 0) || (value > 20)) return BadValue; + if ((value < 1) || (value > 21)) return BadValue; priv->common->wcmThreshold = (int)((double)(value*priv->common->wcmMaxZ)/100.00+0.5); xf86ReplaceIntOption(local->options, "Threshold", @@ -4353,7 +4649,21 @@ break; case XWACOM_PARAM_GIMP: if ((value != 0) && (value != 1)) return BadValue; - priv->common->wcmGimp = value; + priv->common->wcmMMonitor = value; + break; + case XWACOM_PARAM_MMT: + if ((value != 0) && (value != 1)) return BadValue; + priv->common->wcmMMonitor = value; + break; + case XWACOM_PARAM_TPCBUTTON: + if ((value != 0) && (value != 1)) return BadValue; + priv->common->wcmTPCButton = value; + if (value) { + xf86ReplaceStrOption(local->options, "TPCButton", "on"); + } + else { + xf86ReplaceStrOption(local->options, "TPCButton", "off"); + } break; default: DBG(10, ErrorF("xf86WcmSetParam invalid param %d\n",param)); @@ -4372,7 +4682,7 @@ char fileName[80] = "/etc/X11/wcm."; char command[256]; FILE *fp = 0; - int value; + int value,p1,p2,p3,p4; double speed; char *s; @@ -4417,8 +4727,12 @@ fprintf(fp, "xsetwacom set %s Button5 %s\n", local->name, s); s = xf86FindOptionValue(local->options, "PressCurve"); - if ( s && !IsCursor(priv) ) - fprintf(fp, "xsetwacom set %s PressCurve %s\n", local->name, s); + if ( s && !IsCursor(priv) ) { + sscanf(s, "%d,%d,%d,%d", &p1, &p2, &p3, &p4); + if ( p1 || p2 || p3 != 100 || p4 != 100 ) + fprintf(fp, "xsetwacom set %s PressCurve %d %d %d %d\n", + local->name, p1, p2, p3, p4); + } s = xf86FindOptionValue(local->options, "Mode"); if ( s && (((priv->flags & ABSOLUTE_FLAG) && IsCursor(priv)) @@ -4431,21 +4745,18 @@ s = xf86FindOptionValue(local->options, "Accel"); if ( s && priv->accel ) - fprintf(fp, "xsetwacom set %s Accel %s\n", local->name, s); - - s = xf86FindOptionValue(local->options, "Suppress"); - if ( s ) - fprintf(fp, "xsetwacom set %s Suppress %s\n", local->name, s); + fprintf(fp, "xsetwacom set %s Accel %d\n", local->name, priv->accel+1); s = xf86FindOptionValue(local->options, "Speed"); if ( s && priv->speed != DEFAULT_SPEED ) { speed = strtod(s, NULL); - if(speed > 10.00) value = 10; - else if(speed >= 1.00) value = (int)(speed/2.00 + 5.00); - else if(speed < (double)(1.00/6.00)) value = 0; - else value = (int)(speed*6.00 - 0.50); - fprintf(fp, "xsetwacom set %s SpeedLevel %d\n", local->name, value); + if(speed >= 10.00) value = 11; + else if(speed >= 1.00) value = (int)(speed/2.00 + 6.00); + else if(speed < (double)(1.00/6.00)) value = 1; + else value = (int)(speed*6.00 + 0.50); + if ( value != 6 ) + fprintf(fp, "xsetwacom set %s SpeedLevel %d\n", local->name, value); } s = xf86FindOptionValue(local->options, "Threshold"); @@ -4453,19 +4764,32 @@ { value = atoi(s); value = (int)((double)value*100.00/(double)priv->common->wcmMaxZ+0.5); - fprintf(fp, "xsetwacom set %s ClickForce %d\n", local->name, value); + if ( value != 6 ) + fprintf(fp, "xsetwacom set %s ClickForce %d\n", local->name, value); + } + + s = xf86FindOptionValue(local->options, "ForceDevice"); + if ( s ) { + if ( !priv->common->wcmTPCButton ) + fprintf(fp, "xsetwacom set %s TPCButton off\n", local->name); + fprintf(fp, "default TPCButton on\n"); + } + else { + if ( priv->common->wcmTPCButton ) + fprintf(fp, "xsetwacom set %s TPCButton on\n", local->name); + fprintf(fp, "default TPCButton off\n"); } fprintf(fp, "%s", "default TopX 0\n"); fprintf(fp, "%s", "default TopY 0\n"); fprintf(fp, "default BottomX %d\n", priv->common->wcmMaxX); fprintf(fp, "default BottomY %d\n", priv->common->wcmMaxY); - if (IsCursor(priv)) + if (IsCursor(priv) || IsPad(priv)) sprintf(command, "default Mode Relative\n"); else sprintf(command, "default Mode Absolute\n"); fprintf(fp, "%s", command); - fprintf(fp, "%s", "default SpeedLevel 5\n"); + fprintf(fp, "%s", "default SpeedLevel 6\n"); fprintf(fp, "%s", "default ClickForce 6\n"); fprintf(fp, "%s", "default Accel 0\n"); fclose(fp); @@ -4494,9 +4818,10 @@ lprv = (WacomDevicePtr)localDevices->private; else lprv = NULL; - if (lprv && lprv->common) { + if (lprv && lprv->common && lprv->common->wcmModel) { sscanf((char*)(lprv->common->wcmModel)->name, "%s %s", m1, m2); - fprintf(fp, "%s %s %s\n", localDevices->name, m2, m3); + if ( lprv->common->wcmEraserID ) + fprintf(fp, "%s %s %s %s\n", localDevices->name, m2, m3, lprv->common->wcmEraserID); if (lprv->twinview != TV_NONE) { priv = lprv; } @@ -4680,11 +5005,9 @@ priv->button[i] = i+1; /* button i value */ priv->numScreen = screenInfo.numScreens; /* number of configureed screens */ priv->currentScreen = 0; /* current screen in display */ - priv->dscaleX = 1.0; /* dual screen scale X factor */ - priv->dscaleY = 1.0; /* dual screen scale Y factor */ - priv->doffsetX = 0; /* dual screen offset X */ - priv->doffsetY = 0; /* dual screen offset Y */ priv->twinview = TV_NONE; /* not using twinview gfx */ + priv->tvoffsetX = 0; /* none X edge offset for TwinView setup */ + priv->tvoffsetY = 0; /* none Y edge offset for TwinView setup */ for (i=0; i<4; i++) priv->tvResolution[i] = 0; /* unconfigured twinview resolution */ priv->throttleValue = 0; @@ -4710,7 +5033,12 @@ common->wcmLinkSpeed = 9600; /* serial link speed */ common->wcmDevCls = &gWacomSerialDevice; /* device-specific functions */ common->wcmModel = NULL; /* model-specific functions */ - common->wcmGimp = 1; /* enabled (=1) to support Gimp when Xinerama Enabled in multi-monitor desktop. Needs to be disabled (=0) for Cintiq calibration */ + common->wcmEraserID = 0; /* eraser id associated with the stylus */ + common->wcmGimp = 1; /* enabled (=1) to support Gimp when Xinerama Enabled in multi-monitor desktop. Needs to be disabled (=0) for Cintiq and ISDV4 calibration */ + common->wcmMMonitor = 1; /* enabled (=1) to support multi-monitor desktop. */ + /* disabled (=0) when user doesn't want to move the */ + /* cursor from one screen to another screen */ + common->wcmTPCButton = 0; /* set Tablet PC button on/off, default is off */ return local; } @@ -4765,6 +5093,17 @@ return local; } +/* xf86WcmAllocatePad */ + +LocalDevicePtr xf86WcmAllocatePad(void) +{ + LocalDevicePtr local = xf86WcmAllocate(XI_ERASER, ABSOLUTE_FLAG|PAD_ID); + + if (local) local->type_name = "Wacom Pad"; + + return local; +} + /* * xf86WcmUninit -- * @@ -4798,11 +5137,20 @@ WacomDevicePtr privMatch = (WacomDevicePtr)pMatch->private; WacomDevicePtr priv = (WacomDevicePtr)pLocal->private; WacomCommonPtr common = priv->common; + char *type; if ((pLocal != pMatch) && (pMatch->device_control == gWacomModule.DevProc) && !strcmp(privMatch->common->wcmDevice, common->wcmDevice)) { DBG(2, ErrorF("xf86WcmInit wacom port share between" " %s and %s\n", pLocal->name, pMatch->name)); + type = xf86FindOptionValue(pMatch->options, "Type"); + if ( type && (strstr(type, "eraser")) ) + privMatch->common->wcmEraserID=pMatch->name; + else { + type = xf86FindOptionValue(pLocal->options, "Type"); + if ( type && (strstr(type, "eraser")) ) + privMatch->common->wcmEraserID=pLocal->name; + } xfree(common->wcmDevices); xfree(common); common = priv->common = privMatch->common; @@ -4859,7 +5207,9 @@ else if (s && (xf86NameCmp(s, "eraser") == 0)) { local = xf86WcmAllocateEraser(); } - else { + else if (s && (xf86NameCmp(s, "pad") == 0)) + local = xf86WcmAllocatePad(); + else { xf86Msg(X_ERROR, "%s: No type or invalid type specified.\n" "Must be one of stylus, cursor or eraser\n", dev->identifier); @@ -4934,6 +5284,9 @@ else priv->flags |= ABSOLUTE_FLAG; } + /* pad always in relative mode since it doesn't move the cursor */ + if (IsPad(priv)) priv->flags &= ~ABSOLUTE_FLAG; + xf86Msg(X_CONFIG, "%s is in %s mode\n", local->name, (priv->flags & ABSOLUTE_FLAG) ? "absolute" : "relative"); @@ -5102,6 +5455,13 @@ xf86Msg(X_CONFIG, "%s: buttons only\n", dev->identifier); } + /* Tablet PC button applied to the whole tablet. Not just one tool */ + if ( !common->wcmTPCButton ) { + common->wcmTPCButton = xf86SetBoolOption(local->options, "TPCButton", 0); + if ( common->wcmTPCButton ) + xf86Msg(X_CONFIG, "%s: Tablet PC buttons on \n", common->wcmDevice); + } + for (i=0; i<16; i++) { sprintf(b, "Button%d", i+1); @@ -5149,16 +5509,8 @@ if (s) xf86Msg(X_CONFIG, "%s: Twinview = %s\n", dev->identifier, s); if (s && xf86NameCmp(s, "none") == 0) { priv->twinview = TV_NONE; - priv->dscaleX = 1.0; - priv->dscaleY = 1.0; - priv->doffsetX = 0; - priv->doffsetY = 0; } else if (s && xf86NameCmp(s, "horizontal") == 0) { priv->twinview = TV_LEFT_RIGHT; - priv->dscaleX = 2.0; - priv->dscaleY = 1.0; - priv->doffsetX = 0; - priv->doffsetY = 0; /* default resolution */ if(!priv->tvResolution[0]) { priv->tvResolution[0] = screenInfo.screens[0]->width/2; @@ -5168,10 +5520,6 @@ } } else if (s && xf86NameCmp(s, "vertical") == 0) { priv->twinview = TV_ABOVE_BELOW; - priv->dscaleX = 1.0; - priv->dscaleY = 2.0; - priv->doffsetX = 0; - priv->doffsetY = 0; /* default resolution */ if(!priv->tvResolution[0]) { priv->tvResolution[0] = screenInfo.screens[0]->width; @@ -5183,10 +5531,6 @@ xf86Msg(X_ERROR, "%s: invalid Twinview (should be none, vertical or horizontal). Using none.\n", dev->identifier); priv->twinview = TV_NONE; - priv->dscaleX = 1.0; - priv->dscaleY = 1.0; - priv->doffsetX = 0; - priv->doffsetY = 0; } /* mark the device configured */