mipointer.c revision eee80088
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/** 27 * @file 28 * This file contains functions to move the pointer on the screen and/or 29 * restrict its movement. These functions are divided into two sets: 30 * Screen-specific functions that are used as function pointers from other 31 * parts of the server (and end up heavily wrapped by e.g. animcur and 32 * xfixes): 33 * miPointerConstrainCursor 34 * miPointerCursorLimits 35 * miPointerDisplayCursor 36 * miPointerRealizeCursor 37 * miPointerUnrealizeCursor 38 * miPointerSetCursorPosition 39 * miRecolorCursor 40 * miPointerDeviceInitialize 41 * miPointerDeviceCleanup 42 * If wrapped, these are the last element in the wrapping chain. They may 43 * call into sprite-specific code through further function pointers though. 44 * 45 * The second type of functions are those that are directly called by the 46 * DIX, DDX and some drivers. 47 */ 48 49#ifdef HAVE_DIX_CONFIG_H 50#include <dix-config.h> 51#endif 52 53#include <X11/X.h> 54#include <X11/Xmd.h> 55#include <X11/Xproto.h> 56#include "misc.h" 57#include "windowstr.h" 58#include "pixmapstr.h" 59#include "mi.h" 60#include "scrnintstr.h" 61#include "mipointrst.h" 62#include "cursorstr.h" 63#include "dixstruct.h" 64#include "inputstr.h" 65#include "inpututils.h" 66#include "eventstr.h" 67 68typedef struct { 69 ScreenPtr pScreen; /* current screen */ 70 ScreenPtr pSpriteScreen; /* screen containing current sprite */ 71 CursorPtr pCursor; /* current cursor */ 72 CursorPtr pSpriteCursor; /* cursor on screen */ 73 BoxRec limits; /* current constraints */ 74 Bool confined; /* pointer can't change screens */ 75 int x, y; /* hot spot location */ 76 int devx, devy; /* sprite position */ 77 Bool generateEvent; /* generate an event during warping? */ 78} miPointerRec, *miPointerPtr; 79 80DevPrivateKeyRec miPointerScreenKeyRec; 81 82#define GetScreenPrivate(s) ((miPointerScreenPtr) \ 83 dixLookupPrivate(&(s)->devPrivates, miPointerScreenKey)) 84#define SetupScreen(s) miPointerScreenPtr pScreenPriv = GetScreenPrivate(s) 85 86DevPrivateKeyRec miPointerPrivKeyRec; 87 88#define MIPOINTER(dev) \ 89 (IsFloating(dev) ? \ 90 (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ 91 (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) 92 93static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 94 CursorPtr pCursor); 95static Bool miPointerUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 96 CursorPtr pCursor); 97static Bool miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 98 CursorPtr pCursor); 99static void miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 100 BoxPtr pBox); 101static void miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, 102 CursorPtr pCursor, BoxPtr pHotBox, 103 BoxPtr pTopLeftBox); 104static Bool miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, 105 int x, int y, Bool generateEvent); 106static Bool miPointerCloseScreen(ScreenPtr pScreen); 107static void miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); 108static Bool miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen); 109static void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen); 110static void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, 111 int y); 112 113static InternalEvent *mipointermove_events; /* for WarpPointer MotionNotifies */ 114 115Bool 116miPointerInitialize(ScreenPtr pScreen, 117 miPointerSpriteFuncPtr spriteFuncs, 118 miPointerScreenFuncPtr screenFuncs, Bool waitForUpdate) 119{ 120 miPointerScreenPtr pScreenPriv; 121 122 if (!dixRegisterPrivateKey(&miPointerScreenKeyRec, PRIVATE_SCREEN, 0)) 123 return FALSE; 124 125 if (!dixRegisterPrivateKey(&miPointerPrivKeyRec, PRIVATE_DEVICE, 0)) 126 return FALSE; 127 128 pScreenPriv = malloc(sizeof(miPointerScreenRec)); 129 if (!pScreenPriv) 130 return FALSE; 131 pScreenPriv->spriteFuncs = spriteFuncs; 132 pScreenPriv->screenFuncs = screenFuncs; 133 pScreenPriv->waitForUpdate = waitForUpdate; 134 pScreenPriv->showTransparent = FALSE; 135 pScreenPriv->CloseScreen = pScreen->CloseScreen; 136 pScreen->CloseScreen = miPointerCloseScreen; 137 dixSetPrivate(&pScreen->devPrivates, miPointerScreenKey, pScreenPriv); 138 /* 139 * set up screen cursor method table 140 */ 141 pScreen->ConstrainCursor = miPointerConstrainCursor; 142 pScreen->CursorLimits = miPointerCursorLimits; 143 pScreen->DisplayCursor = miPointerDisplayCursor; 144 pScreen->RealizeCursor = miPointerRealizeCursor; 145 pScreen->UnrealizeCursor = miPointerUnrealizeCursor; 146 pScreen->SetCursorPosition = miPointerSetCursorPosition; 147 pScreen->RecolorCursor = miRecolorCursor; 148 pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; 149 pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; 150 151 mipointermove_events = NULL; 152 return TRUE; 153} 154 155/** 156 * Destroy screen-specific information. 157 * 158 * @param index Screen index of the screen in screenInfo.screens[] 159 * @param pScreen The actual screen pointer 160 */ 161static Bool 162miPointerCloseScreen(ScreenPtr pScreen) 163{ 164 SetupScreen(pScreen); 165 166 pScreen->CloseScreen = pScreenPriv->CloseScreen; 167 free((void *) pScreenPriv); 168 FreeEventList(mipointermove_events, GetMaximumEventsNum()); 169 mipointermove_events = NULL; 170 return (*pScreen->CloseScreen) (pScreen); 171} 172 173/* 174 * DIX/DDX interface routines 175 */ 176 177static Bool 178miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 179{ 180 SetupScreen(pScreen); 181 return (*pScreenPriv->spriteFuncs->RealizeCursor) (pDev, pScreen, pCursor); 182} 183 184static Bool 185miPointerUnrealizeCursor(DeviceIntPtr pDev, 186 ScreenPtr pScreen, CursorPtr pCursor) 187{ 188 SetupScreen(pScreen); 189 return (*pScreenPriv->spriteFuncs->UnrealizeCursor) (pDev, pScreen, 190 pCursor); 191} 192 193static Bool 194miPointerDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 195{ 196 miPointerPtr pPointer; 197 198 /* return for keyboards */ 199 if (!IsPointerDevice(pDev)) 200 return FALSE; 201 202 pPointer = MIPOINTER(pDev); 203 204 pPointer->pCursor = pCursor; 205 pPointer->pScreen = pScreen; 206 miPointerUpdateSprite(pDev); 207 return TRUE; 208} 209 210/** 211 * Set up the constraints for the given device. This function does not 212 * actually constrain the cursor but merely copies the given box to the 213 * internal constraint storage. 214 * 215 * @param pDev The device to constrain to the box 216 * @param pBox The rectangle to constrain the cursor to 217 * @param pScreen Used for copying screen confinement 218 */ 219static void 220miPointerConstrainCursor(DeviceIntPtr pDev, ScreenPtr pScreen, BoxPtr pBox) 221{ 222 miPointerPtr pPointer; 223 224 pPointer = MIPOINTER(pDev); 225 226 pPointer->limits = *pBox; 227 pPointer->confined = PointerConfinedToScreen(pDev); 228} 229 230/** 231 * Should calculate the box for the given cursor, based on screen and the 232 * confinement given. But we assume that whatever box is passed in is valid 233 * anyway. 234 * 235 * @param pDev The device to calculate the cursor limits for 236 * @param pScreen The screen the confinement happens on 237 * @param pCursor The screen the confinement happens on 238 * @param pHotBox The confinement box for the cursor 239 * @param[out] pTopLeftBox The new confinement box, always *pHotBox. 240 */ 241static void 242miPointerCursorLimits(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, 243 BoxPtr pHotBox, BoxPtr pTopLeftBox) 244{ 245 *pTopLeftBox = *pHotBox; 246} 247 248/** 249 * Set the device's cursor position to the x/y position on the given screen. 250 * Generates and event if required. 251 * 252 * This function is called from: 253 * - sprite init code to place onto initial position 254 * - the various WarpPointer implementations (core, XI, Xinerama, dmx,…) 255 * - during the cursor update path in CheckMotion 256 * - in the Xinerama part of NewCurrentScreen 257 * - when a RandR/RandR1.2 mode was applied (it may have moved the pointer, so 258 * it's set back to the original pos) 259 * 260 * @param pDev The device to move 261 * @param pScreen The screen the device is on 262 * @param x The x coordinate in per-screen coordinates 263 * @param y The y coordinate in per-screen coordinates 264 * @param generateEvent True if the pointer movement should generate an 265 * event. 266 * 267 * @return TRUE in all cases 268 */ 269static Bool 270miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, 271 int x, int y, Bool generateEvent) 272{ 273 SetupScreen(pScreen); 274 miPointerPtr pPointer = MIPOINTER(pDev); 275 276 pPointer->generateEvent = generateEvent; 277 278 if (pScreen->ConstrainCursorHarder) 279 pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y); 280 281 /* device dependent - must pend signal and call miPointerWarpCursor */ 282 (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); 283 if (!generateEvent) 284 miPointerUpdateSprite(pDev); 285 return TRUE; 286} 287 288void 289miRecolorCursor(DeviceIntPtr pDev, ScreenPtr pScr, 290 CursorPtr pCurs, Bool displayed) 291{ 292 /* 293 * This is guaranteed to correct any color-dependent state which may have 294 * been bound up in private state created by RealizeCursor 295 */ 296 pScr->UnrealizeCursor(pDev, pScr, pCurs); 297 pScr->RealizeCursor(pDev, pScr, pCurs); 298 if (displayed) 299 pScr->DisplayCursor(pDev, pScr, pCurs); 300} 301 302/** 303 * Set up sprite information for the device. 304 * This function will be called once for each device after it is initialized 305 * in the DIX. 306 * 307 * @param pDev The newly created device 308 * @param pScreen The initial sprite scree. 309 */ 310static Bool 311miPointerDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) 312{ 313 miPointerPtr pPointer; 314 315 SetupScreen(pScreen); 316 317 pPointer = malloc(sizeof(miPointerRec)); 318 if (!pPointer) 319 return FALSE; 320 321 pPointer->pScreen = NULL; 322 pPointer->pSpriteScreen = NULL; 323 pPointer->pCursor = NULL; 324 pPointer->pSpriteCursor = NULL; 325 pPointer->limits.x1 = 0; 326 pPointer->limits.x2 = 32767; 327 pPointer->limits.y1 = 0; 328 pPointer->limits.y2 = 32767; 329 pPointer->confined = FALSE; 330 pPointer->x = 0; 331 pPointer->y = 0; 332 pPointer->generateEvent = FALSE; 333 334 if (!((*pScreenPriv->spriteFuncs->DeviceCursorInitialize) (pDev, pScreen))) { 335 free(pPointer); 336 return FALSE; 337 } 338 339 dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, pPointer); 340 return TRUE; 341} 342 343/** 344 * Clean up after device. 345 * This function will be called once before the device is freed in the DIX 346 * 347 * @param pDev The device to be removed from the server 348 * @param pScreen Current screen of the device 349 */ 350static void 351miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) 352{ 353 SetupScreen(pScreen); 354 355 if (!IsMaster(pDev) && !IsFloating(pDev)) 356 return; 357 358 (*pScreenPriv->spriteFuncs->DeviceCursorCleanup) (pDev, pScreen); 359 free(dixLookupPrivate(&pDev->devPrivates, miPointerPrivKey)); 360 dixSetPrivate(&pDev->devPrivates, miPointerPrivKey, NULL); 361} 362 363/** 364 * Warp the pointer to the given position on the given screen. May generate 365 * an event, depending on whether we're coming from miPointerSetPosition. 366 * 367 * Once signals are ignored, the WarpCursor function can call this 368 * 369 * @param pDev The device to warp 370 * @param pScreen Screen to warp on 371 * @param x The x coordinate in per-screen coordinates 372 * @param y The y coordinate in per-screen coordinates 373 */ 374 375void 376miPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 377{ 378 miPointerPtr pPointer; 379 BOOL changedScreen = FALSE; 380 381 pPointer = MIPOINTER(pDev); 382 383 if (pPointer->pScreen != pScreen) { 384 mieqSwitchScreen(pDev, pScreen, TRUE); 385 changedScreen = TRUE; 386 } 387 388 if (pPointer->generateEvent) 389 miPointerMove(pDev, pScreen, x, y); 390 else 391 miPointerMoveNoEvent(pDev, pScreen, x, y); 392 393 /* Don't call USFS if we use Xinerama, otherwise the root window is 394 * updated to the second screen, and we never receive any events. 395 * (FDO bug #18668) */ 396 if (changedScreen 397#ifdef PANORAMIX 398 && noPanoramiXExtension 399#endif 400 ) { 401 DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER); 402 /* Hack for CVE-2023-5380: if we're moving 403 * screens PointerWindows[] keeps referring to the 404 * old window. If that gets destroyed we have a UAF 405 * bug later. Only happens when jumping from a window 406 * to the root window on the other screen. 407 * Enter/Leave events are incorrect for that case but 408 * too niche to fix. 409 */ 410 LeaveWindow(pDev); 411 if (master) 412 LeaveWindow(master); 413 UpdateSpriteForScreen(pDev, pScreen); 414 } 415} 416 417/** 418 * Synchronize the sprite with the cursor. 419 * 420 * @param pDev The device to sync 421 */ 422void 423miPointerUpdateSprite(DeviceIntPtr pDev) 424{ 425 ScreenPtr pScreen; 426 miPointerScreenPtr pScreenPriv; 427 CursorPtr pCursor; 428 int x, y, devx, devy; 429 miPointerPtr pPointer; 430 431 if (!pDev || !pDev->coreEvents) 432 return; 433 434 pPointer = MIPOINTER(pDev); 435 436 if (!pPointer) 437 return; 438 439 pScreen = pPointer->pScreen; 440 if (!pScreen) 441 return; 442 443 x = pPointer->x; 444 y = pPointer->y; 445 devx = pPointer->devx; 446 devy = pPointer->devy; 447 448 pScreenPriv = GetScreenPrivate(pScreen); 449 /* 450 * if the cursor has switched screens, disable the sprite 451 * on the old screen 452 */ 453 if (pScreen != pPointer->pSpriteScreen) { 454 if (pPointer->pSpriteScreen) { 455 miPointerScreenPtr pOldPriv; 456 457 pOldPriv = GetScreenPrivate(pPointer->pSpriteScreen); 458 if (pPointer->pCursor) { 459 (*pOldPriv->spriteFuncs->SetCursor) 460 (pDev, pPointer->pSpriteScreen, NullCursor, 0, 0); 461 } 462 (*pOldPriv->screenFuncs->CrossScreen) (pPointer->pSpriteScreen, 463 FALSE); 464 } 465 (*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE); 466 (*pScreenPriv->spriteFuncs->SetCursor) 467 (pDev, pScreen, pPointer->pCursor, x, y); 468 pPointer->devx = x; 469 pPointer->devy = y; 470 pPointer->pSpriteCursor = pPointer->pCursor; 471 pPointer->pSpriteScreen = pScreen; 472 } 473 /* 474 * if the cursor has changed, display the new one 475 */ 476 else if (pPointer->pCursor != pPointer->pSpriteCursor) { 477 pCursor = pPointer->pCursor; 478 if (!pCursor || 479 (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)) 480 pCursor = NullCursor; 481 (*pScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, pCursor, x, y); 482 483 pPointer->devx = x; 484 pPointer->devy = y; 485 pPointer->pSpriteCursor = pPointer->pCursor; 486 } 487 else if (x != devx || y != devy) { 488 pPointer->devx = x; 489 pPointer->devy = y; 490 if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) 491 (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); 492 } 493} 494 495/** 496 * Invalidate the current sprite and force it to be reloaded on next cursor setting 497 * operation 498 * 499 * @param pDev The device to invalidate the sprite fore 500 */ 501void 502miPointerInvalidateSprite(DeviceIntPtr pDev) 503{ 504 miPointerPtr pPointer; 505 506 pPointer = MIPOINTER(pDev); 507 pPointer->pSpriteCursor = (CursorPtr) 1; 508} 509 510/** 511 * Set the device to the coordinates on the given screen. 512 * 513 * @param pDev The device to move 514 * @param screen_no Index of the screen to move to 515 * @param x The x coordinate in per-screen coordinates 516 * @param y The y coordinate in per-screen coordinates 517 */ 518void 519miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y) 520{ 521 ScreenPtr pScreen; 522 miPointerPtr pPointer; 523 524 pPointer = MIPOINTER(pDev); 525 526 pScreen = screenInfo.screens[screen_no]; 527 mieqSwitchScreen(pDev, pScreen, FALSE); 528 NewCurrentScreen(pDev, pScreen, x, y); 529 530 pPointer->limits.x2 = pScreen->width; 531 pPointer->limits.y2 = pScreen->height; 532} 533 534/** 535 * @return The current screen of the given device or NULL. 536 */ 537ScreenPtr 538miPointerGetScreen(DeviceIntPtr pDev) 539{ 540 miPointerPtr pPointer = MIPOINTER(pDev); 541 542 return (pPointer) ? pPointer->pScreen : NULL; 543} 544 545/* Controls whether the cursor image should be updated immediately when 546 moved (FALSE) or if something else will be responsible for updating 547 it later (TRUE). Returns current setting. 548 Caller is responsible for calling OsBlockSignal first. 549*/ 550Bool 551miPointerSetWaitForUpdate(ScreenPtr pScreen, Bool wait) 552{ 553 SetupScreen(pScreen); 554 Bool prevWait = pScreenPriv->waitForUpdate; 555 556 pScreenPriv->waitForUpdate = wait; 557 return prevWait; 558} 559 560/* Move the pointer on the current screen, and update the sprite. */ 561static void 562miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 563{ 564 miPointerPtr pPointer; 565 566 SetupScreen(pScreen); 567 568 pPointer = MIPOINTER(pDev); 569 570 /* Hack: We mustn't call into ->MoveCursor for anything but the 571 * VCP, as this may cause a non-HW rendered cursor to be rendered while 572 * not holding the input lock. This would race with building the command 573 * buffer for other rendering. 574 */ 575 if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer 576 &&!pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen) { 577 pPointer->devx = x; 578 pPointer->devy = y; 579 if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask) 580 (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y); 581 } 582 583 pPointer->x = x; 584 pPointer->y = y; 585 pPointer->pScreen = pScreen; 586} 587 588/** 589 * Set the devices' cursor position to the given x/y position. 590 * 591 * This function is called during the pointer update path in 592 * GetPointerEvents and friends (and the same in the xwin DDX). 593 * 594 * The coordinates provided are always absolute. The parameter mode whether 595 * it was relative or absolute movement that landed us at those coordinates. 596 * 597 * If the cursor was constrained by a barrier, ET_Barrier* events may be 598 * generated and appended to the InternalEvent list provided. 599 * 600 * @param pDev The device to move 601 * @param mode Movement mode (Absolute or Relative) 602 * @param[in,out] screenx The x coordinate in desktop coordinates 603 * @param[in,out] screeny The y coordinate in desktop coordinates 604 * @param[in,out] nevents The number of events in events (before/after) 605 * @param[in,out] events The list of events before/after being constrained 606 */ 607ScreenPtr 608miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, 609 double *screeny, 610 int *nevents, InternalEvent* events) 611{ 612 miPointerScreenPtr pScreenPriv; 613 ScreenPtr pScreen; 614 ScreenPtr newScreen; 615 int x, y; 616 Bool switch_screen = FALSE; 617 Bool should_constrain_barriers = FALSE; 618 int i; 619 620 miPointerPtr pPointer; 621 622 pPointer = MIPOINTER(pDev); 623 pScreen = pPointer->pScreen; 624 625 x = trunc(*screenx); 626 y = trunc(*screeny); 627 628 switch_screen = !point_on_screen(pScreen, x, y); 629 630 /* Switch to per-screen coordinates for CursorOffScreen and 631 * Pointer->limits */ 632 x -= pScreen->x; 633 y -= pScreen->y; 634 635 should_constrain_barriers = (mode == Relative); 636 637 if (should_constrain_barriers) { 638 /* coordinates after clamped to a barrier */ 639 int constrained_x, constrained_y; 640 int current_x, current_y; /* current position in per-screen coord */ 641 642 current_x = MIPOINTER(pDev)->x - pScreen->x; 643 current_y = MIPOINTER(pDev)->y - pScreen->y; 644 645 input_constrain_cursor(pDev, pScreen, 646 current_x, current_y, x, y, 647 &constrained_x, &constrained_y, 648 nevents, events); 649 650 x = constrained_x; 651 y = constrained_y; 652 } 653 654 if (switch_screen) { 655 pScreenPriv = GetScreenPrivate(pScreen); 656 if (!pPointer->confined) { 657 newScreen = pScreen; 658 (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y); 659 if (newScreen != pScreen) { 660 pScreen = newScreen; 661 mieqSwitchScreen(pDev, pScreen, FALSE); 662 /* Smash the confine to the new screen */ 663 pPointer->limits.x2 = pScreen->width; 664 pPointer->limits.y2 = pScreen->height; 665 } 666 } 667 } 668 /* Constrain the sprite to the current limits. */ 669 if (x < pPointer->limits.x1) 670 x = pPointer->limits.x1; 671 if (x >= pPointer->limits.x2) 672 x = pPointer->limits.x2 - 1; 673 if (y < pPointer->limits.y1) 674 y = pPointer->limits.y1; 675 if (y >= pPointer->limits.y2) 676 y = pPointer->limits.y2 - 1; 677 678 if (pScreen->ConstrainCursorHarder) 679 pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y); 680 681 if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen) 682 miPointerMoveNoEvent(pDev, pScreen, x, y); 683 684 /* check if we generated any barrier events and if so, update root x/y 685 * to the fully constrained coords */ 686 if (should_constrain_barriers) { 687 for (i = 0; i < *nevents; i++) { 688 if (events[i].any.type == ET_BarrierHit || 689 events[i].any.type == ET_BarrierLeave) { 690 events[i].barrier_event.root_x = x; 691 events[i].barrier_event.root_y = y; 692 } 693 } 694 } 695 696 /* Convert to desktop coordinates again */ 697 x += pScreen->x; 698 y += pScreen->y; 699 700 /* In the event we actually change screen or we get confined, we just 701 * drop the float component on the floor 702 * FIXME: only drop remainder for ConstrainCursorHarder, not for screen 703 * crossings */ 704 if (x != trunc(*screenx)) 705 *screenx = x; 706 if (y != trunc(*screeny)) 707 *screeny = y; 708 709 return pScreen; 710} 711 712/** 713 * Get the current position of the device in desktop coordinates. 714 * 715 * @param x Return value for the current x coordinate in desktop coordinates. 716 * @param y Return value for the current y coordinate in desktop coordinates. 717 */ 718void 719miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) 720{ 721 *x = MIPOINTER(pDev)->x; 722 *y = MIPOINTER(pDev)->y; 723} 724 725/** 726 * Move the device's pointer to the x/y coordinates on the given screen. 727 * This function generates and enqueues pointer events. 728 * 729 * @param pDev The device to move 730 * @param pScreen The screen the device is on 731 * @param x The x coordinate in per-screen coordinates 732 * @param y The y coordinate in per-screen coordinates 733 */ 734void 735miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 736{ 737 int i, nevents; 738 int valuators[2]; 739 ValuatorMask mask; 740 741 miPointerMoveNoEvent(pDev, pScreen, x, y); 742 743 /* generate motion notify */ 744 valuators[0] = x; 745 valuators[1] = y; 746 747 if (!mipointermove_events) { 748 mipointermove_events = InitEventList(GetMaximumEventsNum()); 749 750 if (!mipointermove_events) { 751 FatalError("Could not allocate event store.\n"); 752 return; 753 } 754 } 755 756 valuator_mask_set_range(&mask, 0, 2, valuators); 757 nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0, 758 POINTER_SCREEN | POINTER_ABSOLUTE | 759 POINTER_NORAW, &mask); 760 761 input_lock(); 762 for (i = 0; i < nevents; i++) 763 mieqEnqueue(pDev, &mipointermove_events[i]); 764 input_unlock(); 765} 766