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