xserver: Branch 'mpx' - 2 commits

Peter Hutterer whot at kemper.freedesktop.org
Thu Feb 22 11:37:44 EET 2007


 Xi/Makefile.am      |   10 +
 Xi/chaccess.c       |  177 ++++++++++++++++++++++++++++++++
 Xi/chaccess.h       |   39 +++++++
 Xi/chpkpair.c       |   12 +-
 Xi/extinit.c        |   31 +++++
 Xi/grabacc.c        |  102 ++++++++++++++++++
 Xi/grabacc.h        |   41 +++++++
 Xi/qryacces.c       |  128 +++++++++++++++++++++++
 Xi/qryacces.h       |   41 +++++++
 Xi/regpair.c        |  108 +++++++++++++++++++
 Xi/regpair.h        |   43 +++++++
 dix/Makefile.am     |    1 
 dix/access.c        |  287 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 dix/devices.c       |   52 +++++++++
 dix/dispatch.c      |    2 
 dix/events.c        |   23 ++--
 dix/window.c        |   21 +++
 include/input.h     |   31 +++++
 include/windowstr.h |    9 +
 19 files changed, 1145 insertions(+), 13 deletions(-)

New commits:
diff-tree 4b8b0e377a27ec904b2028c89aed11c6416af26c (from cd0af7a7856e8246e27acc5513d219a094211625)
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Feb 22 20:00:59 2007 +1030

    Xi: 	Add access control request handling.
    
    dix:	New file access.c to handle all access control for devices.

diff --git a/Xi/Makefile.am b/Xi/Makefile.am
index 5d3417e..e77c8a3 100644
--- a/Xi/Makefile.am
+++ b/Xi/Makefile.am
@@ -20,7 +20,9 @@ libXi_la_SOURCES =	\
 	chgptr.c \
 	chgptr.h \
 	chpkpair.c \
-	chpkpair.h \ 
+	chpkpair.h \
+	chaccess.c \
+	chaccess.h \
 	closedev.c \
 	closedev.h \
 	devbell.c \
@@ -46,6 +48,8 @@ libXi_la_SOURCES =	\
 	getselev.h \
 	getvers.c \
 	getvers.h \
+        grabacc.c \
+        grabacc.h \
 	grabdev.c \
 	grabdev.h \
 	grabdevb.c \
@@ -62,6 +66,8 @@ libXi_la_SOURCES =	\
 	querydp.h \
 	queryst.c \
 	queryst.h \
+	qryacces.c \
+	qryacces.h \
 	regpair.c \
 	regpair.h \
 	selectev.c \
diff --git a/Xi/chaccess.c b/Xi/chaccess.c
new file mode 100644
index 0000000..5005e94
--- /dev/null
+++ b/Xi/chaccess.c
@@ -0,0 +1,177 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#define	 NEED_EVENTS
+#define	 NEED_REPLIES
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>	/* for inputstr.h    */
+#include <X11/Xproto.h>	/* Request macro     */
+#include "inputstr.h"	/* DeviceIntPtr      */
+#include "windowstr.h"	/* window structure  */
+#include "scrnintstr.h"	/* screen structure  */
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "extnsionst.h"
+#include "extinit.h"	/* LookupDeviceIntRec */
+#include "exevents.h"
+#include "exglobals.h"
+
+#include "chaccess.h"
+
+/***********************************************************************
+ * This procedure allows a client to change window access control.
+ */
+
+int 
+SProcXChangeWindowAccess(ClientPtr client)
+{    
+    char n;
+    REQUEST(xChangeWindowAccessReq);
+
+    swaps(&stuff->length, n);
+    swapl(&stuff->win, n);
+    return ProcXChangeWindowAccess(client);
+}
+
+int 
+ProcXChangeWindowAccess(ClientPtr client)
+{
+    int padding, err, i;
+    CARD8* deviceids = NULL;
+    WindowPtr win;
+    DeviceIntPtr* perm_devices = NULL;
+    DeviceIntPtr* deny_devices = NULL;
+    REQUEST(xChangeWindowAccessReq);
+    REQUEST_AT_LEAST_SIZE(xChangeWindowAccessReq);
+    
+
+    padding = (4 - ((stuff->npermit + stuff->ndeny) % 4)) % 4;
+
+    if (stuff->length != ((sizeof(xChangeWindowAccessReq)  + 
+            (stuff->npermit + stuff->ndeny + padding)) >> 2))
+    {
+        SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 
+                0, BadLength);
+        return Success;
+    }
+
+
+    err = dixLookupWindow(&win, stuff->win, client, DixWriteAccess);
+    if (err != Success)
+    {
+        SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 
+                          stuff->win, err);
+        return Success;
+    }
+
+    /* Are we clearing? if so, ignore the rest */
+    if (stuff->clear)
+    {
+        err = ACClearWindowAccess(client, win, stuff->clear);
+        if (err != Success)
+            SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 0, err);
+        return Success;
+    }
+
+    if (stuff->npermit || stuff->ndeny)
+        deviceids = (CARD8*)&stuff[1];
+
+    if (stuff->npermit)
+    {
+        perm_devices = 
+            (DeviceIntPtr*)xalloc(stuff->npermit * sizeof(DeviceIntPtr));
+        if (!perm_devices)
+        {
+            ErrorF("ProcXChangeWindowAccess: alloc failure.\n");
+            SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 0, 
+                    BadImplementation);
+            return Success;
+        }
+
+        /* if one of the devices cannot be accessed, we don't do anything.*/
+        for (i = 0; i < stuff->npermit; i++)
+        {
+            perm_devices[i] = LookupDeviceIntRec(deviceids[i]);
+            if (!perm_devices[i])
+            {
+                xfree(perm_devices);
+                SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 
+                        deviceids[i], BadDevice); 
+                return Success;
+            }
+        }
+    }
+
+    if (stuff->ndeny)
+    {
+        deny_devices = 
+            (DeviceIntPtr*)xalloc(stuff->ndeny * sizeof(DeviceIntPtr));
+        if (!deny_devices)
+        {
+            ErrorF("ProcXChangeWindowAccecss: alloc failure.\n");
+            SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 0, 
+                    BadImplementation);
+
+            xfree(perm_devices);
+            return Success;
+        }
+
+        for (i = 0; i < stuff->ndeny; i++)
+        {
+            deny_devices[i] = 
+                LookupDeviceIntRec(deviceids[i+stuff->npermit]);
+            
+            if (!deny_devices[i])
+            {
+                xfree(perm_devices);
+                xfree(deny_devices);
+                SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 
+                        deviceids[i + stuff->npermit], BadDevice); 
+                return Success;
+            }
+        }
+    }
+
+    err = ACChangeWindowAccess(client, win, stuff->defaultRule,
+                               perm_devices, stuff->npermit,
+                               deny_devices, stuff->ndeny);
+    if (err != Success)
+    {
+        SendErrorToClient(client, IReqCode, X_ChangeWindowAccess, 
+                          stuff->win, err);
+        return Success;
+    }
+    
+    xfree(perm_devices);
+    xfree(deny_devices);
+    return Success;
+}
+
diff --git a/Xi/chaccess.h b/Xi/chaccess.h
new file mode 100644
index 0000000..8c2c600
--- /dev/null
+++ b/Xi/chaccess.h
@@ -0,0 +1,39 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef CHACCESS_H
+#define CHACCESS_H 1
+
+int SProcXChangeWindowAccess(ClientPtr /* client */);
+int ProcXChangeWindowAccess(ClientPtr /* client */);
+
+#endif /* CHACCESS_H */
diff --git a/Xi/extinit.c b/Xi/extinit.c
index cf4f509..598348e 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -74,6 +74,7 @@ SOFTWARE.
 
 /* modules local to Xi */
 #include "allowev.h"
+#include "chaccess.h"
 #include "chdevcur.h"
 #include "chgdctl.h"
 #include "chgfctl.h"
@@ -94,12 +95,14 @@ SOFTWARE.
 #include "getselev.h"
 #include "getvers.h"
 #include "getvers.h"
+#include "grabacc.h"
 #include "grabdev.h"
 #include "grabdevb.h"
 #include "grabdevk.h"
 #include "gtmotion.h"
 #include "listdev.h"
 #include "opendev.h"
+#include "qryacces.c"
 #include "querydp.h"
 #include "queryst.h"
 #include "regpair.h"
@@ -358,6 +361,12 @@ ProcIDispatch(register ClientPtr client)
         return (ProcXChangePointerKeyboardPairing(client));
     else if (stuff->data == X_RegisterPairingClient)
         return (ProcXRegisterPairingClient(client));
+    else if (stuff->data == X_GrabAccessControl)
+        return (ProcXGrabAccessControl(client));
+    else if (stuff->data == X_ChangeWindowAccess)
+        return (ProcXChangeWindowAccess(client));
+    else if (stuff->data == X_QueryWindowAccess)
+        return ProcXQueryWindowAccess(client);
     else {
 	SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest);
     }
@@ -457,6 +466,12 @@ SProcIDispatch(register ClientPtr client
         return (SProcXChangePointerKeyboardPairing(client));
     else if (stuff->data == X_RegisterPairingClient)
         return (SProcXRegisterPairingClient(client));
+    else if (stuff->data == X_GrabAccessControl)
+        return (SProcXGrabAccessControl(client));
+    else if (stuff->data == X_ChangeWindowAccess)
+        return (SProcXChangeWindowAccess(client));
+    else if (stuff->data == X_QueryWindowAccess)
+        return SProcXQueryWindowAccess(client);
     else {
 	SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest);
     }
@@ -531,10 +546,16 @@ SReplyIDispatch(ClientPtr client, int le
 				 (xChangeDeviceControlReply *) rep);
     else if (rep->RepType == X_QueryDevicePointer)
 	SRepXQueryDevicePointer(client, len,
-				 (xQueryDevicePointerReply *) rep);
+				(xQueryDevicePointerReply *) rep);
     else if (rep->RepType == X_RegisterPairingClient)
 	SRepXRegisterPairingClient(client, len,
-				 (xRegisterPairingClientReply *) rep);
+				  (xRegisterPairingClientReply *) rep);
+    else if (rep->RepType == X_GrabAccessControl)
+        SRepXGrabAccessControl(client, len,
+                                  (xGrabAccessControlReply*) rep);
+    else if (rep->RepType == X_QueryWindowAccess)
+        SRepXQueryWindowAccess(client, len,
+                               (xQueryWindowAccessReply*) rep);
     else {
 	FatalError("XINPUT confused sending swapped reply");
     }
diff --git a/Xi/grabacc.c b/Xi/grabacc.c
new file mode 100644
index 0000000..db9c9f2
--- /dev/null
+++ b/Xi/grabacc.c
@@ -0,0 +1,102 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#define	 NEED_EVENTS
+#define	 NEED_REPLIES
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>	/* for inputstr.h    */
+#include <X11/Xproto.h>	/* Request macro     */
+#include "inputstr.h"	/* DeviceIntPtr      */
+#include "windowstr.h"	/* window structure  */
+#include "scrnintstr.h"	/* screen structure  */
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "extnsionst.h"
+#include "extinit.h"	/* LookupDeviceIntRec */
+#include "exevents.h"
+#include "exglobals.h"
+
+#include "grabacc.h"
+
+/***********************************************************************
+ *
+ * This procedure allows a client to register as the global client to control
+ * any window access.
+ *
+ */
+int
+SProcXGrabAccessControl(ClientPtr client)
+{
+    char n;
+    REQUEST(xGrabAccessControlReq);
+
+    swaps(&stuff->length, n);
+    return ProcXGrabAccessControl(client);
+}
+
+int 
+ProcXGrabAccessControl(ClientPtr client)
+{
+    xGrabAccessControlReply rep;
+    REQUEST(xGrabAccessControlReq);
+    REQUEST_SIZE_MATCH(xGrabAccessControlReq);
+
+    if (stuff->ungrab)
+        ACUnregisterClient(client);
+
+    rep.repType = X_Reply;
+    rep.RepType = X_GrabAccessControl;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.success = stuff->ungrab || ACRegisterClient(client);
+
+    WriteReplyToClient(client, sizeof(xGrabAccessControlReply), &rep);
+    return Success;
+}
+
+/***********************************************************************
+ *
+ * This procedure writes the reply for the XGrabAccessControl function,
+ * if the client and server have a different byte ordering.
+ *
+ */
+
+void
+SRepXGrabAccessControl(ClientPtr client, int size, 
+        xGrabAccessControlReply* rep)
+{
+    register char n;
+
+    swaps(&rep->sequenceNumber, n);
+    swapl(&rep->length, n);
+    WriteToClient(client, size, (char *)rep);
+}
+
diff --git a/Xi/grabacc.h b/Xi/grabacc.h
new file mode 100644
index 0000000..6dcbcad
--- /dev/null
+++ b/Xi/grabacc.h
@@ -0,0 +1,41 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef GRABACC_H
+#define GRABACC_H 1
+
+int SProcXGrabAccessControl(ClientPtr /* client */);
+
+int ProcXGrabAccessControl(ClientPtr /* client */);
+void SRepXGrabAccessControl(ClientPtr client, int size, 
+        xGrabAccessControlReply* rep);
+#endif /* GRABACC_H */
diff --git a/Xi/qryacces.c b/Xi/qryacces.c
new file mode 100644
index 0000000..817bec8
--- /dev/null
+++ b/Xi/qryacces.c
@@ -0,0 +1,128 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#define	 NEED_EVENTS
+#define	 NEED_REPLIES
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>	/* for inputstr.h    */
+#include <X11/Xproto.h>	/* Request macro     */
+#include "inputstr.h"	/* DeviceIntPtr      */
+#include "windowstr.h"	/* window structure  */
+#include "scrnintstr.h"	/* screen structure  */
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "extnsionst.h"
+#include "extinit.h"	/* LookupDeviceIntRec */
+#include "exevents.h"
+#include "exglobals.h"
+
+#include "qryacces.h"
+
+/***********************************************************************
+ * This procedure allows a client to query window access control.
+ */
+
+int
+SProcXQueryWindowAccess(ClientPtr client)
+{
+    char n;
+    REQUEST(xQueryWindowAccessReq);
+
+    swaps(&stuff->length, n);
+    swapl(&stuff->win, n);
+    return ProcXQueryWindowAccess(client);
+}
+
+int
+ProcXQueryWindowAccess(ClientPtr client)
+{
+    int err;
+    WindowPtr win;
+    DeviceIntPtr *perm, *deny;
+    int nperm, ndeny, i;
+    int defaultRule;
+    CARD8* deviceids;
+    xQueryWindowAccessReply rep;
+
+    REQUEST(xQueryWindowAccessReq);
+    REQUEST_SIZE_MATCH(xQueryWindowAccessReq);
+
+    err = dixLookupWindow(&win, stuff->win, client, DixReadAccess);
+    if (err != Success)
+    {
+        SendErrorToClient(client, IReqCode, X_QueryWindowAccess, 
+                          stuff->win, err); 
+        return Success;
+    }
+
+    ACQueryWindowAccess(win, &defaultRule, &perm, &nperm, &deny, &ndeny);
+
+    rep.repType = X_Reply;
+    rep.RepType = X_QueryWindowAccess;
+    rep.sequenceNumber = client->sequence;
+    rep.length = (nperm + ndeny + 3) >> 2;
+    rep.defaultRule = defaultRule;
+    rep.npermit = nperm;
+    rep.ndeny = ndeny;
+    WriteReplyToClient(client, sizeof(xQueryWindowAccessReply), &rep);
+
+    if (nperm + ndeny)
+    {
+        deviceids = (CARD8*)xalloc((nperm + ndeny) * sizeof(CARD8));
+        if (!deviceids)
+        {
+            ErrorF("ProcXQueryWindowAccess: xalloc failure.\n");
+            SendErrorToClient(client, IReqCode, X_QueryWindowAccess, 
+                    0, BadImplementation); 
+            return Success;
+        }
+
+        for (i = 0; i < nperm; i++)
+            deviceids[i] = perm[i]->id;
+        for (i = 0; i < ndeny; i++)
+            deviceids[i + nperm] = deny[i]->id;
+
+        WriteToClient(client, nperm + ndeny, (char*)deviceids);
+        xfree(deviceids);
+    }
+    return Success;
+}
+
+void
+SRepXQueryWindowAccess(ClientPtr client, 
+                      int size, 
+                      xQueryWindowAccessReply* rep)
+{
+    char n;
+    swaps(&rep->sequenceNumber, n);
+    swapl(&rep->length, n);
+    WriteToClient(client, size, (char*)rep);
+}
diff --git a/Xi/qryacces.h b/Xi/qryacces.h
new file mode 100644
index 0000000..5fce9ae
--- /dev/null
+++ b/Xi/qryacces.h
@@ -0,0 +1,41 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef QRYACCES_H
+#define QRYACCES_H 1
+
+int SProcXQueryWindowAccess(ClientPtr /* client */);
+int ProcXQueryWindowAccess(ClientPtr /* client */);
+void SRepXQueryWindowAccess(ClientPtr /* client */,
+                            int /* size */,
+                            xQueryWindowAccessReply* /* rep */);
+#endif
diff --git a/dix/Makefile.am b/dix/Makefile.am
index a1f02c1..d9083ea 100644
--- a/dix/Makefile.am
+++ b/dix/Makefile.am
@@ -5,6 +5,7 @@ AM_CFLAGS = $(DIX_CFLAGS) \
 	-DVENDOR_RELEASE="@VENDOR_RELEASE@"
 
 libdix_la_SOURCES = 	\
+        access.c        \
 	atom.c		\
 	colormap.c	\
 	cursor.c	\
diff --git a/dix/access.c b/dix/access.c
new file mode 100644
index 0000000..970d7c4
--- /dev/null
+++ b/dix/access.c
@@ -0,0 +1,287 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+/* This file controls the access control lists for each window. 
+ * Each device can be explicitely allowed or denied access to a given window.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XI.h>
+
+#include "input.h"
+#include "inputstr.h"
+#include "windowstr.h"
+
+
+/* Only one single client can be responsible for window access control. */
+static ClientPtr ACClient = NULL;
+
+
+/* Forward declarations */
+static void acReplaceList(DeviceIntPtr** list, 
+                          int* count, 
+                          DeviceIntPtr* devices, 
+                          int ndevices);
+
+/* Register global window access control client
+ * Return True on success or False otherwise.
+ */ 
+
+Bool
+ACRegisterClient(ClientPtr client)
+{
+    if (ACClient && ACClient != client)
+        return False;
+
+    ACClient = client;
+    return True;
+}
+
+
+/* Unregister global client. If client is not the registered client, nothing
+ * happens and False is returned. If no client is registered, return True.
+ * Returns True if client was registred and is now unregistered.
+ */ 
+
+Bool
+ACUnregisterClient(ClientPtr client)
+{
+    if (ACClient && ACClient != client)
+        return False;
+
+    ACClient = NULL;
+    return True;
+}
+
+/* Clears all access control for the window and remove the default rule,
+ * depending on what is set. */
+int ACClearWindowAccess(ClientPtr client,
+                        WindowPtr win,
+                        int what)
+{
+    if (client != ACClient && client != wClient(win))
+        return BadAccess;
+
+    if (!win->optional)
+    {
+        /* we shouldn't get here if programmers know what they're doing. 
+         * A client should not request to clear a window's access controls 
+         * if they've never been set before anyway. If they do, do nothing and
+         * let the client figure out what to do next.
+         */
+        return Success;
+    }
+
+    if (what & WindowAccessClearPerm)
+    {
+        xfree(win->optional->access.perm);
+        win->optional->access.perm = NULL;
+        win->optional->access.nperm = 0;
+    }
+
+    if (what & WindowAccessClearDeny)
+    {
+        xfree(win->optional->access.deny);
+        win->optional->access.deny = NULL;
+        win->optional->access.ndeny = 0;
+    }
+
+    if (what & WindowAccessClearRule)
+        win->optional->access.defaultRule = WindowAccessNoRule;
+
+    return Success;
+}
+
+/*
+ * Changes window access control.
+ *
+ * Returns Success or BadAccess if the client is not allowed to change
+ * anything.
+ */
+
+int
+ACChangeWindowAccess(ClientPtr client, 
+                     WindowPtr win, 
+                     int defaultRule,
+                     DeviceIntPtr* perm_devices,
+                     int nperm,
+                     DeviceIntPtr* deny_devices,
+                     int ndeny)
+{
+    if (client != ACClient && client != wClient(win))
+        return BadAccess;
+
+    if (!win->optional && !MakeWindowOptional(win))
+    {
+        ErrorF("ACChangeWindowAcccess: Failed to make window optional.\n");
+        return BadImplementation;
+    }
+
+    if (defaultRule != WindowAccessKeepRule)
+        win->optional->access.defaultRule = defaultRule;
+
+    if (nperm)
+    {
+        acReplaceList(&win->optional->access.perm, 
+                      &win->optional->access.nperm,
+                      perm_devices, nperm);
+    }
+
+    if (ndeny)
+    {
+        acReplaceList(&win->optional->access.deny, 
+                &win->optional->access.ndeny,
+                deny_devices, ndeny);
+    }
+
+    return Success;
+}
+
+static void
+acReplaceList(DeviceIntPtr** list, 
+              int* count, 
+              DeviceIntPtr* devices, 
+              int ndevices)
+{
+    xfree(*list);
+    *list = NULL;
+    *count = 0;
+
+    if (ndevices)
+    {
+        *list = 
+            xalloc(ndevices * sizeof(DeviceIntPtr*));
+        if (!*list)
+        {
+            ErrorF("ACChangeWindowAccess: out of memory\n");
+            return;
+        }
+        memcpy(*list,
+                devices, 
+                ndevices * sizeof(DeviceIntPtr));
+        *count = ndevices;
+    }
+    return;
+}
+
+/*
+ * Query the given window for the devices allowed to access a window.
+ * The caller is responsible for freeing perm and deny.
+ */
+void
+ACQueryWindowAccess(WindowPtr win, 
+                    int* defaultRule,
+                    DeviceIntPtr** perm,
+                    int* nperm,
+                    DeviceIntPtr** deny,
+                    int* ndeny)
+{
+    *defaultRule = WindowAccessNoRule;
+    *perm = NULL;
+    *nperm = 0;
+    *deny = NULL;
+    *ndeny = 0;
+
+    if (!win->optional)
+        return;
+
+    *defaultRule = win->optional->access.defaultRule;
+
+    if (win->optional->access.nperm)
+    {
+        *nperm = win->optional->access.nperm;
+        *perm = (DeviceIntPtr*)xalloc(*nperm * sizeof(DeviceIntPtr));
+        if (!*perm)
+        {
+            ErrorF("ACQuerywinAccess: xalloc failure\n");
+            return;
+        }
+        memcpy(*perm, 
+               win->optional->access.perm, 
+               *nperm * sizeof(DeviceIntPtr));
+    }
+
+    if (win->optional->access.ndeny)
+    {
+        *ndeny = win->optional->access.ndeny;
+        *deny = (DeviceIntPtr*)xalloc(*ndeny * sizeof(DeviceIntPtr));
+        if (!*deny)
+        {
+            ErrorF("ACQuerywinAccess: xalloc failure\n");
+            return;
+        }
+        memcpy(*deny, 
+               win->optional->access.deny, 
+               *ndeny * sizeof(DeviceIntPtr));
+    }
+}
+
+/*
+ * Check if the given device is allowed to send events to the window. Returns
+ * true if device is allowed or false otherwise.
+ *
+ * Checks are done in the following order until a result is found:
+ * If the device is explicitely permitted, allow.
+ * If the window has a default of DenyAll, do not allow.
+ * If the device is explicitely denied, do not allow.
+ * Check parent window. Rinse, wash, repeat.
+ * If no rule could be found, allow.
+ */
+Bool
+ACDeviceAllowed(WindowPtr win, DeviceIntPtr dev)
+{
+    int i;
+
+    if (!win) /* happens for parent of RootWindow */
+        return True;
+
+    if (!win->optional) /* no list, check parent */
+        return ACDeviceAllowed(win->parent, dev);
+
+    for (i = 0; i < win->optional->access.nperm; i++)
+    {
+        if (win->optional->access.perm[i]->id == dev->id)
+            return True;
+    }
+
+    if (win->optional->access.defaultRule == WindowAccessDenyAll)
+        return False;
+
+    for (i = 0; i < win->optional->access.ndeny; i++)
+    {
+        if (win->optional->access.deny[i]->id == dev->id)
+            return False;
+    }
+
+    return ACDeviceAllowed(win->parent, dev);
+}
+
diff --git a/dix/dispatch.c b/dix/dispatch.c
index a795d17..98183cc 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3568,6 +3568,7 @@ CloseDownClient(register ClientPtr clien
 	DeleteClientFromAnySelections(client);
 	ReleaseActiveGrabs(client);
 	DeleteClientFontStuff(client);
+        ACUnregisterClient(client);
         UnregisterPairingClient(client); /* other clients can pair devices */
 	if (!really_close_down)
 	{
diff --git a/dix/events.c b/dix/events.c
index 57a356d..5ea9a65 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1663,6 +1663,9 @@ DeliverEventsToWindow(DeviceIntPtr pDev,
     Mask deliveryMask = 0; /* If a grab occurs due to a button press, then
 		              this mask is the mask of the grab. */
     int type = pEvents->u.u.type;
+    
+    if (!ACDeviceAllowed(pWin, pDev))
+        return 0;
 
     /* CantBeFiltered means only window owner gets the event */
     if ((filter == CantBeFiltered) || !(type & EXTENSION_EVENT_BASE))
@@ -2748,16 +2751,20 @@ DeliverGrabbedEvent(register xEvent *xE,
     }
     if (!deliveries)
     {
-	FixUpEventFromWindow(thisDev, xE, grab->window, None, TRUE);
-	deliveries = TryClientEvents(rClient(grab), xE, count,
-				     (Mask)grab->eventMask,
-				     filters[xE->u.u.type], grab);
-	if (deliveries && (xE->u.u.type == MotionNotify
+        if (ACDeviceAllowed(grab->window, thisDev))
+        {
+
+            FixUpEventFromWindow(thisDev, xE, grab->window, None, TRUE);
+            deliveries = TryClientEvents(rClient(grab), xE, count,
+                    (Mask)grab->eventMask,
+                    filters[xE->u.u.type], grab);
+            if (deliveries && (xE->u.u.type == MotionNotify
 #ifdef XINPUT
-			   || xE->u.u.type == DeviceMotionNotify
+                        || xE->u.u.type == DeviceMotionNotify
 #endif
-			   ))
-	    thisDev->valuator->motionHintWindow = grab->window;
+                        ))
+                thisDev->valuator->motionHintWindow = grab->window;
+        }
     }
     if (deliveries && !deactivateGrab && (xE->u.u.type != MotionNotify
 #ifdef XINPUT
diff --git a/dix/window.c b/dix/window.c
index 604af38..3d79728 100644
--- a/dix/window.c
+++ b/dix/window.c
@@ -452,6 +452,13 @@ CreateRootWindow(ScreenPtr pScreen)
     pWin->optional->inputMasks = NULL;
     pWin->optional->deviceCursors = NULL;
 #endif
+
+    pWin->optional->access.perm = NULL;
+    pWin->optional->access.deny = NULL;
+    pWin->optional->access.nperm = 0;
+    pWin->optional->access.ndeny = 0;
+    pWin->optional->access.defaultRule = 0;
+
     pWin->optional->colormap = pScreen->defColormap;
     pWin->optional->visual = pScreen->rootVisual;
 
@@ -505,7 +512,6 @@ CreateRootWindow(ScreenPtr pScreen)
 		
     if (disableSaveUnders)
 	pScreen->saveUnderSupport = NotUseful;
-
     return TRUE;
 }
 
@@ -523,6 +529,7 @@ InitRootWindow(WindowPtr pWin)
     pWin->optional->cursor = rootCursor;
     rootCursor->refcnt++;
 
+
     if (!blackRoot && !whiteRoot) {
         MakeRootTile(pWin);
         backFlag |= CWBackPixmap;
@@ -3660,6 +3667,9 @@ CheckWindowOptionalNeed (register Window
             pNode = pNode->next;
         }
     }
+    if (optional->access.nperm != 0 ||
+            optional->access.ndeny != 0)
+        return;
 
     parentOptional = FindWindowWithOptional(w)->optional;
     if (optional->visual != parentOptional->visual)
@@ -3705,8 +3715,12 @@ MakeWindowOptional (register WindowPtr p
 #endif
 #ifdef XINPUT
     optional->inputMasks = NULL;
-    optional->deviceCursors = NULL;
 #endif
+    optional->deviceCursors = NULL;
+    optional->access.nperm = 0;
+    optional->access.ndeny = 0;
+    optional->access.perm = NULL;
+    optional->access.deny = NULL;
     parentOptional = FindWindowWithOptional(pWin)->optional;
     optional->visual = parentOptional->visual;
     if (!pWin->cursorIsNone)
@@ -3771,6 +3785,9 @@ DisposeWindowOptional (register WindowPt
         pWin->optional->deviceCursors = NULL;
     }
 
+    xfree(pWin->optional->access.perm);
+    xfree(pWin->optional->access.deny);
+
     xfree (pWin->optional);
     pWin->optional = NULL;
 }
diff --git a/include/input.h b/include/input.h
index d2e26ef..a7b1e84 100644
--- a/include/input.h
+++ b/include/input.h
@@ -445,6 +445,37 @@ extern void SwitchCorePointer(DeviceIntP
 extern DeviceIntPtr LookupDeviceIntRec(
     CARD8 deviceid);
 
+/* Pairing input devices */
+extern int PairDevices(ClientPtr client, 
+                       DeviceIntPtr pointer, 
+                       DeviceIntPtr keyboard);
+
+extern Bool RegisterPairingClient(ClientPtr client);
+extern Bool UnregisterPairingClient(ClientPtr client);
+
+/* Window/device based access control */
+extern Bool ACRegisterClient(ClientPtr client);
+extern Bool ACUnregisterClient(ClientPtr client);
+extern int ACClearWindowAccess(ClientPtr client,
+                        WindowPtr win,
+                        int what);
+extern int ACChangeWindowAccess(ClientPtr client, 
+                                WindowPtr win, 
+                                int defaultRule,
+                                DeviceIntPtr* perm_devices,
+                                int npermit,
+                                DeviceIntPtr* deny_devices,
+                                int ndeny);
+extern void ACQueryWindowAccess(WindowPtr win, 
+                                int* defaultRule,
+                                DeviceIntPtr** perm,
+                                int* nperm,
+                                DeviceIntPtr** deny,
+                                int* ndeny);
+
+extern Bool ACDeviceAllowed(WindowPtr win, 
+                            DeviceIntPtr dev);
+
 /* Implemented by the DDX. */
 extern int NewInputDeviceRequest(
     InputOption *options);
@@ -454,11 +485,4 @@ extern void DDXRingBell(
     int pitch,
     int duration);
 
-extern int PairDevices(ClientPtr client, 
-                       DeviceIntPtr pointer, 
-                       DeviceIntPtr keyboard);
-
-extern Bool RegisterPairingClient(ClientPtr client);
-extern Bool UnregisterPairingClient(ClientPtr client);
-
 #endif /* INPUT_H */
diff --git a/include/windowstr.h b/include/windowstr.h
index 4e9c82c..882f8a5 100644
--- a/include/windowstr.h
+++ b/include/windowstr.h
@@ -77,6 +77,14 @@ typedef struct _DevCursorNode {
     struct _DevCursorNode*      next;
 } DevCursNodeRec, *DevCursNodePtr, *DevCursorList;
 
+typedef struct _WindowAccessRec {
+    int                  defaultRule;      /* WindowAccessDenyAll */
+    DeviceIntPtr*        perm;
+    int                  nperm;
+    DeviceIntPtr*        deny;
+    int                  ndeny;
+} WindowAccessRec, *WindowAccessPtr;
+
 typedef struct _WindowOpt {
     VisualID		visual;		   /* default: same as parent */
     CursorPtr		cursor;		   /* default: window.cursorNone */
@@ -97,6 +105,7 @@ typedef struct _WindowOpt {
     struct _OtherInputMasks *inputMasks;   /* default: NULL */
 #endif
     DevCursorList       deviceCursors;     /* default: NULL */
+    WindowAccessRec     access;
 } WindowOptRec, *WindowOptPtr;
 
 #define BackgroundPixel	    2L
diff-tree cd0af7a7856e8246e27acc5513d219a094211625 (from f6c3b9fa97ccf85e96f15435d564a1c261e40532)
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Feb 21 10:08:41 2007 +1030

    Xi, dix: Only one client at a time can change the pointer-keyboard pairing,
             using xRegisterPairingClient request.

diff --git a/Xi/Makefile.am b/Xi/Makefile.am
index 9000030..5d3417e 100644
--- a/Xi/Makefile.am
+++ b/Xi/Makefile.am
@@ -62,6 +62,8 @@ libXi_la_SOURCES =	\
 	querydp.h \
 	queryst.c \
 	queryst.h \
+	regpair.c \
+	regpair.h \
 	selectev.c \
 	selectev.h \
 	sendexev.c \
diff --git a/Xi/chpkpair.c b/Xi/chpkpair.c
index b862417..8e79a75 100644
--- a/Xi/chpkpair.c
+++ b/Xi/chpkpair.c
@@ -73,10 +73,13 @@ int
 ProcXChangePointerKeyboardPairing(register ClientPtr client)
 {
     DeviceIntPtr pPointer, pKeyboard;
+    int ret;
 
     REQUEST(xChangePointerKeyboardPairingReq);
     REQUEST_SIZE_MATCH(xChangePointerKeyboardPairingReq);
 
+    /* check if client is registered */
+
     pPointer = LookupDeviceIntRec(stuff->pointer);
     if (pPointer == NULL)
     {
@@ -93,7 +96,14 @@ ProcXChangePointerKeyboardPairing(regist
         return Success;
     }
 
-    pKeyboard->pSprite = pPointer->pSprite;
+    ret = PairDevices(client, pPointer, pKeyboard);
+    if (ret != Success)
+    {
+        SendErrorToClient(client, IReqCode, X_ChangePointerKeyboardPairing,
+                0, ret);
+        return Success;
+    }
+
 
     /* TODO: generate event here... */
     return Success;
diff --git a/Xi/extinit.c b/Xi/extinit.c
index a08ec77..cf4f509 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -102,6 +102,7 @@ SOFTWARE.
 #include "opendev.h"
 #include "querydp.h"
 #include "queryst.h"
+#include "regpair.h"
 #include "selectev.h"
 #include "sendexev.h"
 #include "chgkmap.h"
@@ -355,6 +356,8 @@ ProcIDispatch(register ClientPtr client)
         return (ProcXChangeDeviceCursor(client));
     else if (stuff->data == X_ChangePointerKeyboardPairing)
         return (ProcXChangePointerKeyboardPairing(client));
+    else if (stuff->data == X_RegisterPairingClient)
+        return (ProcXRegisterPairingClient(client));
     else {
 	SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest);
     }
@@ -452,6 +455,8 @@ SProcIDispatch(register ClientPtr client
         return (SProcXChangeDeviceCursor(client));
     else if (stuff->data == X_ChangePointerKeyboardPairing)
         return (SProcXChangePointerKeyboardPairing(client));
+    else if (stuff->data == X_RegisterPairingClient)
+        return (SProcXRegisterPairingClient(client));
     else {
 	SendErrorToClient(client, IReqCode, stuff->data, 0, BadRequest);
     }
@@ -527,6 +532,9 @@ SReplyIDispatch(ClientPtr client, int le
     else if (rep->RepType == X_QueryDevicePointer)
 	SRepXQueryDevicePointer(client, len,
 				 (xQueryDevicePointerReply *) rep);
+    else if (rep->RepType == X_RegisterPairingClient)
+	SRepXRegisterPairingClient(client, len,
+				 (xRegisterPairingClientReply *) rep);
     else {
 	FatalError("XINPUT confused sending swapped reply");
     }
diff --git a/Xi/regpair.c b/Xi/regpair.c
new file mode 100644
index 0000000..cfaddb8
--- /dev/null
+++ b/Xi/regpair.c
@@ -0,0 +1,108 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+/***********************************************************************
+ *
+ * Request to authenticate as pairing client
+ *
+ */
+
+#define	 NEED_EVENTS
+#define	 NEED_REPLIES
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>	/* for inputstr.h    */
+#include <X11/Xproto.h>	/* Request macro     */
+#include "inputstr.h"	/* DeviceIntPtr      */
+#include "windowstr.h"	/* window structure  */
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "extnsionst.h"
+#include "exevents.h"
+#include "exglobals.h"
+
+#include "regpair.h"
+
+/***********************************************************************
+ *
+ * This procedure allows a client to register the pairing of a pointer 
+ * with a keyboard.
+ *
+ */
+
+int 
+SProcXRegisterPairingClient(ClientPtr client)
+{
+    char n;
+    REQUEST(xRegisterPairingClientReq);
+    swaps(&stuff->length, n);
+    return ProcXRegisterPairingClient(client);
+}
+
+int 
+ProcXRegisterPairingClient(ClientPtr client)
+{
+    xRegisterPairingClientReply rep;
+
+    REQUEST(xRegisterPairingClientReq);
+    REQUEST_SIZE_MATCH(xRegisterPairingClientReq);
+
+    if (stuff->disable)
+        UnregisterPairingClient(client);
+
+    rep.repType = X_Reply;
+    rep.RepType = X_RegisterPairingClient;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.success = stuff->disable || RegisterPairingClient(client);
+
+    WriteReplyToClient(client, sizeof(xRegisterPairingClientReply), &rep);
+    return Success;
+}
+
+/***********************************************************************
+ *
+ * This procedure writes the reply for the XRegisterPairingClient function,
+ * if the client and server have a different byte ordering.
+ *
+ */
+
+void
+SRepXRegisterPairingClient(ClientPtr client, int size, 
+        xRegisterPairingClientReply* rep)
+{
+    register char n;
+
+    swaps(&rep->sequenceNumber, n);
+    swapl(&rep->length, n);
+    WriteToClient(client, size, (char *)rep);
+}
+
diff --git a/Xi/regpair.h b/Xi/regpair.h
new file mode 100644
index 0000000..b2bfaff
--- /dev/null
+++ b/Xi/regpair.h
@@ -0,0 +1,43 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef REGPAIR_H
+#define REGPAIR_H 1
+
+int SProcXRegisterPairingClient(ClientPtr /* client */);
+int ProcXRegisterPairingClient(ClientPtr /* client */);
+
+void SRepXRegisterPairingClient(ClientPtr /* client */, 
+                                int /* size */,
+                                xRegisterPairingClientReply* /* rep */);
+
+#endif /* REGPAIR_H */
diff --git a/dix/devices.c b/dix/devices.c
index bc7ca89..ad5cd50 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -81,6 +81,9 @@ SOFTWARE.
 
 int CoreDevicePrivatesIndex = 0, CoreDevicePrivatesGeneration = -1;
 
+/* The client that is allowed to change pointer-keyboard pairings. */
+static ClientPtr pairingClient = NULL;
+
 DeviceIntPtr
 AddInputDevice(DeviceProc deviceProc, Bool autoStart)
 {
@@ -1926,5 +1929,54 @@ ProcQueryKeymap(ClientPtr client)
 	bzero((char *)&rep.map[0], 32);
 
     WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep);
+ 
+   return Success;
+}
+
+/* Pair the keyboard to the pointer device. Keyboard events will follow the
+ * pointer sprite. 
+ */
+int 
+PairDevices(ClientPtr client, DeviceIntPtr pointer, DeviceIntPtr keyboard)
+{
+    if (!pairingClient)
+        RegisterPairingClient(client);
+    else if (pairingClient != client)
+        return BadAccess;
+
+    keyboard->pSprite = pointer->pSprite;
     return Success;
 }
+
+/*
+ * Register a client to be able to pair devices. 
+ */
+Bool
+RegisterPairingClient(ClientPtr client)
+{
+    if (!pairingClient)
+    {
+        pairingClient = client;
+    } else if (pairingClient != client)
+    {
+        return False;
+    }
+    return True;
+}
+
+/*
+ * Unregister pairing client;
+ */
+Bool 
+UnregisterPairingClient(ClientPtr client)
+{
+    if (pairingClient) 
+    {
+        if ( pairingClient == client)
+        {
+            pairingClient = NULL;
+        } else 
+            return False;
+    }
+    return True;
+}
diff --git a/dix/dispatch.c b/dix/dispatch.c
index d44687e..a795d17 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3568,6 +3568,7 @@ CloseDownClient(register ClientPtr clien
 	DeleteClientFromAnySelections(client);
 	ReleaseActiveGrabs(client);
 	DeleteClientFontStuff(client);
+        UnregisterPairingClient(client); /* other clients can pair devices */
 	if (!really_close_down)
 	{
 	    /*  This frees resources that should never be retained
diff --git a/include/input.h b/include/input.h
index 96a28a5..d2e26ef 100644
--- a/include/input.h
+++ b/include/input.h
@@ -454,4 +454,11 @@ extern void DDXRingBell(
     int pitch,
     int duration);
 
+extern int PairDevices(ClientPtr client, 
+                       DeviceIntPtr pointer, 
+                       DeviceIntPtr keyboard);
+
+extern Bool RegisterPairingClient(ClientPtr client);
+extern Bool UnregisterPairingClient(ClientPtr client);
+
 #endif /* INPUT_H */



More information about the xorg-commit mailing list