1/* $Xorg: sunMouse.c,v 1.3 2000/08/17 19:48:32 cpqbld Exp $ */ 2/*- 3 * Copyright 1987 by the Regents of the University of California 4 * 5 * Permission to use, copy, modify, and distribute this 6 * software and its documentation for any purpose and without 7 * fee is hereby granted, provided that the above copyright 8 * notice appear in all copies. The University of California 9 * makes no representations about the suitability of this 10 * software for any purpose. It is provided "as is" without 11 * express or implied warranty. 12 */ 13 14/************************************************************ 15Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA. 16 17 All Rights Reserved 18 19Permission to use, copy, modify, and distribute this 20software and its documentation for any purpose and without 21fee is hereby granted, provided that the above copyright no- 22tice appear in all copies and that both that copyright no- 23tice and this permission notice appear in supporting docu- 24mentation, and that the names of Sun or The Open Group 25not be used in advertising or publicity pertaining to 26distribution of the software without specific prior 27written permission. Sun and The Open Group make no 28representations about the suitability of this software for 29any purpose. It is provided "as is" without any express or 30implied warranty. 31 32SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 33INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- 34NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- 35ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 36ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 37PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 38OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 39THE USE OR PERFORMANCE OF THIS SOFTWARE. 40 41********************************************************/ 42/* 43 * Copyright 1991, 1992, 1993 Kaleb S. Keithley 44 * 45 * Permission to use, copy, modify, and distribute this 46 * software and its documentation for any purpose and without 47 * fee is hereby granted, provided that the above copyright 48 * notice appear in all copies. Kaleb S. Keithley makes no 49 * representations about the suitability of this software for 50 * any purpose. It is provided "as is" without express or 51 * implied warranty. 52 */ 53/* $XFree86: xc/programs/Xserver/hw/sun/sunMouse.c,v 1.4 2003/11/17 22:20:36 dawes Exp $ */ 54 55#define NEED_EVENTS 56#include "sun.h" 57#include "mi.h" 58#include "cursor.h" 59#include "input.h" 60#include "inpututils.h" 61#include "exevents.h" 62#include "xserver-properties.h" 63 64/* 65 * Data private to any sun pointer device. 66 */ 67typedef struct { 68 int fd; 69 int bmask; /* last known button state */ 70 int oformat; /* saved value of VUIDGFORMAT */ 71 Firm_event evbuf[SUN_MAXEVENTS]; /* Buffer for Firm_events */ 72} sunPtrPrivRec, *sunPtrPrivPtr; 73 74Bool sunActiveZaphod = TRUE; 75DeviceIntPtr sunPointerDevice = NULL; 76 77static void sunMouseEvents(int, int, void *); 78static void sunMouseCtrl(DeviceIntPtr, PtrCtrl *); 79static int sunMouseGetEvents(DeviceIntPtr); 80static void sunMouseEnqueueEvent(DeviceIntPtr, Firm_event *); 81static Bool sunCursorOffScreen(ScreenPtr *, int *, int *); 82static void sunCrossScreen(ScreenPtr, int); 83static void sunWarpCursor(DeviceIntPtr, ScreenPtr, int, int); 84 85miPointerScreenFuncRec sunPointerScreenFuncs = { 86 sunCursorOffScreen, 87 sunCrossScreen, 88 sunWarpCursor, 89}; 90 91static void 92sunMouseEvents(int fd, int ready, void *data) 93{ 94 int i, numEvents; 95 DeviceIntPtr device = (DeviceIntPtr)data; 96 DevicePtr pMouse = &device->public; 97 sunPtrPrivPtr pPriv = pMouse->devicePrivate; 98 99 input_lock(); 100 101 do { 102 numEvents = sunMouseGetEvents(device); 103 for (i = 0; i < numEvents; i++) { 104 sunMouseEnqueueEvent(device, &pPriv->evbuf[i]); 105 } 106 } while (numEvents == SUN_MAXEVENTS); 107 108 input_unlock(); 109} 110 111/*- 112 *----------------------------------------------------------------------- 113 * sunMouseCtrl -- 114 * Alter the control parameters for the mouse. Since acceleration 115 * etc. is done from the PtrCtrl record in the mouse's device record, 116 * there's nothing to do here. 117 * 118 * Results: 119 * None. 120 * 121 * Side Effects: 122 * None. 123 * 124 *----------------------------------------------------------------------- 125 */ 126/*ARGSUSED*/ 127static void 128sunMouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl) 129{ 130} 131 132/*- 133 *----------------------------------------------------------------------- 134 * sunMouseProc -- 135 * Handle the initialization, etc. of a mouse 136 * 137 * Results: 138 * none. 139 * 140 * Side Effects: 141 * 142 * Note: 143 * When using sunwindows, all input comes off a single fd, stored in the 144 * global windowFd. Therefore, only one device should be enabled and 145 * disabled, even though the application still sees both mouse and 146 * keyboard. We have arbitrarily chosen to enable and disable windowFd 147 * in the keyboard routine sunKbdProc rather than in sunMouseProc. 148 * 149 *----------------------------------------------------------------------- 150 */ 151int 152sunMouseProc(DeviceIntPtr device, int what) 153{ 154 DevicePtr pMouse = &device->public; 155 sunPtrPrivPtr pPriv; 156 int format; 157 BYTE map[4]; 158 Atom btn_labels[3] = {0}; 159 Atom axes_labels[2] = { 0, 0 }; 160 161 switch (what) { 162 case DEVICE_INIT: 163 pPriv = malloc(sizeof(*pPriv)); 164 if (pPriv == NULL) { 165 LogMessage(X_ERROR, "Cannot allocate private data for mouse\n"); 166 return !Success; 167 } 168 pPriv->fd = open("/dev/mouse", O_RDWR | O_NONBLOCK, 0); 169 if (pPriv->fd < 0) { 170 LogMessage(X_ERROR, "Cannot open /dev/mouse, error %d\n", 171 errno); 172 free(pPriv); 173 return !Success; 174 } 175 pPriv->bmask = 0; 176 pPriv->oformat = 0; 177 pMouse->devicePrivate = pPriv; 178 pMouse->on = FALSE; 179 180 map[1] = 1; 181 map[2] = 2; 182 map[3] = 3; 183 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 184 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 185 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 186 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 187 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 188 189 InitPointerDeviceStruct(pMouse, map, 3, btn_labels, 190 sunMouseCtrl, GetMotionHistorySize(), 191 2, axes_labels); 192 193 /* X valuator */ 194 InitValuatorAxisStruct(device, 0, axes_labels[0], 195 NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative); 196 device->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; 197 device->last.valuators[0] = device->valuator->axisVal[0]; 198 199 /* Y valuator */ 200 InitValuatorAxisStruct(device, 1, axes_labels[1], 201 NO_AXIS_LIMITS, NO_AXIS_LIMITS, 1, 0, 1, Relative); 202 device->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; 203 device->last.valuators[1] = device->valuator->axisVal[1]; 204 205 break; 206 207 case DEVICE_ON: 208 pPriv = (sunPtrPrivPtr)pMouse->devicePrivate; 209 if (ioctl(pPriv->fd, VUIDGFORMAT, &pPriv->oformat) == -1) { 210 LogMessage(X_ERROR, "sunMouseProc ioctl VUIDGFORMAT\n"); 211 return !Success; 212 } 213 format = VUID_FIRM_EVENT; 214 if (ioctl(pPriv->fd, VUIDSFORMAT, &format) == -1) { 215 LogMessage(X_ERROR, "sunMouseProc ioctl VUIDSFORMAT\n"); 216 return !Success; 217 } 218 219 SetNotifyFd(pPriv->fd, sunMouseEvents, X_NOTIFY_READ, device); 220 221 pPriv->bmask = 0; 222 pMouse->on = TRUE; 223 break; 224 225 case DEVICE_OFF: 226 pPriv = (sunPtrPrivPtr)pMouse->devicePrivate; 227 RemoveNotifyFd(pPriv->fd); 228 if (ioctl(pPriv->fd, VUIDSFORMAT, &pPriv->oformat) == -1) 229 LogMessage(X_ERROR, "sunMouseProc ioctl VUIDSFORMAT\n"); 230 pMouse->on = FALSE; 231 break; 232 233 case DEVICE_CLOSE: 234 pPriv = (sunPtrPrivPtr)pMouse->devicePrivate; 235 close(pPriv->fd); 236 free(pPriv); 237 pMouse->devicePrivate = NULL; 238 break; 239 240 case DEVICE_ABORT: 241 break; 242 } 243 return Success; 244} 245 246/*- 247 *----------------------------------------------------------------------- 248 * sunMouseGetEvents -- 249 * Return the events waiting in the wings for the given mouse. 250 * 251 * Results: 252 * Update Firm_event buffer in DeviceIntPtr if events are received. 253 * Return the number of received Firm_events in the buffer. 254 * 255 * Side Effects: 256 * None. 257 *----------------------------------------------------------------------- 258 */ 259 260static int 261sunMouseGetEvents(DeviceIntPtr device) 262{ 263 DevicePtr pMouse = &device->public; 264 sunPtrPrivPtr pPriv = pMouse->devicePrivate; 265 int nBytes; /* number of bytes of events available. */ 266 int NumEvents = 0; 267 268 nBytes = read(pPriv->fd, pPriv->evbuf, sizeof(pPriv->evbuf)); 269 if (nBytes == -1) { 270 if (errno != EWOULDBLOCK) { 271 LogMessage(X_ERROR, "Unexpected error on reading mouse\n"); 272 FatalError("Could not read from mouse"); 273 } 274 } else { 275 NumEvents = nBytes / sizeof(pPriv->evbuf[0]); 276 } 277 return NumEvents; 278} 279 280 281/*- 282 *----------------------------------------------------------------------- 283 * sunMouseEnqueueEvent -- 284 * Given a Firm_event for a mouse, pass it off the the dix layer 285 * properly converted... 286 * 287 * Results: 288 * None. 289 * 290 * Side Effects: 291 * The cursor may be redrawn...? devPrivate/x/y will be altered. 292 * 293 *----------------------------------------------------------------------- 294 */ 295 296static void 297sunMouseEnqueueEvent(DeviceIntPtr device, Firm_event *fe) 298{ 299 sunPtrPrivPtr pPriv; /* Private data for pointer */ 300 int bmask; /* Temporary button mask */ 301 int x, y; 302 double tmpx, tmpy; 303 int type, buttons, flag; 304 int valuators[2]; 305 ValuatorMask mask; 306 307 pPriv = (sunPtrPrivPtr)device->public.devicePrivate; 308 309 switch (fe->id) { 310 case MS_LEFT: 311 case MS_MIDDLE: 312 case MS_RIGHT: 313 /* 314 * A button changed state. Sometimes we will get two events 315 * for a single state change. Should we get a button event which 316 * reflects the current state of affairs, that event is discarded. 317 * 318 * Mouse buttons start at 1. 319 */ 320 buttons = (fe->id - MS_LEFT) + 1; 321 bmask = 1 << buttons; 322 if (fe->value == VKEY_UP) { 323 if (pPriv->bmask & bmask) { 324 type = ButtonRelease; 325 pPriv->bmask &= ~bmask; 326 } else { 327 return; 328 } 329 } else { 330 if ((pPriv->bmask & bmask) == 0) { 331 type = ButtonPress; 332 pPriv->bmask |= bmask; 333 } else { 334 return; 335 } 336 } 337 flag = POINTER_RELATIVE; 338 valuator_mask_zero(&mask); 339 QueuePointerEvents(device, type, buttons, flag, &mask); 340 break; 341 case LOC_X_DELTA: 342 valuators[0] = fe->value; 343 valuators[1] = 0; 344 valuator_mask_set_range(&mask, 0, 2, valuators); 345 flag = POINTER_RELATIVE | POINTER_ACCELERATE; 346 QueuePointerEvents(device, MotionNotify, 0, flag, &mask); 347 break; 348 case LOC_Y_DELTA: 349 /* 350 * For some reason, motion up generates a positive y delta 351 * and motion down a negative delta, so we must subtract 352 * here instead of add... 353 */ 354 valuators[0] = 0; 355 valuators[1] = -fe->value; 356 valuator_mask_set_range(&mask, 0, 2, valuators); 357 flag = POINTER_RELATIVE | POINTER_ACCELERATE; 358 QueuePointerEvents(device, MotionNotify, 0, flag, &mask); 359 break; 360 case LOC_X_ABSOLUTE: 361 miPointerGetPosition(device, &x, &y); 362 tmpx = fe->value; 363 tmpy = y; 364 miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL); 365 break; 366 case LOC_Y_ABSOLUTE: 367 miPointerGetPosition(device, &x, &y); 368 tmpx = x; 369 tmpy = fe->value; 370 miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL); 371 break; 372 default: 373 FatalError ("sunMouseEnqueueEvent: unrecognized id\n"); 374 break; 375 } 376} 377 378/*ARGSUSED*/ 379static Bool 380sunCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) 381{ 382 int index, ret = FALSE; 383 DeviceIntPtr device = sunPointerDevice; /* XXX */ 384 385 if (device && PointerConfinedToScreen(device)) 386 return TRUE; 387 /* 388 * Active Zaphod implementation: 389 * increment or decrement the current screen 390 * if the x is to the right or the left of 391 * the current screen. 392 */ 393 if (sunActiveZaphod && 394 screenInfo.numScreens > 1 && (*x >= (*pScreen)->width || *x < 0)) { 395 index = (*pScreen)->myNum; 396 if (*x < 0) { 397 index = (index ? index : screenInfo.numScreens) - 1; 398 *pScreen = screenInfo.screens[index]; 399 *x += (*pScreen)->width; 400 } else { 401 *x -= (*pScreen)->width; 402 index = (index + 1) % screenInfo.numScreens; 403 *pScreen = screenInfo.screens[index]; 404 } 405 ret = TRUE; 406 } 407 return ret; 408} 409 410static void 411sunCrossScreen(ScreenPtr pScreen, int entering) 412{ 413 if (sunFbs[pScreen->myNum].EnterLeave) 414 (*sunFbs[pScreen->myNum].EnterLeave) (pScreen, entering ? 0 : 1); 415} 416 417static void 418sunWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 419{ 420 input_lock(); 421 miPointerWarpCursor (pDev, pScreen, x, y); 422 input_unlock(); 423} 424