summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2010-11-15 14:29:14 -0500
committerAdam Jackson <ajax@redhat.com>2011-03-14 13:35:51 -0400
commit56c90e29f04727c903bd0f084d23bf44eb1a0a11 (patch)
tree1162b4ee3cee6e5267d66cdaf0f23a596b05ce7f
parent810fbfa44626bff9f443ab17c0ad27ff7ae121d7 (diff)
randr: Add RRConstrainCursorHarder
Confine cursor motion to within the bounds of a single CRTC, iff all the CRTCs within a ScreenRec are reachable from each other. If not you get the same "cursor floats within the bounding rect" behaviour you get now. v3: - Incorporate review feedback from Christopher James Halse Rogers v4: - Add mode field. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--randr/randr.c2
-rw-r--r--randr/randrstr.h4
-rw-r--r--randr/rrcrtc.c155
3 files changed, 161 insertions, 0 deletions
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;
+ }
+ }
+}