(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 <[email protected]>
---
 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

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to