[PATCH 2/2] randr: Add RRConstrainCursorHarder

Adam Jackson ajax at redhat.com
Tue Jan 18 21:58:41 PST 2011


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

Signed-off-by: Adam Jackson <ajax at redhat.com>
---
 randr/randr.c    |    2 +
 randr/randrstr.h |    5 ++-
 randr/rrcrtc.c   |  154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 160 insertions(+), 1 deletions(-)

diff --git a/randr/randr.c b/randr/randr.c
index c22657e..6b3af0f 100644
--- a/randr/randr.c
+++ b/randr/randr.c
@@ -273,6 +273,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 7c553f2..e474e76 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -371,7 +371,7 @@ typedef struct _rrScrPriv {
     int			    rate;
     int			    size;
 #endif
-
+    Bool                   discontiguous;
 } rrScrPrivRec, *rrScrPrivPtr;
 
 extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
@@ -831,6 +831,9 @@ ProcRRGetCrtcSpriteTransform (ClientPtr client);
 int
 ProcRRSetCrtcConfigs (ClientPtr client);
 
+void
+RRConstrainCursorHarder (DeviceIntPtr, ScreenPtr, int *, int *);
+
 /* rrdispatch.c */
 extern _X_EXPORT Bool
 RRClientKnowsRates (ClientPtr	pClient);
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 5fe6900..3ec2041 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;
 
@@ -312,6 +314,91 @@ 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)
+{
+    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(sizeof(int), n);
+    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
  */
@@ -327,6 +414,7 @@ RRCrtcSet (RRCrtcPtr    crtc,
 {
     ScreenPtr	pScreen = crtc->pScreen;
     Bool	ret = FALSE;
+    Bool	recompute = TRUE;
     rrScrPriv(pScreen);
 
     /* See if nothing changed */
@@ -340,6 +428,7 @@ RRCrtcSet (RRCrtcPtr    crtc,
 	!RRCrtcPendingTransform (crtc) &&
 	crtc->scanoutPixmap == scanout_pixmap)
     {
+	recompute = FALSE;
 	ret = TRUE;
     }
     else
@@ -403,6 +492,10 @@ RRCrtcSet (RRCrtcPtr    crtc,
 		RRPostPendingProperties (outputs[o]);
 	}
     }
+
+    if (recompute)
+       RRComputeContiguity(pScreen);
+
     return ret;
 }
 
@@ -1797,3 +1890,64 @@ sendReply:
 
     return Success;
 }
+
+void
+RRConstrainCursorHarder(DeviceIntPtr 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, 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;
+       }
+    }
+}
-- 
1.7.3.4



More information about the xorg-devel mailing list