diff --git a/randr/randr.c b/randr/randr.c index 607770520..d33712928 100644 --- a/randr/randr.c +++ b/randr/randr.c @@ -270,6 +270,8 @@ Bool RRScreenInit(ScreenPtr pScreen) wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen); + pScreen->ConstrainCursorHarder = RRConstrainCursorHarder; + pScrPriv->numOutputs = 0; pScrPriv->outputs = NULL; pScrPriv->numCrtcs = 0; diff --git a/randr/randrstr.h b/randr/randrstr.h index 7ea608003..d8dd37d96 100644 --- a/randr/randrstr.h +++ b/randr/randrstr.h @@ -297,6 +297,7 @@ typedef struct _rrScrPriv { int rate; int size; #endif + Bool discontiguous; } rrScrPrivRec, *rrScrPrivPtr; extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec; @@ -700,6 +701,9 @@ ProcRRGetPanning (ClientPtr client); int ProcRRSetPanning (ClientPtr client); +void +RRConstrainCursorHarder (DeviceIntPtr, ScreenPtr, int, int *, int *); + /* rrdispatch.c */ extern _X_EXPORT Bool RRClientKnowsRates (ClientPtr pClient); diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c index 98206a2b9..d4d8f2ad2 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -1,5 +1,6 @@ /* * Copyright © 2006 Keith Packard + * Copyright 2010 Red Hat, Inc * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -22,6 +23,7 @@ #include "randrstr.h" #include "swaprep.h" +#include "mipointer.h" RESTYPE RRCrtcType; @@ -292,6 +294,92 @@ RRCrtcPendingProperties (RRCrtcPtr crtc) return FALSE; } +static void +crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom) +{ + *left = crtc->x; + *top = crtc->y; + + switch (crtc->rotation) { + case RR_Rotate_0: + case RR_Rotate_180: + default: + *right = crtc->x + crtc->mode->mode.width; + *bottom = crtc->y + crtc->mode->mode.height; + return; + case RR_Rotate_90: + case RR_Rotate_270: + *right = crtc->x + crtc->mode->mode.height; + *bottom = crtc->y + crtc->mode->mode.width; + return; + } +} + +/* overlapping counts as adjacent */ +static Bool +crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b) +{ + /* left, right, top, bottom... */ + int al, ar, at, ab; + int bl, br, bt, bb; + int cl, cr, ct, cb; /* the overlap, if any */ + + crtc_bounds(a, &al, &ar, &at, &ab); + crtc_bounds(b, &bl, &br, &bt, &bb); + + cl = max(al, bl); + cr = min(ar, br); + ct = max(at, bt); + cb = min(ab, bb); + + return (cl <= cr) && (ct <= cb); +} + +/* Depth-first search and mark all CRTCs reachable from cur */ +static void +mark_crtcs (rrScrPrivPtr pScrPriv, int *reachable, int cur) +{ + int i; + reachable[cur] = TRUE; + for (i = 0; i < pScrPriv->numCrtcs; ++i) { + if (reachable[i] || !pScrPriv->crtcs[i]->mode) + continue; + if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i])) + mark_crtcs(pScrPriv, reachable, i); + } +} + +static void +RRComputeContiguity (ScreenPtr pScreen) +{ + rrScrPriv(pScreen); + Bool discontiguous = TRUE; + int i, n = pScrPriv->numCrtcs; + + int *reachable = calloc(n, sizeof(int)); + if (!reachable) + goto out; + + /* Find first enabled CRTC and start search for reachable CRTCs from it */ + for (i = 0; i < n; ++i) { + if (pScrPriv->crtcs[i]->mode) { + mark_crtcs(pScrPriv, reachable, i); + break; + } + } + + /* Check that all enabled CRTCs were marked as reachable */ + for (i = 0; i < n; ++i) + if (pScrPriv->crtcs[i]->mode && !reachable[i]) + goto out; + + discontiguous = FALSE; + +out: + free(reachable); + pScrPriv->discontiguous = discontiguous; +} + /* * Request that the Crtc be reconfigured */ @@ -306,6 +394,7 @@ RRCrtcSet (RRCrtcPtr crtc, { ScreenPtr pScreen = crtc->pScreen; Bool ret = FALSE; + Bool recompute = TRUE; rrScrPriv(pScreen); /* See if nothing changed */ @@ -318,6 +407,7 @@ RRCrtcSet (RRCrtcPtr crtc, !RRCrtcPendingProperties (crtc) && !RRCrtcPendingTransform (crtc)) { + recompute = FALSE; ret = TRUE; } else @@ -381,6 +471,10 @@ RRCrtcSet (RRCrtcPtr crtc, RRPostPendingProperties (outputs[o]); } } + + if (recompute) + RRComputeContiguity(pScreen); + return ret; } @@ -1349,3 +1443,64 @@ ProcRRGetCrtcTransform (ClientPtr client) free(reply); return Success; } + +void +RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, int *y) +{ + rrScrPriv (pScreen); + int i; + + /* intentional dead space -> let it float */ + if (pScrPriv->discontiguous) + return; + + /* if we're moving inside a crtc, we're fine */ + for (i = 0; i < pScrPriv->numCrtcs; i++) { + RRCrtcPtr crtc = pScrPriv->crtcs[i]; + + int left, right, top, bottom; + + if (!crtc->mode) + continue; + + crtc_bounds(crtc, &left, &right, &top, &bottom); + + if ((*x >= left) && (*x <= right) && (*y >= top) && (*y <= bottom)) + return; + } + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + for (i = 0; i < pScrPriv->numCrtcs; i++) { + RRCrtcPtr crtc = pScrPriv->crtcs[i]; + int nx, ny; + int left, right, top, bottom; + + if (!crtc->mode) + continue; + + crtc_bounds(crtc, &left, &right, &top, &bottom); + miPointerGetPosition(pDev, &nx, &ny); + + if ((nx >= left) && (nx <= right) && (ny >= top) && (ny <= bottom)) { + if ((*x <= left) || (*x >= right)) { + int dx = *x - nx; + + if (dx > 0) + *x = right; + else if (dx < 0) + *x = left; + } + + if ((*y <= top) || (*y >= bottom)) { + int dy = *y - ny; + + if (dy > 0) + *y = bottom; + else if (dy < 0) + *y = top; + } + + return; + } + } +}