[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