mipointer.c revision 6747b715
1/* 2 3Copyright 1989, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24*/ 25 26#ifdef HAVE_DIX_CONFIG_H 27#include <dix-config.h> 28#endif 29 30# include <X11/X.h> 31# include <X11/Xmd.h> 32# include <X11/Xproto.h> 33# include "misc.h" 34# include "windowstr.h" 35# include "pixmapstr.h" 36# include "mi.h" 37# include "scrnintstr.h" 38# include "mipointrst.h" 39# include "cursorstr.h" 40# include "dixstruct.h" 41# include "inputstr.h" 42 43DevPrivateKeyRec miPointerScreenKeyRec; 44 45#define GetScreenPrivate(s) ((miPointerScreenPtr) \ 46 dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) 47#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) 48 49DevPrivateKeyRec miPointerPrivKeyRec; 50 51#define MIPOINTER(dev) \ 52 ((!IsMaster(dev) && !dev->u.master) ? \ 53 (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ 54 (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) 55 56static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 57 CursorPtr pCursor); 58static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 59 CursorPtr pCursor); 60static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 61 CursorPtr pCursor); 62static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 63 BoxPtr pBox); 64static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, 65 CursorPtr pCursor, BoxPtr pHotBox, 66 BoxPtr pTopLeftBox); 67static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, 68 int x, int y, 69 Bool generateEvent); 70static Bool miPointerCloseScreen(int index, ScreenPtr pScreen); 71static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, 72 int x, int y); 73static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); 74static void miPointerDeviceCleanup(DeviceIntPtr pDev, 75 ScreenPtr pScreen); 76static void miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); 77 78static EventList* events; /* for WarpPointer MotionNotifies */ 79 80Bool 81miPointerInitialize (ScreenPtr pScreen, 82 miPointerSpriteFuncPtr spriteFuncs, 83 miPointerScreenFuncPtr screenFuncs, 84 Bool waitForUpdate) 85{ 86 miPointerScreenPtr pScreenPriv; 87 88 if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0)) 89 return FALSE; 90 91 if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0)) 92 return FALSE; 93 94 pScreenPriv = malloc(sizeof (miPointerScreenRec)); 95 if (!pScreenPriv) 96 return FALSE; 97 pScreenPriv->spriteFuncs = spriteFuncs; 98 pScreenPriv->screenFuncs = screenFuncs; 99 /* 100 * check for uninitialized methods 101 */ 102 if (!screenFuncs->EnqueueEvent) 103 screenFuncs->EnqueueEvent = mieqEnqueue; 104 if (!screenFuncs->NewEventScreen) 105 screenFuncs->NewEventScreen = mieqSwitchScreen; 106 pScreenPriv->waitForUpdate = waitForUpdate; 107 pScreenPriv->showTransparent = FALSE; 108 pScreenPriv->CloseScreen = pScreen->CloseScreen; 109 pScreen->CloseScreen = miPointerCloseScreen; 110 dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); 111 /* 112 * set up screen cursor method table 113 */ 114 pScreen->ConstrainCursor = miPointerConstrainCursor; 115 pScreen->CursorLimits = miPointerCursorLimits; 116 pScreen->DisplayCursor = miPointerDisplayCursor; 117 pScreen->RealizeCursor = miPointerRealizeCursor; 118 pScreen->UnrealizeCursor = miPointerUnrealizeCursor; 119 pScreen->SetCursorPosition = miPointerSetCursorPosition; 120 pScreen->RecolorCursor = miRecolorCursor; 121 pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; 122 pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; 123 124 events = NULL; 125 return TRUE; 126} 127 128static Bool 129miPointerCloseScreen (int index, ScreenPtr pScreen) 130{ 131#if 0 132 miPointerPtr pPointer; 133 DeviceIntPtr pDev; 134#endif 135 136 SetupScreen(pScreen); 137 138#if 0 139 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) 140 { 141 if (DevHasCursor(pDev)) 142 { 143 pPointer = MIPOINTER(pDev); 144 145 if (pScreen == pPointer->pScreen) 146 pPointer->pScreen = 0; 147 if (pScreen == pPointer->pSpriteScreen) 148 pPointer->pSpriteScreen = 0; 149 } 150 } 151 152 if (MIPOINTER(inputInfo.pointer)->pScreen == pScreen) 153 MIPOINTER(inputInfo.pointer)->pScreen = 0; 154 if (MIPOINTER(inputInfo.pointer)->pSpriteScreen == pScreen) 155 MIPOINTER(inputInfo.pointer)->pSpriteScreen = 0; 156#endif 157 158 pScreen->CloseScreen = pScreenPriv->CloseScreen; 159 free((pointer) pScreenPriv); 160 FreeEventList(events, GetMaximumEventsNum()); 161 events = NULL; 162 return (*pScreen->CloseScreen) (index, pScreen); 163} 164 165/* 166 * DIX/DDX interface routines 167 */ 168 169static Bool 170miPointerRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 171{ 172 SetupScreen(pScreen); 173 return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); 174} 175 176static Bool 177miPointerUnrealizeCursor (DeviceIntPtr pDev, 178 ScreenPtr pScreen, 179 CursorPtr pCursor) 180{ 181 SetupScreen(pScreen); 182 return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, pCursor); 183} 184 185static Bool 186miPointerDisplayCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 187{ 188 miPointerPtr pPointer; 189 190 /* return for keyboards */ 191 if ((IsMaster(pDev) && !DevHasCursor(pDev)) || 192 (!IsMaster(pDev) && pDev->u.master && !DevHasCursor(pDev->u.master))) 193 return FALSE; 194 195 pPointer = MIPOINTER(pDev); 196 197 pPointer->pCursor = pCursor; 198 pPointer->pScreen = pScreen; 199 miPointerUpdateSprite(pDev); 200 return TRUE; 201} 202 203static void 204miPointerConstrainCursor (DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) 205{ 206 miPointerPtr pPointer; 207 208 pPointer = MIPOINTER(pDev); 209 210 pPointer->limits = *pBox; 211 pPointer->confined = PointerConfinedToScreen(pDev); 212} 213 214/*ARGSUSED*/ 215static void 216miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, 217 BoxPtr pHotBox, BoxPtr pTopLeftBox) 218{ 219 *pTopLeftBox = *pHotBox; 220} 221 222static Bool GenerateEvent; 223 224static Bool 225miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, 226 int x, int y, Bool generateEvent) 227{ 228 SetupScreen (pScreen); 229 230 GenerateEvent = generateEvent; 231 /* device dependent - must pend signal and call miPointerWarpCursor */ 232 (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); 233 if (!generateEvent) 234 miPointerUpdateSprite(pDev); 235 return TRUE; 236} 237 238/* Set up sprite information for the device. 239 This function will be called once for each device after it is initialized 240 in the DIX. 241 */ 242static Bool 243miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) 244{ 245 miPointerPtr pPointer; 246 SetupScreen (pScreen); 247 248 pPointer = malloc(sizeof(miPointerRec)); 249 if (!pPointer) 250 return FALSE; 251 252 pPointer->pScreen = NULL; 253 pPointer->pSpriteScreen = NULL; 254 pPointer->pCursor = NULL; 255 pPointer->pSpriteCursor = NULL; 256 pPointer->limits.x1 = 0; 257 pPointer->limits.x2 = 32767; 258 pPointer->limits.y1 = 0; 259 pPointer->limits.y2 = 32767; 260 pPointer->confined = FALSE; 261 pPointer->x = 0; 262 pPointer->y = 0; 263 264 if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize)(pDev, pScreen))) 265 { 266 free(pPointer); 267 return FALSE; 268 } 269 270 dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); 271 return TRUE; 272} 273 274/* Clean up after device. 275 This function will be called once before the device is freed in the DIX 276 */ 277static void 278miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) 279{ 280 SetupScreen(pScreen); 281 282 if (!IsMaster(pDev) && pDev->u.master) 283 return; 284 285 (*pScreenPriv->spriteFuncs->DeviceCursorCleanup)(pDev, pScreen); 286 free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); 287 dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); 288} 289 290 291/* Once signals are ignored, the WarpCursor function can call this */ 292 293void 294miPointerWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 295{ 296 miPointerPtr pPointer; 297 BOOL changedScreen = FALSE; 298 299 SetupScreen (pScreen); 300 pPointer = MIPOINTER(pDev); 301 302 if (pPointer->pScreen != pScreen) 303 { 304 (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, TRUE); 305 changedScreen = TRUE; 306 } 307 308 if (GenerateEvent) 309 miPointerMove (pDev, pScreen, x, y); 310 else 311 miPointerMoveNoEvent(pDev, pScreen, x, y); 312 313 /* Don't call USFS if we use Xinerama, otherwise the root window is 314 * updated to the second screen, and we never receive any events. 315 * (FDO bug #18668) */ 316 if (changedScreen 317#ifdef PANORAMIX 318 && noPanoramiXExtension 319#endif 320 ) 321 UpdateSpriteForScreen (pDev, pScreen) ; 322} 323 324/* 325 * Pointer/CursorDisplay interface routines 326 */ 327 328/* 329 * miPointerUpdateSprite 330 * 331 * Syncronize the sprite with the cursor - called from ProcessInputEvents 332 */ 333 334void 335miPointerUpdateSprite (DeviceIntPtr pDev) 336{ 337 ScreenPtr pScreen; 338 miPointerScreenPtr pScreenPriv; 339 CursorPtr pCursor; 340 int x, y, devx, devy; 341 miPointerPtr pPointer; 342 343 if (!pDev || !pDev->coreEvents) 344 return; 345 346 pPointer = MIPOINTER(pDev); 347 348 if (!pPointer) 349 return; 350 351 pScreen = pPointer->pScreen; 352 if (!pScreen) 353 return; 354 355 x = pPointer->x; 356 y = pPointer->y; 357 devx = pPointer->devx; 358 devy = pPointer->devy; 359 360 pScreenPriv = GetScreenPrivate (pScreen); 361 /* 362 * if the cursor has switched screens, disable the sprite 363 * on the old screen 364 */ 365 if (pScreen != pPointer->pSpriteScreen) 366 { 367 if (pPointer->pSpriteScreen) 368 { 369 miPointerScreenPtr pOldPriv; 370 371 pOldPriv = GetScreenPrivate (pPointer->pSpriteScreen); 372 if (pPointer->pCursor) 373 { 374 (*pOldPriv->spriteFuncs->SetCursor) 375 (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); 376 } 377 (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, FALSE); 378 } 379 (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); 380 (*pScreenPriv->spriteFuncs->SetCursor) 381 (pDev, pScreen, pPointer->pCursor, x, y); 382 pPointer->devx = x; 383 pPointer->devy = y; 384 pPointer->pSpriteCursor = pPointer->pCursor; 385 pPointer->pSpriteScreen = pScreen; 386 } 387 /* 388 * if the cursor has changed, display the new one 389 */ 390 else if (pPointer->pCursor != pPointer->pSpriteCursor) 391 { 392 pCursor = pPointer->pCursor; 393 if (!pCursor || (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) 394 pCursor = NullCursor; 395 (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); 396 397 pPointer->devx = x; 398 pPointer->devy = y; 399 pPointer->pSpriteCursor = pPointer->pCursor; 400 } 401 else if (x != devx || y != devy) 402 { 403 pPointer->devx = x; 404 pPointer->devy = y; 405 if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) 406 (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); 407 } 408} 409 410void 411miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) 412{ 413 miPointerScreenPtr pScreenPriv; 414 ScreenPtr pScreen; 415 miPointerPtr pPointer; 416 417 pPointer = MIPOINTER(pDev); 418 419 pScreen = screenInfo.screens[screen_no]; 420 pScreenPriv = GetScreenPrivate (pScreen); 421 (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, FALSE); 422 NewCurrentScreen (pDev, pScreen, x, y); 423 424 pPointer->limits.x2 = pScreen->width; 425 pPointer->limits.y2 = pScreen->height; 426} 427 428ScreenPtr 429miPointerCurrentScreen (void) 430{ 431 return miPointerGetScreen(inputInfo.pointer); 432} 433 434ScreenPtr 435miPointerGetScreen(DeviceIntPtr pDev) 436{ 437 miPointerPtr pPointer = MIPOINTER(pDev); 438 return (pPointer) ? pPointer->pScreen : NULL; 439} 440 441/* Controls whether the cursor image should be updated immediately when 442 moved (FALSE) or if something else will be responsible for updating 443 it later (TRUE). Returns current setting. 444 Caller is responsible for calling OsBlockSignal first. 445*/ 446Bool 447miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait) 448{ 449 SetupScreen(pScreen); 450 Bool prevWait = pScreenPriv->waitForUpdate; 451 452 pScreenPriv->waitForUpdate = wait; 453 return prevWait; 454} 455 456 457/* Move the pointer on the current screen, and update the sprite. */ 458static void 459miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, 460 int x, int y) 461{ 462 miPointerPtr pPointer; 463 SetupScreen(pScreen); 464 465 pPointer = MIPOINTER(pDev); 466 467 /* Hack: We mustn't call into ->MoveCursor for anything but the 468 * VCP, as this may cause a non-HW rendered cursor to be rendered during 469 * SIGIO. This again leads to allocs during SIGIO which leads to SIGABRT. 470 */ 471 if ((pDev == inputInfo.pointer || (!IsMaster(pDev) && pDev->u.master == inputInfo.pointer)) 472 && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) 473 { 474 pPointer->devx = x; 475 pPointer->devy = y; 476 if(pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) 477 (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); 478 } 479 480 pPointer->x = x; 481 pPointer->y = y; 482 pPointer->pScreen = pScreen; 483} 484 485void 486miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) 487{ 488 miPointerScreenPtr pScreenPriv; 489 ScreenPtr pScreen; 490 ScreenPtr newScreen; 491 492 miPointerPtr pPointer; 493 494 if (!pDev || !pDev->coreEvents) 495 return; 496 497 pPointer = MIPOINTER(pDev); 498 pScreen = pPointer->pScreen; 499 if (!pScreen) 500 return; /* called before ready */ 501 502 if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) 503 { 504 pScreenPriv = GetScreenPrivate (pScreen); 505 if (!pPointer->confined) 506 { 507 newScreen = pScreen; 508 (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, x, y); 509 if (newScreen != pScreen) 510 { 511 pScreen = newScreen; 512 (*pScreenPriv->screenFuncs->NewEventScreen) (pDev, pScreen, 513 FALSE); 514 pScreenPriv = GetScreenPrivate (pScreen); 515 /* Smash the confine to the new screen */ 516 pPointer->limits.x2 = pScreen->width; 517 pPointer->limits.y2 = pScreen->height; 518 } 519 } 520 } 521 /* Constrain the sprite to the current limits. */ 522 if (*x < pPointer->limits.x1) 523 *x = pPointer->limits.x1; 524 if (*x >= pPointer->limits.x2) 525 *x = pPointer->limits.x2 - 1; 526 if (*y < pPointer->limits.y1) 527 *y = pPointer->limits.y1; 528 if (*y >= pPointer->limits.y2) 529 *y = pPointer->limits.y2 - 1; 530 531 if (pPointer->x == *x && pPointer->y == *y && 532 pPointer->pScreen == pScreen) 533 return; 534 535 miPointerMoveNoEvent(pDev, pScreen, *x, *y); 536} 537 538void 539miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) 540{ 541 *x = MIPOINTER(pDev)->x; 542 *y = MIPOINTER(pDev)->y; 543} 544 545#ifdef XQUARTZ 546#include <pthread.h> 547void darwinEvents_lock(void); 548void darwinEvents_unlock(void); 549#endif 550 551void 552miPointerMove (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 553{ 554 int i, nevents; 555 int valuators[2]; 556 557 miPointerMoveNoEvent(pDev, pScreen, x, y); 558 559 /* generate motion notify */ 560 valuators[0] = x; 561 valuators[1] = y; 562 563 if (!events) 564 { 565 events = InitEventList(GetMaximumEventsNum()); 566 567 if (!events) 568 { 569 FatalError("Could not allocate event store.\n"); 570 return; 571 } 572 } 573 574 nevents = GetPointerEvents(events, pDev, MotionNotify, 0, POINTER_SCREEN | POINTER_ABSOLUTE, 0, 2, valuators); 575 576 OsBlockSignals(); 577#ifdef XQUARTZ 578 darwinEvents_lock(); 579#endif 580 for (i = 0; i < nevents; i++) 581 mieqEnqueue(pDev, (InternalEvent*)events[i].event); 582#ifdef XQUARTZ 583 darwinEvents_unlock(); 584#endif 585 OsReleaseSignals(); 586} 587