| 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 | |
| 34 | static Bool |
| 35 | RRCrtcContainsPosition(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 | */ |
| 54 | static void |
| 55 | RRPointerToNearestCrtc(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) |
| 81 | dx = x - (crtc->x + scan_width); |
| 82 | else |
| 83 | dx = 0; |
| 84 | if (y < crtc->y) |
| 85 | dy = crtc->y - y; |
| 86 | else if (y > crtc->y + scan_height) |
| 87 | dy = y - (crtc->y + scan_height); |
| 88 | else |
| 89 | dy = 0; |
| 90 | dist = dx + dy; |
| 91 | if (!nearest || dist < best) { |
| 92 | nearest = crtc; |
| 93 | best_dx = dx; |
| 94 | best_dy = dy; |
| 95 | } |
| 96 | } |
| 97 | if (best_dx || best_dy) |
| 98 | (*pScreen->SetCursorPosition) (pDev, pScreen, x + best_dx, y + best_dy, |
| 99 | TRUE); |
| 100 | pScrPriv->pointerCrtc = nearest; |
| 101 | } |
| 102 | |
| 103 | void |
| 104 | RRPointerMoved(ScreenPtr pScreen, int x, int y) |
| 105 | { |
| 106 | rrScrPriv(pScreen); |
| 107 | RRCrtcPtr pointerCrtc = pScrPriv->pointerCrtc; |
| 108 | int c; |
| 109 | |
| 110 | /* Check last known CRTC */ |
| 111 | if (pointerCrtc && RRCrtcContainsPosition(pointerCrtc, x, y)) |
| 112 | return; |
| 113 | |
| 114 | /* Check all CRTCs */ |
| 115 | for (c = 0; c < pScrPriv->numCrtcs; c++) { |
| 116 | RRCrtcPtr crtc = pScrPriv->crtcs[c]; |
| 117 | |
| 118 | if (RRCrtcContainsPosition(crtc, x, y)) { |
| 119 | /* Remember containing CRTC */ |
| 120 | pScrPriv->pointerCrtc = crtc; |
| 121 | return; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /* None contain pointer, find nearest */ |
| 126 | ErrorF("RRPointerMoved: Untested, may cause \"bogus pointer event\"\n"); |
| 127 | RRPointerToNearestCrtc(inputInfo.pointer, pScreen, x, y, pointerCrtc); |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | * When the screen is reconfigured, move all pointers to the nearest |
| 132 | * CRTC |
| 133 | */ |
| 134 | void |
| 135 | RRPointerScreenConfigured(ScreenPtr pScreen) |
| 136 | { |
| 137 | WindowPtr pRoot; |
| 138 | ScreenPtr pCurrentScreen; |
| 139 | int x, y; |
| 140 | DeviceIntPtr pDev; |
| 141 | |
| 142 | for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { |
| 143 | if (IsPointerDevice(pDev)) { |
| 144 | pRoot = GetCurrentRootWindow(pDev); |
| 145 | pCurrentScreen = pRoot ? pRoot->drawable.pScreen : NULL; |
| 146 | |
| 147 | if (pScreen == pCurrentScreen) { |
| 148 | GetSpritePosition(pDev, &x, &y); |
| 149 | RRPointerToNearestCrtc(pDev, pScreen, x, y, NULL); |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | } |