1/* 2 * Copyright © 2006 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "randrstr.h" 24#include "inputstr.h" 25 26/* 27 * When the pointer moves, check to see if the specified position is outside 28 * any of theavailable CRTCs and move it to a 'sensible' place if so, where 29 * sensible is the closest monitor to the departing edge. 30 * 31 * Returns whether the position was adjusted 32 */ 33 34static Bool 35RRCrtcContainsPosition(RRCrtcPtr crtc, int x, int y) 36{ 37 RRModePtr mode = crtc->mode; 38 int scan_width, scan_height; 39 40 if (!mode) 41 return FALSE; 42 43 RRCrtcGetScanoutSize(crtc, &scan_width, &scan_height); 44 45 if (crtc->x <= x && x < crtc->x + scan_width && 46 crtc->y <= y && y < crtc->y + scan_height) 47 return TRUE; 48 return FALSE; 49} 50 51/* 52 * Find the CRTC nearest the specified position, ignoring 'skip' 53 */ 54static void 55RRPointerToNearestCrtc(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y, 56 RRCrtcPtr skip) 57{ 58 rrScrPriv(pScreen); 59 int c; 60 RRCrtcPtr nearest = NULL; 61 int best = 0; 62 int best_dx = 0, best_dy = 0; 63 64 for (c = 0; c < pScrPriv->numCrtcs; c++) { 65 RRCrtcPtr crtc = pScrPriv->crtcs[c]; 66 RRModePtr mode = crtc->mode; 67 int dx, dy; 68 int dist; 69 int scan_width, scan_height; 70 71 if (!mode) 72 continue; 73 if (crtc == skip) 74 continue; 75 76 RRCrtcGetScanoutSize(crtc, &scan_width, &scan_height); 77 78 if (x < crtc->x) 79 dx = crtc->x - x; 80 else if (x > crtc->x + scan_width - 1) 81 dx = crtc->x + (scan_width - 1) - x; 82 else 83 dx = 0; 84 if (y < crtc->y) 85 dy = crtc->y - y; 86 else if (y > crtc->y + scan_height - 1) 87 dy = crtc->y + (scan_height - 1) - y; 88 else 89 dy = 0; 90 dist = dx * dx + dy * dy; 91 if (!nearest || dist < best) { 92 nearest = crtc; 93 best_dx = dx; 94 best_dy = dy; 95 best = dist; 96 } 97 } 98 if (best_dx || best_dy) 99 (*pScreen->SetCursorPosition) (pDev, pScreen, x + best_dx, y + best_dy, 100 TRUE); 101 pScrPriv->pointerCrtc = nearest; 102} 103 104void 105RRPointerMoved(ScreenPtr pScreen, int x, int y) 106{ 107 rrScrPriv(pScreen); 108 RRCrtcPtr pointerCrtc = pScrPriv->pointerCrtc; 109 int c; 110 111 /* Check last known CRTC */ 112 if (pointerCrtc && RRCrtcContainsPosition(pointerCrtc, x, y)) 113 return; 114 115 /* Check all CRTCs */ 116 for (c = 0; c < pScrPriv->numCrtcs; c++) { 117 RRCrtcPtr crtc = pScrPriv->crtcs[c]; 118 119 if (RRCrtcContainsPosition(crtc, x, y)) { 120 /* Remember containing CRTC */ 121 pScrPriv->pointerCrtc = crtc; 122 return; 123 } 124 } 125 126 /* None contain pointer, find nearest */ 127 ErrorF("RRPointerMoved: Untested, may cause \"bogus pointer event\"\n"); 128 RRPointerToNearestCrtc(inputInfo.pointer, pScreen, x, y, pointerCrtc); 129} 130 131/* 132 * When the screen is reconfigured, move all pointers to the nearest 133 * CRTC 134 */ 135void 136RRPointerScreenConfigured(ScreenPtr pScreen) 137{ 138 WindowPtr pRoot; 139 ScreenPtr pCurrentScreen; 140 int x, y; 141 DeviceIntPtr pDev; 142 143 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { 144 if (IsPointerDevice(pDev)) { 145 pRoot = GetCurrentRootWindow(pDev); 146 pCurrentScreen = pRoot ? pRoot->drawable.pScreen : NULL; 147 148 if (pScreen == pCurrentScreen) { 149 GetSpritePosition(pDev, &x, &y); 150 RRPointerToNearestCrtc(pDev, pScreen, x, y, NULL); 151 } 152 } 153 } 154} 155