[RFC PATCH] randr: crtc cursor confinement
Adam Jackson
ajax at redhat.com
Tue Oct 12 11:36:49 PDT 2010
(Not finished, definitely a bit ugly, looking for review)
Provide a screen hook for cursor confinement beyond simple Screen
boundaries. Wire it up to RANDR and confine the cursor to CRTCs if the
geometry is such that that's likely what's desired (in particular, iff
the set of pixels lit by all CRTCs is path-connected).
The major issue I have with this so far is that I'm certain there's a
better way to get at the pointer data than diving to miPointerRec, but
that code is a twisty maze of typedefs and I got lost. It'll also be
a bit bizarre in the face of multiple GPUs, but that's not really
different from what we have now.
Signed-off-by: Adam Jackson <ajax at redhat.com>
---
include/scrnintstr.h | 11 +++-
mi/mibstore.c | 1 -
mi/mipointer.c | 3 +
mi/mipointrst.h | 4 +-
mi/miscrinit.c | 1 -
randr/randr.c | 2 +
randr/randrstr.h | 4 +
randr/rrcrtc.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 209 insertions(+), 5 deletions(-)
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index e36b15f..be3b2a7 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -453,6 +453,11 @@ typedef void (* DeviceCursorCleanupProcPtr)(
DeviceIntPtr /* pDev */,
ScreenPtr /* pScreen */);
+typedef struct _miPointer *miPointerPtr;
+
+typedef void (*ConstrainCursorHarderProcPtr)(
+ miPointerPtr, ScreenPtr, int *, int *);
+
typedef struct _Screen {
int myNum; /* index of this instance in Screens[] */
ATOM id;
@@ -511,9 +516,13 @@ typedef struct _Screen {
CreatePixmapProcPtr CreatePixmap;
DestroyPixmapProcPtr DestroyPixmap;
- /* Backing store procedures */
+ /* Reuse the SDA slot for CCH for minimal ABI hassle */
+ ConstrainCursorHarderProcPtr ConstrainCursorHarder;
+ /* Backing store procedures */
+#if 0
SaveDoomedAreasProcPtr SaveDoomedAreas;
+#endif
RestoreAreasProcPtr RestoreAreas;
ExposeCopyProcPtr ExposeCopy;
TranslateBackingStoreProcPtr TranslateBackingStore;
diff --git a/mi/mibstore.c b/mi/mibstore.c
index 262b494..1388189 100644
--- a/mi/mibstore.c
+++ b/mi/mibstore.c
@@ -40,7 +40,6 @@
void
miInitializeBackingStore (ScreenPtr pScreen)
{
- pScreen->SaveDoomedAreas = NULL;
pScreen->RestoreAreas = NULL;
pScreen->ExposeCopy = NULL;
pScreen->TranslateBackingStore = NULL;
diff --git a/mi/mipointer.c b/mi/mipointer.c
index d8aaf8c..bca2e3c 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -528,6 +528,9 @@ miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y)
if (*y >= pPointer->limits.y2)
*y = pPointer->limits.y2 - 1;
+ if (pScreen->ConstrainCursorHarder)
+ pScreen->ConstrainCursorHarder(pPointer, pScreen, x, y);
+
if (pPointer->x == *x && pPointer->y == *y &&
pPointer->pScreen == pScreen)
return;
diff --git a/mi/mipointrst.h b/mi/mipointrst.h
index bd9c24a..f643c01 100644
--- a/mi/mipointrst.h
+++ b/mi/mipointrst.h
@@ -35,7 +35,7 @@ in this Software without prior written authorization from The Open Group.
#include "mipointer.h"
#include "scrnintstr.h"
-typedef struct {
+typedef struct _miPointer {
ScreenPtr pScreen; /* current screen */
ScreenPtr pSpriteScreen;/* screen containing current sprite */
CursorPtr pCursor; /* current cursor */
@@ -44,7 +44,7 @@ typedef struct {
Bool confined; /* pointer can't change screens */
int x, y; /* hot spot location */
int devx, devy; /* sprite position */
-} miPointerRec, *miPointerPtr;
+} miPointerRec /* , *miPointerPtr */;
typedef struct {
miPointerSpriteFuncPtr spriteFuncs; /* sprite-specific methods */
diff --git a/mi/miscrinit.c b/mi/miscrinit.c
index 661ecb2..f1afc25 100644
--- a/mi/miscrinit.c
+++ b/mi/miscrinit.c
@@ -280,7 +280,6 @@ miScreenInit(
pScreen->SetShape = miSetShape;
pScreen->MarkUnrealizedWindow = miMarkUnrealizedWindow;
- pScreen->SaveDoomedAreas = 0;
pScreen->RestoreAreas = 0;
pScreen->ExposeCopy = 0;
pScreen->TranslateBackingStore = 0;
diff --git a/randr/randr.c b/randr/randr.c
index f52a46a..9982880 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 aad126f..ac89363 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;
@@ -731,6 +732,9 @@ ProcRRGetPanning (ClientPtr client);
int
ProcRRSetPanning (ClientPtr client);
+void
+RRConstrainCursorHarder (miPointerPtr, ScreenPtr, int *, int *);
+
/* rrdispatch.c */
extern _X_EXPORT Bool
RRClientKnowsRates (ClientPtr pClient);
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 14f6e45..ce31113 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 "mipointrst.h"
RESTYPE RRCrtcType;
@@ -292,6 +294,125 @@ 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:
+ *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;
+ default:
+ return;
+ }
+}
+
+/* overlapping counts as adjacent */
+static Bool
+crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
+{
+ int al, ar, at, ab;
+ int bl, br, bt, bb;
+ int cl, cr, ct, cb;
+
+ 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, ct);
+ cb = min(ab, bb);
+
+ return (cl <= cr) && (ct <= cb);
+}
+
+/*
+ * This isn't really multiplication, but we don't need it to be. All
+ * we need is a boolean for connectivity, not an integer for number of
+ * paths. As a result we can scale to gratuitously large n without
+ * worrying about integer overflow.
+ */
+static Bool
+matrix_pseudomultiply(char *left, const char *right, int n)
+{
+ int i, j, k;
+ char *res = calloc(1, n * n);
+
+ if (!res)
+ return FALSE;
+
+ for (i = 0; i < n; i++)
+ for (j = 0; j < n; j++)
+ for (k = 0; k < n; k++)
+ res[i*n + j] |= left[i*n + k] && right[k*n + j];
+
+ memcpy(left, res, n * n);
+
+ free(res);
+
+ return TRUE;
+}
+
+static void
+RRComputeContiguity (ScreenPtr pScreen)
+{
+ rrScrPriv(pScreen);
+ Bool discontiguous = TRUE;
+ int i, j, n = pScrPriv->numCrtcs;
+ RRCrtcPtr a, b;
+ char *matrix = NULL, *m = NULL;
+
+ matrix = calloc(1, n*n);
+ m = calloc(1, n*n);
+ if (!matrix || !m)
+ goto out;
+
+ /* compute adjacency matrix; everything is adjacent with itself */
+ for (i = 0; i < n; i++) {
+ a = pScrPriv->crtcs[i];
+
+ if (!a->mode)
+ continue;
+
+ for (j = 0; j < n; j++) {
+ b = pScrPriv->crtcs[j];
+
+ if (!b->mode)
+ continue;
+
+ if (a == b || crtcs_adjacent(a, b))
+ matrix[i*n + j] = 1;
+ }
+ }
+
+ memcpy(m, matrix, n*n);
+
+ /* raise it to the n-1th; finds connected paths */
+ for (i = 0; i < n-1; i++)
+ if (!matrix_pseudomultiply(m, matrix, n))
+ goto out;
+
+ /* check for connectivity */
+ for (i = 0; i < n; i++)
+ if (pScrPriv->crtcs[i]->mode && !m[i])
+ goto out;
+
+ discontiguous = FALSE;
+
+out:
+ free(matrix);
+ free(m);
+ pScrPriv->discontiguous = discontiguous;
+}
+
/*
* Request that the Crtc be reconfigured
*/
@@ -306,6 +427,7 @@ RRCrtcSet (RRCrtcPtr crtc,
{
ScreenPtr pScreen = crtc->pScreen;
Bool ret = FALSE;
+ Bool recompute = TRUE;
rrScrPriv(pScreen);
/* See if nothing changed */
@@ -319,6 +441,7 @@ RRCrtcSet (RRCrtcPtr crtc,
!RRCrtcPendingTransform (crtc))
{
ret = TRUE;
+ recompute = FALSE;
}
else
{
@@ -381,6 +504,10 @@ RRCrtcSet (RRCrtcPtr crtc,
RRPostPendingProperties (outputs[o]);
}
}
+
+ if (recompute)
+ RRComputeContiguity(pScreen);
+
return ret;
}
@@ -1340,3 +1467,64 @@ ProcRRGetCrtcTransform (ClientPtr client)
free(reply);
return Success;
}
+
+void
+RRConstrainCursorHarder(miPointerPtr pDev, ScreenPtr pScreen, 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 = pDev->x;
+ int ny = pDev->y;
+ int left, right, top, bottom;
+
+ if (!crtc->mode)
+ continue;
+
+ crtc_bounds(crtc, &left, &right, &top, &bottom);
+
+ 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;
+ }
+ }
+}
--
1.7.3.1
More information about the xorg-devel
mailing list