Sophie

Sophie

distrib > Mandriva > 2007.1 > x86_64 > by-pkgid > e9d7306cbb3d13290c9b1281bcbf9c3a > files > 6

x11-server-1.2.0-9.1mdv2007.1.src.rpm

diff -u -rNp a/configure.ac b/configure.ac
--- a/configure.ac	2007-01-18 09:28:15.000000000 +0000
+++ b/configure.ac	2007-01-18 09:29:34.000000000 +0000
@@ -431,7 +431,13 @@ AC_ARG_ENABLE(xfree86-utils,     AS_HELP
 
 dnl DDXes.
 AC_ARG_ENABLE(xorg,    	      AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto])
+AC_ARG_ENABLE(xorg_vnc,       AS_HELP_STRING([--enable-xorg-vnc], [Build vnc module for Xorg (default: no)]), [XORG_VNC=$enableval], [XORG_VNC=no])
 AC_ARG_ENABLE(dmx,    	      AS_HELP_STRING([--enable-dmx], [Build DMX server (default: auto)]), [DMX=$enableval], [DMX=auto])
+AC_ARG_ENABLE(xdmx_vnc,       AS_HELP_STRING([--enable-xdmx-vnc], [Enable VNC support for Xdmx (default: no)]), [XDMX_VNC=$enableval], [XDMX_VNC=no])
+
+AC_ARG_ENABLE(xcliplist,      AS_HELP_STRING([--enable-xcliplist], [Build XClipList extension (default: auto)]), [XCLIPLIST=$enableval], [XCLIPLIST=auto])
+AC_ARG_ENABLE(xvnc,    	      AS_HELP_STRING([--enable-xvnc], [Build Xvnc server (default: no)]), [XVNC=$enableval], [XVNC=no])
+
 AC_ARG_ENABLE(xvfb,    	      AS_HELP_STRING([--enable-xvfb], [Build Xvfb server (default: yes)]), [XVFB=$enableval], [XVFB=yes])
 AC_ARG_ENABLE(xnest,   	      AS_HELP_STRING([--enable-xnest], [Build Xnest server (default: auto)]), [XNEST=$enableval], [XNEST=auto])
 AC_ARG_ENABLE(xwin,    	      AS_HELP_STRING([--enable-xwin], [Build XWin server (default: auto)]), [XWIN=$enableval], [XWIN=auto])
@@ -764,6 +770,20 @@ if test "x$XINPUT" = xyes; then
 	XI_INC='-I$(top_srcdir)/Xi'
 fi
 
+if test "x$XCLIPLIST" = xauto; then
+	if test "x$XORG" = xno; then
+		XCLIPLIST=no
+	else
+		PKG_CHECK_MODULES([XCLIPLIST], [xcliplistproto xcliplist], [XCLIPLIST=yes], [XCLIPLIST=no])
+	fi
+fi
+AM_CONDITIONAL(XCLIPLIST, [test "x$XCLIPLIST" = xyes])
+if test "x$XCLIPLIST" = xyes; then
+	AC_DEFINE(XCLIPLIST, 1, [Support XClipList extension])
+	REQUIRED_MODULES="$REQUIRED_MODULES xcliplistproto"
+	XCLIPLIST_LIB='$(top_builddir)/xcliplist/libxcliplist.la'
+fi
+
 AM_CONDITIONAL(XF86UTILS, test "x$XF86UTILS" = xyes)
 
 AC_DEFINE(SHAPE, 1, [Support SHAPE extension])
@@ -877,6 +897,8 @@ MI_EXT_LIB='$(top_builddir)/mi/libmiext.
 MI_INC='-I$(top_srcdir)/mi'
 FB_LIB='$(top_builddir)/fb/libfb.la'
 FB_INC='-I$(top_srcdir)/fb'
+MFB_LIB='$(top_builddir)/mfb/libmfb.la'
+MFB_INC='-I$(top_srcdir)/mfb'
 MIEXT_SHADOW_INC='-I$(top_srcdir)/miext/shadow'
 MIEXT_SHADOW_LIB='$(top_builddir)/miext/shadow/libshadow.la'
 XPSTUBS_LIB='$(top_builddir)/dix/libxpstubs.la'
@@ -995,6 +1017,72 @@ AM_CONDITIONAL([DMX_BUILD_LNX], [test "x
 AM_CONDITIONAL([DMX_BUILD_USB], [test "x$DMX_BUILD_USB" = xyes])
 
 
+
+dnl VNC DDX
+
+AC_MSG_CHECKING([whether to build Xvnc DDX])
+PKG_CHECK_MODULES([VNCMODULES], [xmuu xext x11 xrender xfont xi vncproto xau $XDMCP_MODULES], [have_vnc=yes], [have_vnc=no])
+if test "x$XVNC" = xauto; then
+	XVNC="$have_vnc"
+fi
+AC_MSG_RESULT([$XVNC])
+AM_CONDITIONAL(XVNC, [test "x$XVNC" = xyes])
+
+if test "x$XVNC" = xyes; then
+	if test "x$have_vnc" = xno; then
+		AC_MSG_ERROR([Xvnc build explicitly requested, but required
+		              modules not found.])
+	fi
+	XVNC_CFLAGS="-DVNCSERVER -DHAVE_XVNC_CONFIG_H"
+	AC_SUBST([XVNC_CFLAGS])
+	VNC_INCLUDES="$XEXT_INC $RENDER_INC $XTRAP_INC $RECORD_INC"
+	XVNC_LIBS="$GLX_LIBS $MFB_LIB $FB_LIB $MI_LIB $XEXT_LIB $RENDER_LIB $XTRAP_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $OS_LIB $CWRAP_LIB"
+	AC_SUBST([XVNC_LIBS])
+
+	if test "x$GLX" = xyes; then
+		PKG_CHECK_MODULES([GL], [glproto])
+	fi
+	PKG_CHECK_MODULES([XVNCCONFIG_DEP], [xaw7 xmu xt xpm x11])
+	AC_SUBST(XVNCCONFIG_DEP_CFLAGS)
+	AC_SUBST(XVNCCONFIG_DEP_LIBS)
+fi
+
+
+dnl Xorg VNC module
+
+AC_MSG_CHECKING([whether to build Xorg VNC module])
+
+if test "x$XORG_VNC" = xauto; then
+	XORG_VNC="$have_vnc"
+fi
+AC_MSG_RESULT([$XORG_VNC])
+AM_CONDITIONAL(XORG_VNC, [test "x$XORG_VNC" = xyes])
+
+if test "x$XORG_VNC" = xyes; then
+	if test "x$have_vnc" = xno; then
+		AC_MSG_ERROR([VNC module build explicitly requested, but required
+		              modules not found.])
+	fi
+fi
+
+
+dnl VNC support for Xdmx
+AC_MSG_CHECKING([whether to build Xdmx VNC support])
+
+if test "x$XDMX_VNC" = xauto; then
+	XDMX_VNC="$have_vnc"
+fi
+AC_MSG_RESULT([$XDMX_VNC])
+AM_CONDITIONAL(XDMX_VNC, [test "x$XDMX_VNC" = xyes])
+
+if test "x$XDMX_VNC" = xyes; then
+	if test "x$have_vnc" = xno; then
+		AC_MSG_ERROR([VNC support for Xdmx explicitly requested, but required
+		              modules not found.])
+	fi
+fi
+
+
 dnl Xvfb DDX
 
 AC_MSG_CHECKING([whether to build Xvfb DDX])
@@ -1370,7 +1458,7 @@ AM_CONDITIONAL([LINUX_ALPHA], [test "x$l
 AM_CONDITIONAL([LNXACPI], [test "x$linux_acpi" = xyes])
 AM_CONDITIONAL([SOLARIS_USL_CONSOLE], [test "x$solaris_usl_console" = xyes])
 AM_CONDITIONAL([SOLARIS_ASM_INLINE], [test "x$solaris_asm_inline" = xyes])
-AM_CONDITIONAL(MFB, [test "x$XORG" = xyes])
+AM_CONDITIONAL(MFB, [test "x$XORG" = xyes || test "x$XVNC" = xyes])
 AM_CONDITIONAL(CFB, [test "x$XORG" = xyes])
 AM_CONDITIONAL(AFB, [test "x$XORG" = xyes])
 
@@ -1737,6 +1825,7 @@ Xext/Makefile
 Xi/Makefile
 xfixes/Makefile
 exa/Makefile
+xcliplist/Makefile
 hw/Makefile
 hw/xfree86/Makefile
 hw/xfree86/common/Makefile
@@ -1773,6 +1862,7 @@ hw/xfree86/scanpci/Makefile
 hw/xfree86/shadowfb/Makefile
 hw/xfree86/vbe/Makefile
 hw/xfree86/vgahw/Makefile
+hw/xfree86/vnc/Makefile
 hw/xfree86/x86emu/Makefile
 hw/xfree86/xaa/Makefile
 hw/xfree86/xf1bpp/Makefile
@@ -1793,8 +1883,10 @@ hw/dmx/doc/Makefile
 hw/dmx/examples/Makefile
 hw/dmx/input/Makefile
 hw/dmx/glxProxy/Makefile
+hw/dmx/vnc/Makefile
 hw/dmx/Makefile
 hw/vfb/Makefile
+hw/vnc/Makefile
 hw/xgl/Makefile
 hw/xgl/egl/Makefile
 hw/xgl/egl/module/Makefile
diff -u -rNp a/fb/fbcmap.c b/fb/fbcmap.c
--- a/fb/fbcmap.c	2006-12-01 16:15:53.000000000 +0000
+++ b/fb/fbcmap.c	2007-01-18 09:29:34.000000000 +0000
@@ -39,7 +39,7 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "resource.h"
 #include "fb.h"
 
-#ifndef XFree86Server
+#if !defined(XFree86Server) && !defined(VNCSERVER)
 ColormapPtr FbInstalledMaps[MAXSCREENS];
 
 int
diff -u -rNp a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c
--- a/hw/dmx/dmxinit.c	2006-12-01 16:15:54.000000000 +0000
+++ b/hw/dmx/dmxinit.c	2007-01-18 09:29:34.000000000 +0000
@@ -78,6 +78,10 @@ extern void GlxSetVisualConfigs(
 );
 #endif /* GLXEXT */
 
+#ifdef DMXVNC
+extern void VNCInit2(void);
+#endif
+
 /* Global variables available to all Xserver/hw/dmx routines. */
 int             dmxNumScreens;
 DMXScreenInfo  *dmxScreens;
@@ -813,6 +817,9 @@ void InitOutput(ScreenInfo *pScreenInfo,
 
     dmxLog(dmxInfo, "Shadow framebuffer support %s\n",
 	   dmxShadowFB ? "enabled" : "disabled");
+#ifdef DMXVNC
+    VNCInit2();
+#endif
 }
 
 /* RATS: Assuming the fp string (which comes from the command-line argv
diff -u -rNp a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c
--- a/hw/dmx/dmxsync.c	2006-12-01 16:15:54.000000000 +0000
+++ b/hw/dmx/dmxsync.c	2007-01-18 09:29:34.000000000 +0000
@@ -103,6 +103,10 @@ static void dmxSyncBlockHandler(pointer 
 static void dmxSyncWakeupHandler(pointer blockData, int result,
                                  pointer pReadMask)
 {
+#ifdef DMXVNC
+   extern void rfbWakeupHandler2(void);
+   rfbWakeupHandler2();
+#endif
 }
 
 /** Request the XSync() batching optimization with the specified \a
diff -u -rNp a/hw/dmx/input/dmxinputinit.c b/hw/dmx/input/dmxinputinit.c
--- a/hw/dmx/input/dmxinputinit.c	2006-12-01 16:15:54.000000000 +0000
+++ b/hw/dmx/input/dmxinputinit.c	2007-01-18 09:29:34.000000000 +0000
@@ -342,6 +342,13 @@ static int dmxKeyboardOn(DeviceIntPtr pD
     DevicePtr pDev = &pDevice->public;
 #endif
 
+#ifdef DMXVNC
+    {
+        extern void vncSetKeyboardDevice(DeviceIntPtr kbd);
+        vncSetKeyboardDevice(pDevice);
+    }
+#endif
+
 #ifdef XKB
     if (noXkbExtension) {
 #endif
diff -u -rNp a/hw/dmx/input/Makefile.am b/hw/dmx/input/Makefile.am
--- a/hw/dmx/input/Makefile.am	2006-12-01 22:48:41.000000000 +0000
+++ b/hw/dmx/input/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -68,4 +68,8 @@ AM_CFLAGS = \
             $(GLX_DEFS) \
             @DMXMODULES_CFLAGS@
 
+if XDMX_VNC
+AM_CFLAGS += -DDMXVNC=1
+endif
+
 EXTRA_DIST = dmxdetach.c
diff -u -rNp a/hw/dmx/Makefile.am b/hw/dmx/Makefile.am
--- a/hw/dmx/Makefile.am	2006-12-01 16:15:54.000000000 +0000
+++ b/hw/dmx/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -1,6 +1,9 @@
-DIST_SUBDIRS = input config glxProxy examples doc
+DIST_SUBDIRS = input vnc config glxProxy examples doc
 
-SUBDIRS = input config examples
+if XDMX_VNC
+DMXVNC_SUBDIR = vnc
+endif
+SUBDIRS = input $(DMXVNC_SUBDIR) config examples
 bin_PROGRAMS = Xdmx
 
 if XINERAMA
@@ -92,6 +95,13 @@ Xdmx_CFLAGS = \
               $(DMX_CFLAGS) \
               @DMXMODULES_CFLAGS@
 
+if XDMX_VNC
+Xdmx_LDADD += vnc/libdmxvnc.a \
+              -ljpeg -lcrypt
+Xdmx_CFLAGS += $(DIX_CFLAGS) \
+               -DDMXVNC=1
+endif
+
 # Man page
 appmandir = $(APP_MAN_DIR)
 
diff -u -rNp a/hw/dmx/vnc/auth.c b/hw/dmx/vnc/auth.c
--- a/hw/dmx/vnc/auth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/auth.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,562 @@
+/*
+ * auth.c - deal with authentication.
+ *
+ * This file implements authentication when setting up an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003-2004 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include "rfb.h"
+#include "windowstr.h"
+
+static void rfbSendSecurityType(rfbClientPtr cl, int securityType);
+static void rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType);
+static void rfbSendTunnelingCaps(rfbClientPtr cl);
+static void rfbSendAuthCaps(rfbClientPtr cl);
+static void rfbVncAuthSendChallenge(rfbClientPtr cl);
+
+/*
+ * rfbAuthNewClient is called right after negotiating the protocol
+ * version. Depending on the protocol version, we send either a code
+ * for authentication scheme to be used (protocol 3.3), or a list of
+ * possible "security types" (protocol 3.7).
+ */
+
+void
+rfbAuthNewClient(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int securityType = rfbSecTypeInvalid;
+ 
+    if ((!pVNC->rfbAuthPasswdFile && !pVNC->loginAuthEnabled) || cl->reverseConnection) {
+	securityType = rfbSecTypeNone;
+    } else {
+	if (rfbAuthIsBlocked(cl)) {
+	    rfbLog("Too many authentication failures - client rejected\n");
+	    rfbClientConnFailed(cl, "Too many authentication failures");
+	    return;
+	}
+	if (pVNC->rfbAuthPasswdFile)
+	    securityType = rfbSecTypeVncAuth;
+    }
+ 
+    if (cl->protocol_minor_ver < 7) {
+	/* Make sure we use only RFB 3.3 compatible security types. */
+	if (securityType == rfbSecTypeInvalid) {
+	    rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
+	    rfbClientConnFailed(cl, "Your viewer cannot handle required "
+				"authentication methods");
+	    return;
+	}
+	rfbSendSecurityType(cl, securityType);
+    } else {
+	/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
+	rfbSendSecurityTypeList(cl, securityType);
+    }
+}
+ 
+
+/*
+ * Tell the client what security type will be used (protocol 3.3).
+ */
+
+static void
+rfbSendSecurityType(cl, securityType)
+    rfbClientPtr cl;
+    int securityType;
+{
+    CARD32 value32;
+
+    /* Send the value. */
+    value32 = Swap32IfLE(securityType);
+    if (WriteExact(cl->sock, (char *)&value32, 4) < 0) {
+	rfbLogPerror("rfbSendSecurityType: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Decide what to do next. */
+    switch (securityType) {
+    case rfbSecTypeNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbSecTypeVncAuth:
+	/* Begin the standard VNC authentication procedure. */
+	rfbVncAuthSendChallenge(cl);
+	break;
+    default:
+	/* Impossible case (hopefully). */
+	rfbLogPerror("rfbSendSecurityType: assertion failed");
+	rfbCloseSock(cl->pScreen, cl->sock);
+    }
+}
+
+
+/*
+ * Advertise our supported security types (protocol 3.7). The list
+ * will include one standard security type (if primaryType is not set
+ * to rfbSecTypeInvalid), and then one more value telling the client
+ * that we support TightVNC protocol extensions. Thus, currently,
+ * there will be either 1 or 2 items in the list.
+ */
+
+static void
+rfbSendSecurityTypeList(cl, primaryType)
+    rfbClientPtr cl;
+    int primaryType;
+{
+    int count = 1;
+
+    /* Fill in the list of security types in the client structure. */
+    if (primaryType != rfbSecTypeInvalid) {
+	cl->securityTypes[count++] = (CARD8)primaryType;
+    }
+    cl->securityTypes[count] = (CARD8)rfbSecTypeTight;
+    cl->securityTypes[0] = (CARD8)count++;
+
+    /* Send the list. */
+    if (WriteExact(cl->sock, (char *)cl->securityTypes, count) < 0) {
+	rfbLogPerror("rfbSendSecurityTypeList: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientSecurityType. */
+    cl->state = RFB_SECURITY_TYPE;
+}
+
+
+/*
+ * Read the security type chosen by the client (protocol 3.7).
+ */
+
+void
+rfbProcessClientSecurityType(cl)
+    rfbClientPtr cl;
+{
+    int n, count, i;
+    CARD8 chosenType;
+
+    /* Read the security type. */
+    n = ReadExact(cl->sock, (char *)&chosenType, 1);
+    if (n <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientSecurityType: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientSecurityType: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Make sure it was present in the list sent by the server. */
+    count = (int)cl->securityTypes[0];
+    for (i = 1; i <= count; i++) {
+	if (chosenType == cl->securityTypes[i])
+	    break;
+    }
+    if (i > count) {
+	rfbLog("rfbProcessClientSecurityType: "
+	       "wrong security type requested\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Now go to the proper authentication procedure. */
+    switch (chosenType) {
+    case rfbSecTypeNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbSecTypeVncAuth:
+	/* Begin the standard VNC authentication procedure. */
+	rfbVncAuthSendChallenge(cl);
+	break;
+    case rfbSecTypeTight:
+	/* We are lucky: the viewer supports TightVNC extensions. */
+	rfbLog("Enabling TightVNC protocol extensions\n");
+	/* Switch to the protocol 3.7t. */
+	cl->protocol_tightvnc = TRUE;
+	/* Advertise our tunneling capabilities. */
+	rfbSendTunnelingCaps(cl);
+	break;
+    default:
+	/* Impossible case (hopefully). */
+	rfbLog("rfbProcessClientSecurityType: "
+	       "unknown authentication scheme\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+    }
+}
+
+
+/*
+ * Send the list of our tunneling capabilities (protocol 3.7t).
+ */
+
+static void
+rfbSendTunnelingCaps(cl)
+    rfbClientPtr cl;
+{
+    rfbTunnelingCapsMsg caps;
+    CARD32 nTypes = 0;		/* we don't support tunneling yet */
+
+    caps.nTunnelTypes = Swap32IfLE(nTypes);
+    if (WriteExact(cl->sock, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) {
+	rfbLogPerror("rfbSendTunnelingCaps: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    if (nTypes) {
+	/* Dispatch client input to rfbProcessClientTunnelingType(). */
+	cl->state = RFB_TUNNELING_TYPE;
+    } else {
+	rfbSendAuthCaps(cl);
+    }
+}
+
+
+/*
+ * Read tunneling type requested by the client (protocol 3.7t).
+ * NOTE: Currently, we don't support tunneling, and this function
+ *       can never be called.
+ */
+
+void
+rfbProcessClientTunnelingType(cl)
+    rfbClientPtr cl;
+{
+    /* If we were called, then something's really wrong. */
+    rfbLog("rfbProcessClientTunnelingType: not implemented\n");
+    rfbCloseSock(cl->pScreen, cl->sock);
+    return;
+}
+
+
+/*
+ * Send the list of our authentication capabilities to the client
+ * (protocol 3.7t).
+ */
+
+static void
+rfbSendAuthCaps(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    Bool authRequired;
+    rfbAuthenticationCapsMsg caps;
+    rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
+    int count = 0;
+
+    authRequired = ((pVNC->rfbAuthPasswdFile != NULL || pVNC->loginAuthEnabled) &&
+		    !cl->reverseConnection);
+
+    if (authRequired) {
+	if (pVNC->loginAuthEnabled) {
+	    SetCapInfo(&caplist[count], rfbAuthUnixLogin, rfbTightVncVendor);
+	    cl->authCaps[count++] = rfbAuthUnixLogin;
+	}
+	if (pVNC->rfbAuthPasswdFile != NULL) {
+	    SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
+	    cl->authCaps[count++] = rfbAuthVNC;
+	}
+	if (count == 0) {
+	    /* Should never happen. */
+	    rfbLog("rfbSendAuthCaps: assertion failed\n");
+     	    rfbCloseSock(cl->pScreen, cl->sock);
+ 	    return;
+ 	}
+    }
+ 
+    cl->nAuthCaps = count;
+    caps.nAuthTypes = Swap32IfLE((CARD32)count);
+    if (WriteExact(cl->sock, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
+	rfbLogPerror("rfbSendAuthCaps: write");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+ 
+    if (count) {
+	if (WriteExact(cl->sock, (char *)&caplist[0],
+		       count * sz_rfbCapabilityInfo) < 0) {
+	    rfbLogPerror("rfbSendAuthCaps: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+	/* Dispatch client input to rfbProcessClientAuthType. */
+	cl->state = RFB_AUTH_TYPE;
+     } else {
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+    }
+}
+ 
+
+/*
+ * Read client's preferred authentication type (protocol 3.7t).
+ */
+
+void
+rfbProcessClientAuthType(cl)
+    rfbClientPtr cl;
+{
+    CARD32 auth_type;
+    int n, i;
+
+    /* Read authentication type selected by the client. */
+    n = ReadExact(cl->sock, (char *)&auth_type, sizeof(auth_type));
+    if (n <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientAuthType: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientAuthType: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    auth_type = Swap32IfLE(auth_type);
+
+    /* Make sure it was present in the list sent by the server. */
+    for (i = 0; i < cl->nAuthCaps; i++) {
+	if (auth_type == cl->authCaps[i])
+	    break;
+    }
+    if (i >= cl->nAuthCaps) {
+	rfbLog("rfbProcessClientAuthType: "
+	       "wrong authentication type requested\n");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    switch (auth_type) {
+    case rfbAuthNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+ 	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbAuthVNC:
+	rfbVncAuthSendChallenge(cl);
+	break;
+    case rfbAuthUnixLogin:
+	/* FIXME: Do (cl->state = RFB_LOGIN_AUTH) instead? */
+	rfbLoginAuthProcessClientMessage(cl);
+	break;
+    default:
+	rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+     }
+}
+ 
+
+/*
+ * Send the authentication challenge.
+ */
+
+static void
+rfbVncAuthSendChallenge(cl)
+    rfbClientPtr cl;
+{
+    vncRandomBytes(cl->authChallenge);
+    if (WriteExact(cl->sock, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
+	rfbLogPerror("rfbVncAuthSendChallenge: write");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+ 	return;
+     }
+
+    /* Dispatch client input to rfbVncAuthProcessResponse. */
+    cl->state = RFB_AUTHENTICATION;
+}
+
+/*
+ * rfbVncAuthProcessResponse is called when the client sends its
+ * authentication response.
+ */
+
+void
+rfbVncAuthProcessResponse(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    char passwdFullControl[9];
+    char passwdViewOnly[9];
+    int numPasswords;
+    Bool ok;
+    int n;
+    CARD8 encryptedChallenge1[CHALLENGESIZE];
+    CARD8 encryptedChallenge2[CHALLENGESIZE];
+    CARD8 response[CHALLENGESIZE];
+    CARD32 authResult;
+
+    n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE);
+    if (n <= 0) {
+	if (n != 0)
+	    rfbLogPerror("rfbVncAuthProcessResponse: read");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    numPasswords = vncDecryptPasswdFromFile2(pVNC->rfbAuthPasswdFile,
+					     passwdFullControl,
+					     passwdViewOnly);
+    if (numPasswords == 0) {
+	rfbLog("rfbVncAuthProcessResponse: could not get password from %s\n",
+	       pVNC->rfbAuthPasswdFile);
+
+	authResult = Swap32IfLE(rfbVncAuthFailed);
+
+	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	    rfbLogPerror("rfbVncAuthProcessResponse: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    memcpy(encryptedChallenge1, cl->authChallenge, CHALLENGESIZE);
+    vncEncryptBytes(encryptedChallenge1, passwdFullControl);
+    memcpy(encryptedChallenge2, cl->authChallenge, CHALLENGESIZE);
+    vncEncryptBytes(encryptedChallenge2,
+		    (numPasswords == 2) ? passwdViewOnly : passwdFullControl);
+
+    /* Lose the passwords from memory */
+    memset(passwdFullControl, 0, 9);
+    memset(passwdViewOnly, 0, 9);
+
+    ok = FALSE;
+    if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) {
+	rfbLog("Full-control authentication passed by %s\n", cl->host);
+	ok = TRUE;
+	cl->viewOnly = FALSE;
+    } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) {
+	rfbLog("View-only authentication passed by %s\n", cl->host);
+	ok = TRUE;
+	cl->viewOnly = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	    rfbLogPerror("rfbVncAuthProcessResponse: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	rfbLogPerror("rfbVncAuthProcessResponse: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientInitMessage(). */
+    cl->state = RFB_INITIALISATION;
+}
+
+
+/*
+ * Functions to prevent too many successive authentication failures.
+ * FIXME: This should be performed separately per each client IP.
+ */
+
+/* Maximum authentication failures before blocking connections */
+#define MAX_AUTH_TRIES 5
+
+/* Delay in ms, doubles for each failure over MAX_AUTH_TRIES */
+#define AUTH_TOO_MANY_BASE_DELAY 10 * 1000
+
+/*
+ * This function should not be called directly, it is called by
+ * setting a timer in rfbAuthConsiderBlocking().
+ */
+
+static CARD32
+rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+    rfbClientPtr cl = (rfbClientPtr) arg;
+    VNCSCREENPTR(cl->pScreen);
+    pVNC->rfbAuthTooManyTries = FALSE;
+    return 0;
+}
+
+/*
+ * This function should be called after each authentication failure.
+ * The return value will be true if there was too many failures.
+ */
+
+Bool
+rfbAuthConsiderBlocking(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    int i;
+
+    pVNC->rfbAuthTries++;
+
+    if (pVNC->rfbAuthTries >= MAX_AUTH_TRIES) {
+	CARD32 delay = AUTH_TOO_MANY_BASE_DELAY;
+	for (i = MAX_AUTH_TRIES; i < pVNC->rfbAuthTries; i++)
+	    delay *= 2;
+	pVNC->timer = TimerSet(pVNC->timer, 0, delay, rfbAuthReenable, NULL);
+	pVNC->rfbAuthTooManyTries = TRUE;
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * This function should be called after successful authentication.
+ * It resets the counter of authentication failures. Note that it's
+ * not necessary to clear the rfbAuthTooManyTries flag as it will be
+ * reset by the timer function.
+ */
+
+void
+rfbAuthUnblock(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    pVNC->rfbAuthTries = 0;
+}
+
+/*
+ * This function should be called before authentication process.
+ * The return value will be true if there was too many authentication
+ * failures, and the server should not allow another try.
+ */
+
+Bool
+rfbAuthIsBlocked(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    return pVNC->rfbAuthTooManyTries;
+}
+
diff -u -rNp a/hw/dmx/vnc/cmap.c b/hw/dmx/vnc/cmap.c
--- a/hw/dmx/vnc/cmap.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/cmap.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,163 @@
+/*
+ * cmap.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1993  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+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 X CONSORTIUM 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 X Consortium 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 X Consortium.
+
+*/
+
+#include "rfb.h"
+
+int
+rfbListInstalledColormaps(pScreen, pmaps)
+    ScreenPtr	pScreen;
+    Colormap	*pmaps;
+{
+    VNCSCREENPTR(pScreen);
+    /* By the time we are processing requests, we can guarantee that there
+     * is always a colormap installed */
+    if (pVNC->rfbInstalledColormap)
+    	*pmaps = pVNC->rfbInstalledColormap->mid;
+
+#if XFREE86VNC
+    pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps;
+    (*pScreen->ListInstalledColormaps)(pScreen, pmaps);
+    pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
+#endif
+
+    return (1);
+}
+
+
+void
+rfbInstallColormap(pmap)
+    ColormapPtr	pmap;
+{
+    VNCSCREENPTR(pmap->pScreen);
+
+    if (pmap != pVNC->rfbInstalledColormap) {
+
+	if(pVNC->rfbInstalledColormap != (ColormapPtr)None)
+	    WalkTree(pmap->pScreen, TellLostMap,
+				 (char *)&pVNC->rfbInstalledColormap->mid);
+	/* Install pmap */
+	pVNC->rfbInstalledColormap = pmap;
+	WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+	rfbSetClientColourMaps(0, 0);
+    }
+#if XFREE86VNC
+    pmap->pScreen->InstallColormap = pVNC->InstallColormap;
+    (*pmap->pScreen->InstallColormap)(pmap);
+    pmap->pScreen->InstallColormap = rfbInstallColormap;
+#endif
+}
+
+void
+rfbUninstallColormap(pmap)
+    ColormapPtr	pmap;
+{
+    VNCSCREENPTR(pmap->pScreen);
+
+    if(pmap == pVNC->rfbInstalledColormap)
+    {
+	if (pmap->mid != pmap->pScreen->defColormap)
+	{
+	    pVNC->rfbInstalledColormap = 
+			(ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+						   RT_COLORMAP);
+	    (*pmap->pScreen->InstallColormap)(pVNC->rfbInstalledColormap);
+	}
+    }
+#if XFREE86VNC
+    pmap->pScreen->UninstallColormap = pVNC->UninstallColormap;
+    (*pmap->pScreen->UninstallColormap)(pmap);
+    pmap->pScreen->UninstallColormap = rfbUninstallColormap;
+#endif
+}
+
+
+/*
+ * rfbStoreColors.  We have a set of pixels but they may be in any order.
+ * If some of them happen to be in continuous ascending order then we can
+ * group them together into a single call to rfbSetClientColourMaps.
+ */
+
+void
+rfbStoreColors(pmap, ndef, pdefs)
+    ColormapPtr pmap;
+    int         ndef;
+    xColorItem  *pdefs;
+{
+    VNCSCREENPTR(pmap->pScreen);
+    int i;
+    int first = -1;
+    int n = 0;
+
+    if (pmap == pVNC->rfbInstalledColormap) {
+	for (i = 0; i < ndef; i++) {
+	    if ((first != -1) && (first + n == pdefs[i].pixel)) {
+		n++;
+	    } else {
+		if (first != -1) {
+		    rfbSetClientColourMaps(first, n);
+		}
+		first = pdefs[i].pixel;
+		n = 1;
+	    }
+	}
+	rfbSetClientColourMaps(first, n);
+    }
+#if XFREE86VNC
+    pmap->pScreen->StoreColors = pVNC->StoreColors;
+    (*pmap->pScreen->StoreColors)(pmap, ndef, pdefs);
+    pmap->pScreen->StoreColors = rfbStoreColors;
+#endif
+}
diff -u -rNp a/hw/dmx/vnc/corre.c b/hw/dmx/vnc/corre.c
--- a/hw/dmx/vnc/corre.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/corre.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,355 @@
+/*
+ * corre.c
+ *
+ * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE).  This
+ * code is based on krw's original javatel rfbserver.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rfb.h"
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version.  If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(CARD8 *data, int w, int h);
+static int subrectEncode16(CARD16 *data, int w, int h);
+static int subrectEncode32(CARD32 *data, int w, int h);
+static CARD32 getBgColour(char *data, int size, int bpp);
+static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
+					  int w, int h);
+
+
+/*
+ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
+ * encoding.
+ */
+
+Bool
+rfbSendRectEncodingCoRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    if (h > cl->correMaxHeight) {
+	return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
+		rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight,
+					 w, h - cl->correMaxHeight));
+    }
+
+    if (w > cl->correMaxWidth) {
+	return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
+		rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
+					 w - cl->correMaxWidth, h));
+    }
+
+    return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
+}
+
+
+
+/*
+ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
+ * rectangle using CoRRE encoding.
+ */
+
+static Bool
+rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbRREHeader hdr;
+    int nSubrects;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize = (pVNC->width * pVNC->height
+		      * (cl->format.bitsPerPixel / 8));
+
+    if (rreBeforeBufSize < maxRawSize) {
+	rreBeforeBufSize = maxRawSize;
+	if (rreBeforeBuf == NULL)
+	    rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
+	else
+	    rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+    }
+
+    if (rreAfterBufSize < maxRawSize) {
+	rreAfterBufSize = maxRawSize;
+	if (rreAfterBuf == NULL)
+	    rreAfterBuf = (char *)xalloc(rreAfterBufSize);
+	else
+	    rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+    }
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, rreBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
+	break;
+    case 16:
+	nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
+	break;
+    case 32:
+	nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
+	break;
+    default:
+	rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+	exit(1);
+    }
+	
+    if (nSubrects < 0) {
+
+	/* RRE encoding was too large, use raw */
+
+	return rfbSendRectEncodingRaw(cl, x, y, w, h);
+    }
+
+    cl->rfbRectanglesSent[rfbEncodingCoRRE]++;
+    cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
+					   + sz_rfbRREHeader + rreAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nSubrects = Swap32IfLE(nSubrects);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader);
+    pVNC->ublen += sz_rfbRREHeader;
+
+    for (i = 0; i < rreAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > rreAfterBufLen) {
+	    bytesToCopy = rreAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background 
+ * colour overwritten by single-coloured rectangles.  It returns the number 
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive 
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp)					      \
+static int								      \
+subrectEncode##bpp(data,w,h)						      \
+    CARD##bpp *data;							      \
+    int w;								      \
+    int h;								      \
+{									      \
+    CARD##bpp cl;							      \
+    rfbCoRRERectangle subrect;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp);		      \
+									      \
+    *((CARD##bpp*)rreAfterBuf) = bg;					      \
+									      \
+    rreAfterBufLen = (bpp/8);						      \
+									      \
+    for (y=0; y<h; y++) {						      \
+      line = data+(y*w);						      \
+      for (x=0; x<w; x++) {						      \
+        if (line[x] != bg) {						      \
+          cl = line[x];							      \
+          hy = y-1;							      \
+          hyflag = 1;							      \
+          for (j=y; j<h; j++) {						      \
+            seg = data+(j*w);						      \
+            if (seg[x] != cl) {break;}					      \
+            i = x;							      \
+            while ((seg[i] == cl) && (i < w)) i += 1;			      \
+            i -= 1;							      \
+            if (j == y) vx = hx = i;					      \
+            if (i < vx) vx = i;						      \
+            if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      \
+          }								      \
+          vy = j-1;							      \
+									      \
+          /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  \
+           *  We'll choose the bigger of the two.			      \
+           */								      \
+          hw = hx-x+1;							      \
+          hh = hy-y+1;							      \
+          vw = vx-x+1;							      \
+          vh = vy-y+1;							      \
+									      \
+          thex = x;							      \
+          they = y;							      \
+									      \
+          if ((hw*hh) > (vw*vh)) {					      \
+            thew = hw;							      \
+            theh = hh;							      \
+          } else {							      \
+            thew = vw;							      \
+            theh = vh;							      \
+          }								      \
+									      \
+          subrect.x = thex;						      \
+          subrect.y = they;						      \
+          subrect.w = thew;						      \
+          subrect.h = theh;						      \
+									      \
+	  newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle;	      \
+          if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize))     \
+	    return -1;							      \
+									      \
+	  numsubs += 1;							      \
+	  *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl;		      \
+	  rreAfterBufLen += (bpp/8);					      \
+	  memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
+	  rreAfterBufLen += sz_rfbCoRRERectangle;			      \
+									      \
+          /*								      \
+           * Now mark the subrect as done.				      \
+           */								      \
+          for (j=they; j < (they+theh); j++) {				      \
+            for (i=thex; i < (thex+thew); i++) {			      \
+              data[j*w+i] = bg;						      \
+            }								      \
+          }								      \
+        }								      \
+      }									      \
+    }									      \
+									      \
+    return numsubs;							      \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static CARD32
+getBgColour(data,size,bpp)
+    char *data;
+    int size;
+    int bpp;
+{
+    
+#define NUMCLRS 256
+  
+  static int counts[NUMCLRS];
+  int i,j,k;
+
+  int maxcount = 0;
+  CARD8 maxclr = 0;
+
+  if (bpp != 8) {
+    if (bpp == 16) {
+      return ((CARD16 *)data)[0];
+    } else if (bpp == 32) {
+      return ((CARD32 *)data)[0];
+    } else {
+      rfbLog("getBgColour: bpp %d?\n",bpp);
+      exit(1);
+    }
+  }
+
+  for (i=0; i<NUMCLRS; i++) {
+    counts[i] = 0;
+  }
+
+  for (j=0; j<size; j++) {
+    k = (int)(((CARD8 *)data)[j]);
+    if (k >= NUMCLRS) {
+      rfbLog("getBgColour: unusual colour = %d\n", k);
+      exit(1);
+    }
+    counts[k] += 1;
+    if (counts[k] > maxcount) {
+      maxcount = counts[k];
+      maxclr = ((CARD8 *)data)[j];
+    }
+  }
+  
+  return maxclr;
+}
diff -u -rNp a/hw/dmx/vnc/cursor.c b/hw/dmx/vnc/cursor.c
--- a/hw/dmx/vnc/cursor.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/cursor.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,401 @@
+/*
+ * cursor.c - support for cursor shape updates.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rfb.h"
+#include "mipointer.h"
+#include "sprite.h"
+#include "cursorstr.h"
+#include "servermd.h"
+
+
+/* Copied from Xvnc/lib/font/util/utilbitmap.c */
+static unsigned char _reverse_byte[0x100] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+
+static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt,
+				  CursorPtr pCursor);
+static int EncodeRichCursorData16 (ScreenPtr pScreen,
+				   char *buf, rfbPixelFormat *fmt,
+				   CursorPtr pCursor);
+static int EncodeRichCursorData32 (ScreenPtr pScreen,
+				   char *buf, rfbPixelFormat *fmt,
+				   CursorPtr pCursor);
+
+
+/*
+ * Send cursor shape either in X-style format or in client pixel format.
+ */
+
+Bool
+rfbSendCursorShape(cl, pScreen)
+    rfbClientPtr cl;
+    ScreenPtr pScreen;
+{
+    VNCSCREENPTR(pScreen);
+    CursorPtr pCursor;
+    rfbFramebufferUpdateRectHeader rect;
+    rfbXCursorColors colors;
+    int saved_ublen;
+    int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes;
+    int i, j;
+    CARD8 *bitmapData;
+    CARD8 bitmapByte;
+
+    if (cl->useRichCursorEncoding) {
+	rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
+    } else {
+	rect.encoding = Swap32IfLE(rfbEncodingXCursor);
+    }
+
+    pCursor = pVNC->pCurs;
+
+    /* If there is no cursor, send update with empty cursor data. */
+
+    if ( pCursor != NULL &&
+	 pCursor->bits->width == 1 &&
+	 pCursor->bits->height == 1 &&
+	 pCursor->bits->mask[0] == 0 ) {
+	pCursor = NULL;
+    }
+
+    if (pCursor == NULL) {
+	if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+	rect.r.x = rect.r.y = 0;
+	rect.r.w = rect.r.h = 0;
+	memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	       sz_rfbFramebufferUpdateRectHeader);
+	pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+	cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
+	cl->rfbCursorShapeUpdatesSent++;
+
+	return TRUE;
+    }
+
+    /* Calculate data sizes. */
+
+    bitmapRowBytes = (pCursor->bits->width + 7) / 8;
+    paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1);
+    maskBytes = bitmapRowBytes * pCursor->bits->height;
+    dataBytes = (cl->useRichCursorEncoding) ?
+	(pCursor->bits->width * pCursor->bits->height *
+	 (cl->format.bitsPerPixel / 8)) : maskBytes;
+
+    /* Send buffer contents if needed. */
+
+    if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader +
+	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader +
+	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+	return FALSE;		/* FIXME. */
+    }
+
+    saved_ublen = pVNC->ublen;
+
+    /* Prepare rectangle header. */
+
+    rect.r.x = Swap16IfLE(pCursor->bits->xhot);
+    rect.r.y = Swap16IfLE(pCursor->bits->yhot);
+    rect.r.w = Swap16IfLE(pCursor->bits->width);
+    rect.r.h = Swap16IfLE(pCursor->bits->height);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    /* Prepare actual cursor data (depends on encoding used). */
+
+    if (!cl->useRichCursorEncoding) {
+	/* XCursor encoding. */
+	colors.foreRed   = (char)(pCursor->foreRed   >> 8);
+	colors.foreGreen = (char)(pCursor->foreGreen >> 8);
+	colors.foreBlue  = (char)(pCursor->foreBlue  >> 8);
+	colors.backRed   = (char)(pCursor->backRed   >> 8);
+	colors.backGreen = (char)(pCursor->backGreen >> 8);
+	colors.backBlue  = (char)(pCursor->backBlue  >> 8);
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&colors, sz_rfbXCursorColors);
+	pVNC->ublen += sz_rfbXCursorColors;
+
+	bitmapData = (CARD8 *)pCursor->bits->source;
+
+	for (i = 0; i < pCursor->bits->height; i++) {
+	    for (j = 0; j < bitmapRowBytes; j++) {
+		bitmapByte = bitmapData[i * paddedRowBytes + j];
+		if (screenInfo.bitmapBitOrder == LSBFirst) {
+		    bitmapByte = _reverse_byte[bitmapByte];
+		}
+		pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte;
+	    }
+	}
+    } else {
+	/* RichCursor encoding. */
+	switch (cl->format.bitsPerPixel) {
+	case 8:
+	    pVNC->ublen += EncodeRichCursorData8(&pVNC->updateBuf[pVNC->ublen],
+					   &cl->format, pCursor);
+	    break;
+	case 16:
+	    pVNC->ublen += EncodeRichCursorData16(pScreen, &pVNC->updateBuf[pVNC->ublen],
+					    &cl->format, pCursor);
+	    break;
+	case 32:
+	    pVNC->ublen += EncodeRichCursorData32(pScreen, &pVNC->updateBuf[pVNC->ublen],
+					    &cl->format, pCursor);
+	    break;
+	default:
+	    return FALSE;
+	}
+    }
+
+    /* Prepare transparency mask. */
+
+    bitmapData = (CARD8 *)pCursor->bits->mask;
+
+    for (i = 0; i < pCursor->bits->height; i++) {
+	for (j = 0; j < bitmapRowBytes; j++) {
+	    bitmapByte = bitmapData[i * paddedRowBytes + j];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte;
+	}
+    }
+
+    /* Update statistics. */
+
+    cl->rfbCursorShapeBytesSent += (pVNC->ublen - saved_ublen);
+    cl->rfbCursorShapeUpdatesSent++;
+
+    return TRUE;
+}
+
+/*
+ * Send cursor position (PointerPos pseudo-encoding).
+ */
+Bool
+rfbSendCursorPos(cl, pScreen)
+    rfbClientPtr cl;
+    ScreenPtr pScreen;
+{
+    VNCSCREENPTR(pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+#if XFREE86VNC
+    ScreenPtr   pCursorScreen = miPointerCurrentScreen();
+#endif
+    int x, y;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+#if XFREE86VNC
+    if (pScreen == pCursorScreen) 
+        miPointerPosition(&x, &y);
+#else
+    rfbSpriteGetCursorPos(pScreen, &x, &y);
+#endif
+
+    rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
+    rect.r.x = Swap16IfLE((CARD16)x);
+    rect.r.y = Swap16IfLE((CARD16)y);
+    rect.r.w = 0;
+    rect.r.h = 0;
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
+    cl->rfbCursorPosUpdatesSent++;
+
+    if (!rfbSendUpdateBuf(cl))
+	return FALSE;
+
+    cl->cursorX = x;
+    cl->cursorY = y;
+
+    return TRUE;
+}
+
+/*
+ * Code to convert cursor source bitmap to the desired pixel format.
+ */
+
+#define RGB48_TO_PIXEL(fmt,r,g,b)					\
+    (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift |	\
+     ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift |	\
+     ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift)
+
+static int
+EncodeRichCursorData8(buf, fmt, pCursor)
+    char *buf;
+    rfbPixelFormat *fmt;
+    CursorPtr pCursor;
+{
+    int widthPixels, widthBytes;
+    int x, y, b;
+    CARD8 *src;
+    char pix[2];
+    CARD8 bitmapByte;
+
+    pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen,
+				  pCursor->backBlue);
+    pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen,
+				  pCursor->foreBlue);
+
+    src = (CARD8 *)pCursor->bits->source;
+    widthPixels = pCursor->bits->width;
+    widthBytes = PixmapBytePad(widthPixels, 1);
+
+    for (y = 0; y < pCursor->bits->height; y++) {
+	for (x = 0; x < widthPixels / 8; x++) {
+	    bitmapByte = src[y * widthBytes + x];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    for (b = 7; b >= 0; b--) {
+		*buf++ = pix[bitmapByte >> b & 1];
+	    }
+	}
+	if (widthPixels % 8) {
+	    bitmapByte = src[y * widthBytes + x];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    for (b = 7; b > 7 - widthPixels % 8; b--) {
+		*buf++ = pix[bitmapByte >> b & 1];
+	    }
+	}
+    }
+
+    return (widthPixels * pCursor->bits->height);
+}
+
+#define DEFINE_RICH_ENCODE(bpp)						 \
+									 \
+static int								 \
+EncodeRichCursorData##bpp(pScreen, buf, fmt, pCursor)			 \
+    ScreenPtr pScreen;							 \
+    char *buf;								 \
+    rfbPixelFormat *fmt;						 \
+    CursorPtr pCursor;							 \
+{									 \
+    VNCSCREENPTR(pScreen);						 \
+    int widthPixels, widthBytes;					 \
+    int x, y, b;							 \
+    CARD8 *src;								 \
+    CARD##bpp pix[2];							 \
+    CARD8 bitmapByte;							 \
+									 \
+    pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed,		 \
+				       pCursor->backGreen,		 \
+				       pCursor->backBlue);		 \
+    pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed,		 \
+				       pCursor->foreGreen,		 \
+				       pCursor->foreBlue);		 \
+    if (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian) {		 \
+	pix[0] = Swap##bpp(pix[0]);					 \
+	pix[1] = Swap##bpp(pix[1]);					 \
+    }									 \
+									 \
+    src = (CARD8 *)pCursor->bits->source;				 \
+    widthPixels = pCursor->bits->width;					 \
+    widthBytes = PixmapBytePad(widthPixels, 1);				 \
+									 \
+    for (y = 0; y < pCursor->bits->height; y++) {			 \
+	for (x = 0; x < widthPixels / 8; x++) {				 \
+	    bitmapByte = src[y * widthBytes + x];			 \
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {		 \
+		bitmapByte = _reverse_byte[bitmapByte];			 \
+	    }								 \
+	    for (b = 7; b >= 0; b--) {					 \
+		memcpy (buf, (char *)&pix[bitmapByte >> b & 1],		 \
+			sizeof(CARD##bpp));				 \
+		buf += sizeof(CARD##bpp);				 \
+	    }								 \
+	}								 \
+	if (widthPixels % 8) {						 \
+	    bitmapByte = src[y * widthBytes + x];			 \
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {		 \
+		bitmapByte = _reverse_byte[bitmapByte];			 \
+	    }								 \
+	    for (b = 7; b > 7 - widthPixels % 8; b--) {			 \
+		memcpy (buf, (char *)&pix[bitmapByte >> b & 1],		 \
+			sizeof(CARD##bpp));				 \
+		buf += sizeof(CARD##bpp);				 \
+	    }								 \
+	}								 \
+    }									 \
+									 \
+    return (widthPixels * pCursor->bits->height * (bpp / 8));		 \
+}
+
+DEFINE_RICH_ENCODE(16)
+DEFINE_RICH_ENCODE(32)
+
diff -u -rNp a/hw/dmx/vnc/cutpaste.c b/hw/dmx/vnc/cutpaste.c
--- a/hw/dmx/vnc/cutpaste.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/cutpaste.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,87 @@
+/*
+ * cutpaste.c - routines to deal with cut & paste buffers / selection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include "rfb.h"
+#include "selection.h"
+#include "input.h"
+
+extern Selection *CurrentSelections;
+extern int NumCurrentSelections;
+
+
+static Bool inSetXCutText = FALSE;
+
+/*
+ * rfbSetXCutText sets the cut buffer to be the given string.  We also clear
+ * the primary selection.  Ideally we'd like to set it to the same thing, but I
+ * can't work out how to do that without some kind of helper X client.
+ */
+
+void
+rfbSetXCutText(char *str, int len)
+{
+    int i = 0;
+
+    inSetXCutText = TRUE;
+    ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING,
+			 8, PropModeReplace, len,
+			 (pointer)str, TRUE);
+    
+    while ((i < NumCurrentSelections) && 
+	   CurrentSelections[i].selection != XA_PRIMARY)
+	i++;
+
+    if (i < NumCurrentSelections) {
+	xEvent event;
+
+	if (CurrentSelections[i].client) {
+	    event.u.u.type = SelectionClear;
+	    event.u.selectionClear.time = GetTimeInMillis();
+	    event.u.selectionClear.window = CurrentSelections[i].window;
+	    event.u.selectionClear.atom = CurrentSelections[i].selection;
+	    (void) TryClientEvents (CurrentSelections[i].client, &event, 1,
+				NoEventMask, NoEventMask /* CantBeFiltered */,
+				NullGrab);
+	}
+
+	CurrentSelections[i].window = None;
+	CurrentSelections[i].pWin = NULL;
+	CurrentSelections[i].client = NullClient;
+    }
+
+    inSetXCutText = FALSE;
+}
+
+
+void rfbGotXCutText(char *str, int len)
+{
+    if (!inSetXCutText)
+	rfbSendServerCutText(str, len);
+}
diff -u -rNp a/hw/dmx/vnc/d3des.c b/hw/dmx/vnc/d3des.c
--- a/hw/dmx/vnc/d3des.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/d3des.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,440 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+static unsigned long KnR[32] = { 0L };
+static unsigned long Kn3[32] = { 0L };
+static unsigned char Df_Key[24] = {
+	0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+	0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+	0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
+
+static unsigned short bytebit[8]	= {
+	01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static unsigned long bigbyte[24] = {
+	0x800000L,	0x400000L,	0x200000L,	0x100000L,
+	0x80000L,	0x40000L,	0x20000L,	0x10000L,
+	0x8000L,	0x4000L,	0x2000L,	0x1000L,
+	0x800L, 	0x400L, 	0x200L, 	0x100L,
+	0x80L,		0x40L,		0x20L,		0x10L,
+	0x8L,		0x4L,		0x2L,		0x1L	};
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
+	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
+
+static unsigned char totrot[16] = {
+	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+void deskey(key, edf)	/* Thanks to James Gillogly & Phil Karn! */
+unsigned char *key;
+int edf;
+{
+	register int i, j, l, m, n;
+	unsigned char pc1m[56], pcr[56];
+	unsigned long kn[32];
+
+	for ( j = 0; j < 56; j++ ) {
+		l = pc1[j];
+		m = l & 07;
+		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+		}
+	for( i = 0; i < 16; i++ ) {
+		if( edf == DE1 ) m = (15 - i) << 1;
+		else m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for( j = 0; j < 28; j++ ) {
+			l = j + totrot[i];
+			if( l < 28 ) pcr[j] = pc1m[l];
+			else pcr[j] = pc1m[l - 28];
+			}
+		for( j = 28; j < 56; j++ ) {
+		    l = j + totrot[i];
+		    if( l < 56 ) pcr[j] = pc1m[l];
+		    else pcr[j] = pc1m[l - 28];
+		    }
+		for( j = 0; j < 24; j++ ) {
+			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+			}
+		}
+	cookey(kn);
+	return;
+	}
+
+static void cookey(raw1)
+register unsigned long *raw1;
+{
+	register unsigned long *cook, *raw0;
+	unsigned long dough[32];
+	register int i;
+
+	cook = dough;
+	for( i = 0; i < 16; i++, raw1++ ) {
+		raw0 = raw1++;
+		*cook	 = (*raw0 & 0x00fc0000L) << 6;
+		*cook	|= (*raw0 & 0x00000fc0L) << 10;
+		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook	 = (*raw0 & 0x0003f000L) << 12;
+		*cook	|= (*raw0 & 0x0000003fL) << 16;
+		*cook	|= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+		}
+	usekey(dough);
+	return;
+	}
+
+void cpkey(into)
+register unsigned long *into;
+{
+	register unsigned long *from, *endp;
+
+	from = KnL, endp = &KnL[32];
+	while( from < endp ) *into++ = *from++;
+	return;
+	}
+
+void usekey(from)
+register unsigned long *from;
+{
+	register unsigned long *to, *endp;
+
+	to = KnL, endp = &KnL[32];
+	while( to < endp ) *to++ = *from++;
+	return;
+	}
+
+void des(inblock, outblock)
+unsigned char *inblock, *outblock;
+{
+	unsigned long work[2];
+
+	scrunch(inblock, work);
+	desfunc(work, KnL);
+	unscrun(work, outblock);
+	return;
+	}
+
+static void scrunch(outof, into)
+register unsigned char *outof;
+register unsigned long *into;
+{
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into++ |= (*outof++ & 0xffL);
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into	|= (*outof   & 0xffL);
+	return;
+	}
+
+static void unscrun(outof, into)
+register unsigned long *outof;
+register unsigned char *into;
+{
+	*into++ = (*outof >> 24) & 0xffL;
+	*into++ = (*outof >> 16) & 0xffL;
+	*into++ = (*outof >>  8) & 0xffL;
+	*into++ =  *outof++	 & 0xffL;
+	*into++ = (*outof >> 24) & 0xffL;
+	*into++ = (*outof >> 16) & 0xffL;
+	*into++ = (*outof >>  8) & 0xffL;
+	*into	=  *outof	 & 0xffL;
+	return;
+	}
+
+static unsigned long SP1[64] = {
+	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(block, keys)
+register unsigned long *block, *keys;
+{
+	register unsigned long fval, work, right, leftt;
+	register int round;
+
+	leftt = block[0];
+	right = block[1];
+	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+	work = ((right >> 2) ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+	for( round = 0; round < 8; round++ ) {
+		work  = (right << 28) | (right >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		leftt ^= fval;
+		work  = (leftt << 28) | (leftt >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		right ^= fval;
+		}
+
+	right = (right << 31) | (right >> 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = (leftt << 31) | (leftt >> 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+	*block++ = right;
+	*block = leftt;
+	return;
+	}
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff -u -rNp a/hw/dmx/vnc/d3des.h b/hw/dmx/vnc/d3des.h
--- a/hw/dmx/vnc/d3des.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/d3des.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* d3des.h -
+ *
+ *	Headers and defines for d3des.c
+ *	Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ *	(GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0	0	/* MODE == encrypt */
+#define DE1	1	/* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/*		      hexkey[8]     MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/*		    cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/*		   cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/*		    from[8]	      to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'.  They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff -u -rNp a/hw/dmx/vnc/dispcur.c b/hw/dmx/vnc/dispcur.c
--- a/hw/dmx/vnc/dispcur.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/dispcur.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,804 @@
+/*
+ * dispcur.c
+ *
+ * cursor display routines - based on midispcur.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#if HAVE_DMX_CONFIG_H
+#include "dmx-config.h"
+#endif
+
+#define NEED_EVENTS
+# include   "X11/X.h"
+# include   "misc.h"
+# include   "input.h"
+# include   "cursorstr.h"
+# include   "windowstr.h"
+# include   "regionstr.h"
+# include   "dixstruct.h"
+# include   "scrnintstr.h"
+# include   "servermd.h"
+# include   "mipointer.h"
+# include   "sprite.h"
+# include   "gcstruct.h"
+
+#ifdef ARGB_CURSOR
+# include   "picturestr.h"
+#endif
+
+/* per-screen private data */
+
+static int	rfbDCScreenIndex;
+static unsigned long rfbDCGeneration = 0;
+
+static Bool	rfbDCCloseScreen(int index, ScreenPtr pScreen);
+
+typedef struct {
+    GCPtr	    pSourceGC, pMaskGC;
+    GCPtr	    pSaveGC, pRestoreGC;
+    GCPtr	    pMoveGC;
+    GCPtr	    pPixSourceGC, pPixMaskGC;
+    CloseScreenProcPtr CloseScreen;
+    PixmapPtr	    pSave, pTemp;
+#ifdef ARGB_CURSOR
+    PicturePtr      pRootPicture;
+    PicturePtr      pTempPicture;
+#endif
+} rfbDCScreenRec, *rfbDCScreenPtr;
+
+/* per-cursor per-screen private data */
+typedef struct {
+    PixmapPtr		sourceBits;	    /* source bits */
+    PixmapPtr		maskBits;	    /* mask bits */
+#ifdef ARGB_CURSOR
+    PicturePtr          pPicture;
+#endif
+} rfbDCCursorRec, *rfbDCCursorPtr;
+
+/*
+ * sprite/cursor method table
+ */
+
+static Bool	rfbDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool	rfbDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool	rfbDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor,
+				int x, int y, unsigned long source,
+				unsigned long mask);
+static Bool	rfbDCSaveUnderCursor(ScreenPtr pScreen, int x, int y,
+				    int w, int h);
+static Bool	rfbDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y,
+				       int w, int h);
+static Bool	rfbDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor,
+			       int x, int y, int w, int h, int dx, int dy,
+			       unsigned long source, unsigned long mask);
+static Bool	rfbDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h,	
+			       int dx, int dy);
+
+static rfbSpriteCursorFuncRec rfbDCFuncs = {
+    rfbDCRealizeCursor,
+    rfbDCUnrealizeCursor,
+    rfbDCPutUpCursor,
+    rfbDCSaveUnderCursor,
+    rfbDCRestoreUnderCursor,
+    rfbDCMoveCursor,
+    rfbDCChangeSave,
+};
+
+Bool
+rfbDCInitialize (pScreen, screenFuncs)
+    ScreenPtr		    pScreen;
+    miPointerScreenFuncPtr  screenFuncs;
+{
+    rfbDCScreenPtr   pScreenPriv;
+
+    if (rfbDCGeneration != serverGeneration)
+    {
+	rfbDCScreenIndex = AllocateScreenPrivateIndex ();
+	if (rfbDCScreenIndex < 0)
+	    return FALSE;
+	rfbDCGeneration = serverGeneration;
+    }
+    pScreenPriv = (rfbDCScreenPtr) xalloc (sizeof (rfbDCScreenRec));
+    if (!pScreenPriv)
+	return FALSE;
+
+    /*
+     * initialize the entire private structure to zeros
+     */
+
+    pScreenPriv->pSourceGC =
+	pScreenPriv->pMaskGC =
+	pScreenPriv->pSaveGC =
+ 	pScreenPriv->pRestoreGC =
+	pScreenPriv->pMoveGC =
+ 	pScreenPriv->pPixSourceGC =
+	pScreenPriv->pPixMaskGC = NULL;
+#ifdef ARGB_CURSOR
+    pScreenPriv->pRootPicture = NULL;
+    pScreenPriv->pTempPicture = NULL;
+#endif
+    
+    pScreenPriv->pSave = pScreenPriv->pTemp = NULL;
+
+    pScreenPriv->CloseScreen = pScreen->CloseScreen;
+    pScreen->CloseScreen = rfbDCCloseScreen;
+    
+    pScreen->devPrivates[rfbDCScreenIndex].ptr = (pointer) pScreenPriv;
+
+    if (!rfbSpriteInitialize (pScreen, &rfbDCFuncs, screenFuncs))
+    {
+	xfree ((pointer) pScreenPriv);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+#define tossGC(gc)  (gc ? FreeGC (gc, (GContext) 0) : 0)
+#define tossPix(pix)	(pix ? (*pScreen->DestroyPixmap) (pix) : TRUE)
+#define tossPict(pict)  (pict ? FreePicture (pict, 0) : 0)
+
+static Bool
+rfbDCCloseScreen (index, pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbDCScreenPtr   pScreenPriv;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pScreen->CloseScreen = pScreenPriv->CloseScreen;
+    tossGC (pScreenPriv->pSourceGC);
+    tossGC (pScreenPriv->pMaskGC);
+    tossGC (pScreenPriv->pSaveGC);
+    tossGC (pScreenPriv->pRestoreGC);
+    tossGC (pScreenPriv->pMoveGC);
+    tossGC (pScreenPriv->pPixSourceGC);
+    tossGC (pScreenPriv->pPixMaskGC);
+    tossPix (pScreenPriv->pSave);
+    tossPix (pScreenPriv->pTemp);
+#ifdef ARGB_CURSOR
+    tossPict (pScreenPriv->pRootPicture);
+    tossPict (pScreenPriv->pTempPicture);
+#endif
+    xfree ((pointer) pScreenPriv);
+    return (*pScreen->CloseScreen) (index, pScreen);
+}
+
+static Bool
+rfbDCRealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    if (pCursor->bits->refcnt <= 1)
+	pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
+    return TRUE;
+}
+
+#ifdef ARGB_CURSOR
+#define EnsurePicture(picture,draw,win) (picture || rfbDCMakePicture(&picture,draw,win))
+
+static VisualPtr
+rfbDCGetWindowVisual (WindowPtr pWin)
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    VisualID	    vid = wVisual (pWin);
+    int		    i;
+
+    for (i = 0; i < pScreen->numVisuals; i++)
+	if (pScreen->visuals[i].vid == vid)
+	    return &pScreen->visuals[i];
+    return 0;
+}
+
+static PicturePtr
+rfbDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin)
+{
+    ScreenPtr	    pScreen = pDraw->pScreen;
+    VisualPtr	    pVisual;
+    PictFormatPtr   pFormat;
+    XID		    subwindow_mode = IncludeInferiors;
+    PicturePtr	    pPicture;
+    int		    error;
+    
+    pVisual = rfbDCGetWindowVisual (pWin);
+    if (!pVisual)
+	return 0;
+    pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual);
+    if (!pFormat)
+	return 0;
+    pPicture = CreatePicture (0, pDraw, pFormat,
+			      CPSubwindowMode, &subwindow_mode,
+			      serverClient, &error);
+    *ppPicture = pPicture;
+    return pPicture;
+}
+#endif
+
+static rfbDCCursorPtr
+rfbDCRealize (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbDCCursorPtr   pPriv;
+    GCPtr	    pGC;
+    XID		    gcvals[3];
+
+    pPriv = (rfbDCCursorPtr) xalloc (sizeof (rfbDCCursorRec));
+    if (!pPriv)
+	return (rfbDCCursorPtr)NULL;
+#ifdef ARGB_CURSOR
+    if (pCursor->bits->argb)
+    {
+	PixmapPtr	pPixmap;
+	PictFormatPtr	pFormat;
+	int		error;
+	
+	pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
+	if (!pFormat)
+	{
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	
+	pPriv->sourceBits = 0;
+	pPriv->maskBits = 0;
+	pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
+					    pCursor->bits->height, 32);
+	if (!pPixmap)
+	{
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	pGC = GetScratchGC (32, pScreen);
+	if (!pGC)
+	{
+	    (*pScreen->DestroyPixmap) (pPixmap);
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	ValidateGC (&pPixmap->drawable, pGC);
+	(*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
+			       0, 0, pCursor->bits->width,
+			       pCursor->bits->height,
+			       0, ZPixmap, (char *) pCursor->bits->argb);
+	FreeScratchGC (pGC);
+	pPriv->pPicture = CreatePicture (0, &pPixmap->drawable,
+					pFormat, 0, 0, serverClient, &error);
+        (*pScreen->DestroyPixmap) (pPixmap);
+	if (!pPriv->pPicture)
+	{
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
+	return pPriv;
+    }
+    pPriv->pPicture = 0;
+#endif
+    pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
+    if (!pPriv->sourceBits)
+    {
+	xfree ((pointer) pPriv);
+	return (rfbDCCursorPtr)NULL;
+    }
+    pPriv->maskBits =  (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
+    if (!pPriv->maskBits)
+    {
+	(*pScreen->DestroyPixmap) (pPriv->sourceBits);
+	xfree ((pointer) pPriv);
+	return (rfbDCCursorPtr)NULL;
+    }
+    pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
+
+    /* create the two sets of bits, clipping as appropriate */
+
+    pGC = GetScratchGC (1, pScreen);
+    if (!pGC)
+    {
+	(void) rfbDCUnrealizeCursor (pScreen, pCursor);
+	return (rfbDCCursorPtr)NULL;
+    }
+
+    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->source);
+    gcvals[0] = GXand;
+    ChangeGC (pGC, GCFunction, gcvals);
+    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->mask);
+
+    /* mask bits -- pCursor->mask & ~pCursor->source */
+    gcvals[0] = GXcopy;
+    ChangeGC (pGC, GCFunction, gcvals);
+    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->mask);
+    gcvals[0] = GXandInverted;
+    ChangeGC (pGC, GCFunction, gcvals);
+    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->source);
+    FreeScratchGC (pGC);
+    return pPriv;
+}
+
+static Bool
+rfbDCUnrealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbDCCursorPtr   pPriv;
+
+    pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+    if (pPriv && (pCursor->bits->refcnt <= 1))
+    {
+	if (pPriv->sourceBits)
+	    (*pScreen->DestroyPixmap) (pPriv->sourceBits);
+	if (pPriv->maskBits)
+	    (*pScreen->DestroyPixmap) (pPriv->maskBits);
+#ifdef ARGB_CURSOR
+	if (pPriv->pPicture)
+	    FreePicture (pPriv->pPicture, 0);
+#endif
+	xfree ((pointer) pPriv);
+	pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
+    }
+    return TRUE;
+}
+
+static void
+rfbDCPutBits (pDrawable, pPriv, sourceGC, maskGC, x, y, w, h, source, mask)
+    DrawablePtr	    pDrawable;
+    GCPtr	    sourceGC, maskGC;
+    int             x, y;
+    unsigned        w, h;
+    rfbDCCursorPtr   pPriv;
+    unsigned long   source, mask;
+{
+    XID	    gcvals[1];
+
+    if (sourceGC->fgPixel != source)
+    {
+	gcvals[0] = source;
+	DoChangeGC (sourceGC, GCForeground, gcvals, 0);
+    }
+    if (sourceGC->serialNumber != pDrawable->serialNumber)
+	ValidateGC (pDrawable, sourceGC);
+    (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y);
+    if (maskGC->fgPixel != mask)
+    {
+	gcvals[0] = mask;
+	DoChangeGC (maskGC, GCForeground, gcvals, 0);
+    }
+    if (maskGC->serialNumber != pDrawable->serialNumber)
+	ValidateGC (pDrawable, maskGC);
+    (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y);
+}
+
+#define EnsureGC(gc,win) (gc || rfbDCMakeGC(&gc, win))
+
+static GCPtr
+rfbDCMakeGC(ppGC, pWin)
+    GCPtr	*ppGC;
+    WindowPtr	pWin;
+{
+    GCPtr pGC;
+    int   status;
+    XID   gcvals[2];
+
+    gcvals[0] = IncludeInferiors;
+    gcvals[1] = FALSE;
+    pGC = CreateGC((DrawablePtr)pWin,
+		   GCSubwindowMode|GCGraphicsExposures, gcvals, &status);
+    if (pGC && pWin->drawable.pScreen->DrawGuarantee)
+	(*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
+    *ppGC = pGC;
+    return pGC;
+}
+
+static Bool
+rfbDCPutUpCursor (pScreen, pCursor, x, y, source, mask)
+    ScreenPtr	    pScreen;
+    CursorPtr	    pCursor;
+    int		    x, y;
+    unsigned long   source, mask;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    rfbDCCursorPtr   pPriv;
+    WindowPtr	    pWin;
+
+    pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+    if (!pPriv)
+    {
+	pPriv = rfbDCRealize(pScreen, pCursor);
+	if (!pPriv)
+	    return FALSE;
+    }
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pWin = WindowTable[pScreen->myNum];
+#ifdef ARGB_CURSOR
+    if (pPriv->pPicture)
+    {
+	if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin))
+	    return FALSE;
+	CompositePicture (PictOpOver,
+			  pPriv->pPicture,
+			  NULL,
+			  pScreenPriv->pRootPicture,
+			  0, 0, 0, 0, 
+			  x, y, 
+			  pCursor->bits->width,
+			  pCursor->bits->height);
+    }
+    else
+#endif
+    {
+	if (!EnsureGC(pScreenPriv->pSourceGC, pWin))
+	    return FALSE;
+	if (!EnsureGC(pScreenPriv->pMaskGC, pWin))
+	{
+	    FreeGC (pScreenPriv->pSourceGC, (GContext) 0);
+	    pScreenPriv->pSourceGC = 0;
+	    return FALSE;
+	}
+	rfbDCPutBits ((DrawablePtr)pWin, pPriv,
+		     pScreenPriv->pSourceGC, pScreenPriv->pMaskGC,
+		     x, y, pCursor->bits->width, pCursor->bits->height,
+		     source, mask);
+    }
+    return TRUE;
+}
+
+static Bool
+rfbDCSaveUnderCursor (pScreen, x, y, w, h)
+    ScreenPtr	pScreen;
+    int		x, y, w, h;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    PixmapPtr	    pSave;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pSave = pScreenPriv->pSave;
+    pWin = WindowTable[pScreen->myNum];
+    if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h)
+    {
+	if (pSave)
+	    (*pScreen->DestroyPixmap) (pSave);
+	pScreenPriv->pSave = pSave =
+		(*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth);
+	if (!pSave)
+	    return FALSE;
+    }
+    if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pSaveGC;
+    if (pSave->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pSave, pGC);
+    (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			    x, y, w, h, 0, 0);
+    return TRUE;
+}
+
+static Bool
+rfbDCRestoreUnderCursor (pScreen, x, y, w, h)
+    ScreenPtr	pScreen;
+    int		x, y, w, h;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    PixmapPtr	    pSave;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pSave = pScreenPriv->pSave;
+    pWin = WindowTable[pScreen->myNum];
+    if (!pSave)
+	return FALSE;
+    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pRestoreGC;
+    if (pWin->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pWin, pGC);
+    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			    0, 0, w, h, x, y);
+    return TRUE;
+}
+
+static Bool
+rfbDCChangeSave (pScreen, x, y, w, h, dx, dy)
+    ScreenPtr	    pScreen;
+    int		    x, y, w, h, dx, dy;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    PixmapPtr	    pSave;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+    int		    sourcex, sourcey, destx, desty, copyw, copyh;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pSave = pScreenPriv->pSave;
+    pWin = WindowTable[pScreen->myNum];
+    /*
+     * restore the bits which are about to get trashed
+     */
+    if (!pSave)
+	return FALSE;
+    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pRestoreGC;
+    if (pWin->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pWin, pGC);
+    /*
+     * copy the old bits to the screen.
+     */
+    if (dy > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       0, h - dy, w, dy, x + dx, y + h);
+    }
+    else if (dy < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       0, 0, w, -dy, x + dx, y + dy);
+    }
+    if (dy >= 0)
+    {
+	desty = y + dy;
+	sourcey = 0;
+	copyh = h - dy;
+    }
+    else
+    {
+	desty = y;
+	sourcey = - dy;
+	copyh = h + dy;
+    }
+    if (dx > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       w - dx, sourcey, dx, copyh, x + w, desty);
+    }
+    else if (dx < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       0, sourcey, -dx, copyh, x + dx, desty);
+    }
+    if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pSaveGC;
+    if (pSave->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pSave, pGC);
+    /*
+     * move the bits that are still valid within the pixmap
+     */
+    if (dx >= 0)
+    {
+	sourcex = 0;
+	destx = dx;
+	copyw = w - dx;
+    }
+    else
+    {
+	destx = 0;
+	sourcex = - dx;
+	copyw = w + dx;
+    }
+    if (dy >= 0)
+    {
+	sourcey = 0;
+	desty = dy;
+	copyh = h - dy;
+    }
+    else
+    {
+	desty = 0;
+	sourcey = -dy;
+	copyh = h + dy;
+    }
+    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC,
+			   sourcex, sourcey, copyw, copyh, destx, desty);
+    /*
+     * copy the new bits from the screen into the remaining areas of the
+     * pixmap
+     */
+    if (dy > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x, y, w, dy, 0, 0);
+    }
+    else if (dy < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x, y + h + dy, w, -dy, 0, h + dy);
+    }
+    if (dy >= 0)
+    {
+	desty = dy;
+	sourcey = y + dy;
+	copyh = h - dy;
+    }
+    else
+    {
+	desty = 0;
+	sourcey = y;
+	copyh = h + dy;
+    }
+    if (dx > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x, sourcey, dx, copyh, 0, desty);
+    }
+    else if (dx < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x + w + dx, sourcey, -dx, copyh, w + dx, desty);
+    }
+    return TRUE;
+}
+
+static Bool
+rfbDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask)
+    ScreenPtr	    pScreen;
+    CursorPtr	    pCursor;
+    int		    x, y, w, h, dx, dy;
+    unsigned long   source, mask;
+{
+    rfbDCCursorPtr   pPriv;
+    rfbDCScreenPtr   pScreenPriv;
+    int		    status;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+    XID		    gcval = FALSE;
+    PixmapPtr	    pTemp;
+
+    pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+    if (!pPriv)
+    {
+	pPriv = rfbDCRealize(pScreen, pCursor);
+	if (!pPriv)
+	    return FALSE;
+    }
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pWin = WindowTable[pScreen->myNum];
+    pTemp = pScreenPriv->pTemp;
+    if (!pTemp ||
+	pTemp->drawable.width != pScreenPriv->pSave->drawable.width ||
+	pTemp->drawable.height != pScreenPriv->pSave->drawable.height)
+    {
+	if (pTemp)
+	    (*pScreen->DestroyPixmap) (pTemp);
+#ifdef ARGB_CURSOR
+	if (pScreenPriv->pTempPicture)
+	{
+	    FreePicture (pScreenPriv->pTempPicture, 0);
+	    pScreenPriv->pTempPicture = 0;
+	}
+#endif
+	pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap)
+	    (pScreen, w, h, pScreenPriv->pSave->drawable.depth);
+	if (!pTemp)
+	    return FALSE;
+    }
+    if (!pScreenPriv->pMoveGC)
+    {
+	pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp,
+	    GCGraphicsExposures, &gcval, &status);
+	if (!pScreenPriv->pMoveGC)
+	    return FALSE;
+    }
+    /*
+     * copy the saved area to a temporary pixmap
+     */
+    pGC = pScreenPriv->pMoveGC;
+    if (pGC->serialNumber != pTemp->drawable.serialNumber)
+	ValidateGC ((DrawablePtr) pTemp, pGC);
+    (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave,
+			  (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0);
+    
+    /*
+     * draw the cursor in the temporary pixmap
+     */
+#ifdef ARGB_CURSOR
+    if (pPriv->pPicture)
+    {
+	if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin))
+	    return FALSE;
+	CompositePicture (PictOpOver,
+			  pPriv->pPicture,
+			  NULL,
+			  pScreenPriv->pTempPicture,
+			  0, 0, 0, 0, 
+			  dx, dy, 
+			  pCursor->bits->width,
+			  pCursor->bits->height);
+    }
+    else
+#endif
+    {
+	if (!pScreenPriv->pPixSourceGC)
+	{
+	    pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp,
+		GCGraphicsExposures, &gcval, &status);
+	    if (!pScreenPriv->pPixSourceGC)
+		return FALSE;
+	}
+	if (!pScreenPriv->pPixMaskGC)
+	{
+	    pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp,
+		GCGraphicsExposures, &gcval, &status);
+	    if (!pScreenPriv->pPixMaskGC)
+		return FALSE;
+	}
+	rfbDCPutBits ((DrawablePtr)pTemp, pPriv,
+		     pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC,
+		     dx, dy, pCursor->bits->width, pCursor->bits->height,
+		     source, mask);
+    }
+
+    /*
+     * copy the temporary pixmap onto the screen
+     */
+
+    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pRestoreGC;
+    if (pWin->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pWin, pGC);
+
+    (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin,
+			    pGC,
+			    0, 0, w, h, x, y);
+    return TRUE;
+}
diff -u -rNp a/hw/dmx/vnc/draw.c b/hw/dmx/vnc/draw.c
--- a/hw/dmx/vnc/draw.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/draw.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2097 @@
+/*
+ * draw.c - drawing routines for the RFB X server.  This is a set of
+ * wrappers around the standard MI/MFB/CFB drawing routines which work out
+ * to a fair approximation the region of the screen being modified by the
+ * drawing.  If the RFB client is ready then the modified region of the screen
+ * is sent to the client, otherwise the modified region will simply grow with
+ * each drawing request until the client is ready.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#include "rfb.h"
+
+int rfbDeferUpdateTime = 40; /* ms */
+
+
+/****************************************************************************/
+/*
+ * Macro definitions
+ */
+/****************************************************************************/
+
+#define TRC(x) /* (rfbLog x) */
+
+/* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each
+   client */
+
+#define ADD_TO_MODIFIED_REGION(pScreen,reg)				      \
+  {									      \
+      rfbClientPtr cl;							      \
+      for (cl = rfbClientHead; cl; cl = cl->next) {			      \
+	  REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\
+      }									      \
+  }
+
+/* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an
+   update to be sent to each client if there is one pending and the client is
+   ready for it.  */
+
+#define SCHEDULE_FB_UPDATE(pScreen,pVNC)				\
+  if (!pVNC->dontSendFramebufferUpdate) {				\
+      rfbClientPtr cl, nextCl;						\
+      for (cl = rfbClientHead; cl; cl = nextCl) {			\
+	  nextCl = cl->next;						\
+	  if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && 	\
+	      REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) 		\
+	  {								\
+	      rfbScheduleDeferredUpdate(pScreen, cl);			\
+	  }								\
+      }									\
+  }
+
+/* function prototypes */
+
+static void rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl);
+static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl,
+			  RegionPtr src, RegionPtr dst, int dx, int dy);
+#ifdef DEBUG
+static void PrintRegion(ScreenPtr pScreen, RegionPtr reg);
+#endif
+
+/* GC funcs */
+
+static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr);
+static void rfbChangeGC(GCPtr, unsigned long /*mask*/);
+static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/);
+static void rfbDestroyGC(GCPtr);
+static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/,
+			  int /*nrects*/);
+static void rfbDestroyClip(GCPtr);
+static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/);
+
+/* GC ops */
+
+static void rfbFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted);
+static void rfbSetSpans(DrawablePtr 		pDrawable, 
+	    		GCPtr			pGC, 
+	    		char			*psrc, 
+	    		register DDXPointPtr	ppt, 
+	    		int			*pwidth, 
+	    		int			nspans, 
+	    		int			fSorted);
+static void rfbPutImage();
+static RegionPtr rfbCopyArea();
+static RegionPtr rfbCopyPlane();
+static void rfbPolyPoint();
+static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts);
+static void rfbPolySegment();
+static void rfbPolyRectangle();
+static void rfbPolyArc();
+static void rfbFillPolygon();
+static void rfbPolyFillRect();
+static void rfbPolyFillArc();
+static int rfbPolyText8();
+static int rfbPolyText16();
+static void rfbImageText8();
+static void rfbImageText16();
+static void rfbImageGlyphBlt();
+static void rfbPolyGlyphBlt();
+static void rfbPushPixels();
+
+
+static GCFuncs rfbGCFuncs = {
+    rfbValidateGC,
+    rfbChangeGC,
+    rfbCopyGC,
+    rfbDestroyGC,
+    rfbChangeClip,
+    rfbDestroyClip,
+    rfbCopyClip,
+};
+
+
+static GCOps rfbGCOps = {
+    rfbFillSpans,	rfbSetSpans,	rfbPutImage,	
+    rfbCopyArea,	rfbCopyPlane,	rfbPolyPoint,
+    rfbPolylines,	rfbPolySegment,	rfbPolyRectangle,
+    rfbPolyArc,		rfbFillPolygon,	rfbPolyFillRect,
+    rfbPolyFillArc,	rfbPolyText8,	rfbPolyText16,
+    rfbImageText8,	rfbImageText16,	rfbImageGlyphBlt,
+    rfbPolyGlyphBlt,	rfbPushPixels
+};
+
+
+
+/****************************************************************************/
+/*
+ * Screen functions wrapper stuff
+ */
+/****************************************************************************/
+
+#define SCREEN_PROLOGUE(scrn, field)		\
+    ScreenPtr pScreen = scrn;			\
+    VNCSCREENPTR(pScreen); 		\
+    pScreen->field = pVNC->field;
+
+#define SCREEN_EPILOGUE(field, wrapper) \
+    pScreen->field = wrapper;
+
+
+/*
+ * CloseScreen wrapper -- unwrap everything, free the private data
+ * and call the wrapped CloseScreen function.
+ */
+
+Bool
+rfbCloseScreen (int i, ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+#if XFREE86VNC
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+#endif
+    int sock;
+
+    for (sock = 0; sock <= pVNC->maxFd; sock++) {
+	if (FD_ISSET(sock, &pVNC->allFds))
+	    if (sock != pVNC->rfbListenSock && sock != pVNC->httpListenSock) {
+	    	rfbCloseSock(pScreen, sock);
+	    }
+    }
+
+    if (pVNC->rfbListenSock > 0)
+    	if (close(pVNC->rfbListenSock))
+		ErrorF("Close of port %d failed\n",pVNC->rfbPort);
+
+    if (pVNC->httpListenSock > 0)
+    	if (close(pVNC->httpListenSock))
+		ErrorF("Close of port %d failed\n",pVNC->httpPort);
+
+    pScreen->CloseScreen = pVNC->CloseScreen;
+    pScreen->CreateGC = pVNC->CreateGC;
+    pScreen->PaintWindowBackground = pVNC->PaintWindowBackground;
+    pScreen->PaintWindowBorder = pVNC->PaintWindowBorder;
+    pScreen->CopyWindow = pVNC->CopyWindow;
+    pScreen->ClearToBackground = pVNC->ClearToBackground;
+    pScreen->RestoreAreas = pVNC->RestoreAreas;
+    pScreen->WakeupHandler = pVNC->WakeupHandler;
+
+#if XFREE86VNC
+    pScreen->InstallColormap = pVNC->InstallColormap;
+    pScreen->UninstallColormap = pVNC->UninstallColormap;
+    pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps;
+    pScreen->StoreColors = pVNC->StoreColors;
+    pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess;
+
+    xfree(pVNC);
+#endif
+
+    TRC((stderr,"Unwrapped screen functions\n"));
+
+    return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+#if XFREE86VNC
+void
+rfbEnableDisableFBAccess (int index, Bool enable)
+{
+    ScrnInfoPtr pScrn = xf86Screens[index];
+    VNCSCREENPTR(pScrn->pScreen);
+
+    /* 
+     * Blank the screen for security while inputs are disabled.
+     * When VT switching is fixed, we might be able to allow
+     * control even when switched away. 
+     */
+    if (!enable) {
+	WindowPtr pWin = WindowTable[index];
+    	ScreenPtr pScreen = pWin->drawable.pScreen;
+    	GCPtr pGC;
+    	xRectangle rect;
+
+    	rect.x = 0;
+    	rect.y = 0;
+    	rect.width = pScrn->virtualX;
+    	rect.height = pScrn->virtualY;
+
+    	if (!(pGC = GetScratchGC(pScreen->rootDepth, pScreen))) {
+    	    ErrorF("Couldn't blank screen");
+    	} else {
+	    CARD32 attributes[2];
+	    attributes[0] = pScreen->whitePixel;
+	    attributes[1] = pScreen->blackPixel;
+	    (void)ChangeGC(pGC, GCForeground | GCBackground, attributes);
+
+	    ValidateGC((DrawablePtr)pWin, pGC);
+
+  	    (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, 1, &rect);
+
+   	    FreeScratchGC(pGC);
+    	
+	    /* Flush pending packets */
+	    rfbCheckFds(pScreen);
+	    httpCheckFds(pScreen);
+    	}
+    }
+
+    pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess;
+    (*pScrn->EnableDisableFBAccess)(index, enable);
+    pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess;
+}
+#endif
+
+/*
+ * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC
+ * func "ValidateGC" is called).
+ */
+
+Bool
+rfbCreateGC (GCPtr pGC)
+{
+    Bool ret;
+    rfbGCPtr pGCPriv;
+
+    SCREEN_PROLOGUE(pGC->pScreen,CreateGC);
+
+    pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr;
+
+    ret = (*pScreen->CreateGC) (pGC);
+
+    TRC((stderr,"rfbCreateGC called\n"));
+
+    pGCPriv->wrapOps = NULL;
+    pGCPriv->wrapFuncs = pGC->funcs;
+    pGC->funcs = &rfbGCFuncs;
+
+    SCREEN_EPILOGUE(CreateGC,rfbCreateGC);
+
+    return ret;
+}
+
+/*
+ * PaintWindowBackground - the region being modified is just the given region.
+ */
+
+void
+rfbPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground);
+
+    TRC((stderr,"rfbPaintWindowBackground called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen,pRegion);
+
+    (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground);
+}
+
+/*
+ * PaintWindowBorder - the region being modified is just the given region.
+ */
+
+void
+rfbPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder);
+
+    TRC((stderr,"rfbPaintWindowBorder called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen,pRegion);
+
+    (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder);
+}
+
+#ifdef CHROMIUM
+Bool
+rfbRealizeWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,RealizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 1);
+	 }
+    }
+
+    ret = (*pScreen->RealizeWindow)(pWin);
+
+    SCREEN_EPILOGUE(RealizeWindow,rfbRealizeWindow);
+
+    return ret;
+}
+
+Bool
+rfbUnrealizeWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,UnrealizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 0);
+	 }
+    }
+
+    ret = (*pScreen->UnrealizeWindow)(pWin);
+
+    SCREEN_EPILOGUE(UnrealizeWindow,rfbUnrealizeWindow);
+
+    return ret;
+}
+
+Bool
+rfbDestroyWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 0);
+	 }
+    }
+
+    ret = (*pScreen->DestroyWindow)(pWin);
+
+    SCREEN_EPILOGUE(DestroyWindow,rfbDestroyWindow);
+
+    return ret;
+}
+
+void
+rfbResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ResizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	     rfbSendChromiumMoveResizeWindow(wt->CRwinId, pWin->drawable.x, pWin->drawable.y, w, h);
+	 }
+    }
+
+    (*pScreen->ResizeWindow)(pWin, x, y, w, h, pSib);
+
+    SCREEN_EPILOGUE(ResizeWindow,rfbResizeWindow);
+}
+
+Bool
+rfbPositionWindow(WindowPtr pWin, int x, int y)
+{
+    Bool ret;
+    CRWindowTable *wt, *nextWt;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PositionWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	     rfbSendChromiumMoveResizeWindow(wt->CRwinId, x, y, pWin->drawable.width, pWin->drawable.height);
+	 }
+    }
+
+    ret = (*pScreen->PositionWindow)(pWin, x, y);
+
+    SCREEN_EPILOGUE(PositionWindow,rfbPositionWindow);
+
+    return ret;
+}
+
+void
+rfbClipNotify(WindowPtr pWin, int x, int y)
+{
+    CRWindowTable *wt, *nextWt;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ClipNotify);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    int numClipRects = REGION_NUM_RECTS(&pWin->clipList);
+	    BoxPtr pClipRects = REGION_RECTS(&pWin->clipList);
+
+	    /* Possible optimization - has the cliplist really? changed */
+
+	    rfbSendChromiumClipList(wt->CRwinId, pClipRects, numClipRects);
+	 }
+    }
+
+    if (*pScreen->ClipNotify) 
+    	(*pScreen->ClipNotify)(pWin, x, y);
+
+    SCREEN_EPILOGUE(ClipNotify,rfbClipNotify);
+}
+#endif /* CHROMIUM */
+
+/*
+ * CopyWindow - the region being modified is the translation of the old
+ * region, clipped to the border clip region of the window.  Note that any
+ * parts of the window which have become newly-visible will not be affected by
+ * this call - a separate PaintWindowBackground/Border will be called to do
+ * that.  If the client will accept CopyRect messages then use rfbCopyRegion to
+ * optimise the pending screen changes into a single "copy region" plus the
+ * ordinary modified region.
+ */
+
+void
+rfbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion)
+{
+    rfbClientPtr cl;
+    RegionRec srcRegion, dstRegion;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow);
+
+    TRC((stderr,"rfbCopyWindow called\n"));
+
+    REGION_NULL(pScreen,&dstRegion);
+    REGION_COPY(pScreen,&dstRegion,pOldRegion);
+    REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion,
+		     pWin->drawable.x - ptOldOrg.x,
+		     pWin->drawable.y - ptOldOrg.y);
+    REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion,
+		     &pWin->borderClip);
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (cl->useCopyRect) {
+	    REGION_NULL(pScreen,&srcRegion);
+	    REGION_COPY(pScreen,&srcRegion,pOldRegion);
+
+	    rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion,
+			  pWin->drawable.x - ptOldOrg.x,
+			  pWin->drawable.y - ptOldOrg.y);
+
+	    REGION_UNINIT(pScreen, &srcRegion);
+
+	} else {
+
+	    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			 &dstRegion);
+	}
+    }
+
+    REGION_UNINIT(pScreen, &dstRegion);
+
+    (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow);
+}
+
+/*
+ * ClearToBackground - when generateExposures is false, the region being
+ * modified is the given rectangle (clipped to the "window clip region").
+ */
+
+void
+rfbClearToBackground (WindowPtr pWin, int x, int y, int w, int h, 
+		      Bool generateExposures)
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground);
+
+    TRC((stderr,"rfbClearToBackground called\n"));
+
+    if (!generateExposures) {
+	box.x1 = x + pWin->drawable.x;
+	box.y1 = y + pWin->drawable.y;
+	box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
+	box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
+
+	SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList);
+
+	ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
+
+	REGION_UNINIT(pScreen, &tmpRegion);
+    }
+
+    (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+    if (!generateExposures) {
+	SCHEDULE_FB_UPDATE(pScreen, pVNC);
+    }
+
+    SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground);
+}
+
+/*
+ * RestoreAreas - just be safe here - the region being modified is the whole
+ * exposed region.
+ */
+
+RegionPtr
+rfbRestoreAreas (WindowPtr pWin, RegionPtr prgnExposed)
+{
+    RegionPtr result;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas);
+
+    TRC((stderr,"rfbRestoreAreas called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen, prgnExposed);
+
+    result = (*pScreen->RestoreAreas) (pWin, prgnExposed);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas);
+
+    return result;
+}
+
+
+
+/****************************************************************************/
+/*
+ * GC funcs wrapper stuff
+ *
+ * We only really want to wrap the GC ops, but to do this we need to wrap
+ * ValidateGC and so all the other GC funcs must be wrapped as well.
+ */
+/****************************************************************************/
+
+#define GC_FUNC_PROLOGUE(pGC)						\
+    rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr;	\
+    (pGC)->funcs = pGCPriv->wrapFuncs;					\
+    if (pGCPriv->wrapOps)						\
+	(pGC)->ops = pGCPriv->wrapOps;
+
+#define GC_FUNC_EPILOGUE(pGC)		\
+    pGCPriv->wrapFuncs = (pGC)->funcs;	\
+    (pGC)->funcs = &rfbGCFuncs;		\
+    if (pGCPriv->wrapOps) {		\
+	pGCPriv->wrapOps = (pGC)->ops;	\
+	(pGC)->ops = &rfbGCOps;		\
+    }
+
+
+/*
+ * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if
+ * the drawing will be to a viewable window.
+ */
+
+static void
+rfbValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+    /*VNCSCREENPTR(pGC->pScreen);*/
+    GC_FUNC_PROLOGUE(pGC);
+
+    TRC((stderr,"rfbValidateGC called\n"));
+
+    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+    
+    pGCPriv->wrapOps = NULL;
+    if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable)
+    {
+	WindowPtr   pWin = (WindowPtr) pDrawable;
+	RegionPtr   pRegion = &pWin->clipList;
+
+	if (pGC->subWindowMode == IncludeInferiors)
+	    pRegion = &pWin->borderClip;
+	if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
+	    pGCPriv->wrapOps = pGC->ops;
+	    TRC((stderr,"rfbValidateGC: wrapped GC ops\n"));
+	}
+    }
+
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+/*
+ * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped
+ * function and then rewrap the funcs and ops.
+ */
+
+static void
+rfbChangeGC (pGC, mask)
+    GCPtr	    pGC;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->ChangeGC) (pGC, mask);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbCopyGC (pGCSrc, mask, pGCDst)
+    GCPtr	    pGCSrc, pGCDst;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE(pGCDst);
+    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+    GC_FUNC_EPILOGUE(pGCDst);
+}
+
+static void
+rfbDestroyGC (pGC)
+    GCPtr   pGC;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->DestroyGC) (pGC);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbChangeClip (pGC, type, pvalue, nrects)
+    GCPtr   pGC;
+    int		type;
+    pointer	pvalue;
+    int		nrects;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbDestroyClip(pGC)
+    GCPtr	pGC;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (* pGC->funcs->DestroyClip)(pGC);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbCopyClip(pgcDst, pgcSrc)
+    GCPtr pgcDst, pgcSrc;
+{
+    GC_FUNC_PROLOGUE(pgcDst);
+    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+    GC_FUNC_EPILOGUE(pgcDst);
+}
+
+
+/****************************************************************************/
+/*
+ * GC ops wrapper stuff
+ *
+ * Note that these routines will only have been wrapped for drawing to
+ * viewable windows so we don't need to check each time that the drawable
+ * is a viewable window.
+ */
+/****************************************************************************/
+
+#define GC_OP_PROLOGUE(pDrawable,pGC) \
+    ScreenPtr pScreen = pGC->pScreen;			\
+    VNCSCREENPTR(pScreen);			\
+    rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \
+    GCFuncs *oldFuncs = pGC->funcs; \
+    (void) pScreen; /* silence compiler */ \
+    (pGC)->funcs = pGCPrivate->wrapFuncs; \
+    (pGC)->ops = pGCPrivate->wrapOps;
+
+#define GC_OP_EPILOGUE(pGC) \
+    pGCPrivate->wrapOps = (pGC)->ops; \
+    (pGC)->funcs = oldFuncs; \
+    (pGC)->ops = &rfbGCOps;
+
+
+/*
+ * FillSpans - being very safe - the region being modified is the border clip
+ * region of the window.
+ */
+
+static void
+rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nInit;			/* number of spans to fill */
+    DDXPointPtr pptInit;		/* pointer to list of start points */
+    int		*pwidthInit;		/* pointer to list of n widths */
+    int 	fSorted;
+{
+    GC_OP_PROLOGUE(pDrawable,pGC);
+
+    TRC((stderr,"rfbFillSpans called\n"));
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
+			   &((WindowPtr)pDrawable)->borderClip);
+
+    (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * SetSpans - being very safe - the region being modified is the border clip
+ * region of the window.
+ */
+
+static void
+rfbSetSpans(DrawablePtr 		pDrawable, 
+	    GCPtr			pGC, 
+	    char			*psrc, 
+	    register DDXPointPtr	ppt, 
+	    int				*pwidth, 
+	    int				nspans, 
+	    int				fSorted)
+{
+    GC_OP_PROLOGUE(pDrawable,pGC);
+
+    TRC((stderr,"rfbSetSpans called\n"));
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
+			   &((WindowPtr)pDrawable)->borderClip);
+
+    (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PutImage - the region being modified is the rectangle of the
+ * PutImage (clipped to the window clip region).
+ */
+
+static void
+rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int		  depth;
+    int	    	  x;
+    int	    	  y;
+    int	    	  w;
+    int	    	  h;
+    int		  leftPad;
+    int	    	  format;
+    char    	  *pBits;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPutImage called\n"));
+
+    box.x1 = x + pDrawable->x;
+    box.y1 = y + pDrawable->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+
+    (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h,
+			   leftPad, format, pBits);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * CopyArea - the region being modified is the destination rectangle (clipped
+ * to the window clip region).
+ * If the client will accept CopyRect messages then use rfbCopyRegion
+ * to optimise the pending screen changes into a single "copy region" plus
+ * the ordinary modified region.
+ */
+
+static RegionPtr
+rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    GCPtr   	  pGC;
+    int	    	  srcx;
+    int	    	  srcy;
+    int	    	  w;
+    int	    	  h;
+    int	    	  dstx;
+    int	    	  dsty;
+{
+    rfbClientPtr cl;
+    RegionPtr rgn;
+    RegionRec srcRegion, dstRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDst, pGC);
+
+    TRC((stderr,"rfbCopyArea called\n"));
+
+    box.x1 = dstx + pDst->x;
+    box.y1 = dsty + pDst->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0);
+    REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion,
+		     					pGC->pCompositeClip);
+
+    if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) {
+	box.x1 = srcx + pSrc->x;
+	box.y1 = srcy + pSrc->y;
+	box.x2 = box.x1 + w;
+	box.y2 = box.y1 + h;
+
+	for (cl = rfbClientHead; cl; cl = cl->next) {
+	    if (cl->useCopyRect) {
+		SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0);
+		REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion,
+				 &((WindowPtr)pSrc)->clipList);
+
+		rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion,
+			      dstx + pDst->x - srcx - pSrc->x,
+			      dsty + pDst->y - srcy - pSrc->y);
+
+		REGION_UNINIT(pSrc->pScreen, &srcRegion);
+
+	    } else {
+
+		REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			     &dstRegion);
+	    }
+	}
+
+    } else {
+
+	ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion);
+    }
+
+    REGION_UNINIT(pDst->pScreen, &dstRegion);
+
+    rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				 dstx, dsty);
+
+    SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+
+    return rgn;
+}
+
+
+/*
+ * CopyPlane - the region being modified is the destination rectangle (clipped
+ * to the window clip region).
+ */
+
+static RegionPtr
+rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    register GCPtr pGC;
+    int     	  srcx,
+		  srcy;
+    int     	  w,
+		  h;
+    int     	  dstx,
+		  dsty;
+    unsigned long  plane;
+{
+    RegionPtr rgn;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDst, pGC);
+
+    TRC((stderr,"rfbCopyPlane called\n"));
+
+    box.x1 = dstx + pDst->x;
+    box.y1 = dsty + pDst->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDst->pScreen, &tmpRegion);
+
+    rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx, dsty, plane);
+
+    SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+
+    return rgn;
+}
+
+/*
+ * PolyPoint - find the smallest rectangle which encloses the points drawn
+ * (and clip).
+ */
+
+static void
+rfbPolyPoint (pDrawable, pGC, mode, npt, pts)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		mode;		/* Origin or Previous */
+    int		npt;
+    xPoint 	*pts;
+{
+    int i;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyPoint called\n"));
+
+    if (npt) {
+	int minX = pts[0].x, maxX = pts[0].x;
+	int minY = pts[0].y, maxY = pts[0].y;
+
+	if (mode == CoordModePrevious)
+	{
+	    int x = pts[0].x, y = pts[0].y;
+
+	    for (i = 1; i < npt; i++) {
+		x += pts[i].x;
+		y += pts[i].y;
+		if (x < minX) minX = x;
+		if (x > maxX) maxX = x;
+		if (y < minY) minY = y;
+		if (y > maxY) maxY = y;
+	    }
+	}
+	else
+	{
+	    for (i = 1; i < npt; i++) {
+		if (pts[i].x < minX) minX = pts[i].x;
+		if (pts[i].x > maxX) maxX = pts[i].x;
+		if (pts[i].y < minY) minY = pts[i].y;
+		if (pts[i].y > maxY) maxY = pts[i].y;
+	    }
+	}
+
+	box.x1 = minX + pDrawable->x;
+	box.y1 = minY + pDrawable->y;
+	box.x2 = maxX + 1 + pDrawable->x;
+	box.y2 = maxY + 1 + pDrawable->y;
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+
+    if (npt) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyLines - take the union of bounding boxes around each line (and clip).
+ */
+
+static void
+rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts)
+{
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    int i, extra, nlines, lw;
+    int x1, x2, y1, y2;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolylines called\n"));
+
+    if (npt) {
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	if (npt == 1)
+	{
+	    nlines = 1;
+	    rects = (xRectangle *)xalloc(sizeof(xRectangle));
+	    if (!rects) {
+		FatalError("rfbPolylines: xalloc failed\n");
+	    }
+
+	    rects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe here */
+	    rects[0].y = ppts[0].y - lw + pDrawable->y;
+	    rects[0].width = 2*lw;
+	    rects[0].height = 2*lw;
+	}
+	else
+	{
+	    nlines = npt - 1;
+	    rects = (xRectangle *)xalloc(nlines*sizeof(xRectangle));
+	    if (!rects) {
+		FatalError("rfbPolylines: xalloc failed\n");
+	    }
+
+	    /*
+	     * mitered joins can project quite a way from
+	     * the line end; the 11 degree miter limit limits
+	     * this extension to lw / (2 * tan(11/2)), rounded up
+	     * and converted to int yields 6 * lw
+	     */
+
+	    if (pGC->joinStyle == JoinMiter) {
+		extra = 6 * lw;
+	    } else {
+		extra = lw / 2;
+	    }
+
+	    x1 = ppts[0].x + pDrawable->x;
+	    y1 = ppts[0].y + pDrawable->y;
+
+	    for (i = 0; i < nlines; i++) {
+		if (mode == CoordModeOrigin) {
+		    x2 = pDrawable->x + ppts[i+1].x;
+		    y2 = pDrawable->y + ppts[i+1].y;
+		} else {
+		    x2 = x1 + ppts[i+1].x;
+		    y2 = y1 + ppts[i+1].y;
+		}
+
+		if (x1 > x2) {
+		    rects[i].x = x2 - extra;
+		    rects[i].width = x1 - x2 + 1 + 2 * extra;
+		} else {
+		    rects[i].x = x1 - extra;
+		    rects[i].width = x2 - x1 + 1 + 2 * extra;
+		}
+
+		if (y1 > y2) {
+		    rects[i].y = y2 - extra;
+		    rects[i].height = y1 - y2 + 1 + 2 * extra;
+		} else {
+		    rects[i].y = y1 - extra;
+		    rects[i].height = y2 - y1 + 1 + 2 * extra;
+		}
+
+		x1 = x2;
+		y1 = y2;
+	    }
+	}
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nlines, rects,CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+
+    if (npt) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolySegment - take the union of bounding boxes around each segment (and
+ * clip).
+ */
+
+static void
+rfbPolySegment(pDrawable, pGC, nseg, segs)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int		nseg;
+    xSegment	*segs;
+{
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    int i, extra, lw;
+
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolySegment called\n"));
+
+    if (nseg) {
+	rects = (xRectangle *)xalloc(nseg*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolySegment: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < nseg; i++)
+	{
+	    if (segs[i].x1 > segs[i].x2) {
+		rects[i].x = segs[i].x2 - extra + pDrawable->x;
+		rects[i].width = segs[i].x1 - segs[i].x2 + 1 + 2 * extra;
+	    } else {
+		rects[i].x = segs[i].x1 - extra + pDrawable->x;
+		rects[i].width = segs[i].x2 - segs[i].x1 + 1 + 2 * extra;
+	    }
+
+	    if (segs[i].y1 > segs[i].y2) {
+		rects[i].y = segs[i].y2 - extra + pDrawable->y;
+		rects[i].height = segs[i].y1 - segs[i].y2 + 1 + 2 * extra;
+	    } else {
+		rects[i].y = segs[i].y1 - extra + pDrawable->y;
+		rects[i].height = segs[i].y2 - segs[i].y1 + 1 + 2 * extra;
+	    }
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nseg, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+
+    if (nseg) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyRectangle (rectangle outlines) - take the union of bounding boxes
+ * around each line (and clip).
+ */
+
+static void
+rfbPolyRectangle(pDrawable, pGC, nrects, rects)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*rects;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *regRects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyRectangle called\n"));
+
+    if (nrects) {
+	regRects = (xRectangle *)xalloc(nrects*4*sizeof(xRectangle));
+	if (!regRects) {
+	    FatalError("rfbPolyRectangle: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < nrects; i++)
+	{
+	    regRects[i*4].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4].width = rects[i].width + 1 + 2 * extra;
+	    regRects[i*4].height = 1 + 2 * extra;
+
+	    regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4+1].width = 1 + 2 * extra;
+	    regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
+
+	    regRects[i*4+2].x
+		= rects[i].x + rects[i].width - extra + pDrawable->x;
+	    regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4+2].width = 1 + 2 * extra;
+	    regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
+
+	    regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4+3].y
+		= rects[i].y + rects[i].height - extra + pDrawable->y;
+	    regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
+	    regRects[i*4+3].height = 1 + 2 * extra;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects*4,
+				    regRects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)regRects);
+    }
+
+    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+
+    if (nrects) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyArc - take the union of bounding boxes around each arc (and clip).
+ * Bounding boxes assume each is a full circle / ellipse.
+ */
+
+static void
+rfbPolyArc(pDrawable, pGC, narcs, arcs)
+    DrawablePtr	pDrawable;
+    register GCPtr	pGC;
+    int		narcs;
+    xArc	*arcs;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyArc called\n"));
+
+    if (narcs) {
+	rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolyArc: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < narcs; i++)
+	{
+	    rects[i].x = arcs[i].x - extra + pDrawable->x;
+	    rects[i].y = arcs[i].y - extra + pDrawable->y;
+	    rects[i].width = arcs[i].width + lw;
+	    rects[i].height = arcs[i].height + lw;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+
+    if (narcs) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * FillPolygon - take bounding box around polygon (and clip).
+ */
+
+static void
+rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts)
+    register DrawablePtr pDrawable;
+    register GCPtr	pGC;
+    int			shape, mode;
+    int			count;
+    DDXPointPtr		pts;
+{
+    int i;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbFillPolygon called\n"));
+
+    if (count) {
+	int minX = pts[0].x, maxX = pts[0].x;
+	int minY = pts[0].y, maxY = pts[0].y;
+
+	if (mode == CoordModePrevious)
+	{
+	    int x = pts[0].x, y = pts[0].y;
+
+	    for (i = 1; i < count; i++) {
+		x += pts[i].x;
+		y += pts[i].y;
+		if (x < minX) minX = x;
+		if (x > maxX) maxX = x;
+		if (y < minY) minY = y;
+		if (y > maxY) maxY = y;
+	    }
+	}
+	else
+	{
+	    for (i = 1; i < count; i++) {
+		if (pts[i].x < minX) minX = pts[i].x;
+		if (pts[i].x > maxX) maxX = pts[i].x;
+		if (pts[i].y < minY) minY = pts[i].y;
+		if (pts[i].y > maxY) maxY = pts[i].y;
+	    }
+	}
+
+	box.x1 = minX + pDrawable->x;
+	box.y1 = minY + pDrawable->y;
+	box.x2 = maxX + 1 + pDrawable->x;
+	box.y2 = maxY + 1 + pDrawable->y;
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyFillRect - take the union of the given rectangles (and clip).
+ */
+
+static void
+rfbPolyFillRect(pDrawable, pGC, nrects, rects)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*rects;
+{
+    RegionPtr tmpRegion;
+    xRectangle *regRects;
+    int i;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyFillRect called\n"));
+
+    if (nrects) {
+	regRects = (xRectangle *)xalloc(nrects*sizeof(xRectangle));
+	if (!regRects) {
+	    FatalError("rfbPolyFillRect: xalloc failed\n");
+	}
+
+	for (i = 0; i < nrects; i++) {
+	    regRects[i].x = rects[i].x + pDrawable->x;
+	    regRects[i].y = rects[i].y + pDrawable->y;
+	    regRects[i].width = rects[i].width;
+	    regRects[i].height = rects[i].height;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects, regRects,
+				    CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)regRects);
+    }
+
+    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+
+    if (nrects) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyFillArc - take the union of bounding boxes around each arc (and clip).
+ * Bounding boxes assume each is a full circle / ellipse.
+ */
+
+static void
+rfbPolyFillArc(pDrawable, pGC, narcs, arcs)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		narcs;
+    xArc	*arcs;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyFillArc called\n"));
+
+    if (narcs) {
+	rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolyFillArc: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < narcs; i++)
+	{
+	    rects[i].x = arcs[i].x - extra + pDrawable->x;
+	    rects[i].y = arcs[i].y - extra + pDrawable->y;
+	    rects[i].width = arcs[i].width + lw;
+	    rects[i].height = arcs[i].height + lw;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+
+    if (narcs) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * Get a rough bounding box around n characters of the given font.
+ */
+
+static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox)
+    DrawablePtr pDrawable;
+    FontPtr font;
+    int x, y, n;
+    BoxPtr pbox;
+{
+    int maxAscent, maxDescent, maxCharWidth;
+
+    if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent))
+	maxAscent = FONTASCENT(font);
+    else
+	maxAscent = FONTMAXBOUNDS(font,ascent);
+
+    if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent))
+	maxDescent = FONTDESCENT(font);
+    else
+	maxDescent = FONTMAXBOUNDS(font,descent);
+
+    if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth))
+	maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing);
+    else
+	maxCharWidth = FONTMAXBOUNDS(font,characterWidth);
+
+    pbox->x1 = pDrawable->x + x;
+    pbox->y1 = pDrawable->y + y - maxAscent;
+    pbox->x2 = pbox->x1 + maxCharWidth * n;
+    pbox->y2 = pbox->y1 + maxAscent + maxDescent;
+
+    if (FONTMINBOUNDS(font,leftSideBearing) < 0) {
+	pbox->x1 += FONTMINBOUNDS(font,leftSideBearing);
+    }
+}
+
+
+/*
+ * PolyText8 - use rough bounding box.
+ */
+
+static int
+rfbPolyText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int 	count;
+    char	*chars;
+{
+    int	ret;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyText8 called '%.*s'\n",count,chars));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+    return ret;
+}
+
+/*
+ * PolyText16 - use rough bounding box.
+ */
+
+static int
+rfbPolyText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    int	ret;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyText16 called\n"));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+    return ret;
+}
+
+/*
+ * ImageText8 - use rough bounding box.
+ */
+
+static void
+rfbImageText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    char	*chars;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageText8 called '%.*s'\n",count,chars));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * ImageText16 - use rough bounding box.
+ */
+
+static void
+rfbImageText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageText16 called\n"));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * ImageGlyphBlt - use rough bounding box.
+ */
+
+static void
+rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer 	pglyphBase;	/* start of array of glyphs */
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageGlyphBlt called\n"));
+
+    if (nglyph) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+
+    if (nglyph) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyGlyphBlt - use rough bounding box.
+ */
+
+static void
+rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer	pglyphBase;	/* start of array of glyphs */
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyGlyphBlt called\n"));
+
+    if (nglyph) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    if (nglyph) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PushPixels - be fairly safe - region modified is intersection of the given
+ * rectangle with the window clip region.
+ */
+
+static void
+rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y)
+    GCPtr	pGC;
+    PixmapPtr	pBitMap;
+    DrawablePtr pDrawable;
+    int		w, h, x, y;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPushPixels called\n"));
+
+    box.x1 = x + pDrawable->x;
+    box.y1 = y + pDrawable->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+
+    (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+#ifdef RENDER
+void
+rfbComposite(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pMask,
+    PicturePtr pDst,
+    INT16 xSrc,
+    INT16 ySrc,
+    INT16 xMask,
+    INT16 yMask,
+    INT16 xDst,
+    INT16 yDst,
+    CARD16 width,
+    CARD16 height
+){
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    RegionRec tmpRegion;
+    BoxRec box;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+    box.x1 = pDst->pDrawable->x + xDst;
+    box.y1 = pDst->pDrawable->y + yDst;
+    box.x2 = box.x1 + width;
+    box.y2 = box.y1 + height;
+
+    REGION_INIT(pScreen, &tmpRegion, &box, 0);
+
+    ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
+
+    ps->Composite = pVNC->Composite;
+    (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
+		     xMask, yMask, xDst, yDst, width, height);
+    ps->Composite = rfbComposite;
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    REGION_UNINIT(pScreen, &tmpRegion);
+}
+#endif /* RENDER */
+
+/****************************************************************************/
+/*
+ * Other functions
+ */
+/****************************************************************************/
+
+/*
+ * rfbCopyRegion.  Args are src and dst regions plus a translation (dx,dy).
+ * Takes these args together with the existing modified region and possibly an
+ * existing copy region and translation.  Produces a combined modified region
+ * plus copy region and translation.  Note that the copy region is the
+ * destination of the copy.
+ *
+ * First we trim parts of src which are invalid (ie in the modified region).
+ * Then we see if there is any overlap between the src and the existing copy
+ * region.  If not then the two copies cannot be combined, so we choose
+ * whichever is bigger to form the basis of a new copy, while the other copy is
+ * just done the hard way by being added to the modified region.  So if the
+ * existing copy is bigger then we simply add the destination of the new copy
+ * to the modified region and we're done.  If the new copy is bigger, we add
+ * the old copy region to the modified region and behave as though there is no
+ * existing copy region.
+ * 
+ * At this stage we now know that either the two copies can be combined, or
+ * that there is no existing copy.  We temporarily add both the existing copy
+ * region and dst to the modified region (this is the entire area of the screen
+ * affected in any way).  Finally we calculate the new copy region, and remove
+ * it from the modified region.
+ *
+ * Note:
+ *   1. The src region is modified by this routine.
+ *   2. When the copy region is empty, copyDX and copyDY MUST be set to zero.
+ */
+
+static void
+rfbCopyRegion(pScreen, cl, src, dst, dx, dy)
+    ScreenPtr pScreen;
+    rfbClientPtr cl;
+    RegionPtr src;
+    RegionPtr dst;
+    int dx, dy;
+{
+    RegionRec tmp;
+
+    /* src = src - modifiedRegion */
+
+    REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion);
+
+    if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+
+	REGION_NULL(pScreen, &tmp);
+	REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion);
+
+	if (REGION_NOTEMPTY(pScreen, &tmp)) {
+
+	    /* if src and copyRegion overlap:
+	         src = src intersect copyRegion */
+
+	    REGION_COPY(pScreen, src, &tmp);
+
+	} else {
+
+	    /* if no overlap, find bigger region */
+
+	    int newArea = (((REGION_EXTENTS(pScreen,src))->x2
+			    - (REGION_EXTENTS(pScreen,src))->x1)
+			   * ((REGION_EXTENTS(pScreen,src))->y2
+			      - (REGION_EXTENTS(pScreen,src))->y1));
+
+	    int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2
+			    - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1)
+			   * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2
+			     - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1));
+
+	    if (oldArea > newArea) {
+
+		/* existing copy is bigger:
+		     modifiedRegion = modifiedRegion union dst
+		     copyRegion = copyRegion - dst
+		     return */
+
+		REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			     dst);
+		REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
+				dst);
+		if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+		    cl->copyDX = 0;
+		    cl->copyDY = 0;
+		}
+		return;
+	    }
+
+	    /* new copy is bigger:
+	         modifiedRegion = modifiedRegion union copyRegion
+		 copyRegion = empty */
+
+	    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			 &cl->copyRegion);
+	    REGION_EMPTY(pScreen, &cl->copyRegion);
+	    cl->copyDX = cl->copyDY = 0;
+	}
+    }
+
+
+    /* modifiedRegion = modifiedRegion union dst union copyRegion */
+
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst);
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		 &cl->copyRegion);
+
+    /* copyRegion = T(src) intersect dst */
+
+    REGION_TRANSLATE(pScreen, src, dx, dy);
+    REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst);
+
+    /* modifiedRegion = modifiedRegion - copyRegion */
+
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &cl->copyRegion);
+
+    /* combine new translation T with existing translation */
+
+    if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+	cl->copyDX += dx;
+	cl->copyDY += dy;
+    } else {
+	cl->copyDX = 0;
+	cl->copyDY = 0;
+    }
+}
+
+
+/*
+ * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer
+ * goes off.
+ */
+
+static CARD32
+rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+  rfbClientPtr cl = (rfbClientPtr)arg;
+
+  rfbSendFramebufferUpdate(cl->pScreen, cl);
+
+  cl->deferredUpdateScheduled = FALSE;
+  return 0;
+}
+
+
+/*
+ * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro
+ * to schedule an update.
+ */
+
+static void
+rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl)
+{
+    if (rfbDeferUpdateTime != 0) {
+	cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0,
+					   rfbDeferUpdateTime,
+					   rfbDeferredUpdateCallback, cl);
+	cl->deferredUpdateScheduled = TRUE;
+    } else {
+	rfbSendFramebufferUpdate(pScreen, cl);
+    }
+}
+
+
+/*
+ * PrintRegion is useful for debugging.
+ */
+
+#ifdef DEBUG
+static void
+PrintRegion(ScreenPtr pScreen, RegionPtr reg)
+{
+    int nrects = REGION_NUM_RECTS(reg);
+    int i;
+
+    ErrorF("Region num rects %d extents %d,%d %d,%d\n",nrects,
+	   (REGION_EXTENTS(pScreen,reg))->x1,
+	   (REGION_EXTENTS(pScreen,reg))->y1,
+	   (REGION_EXTENTS(pScreen,reg))->x2,
+	   (REGION_EXTENTS(pScreen,reg))->y2);
+
+    for (i = 0; i < nrects; i++) {
+	ErrorF("    rect %d,%d %dx%d\n",
+	       REGION_RECTS(reg)[i].x1,
+	       REGION_RECTS(reg)[i].y1,
+	       REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1,
+	       REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1);
+    }
+}
+#endif
diff -u -rNp a/hw/dmx/vnc/hextile.c b/hw/dmx/vnc/hextile.c
--- a/hw/dmx/vnc/hextile.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/hextile.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,352 @@
+/*
+ * hextile.c
+ *
+ * Routines to implement Hextile Encoding
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rfb.h"
+
+static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
+static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
+static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
+
+
+/*
+ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
+ */
+
+Bool
+rfbSendRectEncodingHextile(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingHextile);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingHextile]++;
+    cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader;
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	return sendHextiles8(cl, x, y, w, h);
+    case 16:
+	return sendHextiles16(cl, x, y, w, h);
+    case 32:
+	return sendHextiles32(cl, x, y, w, h);
+    }
+
+    rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
+    return FALSE;
+}
+
+
+#define PUT_PIXEL8(pix) (pVNC->updateBuf[pVNC->ublen++] = (pix))
+
+#define PUT_PIXEL16(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1])
+
+#define PUT_PIXEL32(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[2], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[3])
+
+
+#define DEFINE_SEND_HEXTILES(bpp)					      \
+									      \
+									      \
+static Bool subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w,     \
+			       int h, CARD##bpp bg,   			      \
+			       CARD##bpp fg, Bool mono);		      \
+static void testColours##bpp(CARD##bpp *data, int size, Bool *mono,	      \
+			     Bool *solid, CARD##bpp *bg, CARD##bpp *fg);      \
+									      \
+									      \
+/*									      \
+ * rfbSendHextiles							      \
+ */									      \
+									      \
+static Bool								      \
+sendHextiles##bpp(cl, rx, ry, rw, rh)					      \
+    rfbClientPtr cl;							      \
+    int rx, ry, rw, rh;							      \
+{									      \
+    VNCSCREENPTR(cl->pScreen);						      \
+    int x, y, w, h;							      \
+    int startUblen;							      \
+    unsigned char *fbptr;						      \
+    CARD##bpp bg = 0, fg = 0, newBg, newFg;				      \
+    Bool mono, solid;							      \
+    Bool validBg = FALSE;						      \
+    Bool validFg = FALSE;						      \
+    CARD##bpp clientPixelData[16*16*(bpp/8)];				      \
+									      \
+    for (y = ry; y < ry+rh; y += 16) {					      \
+	for (x = rx; x < rx+rw; x += 16) {				      \
+	    w = h = 16;							      \
+	    if (rx+rw - x < 16)						      \
+		w = rx+rw - x;						      \
+	    if (ry+rh - y < 16)						      \
+		h = ry+rh - y;						      \
+									      \
+	    if ((pVNC->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \
+		if (!rfbSendUpdateBuf(cl))				      \
+		    return FALSE;					      \
+	    }								      \
+									      \
+	    fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)	      \
+		     + (x * (pVNC->bitsPerPixel / 8)));		      	      \
+									      \
+	    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,	      \
+			       &pVNC->rfbServerFormat,			      \
+			       &cl->format, fbptr, (char *)clientPixelData,   \
+			       pVNC->paddedWidthInBytes, w, h, x, y); 	      \
+									      \
+	    startUblen = pVNC->ublen;					      \
+	    pVNC->updateBuf[startUblen] = 0;				      \
+	    pVNC->ublen++;						      \
+									      \
+	    testColours##bpp(clientPixelData, w * h,			      \
+			     &mono, &solid, &newBg, &newFg);		      \
+									      \
+	    if (!validBg || (newBg != bg)) {				      \
+		validBg = TRUE;						      \
+		bg = newBg;						      \
+		pVNC->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
+		PUT_PIXEL##bpp(bg);					      \
+	    }								      \
+									      \
+	    if (solid) {						      \
+		cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen;  \
+		continue;						      \
+	    }								      \
+									      \
+	    pVNC->updateBuf[startUblen] |= rfbHextileAnySubrects;	      \
+									      \
+	    if (mono) {							      \
+		if (!validFg || (newFg != fg)) {			      \
+		    validFg = TRUE;					      \
+		    fg = newFg;						      \
+		    pVNC->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
+		    PUT_PIXEL##bpp(fg);					      \
+		}							      \
+	    } else {							      \
+		validFg = FALSE;					      \
+		pVNC->updateBuf[startUblen] |= rfbHextileSubrectsColoured;    \
+	    }								      \
+									      \
+	    if (!subrectEncode##bpp(cl->pScreen, clientPixelData, w, h, bg, fg, mono)) {   \
+		/* encoding was too large, use raw */			      \
+		validBg = FALSE;					      \
+		validFg = FALSE;					      \
+		pVNC->ublen = startUblen;				      \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextileRaw;		      \
+		(*cl->translateFn)(cl->pScreen, cl->translateLookupTable,     \
+				   &pVNC->rfbServerFormat, &cl->format, fbptr,\
+				   (char *)clientPixelData,		      \
+				   pVNC->paddedWidthInBytes, w, h, x, y);     \
+									      \
+		memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)clientPixelData,\
+		       w * h * (bpp/8));				      \
+									      \
+		pVNC->ublen += w * h * (bpp/8);				      \
+	    }								      \
+									      \
+	    cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \
+	}								      \
+    }									      \
+									      \
+    return TRUE;							      \
+}									      \
+									      \
+									      \
+static Bool								      \
+subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, int h,          \
+		   CARD##bpp bg, CARD##bpp fg, Bool mono)		      \
+{									      \
+    VNCSCREENPTR(pScreen);						      \
+    CARD##bpp clientdata;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    int nSubrectsUblen;							      \
+									      \
+    nSubrectsUblen = pVNC->ublen;					      \
+    pVNC->ublen++;							      \
+									      \
+    for (y=0; y<h; y++) {						      \
+	line = data+(y*w);						      \
+	for (x=0; x<w; x++) {						      \
+	    if (line[x] != bg) {					      \
+		clientdata = line[x];					      \
+		hy = y-1;						      \
+		hyflag = 1;						      \
+		for (j=y; j<h; j++) {					      \
+		    seg = data+(j*w);					      \
+		    if (seg[x] != clientdata) {break;}			      \
+		    i = x;						      \
+		    while ((seg[i] == clientdata) && (i < w)) i += 1;	      \
+		    i -= 1;						      \
+		    if (j == y) vx = hx = i;				      \
+		    if (i < vx) vx = i;					      \
+		    if ((hyflag > 0) && (i >= hx)) {			      \
+			hy += 1;					      \
+		    } else {						      \
+			hyflag = 0;					      \
+		    }							      \
+		}							      \
+		vy = j-1;						      \
+									      \
+		/* We now have two possible subrects: (x,y,hx,hy) and	      \
+		 * (x,y,vx,vy).  We'll choose the bigger of the two.	      \
+		 */							      \
+		hw = hx-x+1;						      \
+		hh = hy-y+1;						      \
+		vw = vx-x+1;						      \
+		vh = vy-y+1;						      \
+									      \
+		thex = x;						      \
+		they = y;						      \
+									      \
+		if ((hw*hh) > (vw*vh)) {				      \
+		    thew = hw;						      \
+		    theh = hh;						      \
+		} else {						      \
+		    thew = vw;						      \
+		    theh = vh;						      \
+		}							      \
+									      \
+		if (mono) {						      \
+		    newLen = pVNC->ublen - nSubrectsUblen + 2;		      \
+		} else {						      \
+		    newLen = pVNC->ublen - nSubrectsUblen + bpp/8 + 2;	      \
+		}							      \
+									      \
+		if (newLen > (w * h * (bpp/8)))				      \
+		    return FALSE;					      \
+									      \
+		numsubs += 1;						      \
+									      \
+		if (!mono) PUT_PIXEL##bpp(clientdata);			      \
+									      \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextilePackXY(thex,they); \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextilePackWH(thew,theh); \
+									      \
+		/*							      \
+		 * Now mark the subrect as done.			      \
+		 */							      \
+		for (j=they; j < (they+theh); j++) {			      \
+		    for (i=thex; i < (thex+thew); i++) {		      \
+			data[j*w+i] = bg;				      \
+		    }							      \
+		}							      \
+	    }								      \
+	}								      \
+    }									      \
+									      \
+    pVNC->updateBuf[nSubrectsUblen] = numsubs;				      \
+									      \
+    return TRUE;							      \
+}									      \
+									      \
+									      \
+/*									      \
+ * testColours() tests if there are one (solid), two (mono) or more	      \
+ * colours in a tile and gets a reasonable guess at the best background	      \
+ * pixel, and the foreground pixel for mono.				      \
+ */									      \
+									      \
+static void								      \
+testColours##bpp(data,size,mono,solid,bg,fg)				      \
+    CARD##bpp *data;							      \
+    int size;								      \
+    Bool *mono;								      \
+    Bool *solid;							      \
+    CARD##bpp *bg;							      \
+    CARD##bpp *fg;							      \
+{									      \
+    CARD##bpp colour1 = 0, colour2 = 0;					      \
+    int n1 = 0, n2 = 0;							      \
+    *mono = TRUE;							      \
+    *solid = TRUE;							      \
+									      \
+    for (; size > 0; size--, data++) {					      \
+									      \
+	if (n1 == 0)							      \
+	    colour1 = *data;						      \
+									      \
+	if (*data == colour1) {						      \
+	    n1++;							      \
+	    continue;							      \
+	}								      \
+									      \
+	if (n2 == 0) {							      \
+	    *solid = FALSE;						      \
+	    colour2 = *data;						      \
+	}								      \
+									      \
+	if (*data == colour2) {						      \
+	    n2++;							      \
+	    continue;							      \
+	}								      \
+									      \
+	*mono = FALSE;							      \
+	break;								      \
+    }									      \
+									      \
+    if (n1 > n2) {							      \
+	*bg = colour1;							      \
+	*fg = colour2;							      \
+    } else {								      \
+	*bg = colour2;							      \
+	*fg = colour1;							      \
+    }									      \
+}
+
+DEFINE_SEND_HEXTILES(8)
+DEFINE_SEND_HEXTILES(16)
+DEFINE_SEND_HEXTILES(32)
diff -u -rNp a/hw/dmx/vnc/httpd.c b/hw/dmx/vnc/httpd.c
--- a/hw/dmx/vnc/httpd.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/httpd.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,520 @@
+/*
+ * httpd.c - a simple HTTP server
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <netdb.h>
+
+#ifndef USE_LIBWRAP
+#define USE_LIBWRAP 0
+#endif
+#if USE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include "rfb.h"
+
+#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \
+    "<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \
+    "<BODY><H1>File Not Found</H1></BODY>\n"
+
+#define OK_STR "HTTP/1.0 200 OK\r\n\r\n"
+
+static void httpProcessInput(ScreenPtr pScreen);
+static Bool compareAndSkip(char **ptr, const char *str);
+static Bool parseParams(const char *request, char *result, int max_bytes);
+static Bool validateString(char *str);
+
+/*
+ * httpInitSockets sets up the TCP socket to listen for HTTP connections.
+ */
+
+Bool
+httpInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (!pVNC->httpDir)
+	return FALSE;
+
+    pVNC->buf_filled = 0;
+
+    if (pVNC->httpPort == 0) {
+	pVNC->httpPort = 5800 + atoi(display) + pScreen->myNum;
+    }
+
+    if ((pVNC->httpListenSock = ListenOnTCPPort(pScreen, pVNC->httpPort)) < 0) {
+	rfbLog("ListenOnTCPPort %d failed\n",pVNC->httpPort);
+	pVNC->httpPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for HTTP connections on TCP port %d\n", pVNC->httpPort);
+    rfbLog("  URL http://%s:%d\n",rfbThisHost,pVNC->httpPort);
+
+    AddEnabledDevice(pVNC->httpListenSock);
+
+    return TRUE;
+}
+
+
+/*
+ * httpCheckFds is called from ProcessInputEvents to check for input on the
+ * HTTP socket(s).  If there is input to process, httpProcessInput is called.
+ */
+
+void
+httpCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+
+    if (!pVNC->httpDir)
+	return;
+
+    FD_ZERO(&fds);
+    FD_SET(pVNC->httpListenSock, &fds);
+    if (pVNC->httpSock >= 0) {
+	FD_SET(pVNC->httpSock, &fds);
+    }
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(max(pVNC->httpSock,pVNC->httpListenSock) + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR) 
+		rfbLogPerror("httpCheckFds: select");
+	return;
+    }
+
+    if ((pVNC->httpSock >= 0) && FD_ISSET(pVNC->httpSock, &fds)) {
+	httpProcessInput(pScreen);
+    }
+
+    if (FD_ISSET(pVNC->httpListenSock, &fds)) {
+	int flags;
+
+	if (pVNC->httpSock >= 0) close(pVNC->httpSock);
+
+	if ((pVNC->httpSock = accept(pVNC->httpListenSock,
+			       (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("httpCheckFds: accept");
+	    return;
+	}
+
+#if USE_LIBWRAP
+	if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr),
+		       STRING_UNKNOWN)) {
+	    rfbLog("Rejected HTTP connection from client %s\n",
+		   inet_ntoa(addr.sin_addr));
+  	    close(pVNC->httpSock);
+  	    pVNC->httpSock = -1;
+  	    return;
+  	}
+#endif
+
+	flags = fcntl (pVNC->httpSock, F_GETFL);
+
+	if (flags == -1 ||
+	fcntl (pVNC->httpSock, F_SETFL, flags | O_NONBLOCK) == -1) {
+	    rfbLogPerror("httpCheckFds: fcntl");
+	    close (pVNC->httpSock);
+	    pVNC->httpSock = -1;
+	    return;
+	}
+
+	AddEnabledDevice(pVNC->httpSock);
+    }
+}
+
+
+static void
+httpCloseSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    close(pVNC->httpSock);
+    RemoveEnabledDevice(pVNC->httpSock);
+    pVNC->httpSock = -1;
+    pVNC->buf_filled = 0;
+}
+
+
+/*
+ * httpProcessInput is called when input is received on the HTTP socket.
+ */
+
+static void
+httpProcessInput(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+    char fullFname[512];
+    char params[1024];
+    char *ptr;
+    char *fname;
+    int maxFnameLen;
+    int fd;
+    Bool performSubstitutions = FALSE;
+    char str[256];
+    struct passwd *user = getpwuid(getuid());
+  
+    if (strlen(pVNC->httpDir) > 255) {
+	rfbLog("-httpd directory too long\n");
+  	httpCloseSock(pScreen);
+	return;
+    }
+    strcpy(fullFname, pVNC->httpDir);
+    fname = &fullFname[strlen(fullFname)];
+    maxFnameLen = 511 - strlen(fullFname);
+  
+    /* Read data from the HTTP client until we get a complete request. */
+    while (1) {
+	ssize_t got = read (pVNC->httpSock, pVNC->buf + pVNC->buf_filled,
+			    sizeof (pVNC->buf) - pVNC->buf_filled - 1);
+
+	if (got <= 0) {
+	    if (got == 0) {
+		rfbLog("httpd: premature connection close\n");
+	    } else {
+		if (errno == EAGAIN) {
+		    return;
+		}
+		rfbLogPerror("httpProcessInput: read");
+	    }
+	    httpCloseSock(pScreen);
+  	    return;
+	}
+  
+	pVNC->buf_filled += got;
+	pVNC->buf[pVNC->buf_filled] = '\0';
+  
+	/* Is it complete yet (is there a blank line)? */
+	if (strstr (pVNC->buf, "\r\r") || strstr (pVNC->buf, "\n\n") ||
+	    strstr (pVNC->buf, "\r\n\r\n") || strstr (pVNC->buf, "\n\r\n\r"))
+	    break;
+    }
+  
+    /* Process the request. */
+    if (strncmp(pVNC->buf, "GET ", 4)) {
+	rfbLog("httpd: no GET line\n");
+	httpCloseSock(pScreen);
+	return;
+    } else {
+	/* Only use the first line. */
+	pVNC->buf[strcspn(pVNC->buf, "\n\r")] = '\0';
+    }
+  
+    if (strlen(pVNC->buf) > maxFnameLen) {
+	rfbLog("httpd: GET line too long\n");
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (sscanf(pVNC->buf, "GET %s HTTP/1.0", fname) != 1) {
+	rfbLog("httpd: couldn't parse GET line\n");
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (fname[0] != '/') {
+	rfbLog("httpd: filename didn't begin with '/'\n");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (strchr(fname+1, '/') != NULL) {
+	rfbLog("httpd: asking for file in other directory\n");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    getpeername(pVNC->httpSock, (struct sockaddr *)&addr, &addrlen);
+    rfbLog("httpd: get '%s' for %s\n", fname+1,
+	   inet_ntoa(addr.sin_addr));
+
+    /* Extract parameters from the URL string if necessary */
+
+    params[0] = '\0';
+    ptr = strchr(fname, '?');
+    if (ptr != NULL) {
+	*ptr = '\0';
+	if (!parseParams(&ptr[1], params, 1024)) {
+	    params[0] = '\0';
+	    rfbLog("httpd: bad parameters in the URL\n");
+	}
+    }
+
+    /* If we were asked for '/', actually read the file index.vnc */
+
+    if (strcmp(fname, "/") == 0) {
+	strcpy(fname, "/index.vnc");
+	rfbLog("httpd: defaulting to '%s'\n", fname+1);
+    }
+
+    /* Substitutions are performed on files ending .vnc */
+
+    if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
+	performSubstitutions = TRUE;
+    }
+
+    /* Open the file */
+
+    if ((fd = open(fullFname, O_RDONLY)) < 0) {
+	rfbLogPerror("httpProcessInput: open");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+
+    WriteExact(pVNC->httpSock, OK_STR, strlen(OK_STR));
+
+    while (1) {
+	int n = read(fd, pVNC->buf, HTTP_BUF_SIZE-1);
+	if (n < 0) {
+	    rfbLogPerror("httpProcessInput: read");
+	    close(fd);
+	    httpCloseSock(pScreen);
+	    return;
+	}
+
+	if (n == 0)
+	    break;
+
+	if (performSubstitutions) {
+
+	    /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
+	       This won't quite work properly if the .vnc file is longer than
+	       HTTP_BUF_SIZE, but it's reasonable to assume that .vnc files will
+	       always be short. */
+
+	    char *ptr = pVNC->buf;
+	    char *dollar;
+	    pVNC->buf[n] = 0; /* make sure it's null-terminated */
+
+	    while ((dollar = strchr(ptr, '$'))) {
+		WriteExact(pVNC->httpSock, ptr, (dollar - ptr));
+
+		ptr = dollar;
+
+		if (compareAndSkip(&ptr, "$WIDTH")) {
+
+		    sprintf(str, "%d", pVNC->width);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$HEIGHT")) {
+
+		    sprintf(str, "%d", pVNC->height);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {
+
+		    sprintf(str, "%d", pVNC->width);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {
+
+		    sprintf(str, "%d", pVNC->height + 32);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$PORT")) {
+
+		    sprintf(str, "%d", pVNC->rfbPort);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$DESKTOP")) {
+
+		    WriteExact(pVNC->httpSock, desktopName, strlen(desktopName));
+
+		} else if (compareAndSkip(&ptr, "$DISPLAY")) {
+
+		    sprintf(str, "%s:%s", rfbThisHost, display);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$USER")) {
+
+		    if (user) {
+			WriteExact(pVNC->httpSock, user->pw_name,
+				   strlen(user->pw_name));
+		    } else {
+			WriteExact(pVNC->httpSock, "?", 1);
+		    }
+
+		} else if (compareAndSkip(&ptr, "$PARAMS")) {
+
+		    if (params[0] != '\0')
+			WriteExact(pVNC->httpSock, params, strlen(params));
+
+		} else {
+		    if (!compareAndSkip(&ptr, "$$"))
+			ptr++;
+
+		    if (WriteExact(pVNC->httpSock, "$", 1) < 0) {
+			close(fd);
+			httpCloseSock(pScreen);
+			return;
+		    }
+		}
+	    }
+	    if (WriteExact(pVNC->httpSock, ptr, (&pVNC->buf[n] - ptr)) < 0)
+		break;
+
+	} else {
+
+	    /* For files not ending .vnc, just write out the buffer */
+
+	    if (WriteExact(pVNC->httpSock, pVNC->buf, n) < 0)
+		break;
+	}
+    }
+
+    close(fd);
+    httpCloseSock(pScreen);
+}
+
+
+static Bool
+compareAndSkip(char **ptr, const char *str)
+{
+    if (strncmp(*ptr, str, strlen(str)) == 0) {
+	*ptr += strlen(str);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * Parse the request tail after the '?' character, and format a sequence
+ * of <param> tags for inclusion into an HTML page with embedded applet.
+ */
+
+static Bool
+parseParams(const char *request, char *result, int max_bytes)
+{
+    char param_request[128];
+    char param_formatted[196];
+    const char *tail;
+    char *delim_ptr;
+    char *value_str;
+    int cur_bytes, len;
+
+    result[0] = '\0';
+    cur_bytes = 0;
+
+    tail = request;
+    for (;;) {
+	/* Copy individual "name=value" string into a buffer */
+	delim_ptr = strchr((char *)tail, '&');
+	if (delim_ptr == NULL) {
+	    if (strlen(tail) >= sizeof(param_request)) {
+		return FALSE;
+	    }
+	    strcpy(param_request, tail);
+	} else {
+	    len = delim_ptr - tail;
+	    if (len >= sizeof(param_request)) {
+		return FALSE;
+	    }
+	    memcpy(param_request, tail, len);
+	    param_request[len] = '\0';
+	}
+
+	/* Split the request into parameter name and value */
+	value_str = strchr(&param_request[1], '=');
+	if (value_str == NULL) {
+	    return FALSE;
+	}
+	*value_str++ = '\0';
+	if (strlen(value_str) == 0) {
+	    return FALSE;
+	}
+
+	/* Validate both parameter name and value */
+	if (!validateString(param_request) || !validateString(value_str)) {
+	    return FALSE;
+	}
+
+	/* Prepare HTML-formatted representation of the name=value pair */
+	len = sprintf(param_formatted,
+		      "<PARAM NAME=\"%s\" VALUE=\"%s\">\n",
+		      param_request, value_str);
+	if (cur_bytes + len + 1 > max_bytes) {
+	    return FALSE;
+	}
+	strcat(result, param_formatted);
+	cur_bytes += len;
+
+	/* Go to the next parameter */
+	if (delim_ptr == NULL) {
+	    break;
+	}
+	tail = delim_ptr + 1;
+    }
+    return TRUE;
+}
+
+/*
+ * Check if the string consists only of alphanumeric characters, '+'
+ * signs, underscores, and dots. Replace all '+' signs with spaces.
+ */
+
+static Bool
+validateString(char *str)
+{
+    char *ptr;
+
+    for (ptr = str; *ptr != '\0'; ptr++) {
+	if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.') {
+	    if (*ptr == '+') {
+		*ptr = ' ';
+	    } else {
+		return FALSE;
+	    }
+	}
+    }
+    return TRUE;
+}
+
diff -u -rNp a/hw/dmx/vnc/kbdptr.c b/hw/dmx/vnc/kbdptr.c
--- a/hw/dmx/vnc/kbdptr.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/kbdptr.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,446 @@
+/*
+ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include "rfb.h"
+#include "X11/X.h"
+#define NEED_EVENTS
+#include "X11/Xproto.h"
+#include "inputstr.h"
+#define XK_CYRILLIC
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include "mi.h"
+#include "mipointer.h"
+
+#if DMXVNC
+#include "../dmx.h"
+#include "../dmxinput.h"
+#endif
+
+#if XFREE86VNC
+#if defined(XINPUT)
+#  include "xf86Xinput.h"
+#  define Enqueue(ev) xf86eqEnqueue(ev)
+#else
+#  define Enqueue(ev) mieqEnqueue(ev)
+#endif
+#else /*XFREE86VNC*/
+#if DMXVNC
+#  define Enqueue(ev) dmxeqEnqueue(ev)
+#else
+#  define Enqueue(ev) mieqEnqueue(ev)
+#endif
+#endif /*XFREE86VNC*/
+
+
+#define KEY_IS_PRESSED(keycode) \
+    (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
+
+static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper);
+
+DeviceIntPtr kbdDevice = NULL;
+
+#include "keyboard.h"
+
+void
+vncSetKeyboardDevice(DeviceIntPtr kbd)
+{
+   kbdDevice = kbd;
+}
+
+/*
+ * Called when the rfbserver receives a rfbKeyEvent event from a client.
+ * Put an X keyboard event into the event queue.
+ */
+void
+KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl)
+{
+    xEvent ev, fake;
+    KeySymsPtr keySyms;
+    int i;
+    int keyCode = 0;
+    int freeIndex = -1;
+    unsigned long time;
+    Bool fakeShiftPress = FALSE;
+    Bool fakeShiftLRelease = FALSE;
+    Bool fakeShiftRRelease = FALSE;
+    Bool shiftMustBeReleased = FALSE;
+    Bool shiftMustBePressed = FALSE;
+
+    if (!kbdDevice) return;
+
+    keySyms = &kbdDevice->key->curKeySyms;
+
+#ifdef CORBA
+    if (cl) {
+	CARD32 clientId = cl->sock;
+	ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+			     32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+#endif
+
+    if (down) {
+	ev.u.u.type = KeyPress;
+    } else {
+	ev.u.u.type = KeyRelease;
+    }
+
+    /* NOTE: This is where it gets hairy for XFree86 servers.
+     * I think the best way to deal with this is invent a new protocol
+     * to send over the wire the remote keyboard type and correctly
+     * handle that as XINPUT extension device (we're part of the way
+     * there for that.
+     *
+     * Alan.
+     */
+#if !XFREE86VNC
+    /* First check if it's one of our predefined keys.  If so then we can make
+       some attempt at allowing an xmodmap inside a VNC desktop behave
+       something like you'd expect - e.g. if keys A & B are swapped over and
+       the VNC client sends an A, then map it to a B when generating the X
+       event.  We don't attempt to do this for keycodes which we make up on the
+       fly because it's too hard... */
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+	if (keySym == map[i]) {
+	    keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY;
+
+	    if (map[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) {
+
+		/* this keycode has more than one symbol associated with it,
+		   so shift state is important */
+
+		if ((i % GLYPHS_PER_KEY) == 0)
+		    shiftMustBeReleased = TRUE;
+		else
+		    shiftMustBePressed = TRUE;
+	    }
+	    break;
+	}
+    }
+#endif
+
+    if (!keyCode) {
+
+	/* not one of our predefined keys - see if it's in the current keyboard
+           mapping (i.e. we've already allocated an extra keycode for it) */
+
+	if (keySyms->mapWidth < 2) {
+	    ErrorF("KbdAddEvent: Sanity check failed - Keyboard mapping has "
+		   "less than 2 keysyms per keycode (KeySym 0x%x)\n",
+                   (unsigned) keySym);
+	    return;
+	}
+
+	for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) {
+	    if (keySym == keySyms->map[i]) {
+		keyCode = MIN_KEY_CODE + i / keySyms->mapWidth;
+
+		if (keySyms->map[(i / keySyms->mapWidth)
+					* keySyms->mapWidth + 1] != NoSymbol) {
+
+		    /* this keycode has more than one symbol associated with
+		       it, so shift state is important */
+
+		    if ((i % keySyms->mapWidth) == 0)
+			shiftMustBeReleased = TRUE;
+		    else
+			shiftMustBePressed = TRUE;
+		}
+		break;
+	    }
+	    if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol)
+		&& (i % keySyms->mapWidth) == 0)
+	    {
+		freeIndex = i;
+	    }
+	}
+    }
+
+    if (!keyCode) {
+	KeySym lower, upper;
+
+	/* we don't have an existing keycode - make one up on the fly and add
+	   it to the keyboard mapping.  Thanks to Vlad Harchev for pointing
+	   out problems with non-ascii capitalisation. */
+
+	if (freeIndex == -1) {
+	    ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n",
+		   (unsigned) keySym);
+	    return;
+	}
+
+	keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth;
+
+	vncXConvertCase(keySym, &lower, &upper);
+
+	if (lower == upper) {
+	    keySyms->map[freeIndex] = keySym;
+
+	} else {
+	    keySyms->map[freeIndex] = lower;
+	    keySyms->map[freeIndex+1] = upper;
+
+	    if (keySym == lower)
+		shiftMustBeReleased = TRUE;
+	    else
+		shiftMustBePressed = TRUE;
+	}
+
+	SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient);
+
+	ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n",
+	       (unsigned) keySym, keyCode);
+    }
+
+    time = GetTimeInMillis();
+
+    if (down) {
+	if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) {
+	    fakeShiftPress = TRUE;
+	    fake.u.u.type = KeyPress;
+	    fake.u.u.detail = SHIFT_L_KEY_CODE;
+	    fake.u.keyButtonPointer.time = time;
+	    Enqueue(&fake);
+	}
+	if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) {
+	    if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) {
+		fakeShiftLRelease = TRUE;
+		fake.u.u.type = KeyRelease;
+		fake.u.u.detail = SHIFT_L_KEY_CODE;
+		fake.u.keyButtonPointer.time = time;
+		Enqueue(&fake);
+	    }
+	    if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) {
+		fakeShiftRRelease = TRUE;
+		fake.u.u.type = KeyRelease;
+		fake.u.u.detail = SHIFT_R_KEY_CODE;
+		fake.u.keyButtonPointer.time = time;
+		Enqueue(&fake);
+	    }
+	}
+    }
+
+    ev.u.u.detail = keyCode;
+    ev.u.keyButtonPointer.time = time;
+    Enqueue(&ev);
+
+    if (fakeShiftPress) {
+	fake.u.u.type = KeyRelease;
+	fake.u.u.detail = SHIFT_L_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+    if (fakeShiftLRelease) {
+	fake.u.u.type = KeyPress;
+	fake.u.u.detail = SHIFT_L_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+    if (fakeShiftRRelease) {
+	fake.u.u.type = KeyPress;
+	fake.u.u.detail = SHIFT_R_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+}
+
+/*
+ * Called when the rfbserver receives a rfbPointerEvent event from a client.
+ * Put an X mouse event into the event queue.
+ */
+void
+PtrAddEvent(buttonMask, x, y, cl)
+    int buttonMask;
+    int x;
+    int y;
+    rfbClientPtr cl;
+{
+    xEvent ev;
+    int i;
+    unsigned long time;
+    static int oldButtonMask = 0;
+
+#ifdef CORBA
+    if (cl) {
+	CARD32 clientId = cl->sock;
+	ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+			     32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+#endif
+
+    time = GetTimeInMillis();
+
+#if DMXVNC
+    dmxCoreMotion(x, y, 0, DMX_NO_BLOCK);
+#else
+    miPointerAbsoluteCursor(x, y, time);
+#endif
+
+    for (i = 0; i < 5; i++) {
+	if ((buttonMask ^ oldButtonMask) & (1<<i)) {
+	    if (buttonMask & (1<<i)) {
+		ev.u.u.type = ButtonPress;
+		ev.u.u.detail = i + 1;
+		ev.u.keyButtonPointer.time = time;
+	    } else {
+		ev.u.u.type = ButtonRelease;
+		ev.u.u.detail = i + 1;
+		ev.u.keyButtonPointer.time = time;
+	    }
+ 	    Enqueue(&ev);
+	}
+    }
+
+    oldButtonMask = buttonMask;
+}
+
+void
+KbdReleaseAllKeys()
+{
+    int i, j;
+    xEvent ev;
+    unsigned long time = GetTimeInMillis();
+
+    if (!kbdDevice) 
+	return;
+
+    for (i = 0; i < DOWN_LENGTH; i++) {
+	if (kbdDevice->key->down[i] != 0) {
+	    for (j = 0; j < 8; j++) {
+		if (kbdDevice->key->down[i] & (1 << j)) {
+		    ev.u.u.type = KeyRelease;
+		    ev.u.u.detail = (i << 3) | j;
+		    ev.u.keyButtonPointer.time = time;
+		    Enqueue(&ev);
+		}
+	    }
+	}
+    }
+}
+
+
+/* copied from Xlib source */
+
+static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper)
+{
+    *lower = sym;
+    *upper = sym;
+    switch(sym >> 8) {
+    case 0: /* Latin 1 */
+	if ((sym >= XK_A) && (sym <= XK_Z))
+	    *lower += (XK_a - XK_A);
+	else if ((sym >= XK_a) && (sym <= XK_z))
+	    *upper -= (XK_a - XK_A);
+	else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
+	    *lower += (XK_agrave - XK_Agrave);
+	else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
+	    *upper -= (XK_agrave - XK_Agrave);
+	else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
+	    *lower += (XK_oslash - XK_Ooblique);
+	else if ((sym >= XK_oslash) && (sym <= XK_thorn))
+	    *upper -= (XK_oslash - XK_Ooblique);
+	break;
+    case 1: /* Latin 2 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym == XK_Aogonek)
+	    *lower = XK_aogonek;
+	else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+	    *lower += (XK_lstroke - XK_Lstroke);
+	else if (sym >= XK_Scaron && sym <= XK_Zacute)
+	    *lower += (XK_scaron - XK_Scaron);
+	else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+	    *lower += (XK_zcaron - XK_Zcaron);
+	else if (sym == XK_aogonek)
+	    *upper = XK_Aogonek;
+	else if (sym >= XK_lstroke && sym <= XK_sacute)
+	    *upper -= (XK_lstroke - XK_Lstroke);
+	else if (sym >= XK_scaron && sym <= XK_zacute)
+	    *upper -= (XK_scaron - XK_Scaron);
+	else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+	    *upper -= (XK_zcaron - XK_Zcaron);
+	else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+	    *lower += (XK_racute - XK_Racute);
+	else if (sym >= XK_racute && sym <= XK_tcedilla)
+	    *upper -= (XK_racute - XK_Racute);
+	break;
+    case 2: /* Latin 3 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+	    *lower += (XK_hstroke - XK_Hstroke);
+	else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+	    *lower += (XK_gbreve - XK_Gbreve);
+	else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+	    *upper -= (XK_hstroke - XK_Hstroke);
+	else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+	    *upper -= (XK_gbreve - XK_Gbreve);
+	else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+	    *lower += (XK_cabovedot - XK_Cabovedot);
+	else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+	    *upper -= (XK_cabovedot - XK_Cabovedot);
+	break;
+    case 3: /* Latin 4 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+	    *lower += (XK_rcedilla - XK_Rcedilla);
+	else if (sym >= XK_rcedilla && sym <= XK_tslash)
+	    *upper -= (XK_rcedilla - XK_Rcedilla);
+	else if (sym == XK_ENG)
+	    *lower = XK_eng;
+	else if (sym == XK_eng)
+	    *upper = XK_ENG;
+	else if (sym >= XK_Amacron && sym <= XK_Umacron)
+	    *lower += (XK_amacron - XK_Amacron);
+	else if (sym >= XK_amacron && sym <= XK_umacron)
+	    *upper -= (XK_amacron - XK_Amacron);
+	break;
+    case 6: /* Cyrillic */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+	    *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+	else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+	    *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+	else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+	    *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+	else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+	    *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+        break;
+    case 7: /* Greek */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+	    *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+	else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+		 sym != XK_Greek_iotaaccentdieresis &&
+		 sym != XK_Greek_upsilonaccentdieresis)
+	    *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+	else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+	    *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+	else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+		 sym != XK_Greek_finalsmallsigma)
+	    *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+        break;
+    }
+}
diff -u -rNp a/hw/dmx/vnc/keyboard.h b/hw/dmx/vnc/keyboard.h
--- a/hw/dmx/vnc/keyboard.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/keyboard.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,167 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#define MIN_KEY_CODE		8
+#define MAX_KEY_CODE		255
+#define NO_OF_KEYS		(MAX_KEY_CODE - MIN_KEY_CODE + 1)
+#define GLYPHS_PER_KEY		4
+
+#define CONTROL_L_KEY_CODE	(MIN_KEY_CODE + 29)
+#define CONTROL_R_KEY_CODE	(MIN_KEY_CODE + 101)
+#define SHIFT_L_KEY_CODE	(MIN_KEY_CODE + 42)
+#define SHIFT_R_KEY_CODE	(MIN_KEY_CODE + 54)
+#define META_L_KEY_CODE		(MIN_KEY_CODE + 107)
+#define META_R_KEY_CODE		(MIN_KEY_CODE + 108)
+#define ALT_L_KEY_CODE		(MIN_KEY_CODE + 56)
+#define ALT_R_KEY_CODE		(MIN_KEY_CODE + 105)
+
+static KeySym map[MAX_KEY_CODE * GLYPHS_PER_KEY] = {
+    /* 0x00 */  NoSymbol,       NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x01 */  XK_Escape,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x02 */  XK_1,           XK_exclam,	NoSymbol,	NoSymbol,
+    /* 0x03 */  XK_2,           XK_at,		NoSymbol,	NoSymbol,
+    /* 0x04 */  XK_3,           XK_numbersign,	NoSymbol,	NoSymbol,
+    /* 0x05 */  XK_4,           XK_dollar,	NoSymbol,	NoSymbol,
+    /* 0x06 */  XK_5,           XK_percent,	NoSymbol,	NoSymbol,
+    /* 0x07 */  XK_6,           XK_asciicircum,	NoSymbol,	NoSymbol,
+    /* 0x08 */  XK_7,           XK_ampersand,	NoSymbol,	NoSymbol,
+    /* 0x09 */  XK_8,           XK_asterisk,	NoSymbol,	NoSymbol,
+    /* 0x0a */  XK_9,           XK_parenleft,	NoSymbol,	NoSymbol,
+    /* 0x0b */  XK_0,           XK_parenright,	NoSymbol,	NoSymbol,
+    /* 0x0c */  XK_minus,       XK_underscore,	NoSymbol,	NoSymbol,
+    /* 0x0d */  XK_equal,       XK_plus,	NoSymbol,	NoSymbol,
+    /* 0x0e */  XK_BackSpace,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x0f */  XK_Tab,         XK_ISO_Left_Tab,NoSymbol,	NoSymbol,
+    /* 0x10 */  XK_q,           XK_Q,		NoSymbol,	NoSymbol,
+    /* 0x11 */  XK_w,           XK_W,		NoSymbol,	NoSymbol,
+    /* 0x12 */  XK_e,           XK_E,		NoSymbol,	NoSymbol,
+    /* 0x13 */  XK_r,           XK_R,		NoSymbol,	NoSymbol,
+    /* 0x14 */  XK_t,           XK_T,		NoSymbol,	NoSymbol,
+    /* 0x15 */  XK_y,           XK_Y,		NoSymbol,	NoSymbol,
+    /* 0x16 */  XK_u,           XK_U,		NoSymbol,	NoSymbol,
+    /* 0x17 */  XK_i,           XK_I,		NoSymbol,	NoSymbol,
+    /* 0x18 */  XK_o,           XK_O,		NoSymbol,	NoSymbol,
+    /* 0x19 */  XK_p,           XK_P,		NoSymbol,	NoSymbol,
+    /* 0x1a */  XK_bracketleft, XK_braceleft,	NoSymbol,	NoSymbol,
+    /* 0x1b */  XK_bracketright,XK_braceright,	NoSymbol,	NoSymbol,
+    /* 0x1c */  XK_Return,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x1d */  XK_Control_L,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x1e */  XK_a,           XK_A,		NoSymbol,	NoSymbol,
+    /* 0x1f */  XK_s,           XK_S,		NoSymbol,	NoSymbol,
+    /* 0x20 */  XK_d,           XK_D,		NoSymbol,	NoSymbol,
+    /* 0x21 */  XK_f,           XK_F,		NoSymbol,	NoSymbol,
+    /* 0x22 */  XK_g,           XK_G,		NoSymbol,	NoSymbol,
+    /* 0x23 */  XK_h,           XK_H,		NoSymbol,	NoSymbol,
+    /* 0x24 */  XK_j,           XK_J,		NoSymbol,	NoSymbol,
+    /* 0x25 */  XK_k,           XK_K,		NoSymbol,	NoSymbol,
+    /* 0x26 */  XK_l,           XK_L,		NoSymbol,	NoSymbol,
+    /* 0x27 */  XK_semicolon,   XK_colon,	NoSymbol,	NoSymbol,
+    /* 0x28 */  XK_quoteright,  XK_quotedbl,	NoSymbol,	NoSymbol,
+    /* 0x29 */  XK_quoteleft,	XK_asciitilde,	NoSymbol,	NoSymbol,
+    /* 0x2a */  XK_Shift_L,     NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x2b */  XK_backslash,   XK_bar,		NoSymbol,	NoSymbol,
+    /* 0x2c */  XK_z,           XK_Z,		NoSymbol,	NoSymbol,
+    /* 0x2d */  XK_x,           XK_X,		NoSymbol,	NoSymbol,
+    /* 0x2e */  XK_c,           XK_C,		NoSymbol,	NoSymbol,
+    /* 0x2f */  XK_v,           XK_V,		NoSymbol,	NoSymbol,
+    /* 0x30 */  XK_b,           XK_B,		NoSymbol,	NoSymbol,
+    /* 0x31 */  XK_n,           XK_N,		NoSymbol,	NoSymbol,
+    /* 0x32 */  XK_m,           XK_M,		NoSymbol,	NoSymbol,
+    /* 0x33 */  XK_comma,       XK_less,	NoSymbol,	NoSymbol,
+    /* 0x34 */  XK_period,      XK_greater,	NoSymbol,	NoSymbol,
+    /* 0x35 */  XK_slash,       XK_question,	NoSymbol,	NoSymbol,
+    /* 0x36 */  XK_Shift_R,     NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x37 */  XK_KP_Multiply, NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x38 */  XK_Alt_L,	XK_Meta_L,	NoSymbol,	NoSymbol,
+    /* 0x39 */  XK_space,       NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3a */  XK_Caps_Lock,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3b */  XK_F1,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3c */  XK_F2,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3d */  XK_F3,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3e */  XK_F4,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3f */  XK_F5,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x40 */  XK_F6,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x41 */  XK_F7,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x42 */  XK_F8,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x43 */  XK_F9,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x44 */  XK_F10,         NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x45 */  XK_Num_Lock,    NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x46 */  XK_Scroll_Lock,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x47 */  XK_KP_Home,	XK_KP_7,	NoSymbol,	NoSymbol,
+    /* 0x48 */  XK_KP_Up,	XK_KP_8,	NoSymbol,	NoSymbol,
+    /* 0x49 */  XK_KP_Prior,	XK_KP_9,	NoSymbol,	NoSymbol,
+    /* 0x4a */  XK_KP_Subtract, NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x4b */  XK_KP_Left,	XK_KP_4,	NoSymbol,	NoSymbol,
+    /* 0x4c */  XK_KP_Begin,	XK_KP_5,	NoSymbol,	NoSymbol,
+    /* 0x4d */  XK_KP_Right,	XK_KP_6,	NoSymbol,	NoSymbol,
+    /* 0x4e */  XK_KP_Add,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x4f */  XK_KP_End,	XK_KP_1,	NoSymbol,	NoSymbol,
+    /* 0x50 */  XK_KP_Down,	XK_KP_2,	NoSymbol,	NoSymbol,
+    /* 0x51 */  XK_KP_Next,	XK_KP_3,	NoSymbol,	NoSymbol,
+    /* 0x52 */  XK_KP_Insert,	XK_KP_0,	NoSymbol,	NoSymbol,
+    /* 0x53 */  XK_KP_Delete,	XK_KP_Decimal,	NoSymbol,	NoSymbol,
+    /* 0x54 */  XK_Sys_Req,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x55 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x56 */  XK_less,	XK_greater,	NoSymbol,	NoSymbol,
+    /* 0x57 */  XK_F11,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x58 */  XK_F12,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x59 */  XK_Home,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5a */  XK_Up,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5b */  XK_Prior,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5c */  XK_Left,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5d */  XK_Begin,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5e */  XK_Right,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5f */  XK_End,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x60 */  XK_Down,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x61 */  XK_Next,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x62 */  XK_Insert,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x63 */  XK_Delete,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x64 */  XK_KP_Enter,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x65 */  XK_Control_R,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x66 */  XK_Pause,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x67 */  XK_Print,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x68 */  XK_KP_Divide,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x69 */  XK_Alt_R,	XK_Meta_R,	NoSymbol,	NoSymbol,
+    /* 0x6a */  XK_Break,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6b */  XK_Meta_L,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6c */  XK_Meta_R,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6d */  XK_Menu,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6e */  XK_F13,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6f */  XK_F14,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x70 */  XK_F15,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x71 */  XK_F16,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x72 */  XK_F17,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x73 */  XK_backslash,	XK_underscore,	NoSymbol,	NoSymbol,
+    /* 0x74 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x75 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x76 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x77 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x78 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x79 */  XK_Henkan,	XK_Mode_switch,	NoSymbol,	NoSymbol,
+    /* 0x7a */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7b */  XK_Muhenkan,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7c */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7d */  XK_backslash,	XK_bar,		NoSymbol,	NoSymbol,
+    /* 0x7e */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7f */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+};
+
+#define N_PREDEFINED_KEYS (sizeof(map) / (sizeof(KeySym) * GLYPHS_PER_KEY))
diff -u -rNp a/hw/dmx/vnc/loginauth.c b/hw/dmx/vnc/loginauth.c
--- a/hw/dmx/vnc/loginauth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/loginauth.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ * loginauth.c - deal with login-style Unix authentication.
+ *
+ * This file implements the UnixLogin authentication protocol when setting up
+ * an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003 Constantin Kaplinsky.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef HAVE_DMX_CONFIG_H
+#include <dmx-config.h>
+#endif
+
+#ifdef linux
+#include </usr/include/shadow.h> /* XXX xserver has a shadow.h file too */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "rfb.h"
+
+void rfbLoginAuthProcessClientMessage(rfbClientPtr cl)
+{
+    int n1 = 0, n2 = 0;
+    CARD32 loginLen, passwdLen, authResult;
+    char *loginBuf, *passwdBuf;
+    struct passwd *ps;
+    char *encPasswd1, *encPasswd2;
+    Bool ok;
+
+    if ((n1 = ReadExact(cl->sock, (char *)&loginLen,
+			sizeof(loginLen))) <= 0 ||
+	(n2 = ReadExact(cl->sock, (char *)&passwdLen,
+			sizeof(passwdLen))) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginLen = Swap32IfLE(loginLen);
+    passwdLen = Swap32IfLE(passwdLen);
+    loginBuf = (char *)xalloc(loginLen + 1);
+    passwdBuf = (char *)xalloc(passwdLen + 1);
+
+    n1 = n2 = 0;
+    if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 ||
+	(n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginBuf[loginLen] = '\0';
+    passwdBuf[passwdLen] = '\0';
+
+    encPasswd1 = encPasswd2 = NULL;
+
+    ps = getpwnam(loginBuf);
+    if (ps == NULL) {
+	rfbLog("rfbLoginAuthProcessClientMessage: "
+	       "Cannot get password file entry for \"%s\"\n", loginBuf);
+    } else {
+	encPasswd1 = ps->pw_passwd;
+#ifdef linux
+	if (strlen(ps->pw_passwd) == 1) {
+	    struct spwd *sps;
+
+	    sps = getspnam(loginBuf);
+	    if (sps == NULL) {
+		rfbLog("rfbLoginAuthProcessClientMessage:"
+		       " getspnam() failed for user \"%s\"\n", loginBuf);
+	    } else {
+		encPasswd1 = sps->sp_pwdp;
+	    }
+	}
+#endif
+	encPasswd2 = crypt(passwdBuf, encPasswd1);
+	memset(passwdBuf, 0, strlen(passwdBuf));
+    }
+
+    ok = FALSE;
+    if (encPasswd1 != NULL && encPasswd2 != NULL) {
+	if (strcmp(encPasswd1, encPasswd2) == 0)
+	    ok = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult,
+		       sizeof(authResult)) < 0) {
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    cl->login = strdup(loginBuf);
+    rfbLog("Login-style authentication passed for user %s at %s\n",
+	   cl->login, cl->host);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) {
+	rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    cl->state = RFB_INITIALISATION;
+}
+
diff -u -rNp a/hw/dmx/vnc/Makefile.am b/hw/dmx/vnc/Makefile.am
--- a/hw/dmx/vnc/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,43 @@
+noinst_LIBRARIES = libdmxvnc.a
+
+SRCS = \
+	auth.c \
+	cmap.c \
+	corre.c \
+	cursor.c \
+	cutpaste.c \
+	d3des.c \
+	dispcur.c \
+	draw.c \
+	hextile.c \
+	httpd.c \
+	kbdptr.c \
+	loginauth.c \
+	rdp.c \
+	rfbkeyb.c \
+	rfbmouse.c \
+	rfbserver.c \
+	rre.c \
+	sockets.c \
+	sprite.c \
+	stats.c \
+	tight.c \
+	translate.c \
+	vncauth.c \
+	vncext.c \
+	vncInit.c \
+	xistubs.c \
+	zlib.c
+
+
+libdmxvnc_a_SOURCES = $(SRCS)
+
+AM_CFLAGS = \
+            -I$(top_srcdir)/hw/dmx \
+            -I$(top_srcdir)/hw/xfree86/common \
+            -DHAVE_DMX_CONFIG_H \
+	    $(DIX_CFLAGS) \
+            -DDMXVNC=1 \
+            @DMXMODULES_CFLAGS@
+
+###EXTRA_DIST = dmxdetach.c
diff -u -rNp a/hw/dmx/vnc/rdp.c b/hw/dmx/vnc/rdp.c
--- a/hw/dmx/vnc/rdp.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rdp.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,145 @@
+/*
+ *  Copyright (C) 2004 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include "rfb.h"
+
+typedef struct rdpClientRec {
+	ScreenPtr pScreen;
+} rdpClientRec, *rdpClientPtr;
+
+typedef struct rdpInRec {
+	char version;
+	char pad;
+	short length; 
+	char hdrlen;
+	unsigned char pdu;
+} rdpInRec, *rdpInPtr;
+
+static void
+rdpCloseSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    close(pVNC->rdpListenSock);
+    RemoveEnabledDevice(pVNC->rdpListenSock);
+    pVNC->rdpListenSock = -1;
+}
+
+/*
+ * rdpNewClient is called when a new connection has been made by whatever
+ * means.
+ */
+
+static rdpClientPtr
+rdpNewClient(ScreenPtr pScreen, int sock)
+{
+    rdpInRec in;
+    rdpClientPtr cl;
+    BoxRec box;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
+    VNCSCREENPTR(pScreen);
+    int i;
+
+    cl = (rdpClientPtr)xalloc(sizeof(rdpClientRec));
+
+    cl->pScreen = pScreen;
+
+    in.version = 3;
+    in.pad = 0;
+    in.length = 0x600; /* big endian */
+    in.hdrlen = 0x00; 
+    in.pdu = 0xCC; 
+
+    if (WriteExact(sock, (char *)&in, sizeof(rdpInRec)) < 0) {
+	rfbLogPerror("rfbNewClient: write");
+	rdpCloseSock(pScreen);
+	return NULL;
+    }
+
+    return cl;
+}
+/*
+ * rdpCheckFds is called from ProcessInputEvents to check for input on the
+ * HTTP socket(s).  If there is input to process, rdpProcessInput is called.
+ */
+
+static void
+rdpCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    int sock;
+    const int one =1;
+    SOCKLEN_T addrlen = sizeof(addr);
+
+    FD_ZERO(&fds);
+    FD_SET(pVNC->rdpListenSock, &fds);
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(pVNC->rdpListenSock + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR) 
+		rfbLogPerror("httpCheckFds: select");
+	return;
+    }
+
+    if (pVNC->rdpListenSock != -1 && FD_ISSET(pVNC->rdpListenSock, &fds)) {
+
+	if ((sock = accept(pVNC->rdpListenSock,
+			   (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("rdpCheckFds: accept");
+	    return;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("rdpCheckFds: fcntl");
+	    close(sock);
+	    return;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("rdpCheckFds: setsockopt");
+	    close(sock);
+	    return;
+	}
+
+	rfbLog("\n");
+
+	rfbLog("Got RDP connection from client %s\n", inet_ntoa(addr.sin_addr));
+
+	AddEnabledDevice(sock);
+
+	rdpNewClient(pScreen, sock);
+    }
+}
diff -u -rNp a/hw/dmx/vnc/rfb.h b/hw/dmx/vnc/rfb.h
--- a/hw/dmx/vnc/rfb.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rfb.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,697 @@
+/*
+ * rfb.h - header file for RFB DDX implementation.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000-2004 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if HAVE_DMX_CONFIG_H
+#include "dmx-config.h"
+#endif
+
+#include <zlib.h>
+#include "scrnintstr.h"
+#include "colormapst.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "windowstr.h"
+#include "dixfontstr.h"
+#include "picture.h"
+#include "glyphstr.h"
+#if 0 /* && !XFREE86VNC */
+#include "osdep.h"
+#endif
+#include <rfbproto.h>
+#include <vncauth.h>
+/* 
+ * HTTP_BUF_SIZE for http transfers
+ */
+#define HTTP_BUF_SIZE 32768
+/*
+ * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the
+ * framebuffer.  So for a max screen width of say 2K with 32-bit pixels this
+ * means 8K minimum.
+ */
+#define UPDATE_BUF_SIZE 30000
+#ifdef RENDER
+#include "picturestr.h"
+#endif
+#define _VNC_SERVER
+#include "vncint.h"
+
+#if defined(sun) || defined(hpux)
+#define SOCKLEN_T	int
+#else
+#define SOCKLEN_T	socklen_t
+#endif
+
+/* It's a good idea to keep these values a bit greater than required. */
+#define MAX_ENCODINGS 10
+#define MAX_SECURITY_TYPES 4
+#define MAX_TUNNELING_CAPS 16
+#define MAX_AUTH_CAPS 16
+
+#define VNCSCREENPTR(ptr) \
+	vncScreenPtr pVNC = VNCPTR(ptr)
+
+/*
+ * Per-screen (framebuffer) structure.  There is only one of these, since we
+ * don't allow the X server to have multiple screens.
+ */
+
+typedef struct
+{
+    int			rfbPort;
+    int			rdpPort;
+    int			udpPort;
+    int			rfbListenSock;
+    int			rdpListenSock;
+    int			udpSock;
+    int			httpPort;
+    int			httpListenSock;
+    int			httpSock;
+    char *		httpDir;
+    char		buf[HTTP_BUF_SIZE];
+    Bool		udpSockConnected;
+    char *		rfbAuthPasswdFile;
+    size_t		buf_filled;
+    int			maxFd;
+    fd_set		allFds;
+    Bool		useGetImage;
+    Bool		noCursor;
+    Bool		rfbAlwaysShared;
+    Bool		rfbNeverShared;
+    Bool		rfbDontDisconnect;
+    Bool		rfbUserAccept;
+    Bool		rfbViewOnly;
+    ColormapPtr		savedColormap;
+    ColormapPtr 	rfbInstalledColormap;
+    rfbPixelFormat	rfbServerFormat;
+    Bool		rfbAuthTooManyTries;
+    int			rfbAuthTries;
+    Bool		loginAuthEnabled;
+    struct in_addr	interface;
+    OsTimerPtr 		timer;
+    char updateBuf[UPDATE_BUF_SIZE];
+    int ublen;
+    int width;
+    int paddedWidthInBytes;
+    int height;
+    int depth;
+    int bitsPerPixel;
+    int sizeInBytes;
+    unsigned char *pfbMemory;
+    Pixel blackPixel;
+    Pixel whitePixel;
+
+    /* The following two members are used to minimise the amount of unnecessary
+       drawing caused by cursor movement.  Whenever any drawing affects the
+       part of the screen where the cursor is, the cursor is removed first and
+       then the drawing is done (this is what the sprite routines test for).
+       Afterwards, however, we do not replace the cursor, even when the cursor
+       is logically being moved across the screen.  We only draw the cursor
+       again just as we are about to send the client a framebuffer update.
+
+       We need to be careful when removing and drawing the cursor because of
+       their relationship with the normal drawing routines.  The drawing
+       routines can invoke the cursor routines, but also the cursor routines
+       themselves end up invoking drawing routines.
+
+       Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by
+       doing a CopyArea from a pixmap to the screen, where the pixmap contains
+       the saved contents of the screen under the cursor.  Before doing this,
+       however, we set cursorIsDrawn to FALSE.  Then, when CopyArea is called,
+       it sees that cursorIsDrawn is FALSE and so doesn't feel the need to
+       (recursively!) remove the cursor before doing it.
+
+       Putting up the cursor (rfbSpriteRestoreCursor) involves a call to
+       PushPixels.  While this is happening, cursorIsDrawn must be FALSE so
+       that PushPixels doesn't think it has to remove the cursor first.
+       Obviously cursorIsDrawn is set to TRUE afterwards.
+
+       Another problem we face is that drawing routines sometimes cause a
+       framebuffer update to be sent to the RFB client.  When the RFB client is
+       already waiting for a framebuffer update and some drawing to the
+       framebuffer then happens, the drawing routine sees that the client is
+       ready, so it calls rfbSendFramebufferUpdate.  If the cursor is not drawn
+       at this stage, it must be put up, and so rfbSpriteRestoreCursor is
+       called.  However, if the original drawing routine was actually called
+       from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't
+       want this to happen.  So both the cursor routines set
+       dontSendFramebufferUpdate to TRUE, and all the drawing routines check
+       this before calling rfbSendFramebufferUpdate. */
+
+    Bool cursorIsDrawn;		    /* TRUE if the cursor is currently drawn */
+    Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the
+				       cursor */
+
+    /* wrapped screen functions */
+
+    CloseScreenProcPtr			CloseScreen;
+    CreateGCProcPtr			CreateGC;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    RestoreAreasProcPtr			RestoreAreas;
+    ScreenWakeupHandlerProcPtr 		WakeupHandler;
+#ifdef CHROMIUM
+    RealizeWindowProcPtr		RealizeWindow;
+    UnrealizeWindowProcPtr		UnrealizeWindow;
+    DestroyWindowProcPtr		DestroyWindow;
+    ResizeWindowProcPtr			ResizeWindow;
+    PositionWindowProcPtr		PositionWindow;
+    ClipNotifyProcPtr			ClipNotify;
+#endif
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+#endif
+
+} rfbScreenInfo, *rfbScreenInfoPtr;
+
+
+/*
+ * rfbTranslateFnType is the type of translation functions.
+ */
+
+struct rfbClientRec;
+typedef void (*rfbTranslateFnType)(ScreenPtr pScreen, 
+				   char *table, rfbPixelFormat *in,
+				   rfbPixelFormat *out,
+				   unsigned char *iptr, char *optr,
+				   int bytesBetweenInputLines,
+				   int width, int height,
+				   int x, int y);
+
+
+/*
+ * Per-client structure.
+ */
+
+typedef struct rfbClientRec {
+    int sock;
+    char *host;
+    char *login;
+
+    int protocol_minor_ver;	/* RFB protocol minor version in use. */
+    Bool protocol_tightvnc;	/* TightVNC protocol extensions enabled */
+
+    /* Possible client states: */
+
+    enum {
+	RFB_PROTOCOL_VERSION,	/* establishing protocol version */
+        RFB_SECURITY_TYPE,	/* negotiating security (RFB v.3.7) */
+	RFB_TUNNELING_TYPE,	/* establishing tunneling (RFB v.3.7t) */
+	RFB_AUTH_TYPE,		/* negotiating authentication (RFB v.3.7t) */
+	RFB_AUTHENTICATION,	/* authenticating (VNC authentication) */
+	RFB_INITIALISATION,	/* sending initialisation messages */
+	RFB_NORMAL		/* normal protocol messages */
+    } state;
+
+    Bool viewOnly;		/* Do not accept input from this client. */
+
+    Bool reverseConnection;
+
+    Bool readyForSetColourMapEntries;
+
+    Bool useCopyRect;
+    int preferredEncoding;
+    int correMaxWidth, correMaxHeight;
+
+    /* The list of security types sent to this client (protocol 3.7).
+       Note that the first entry is the number of list items following. */
+
+    CARD8 securityTypes[MAX_SECURITY_TYPES + 1];
+
+    /* Lists of capability codes sent to clients. We remember these
+       lists to restrict clients from choosing those tunneling and
+       authentication types that were not advertised. */
+
+    int nAuthCaps;
+    CARD32 authCaps[MAX_AUTH_CAPS];
+
+    /* This is not useful while we don't support tunneling:
+    int nTunnelingCaps;
+    CARD32 tunnelingCaps[MAX_TUNNELING_CAPS]; */
+
+    /* The following member is only used during VNC authentication */
+
+    CARD8 authChallenge[CHALLENGESIZE];
+
+    /* The following members represent the update needed to get the client's
+       framebuffer from its present state to the current state of our
+       framebuffer.
+
+       If the client does not accept CopyRect encoding then the update is
+       simply represented as the region of the screen which has been modified
+       (modifiedRegion).
+
+       If the client does accept CopyRect encoding, then the update consists of
+       two parts.  First we have a single copy from one region of the screen to
+       another (the destination of the copy is copyRegion), and second we have
+       the region of the screen which has been modified in some other way
+       (modifiedRegion).
+
+       Although the copy is of a single region, this region may have many
+       rectangles.  When sending an update, the copyRegion is always sent
+       before the modifiedRegion.  This is because the modifiedRegion may
+       overlap parts of the screen which are in the source of the copy.
+
+       In fact during normal processing, the modifiedRegion may even overlap
+       the destination copyRegion.  Just before an update is sent we remove
+       from the copyRegion anything in the modifiedRegion. */
+
+    RegionRec copyRegion;	/* the destination region of the copy */
+    int copyDX, copyDY;		/* the translation by which the copy happens */
+
+    RegionRec modifiedRegion;	/* the region of the screen modified in any
+				   other way */
+
+    /* As part of the FramebufferUpdateRequest, a client can express interest
+       in a subrectangle of the whole framebuffer.  This is stored in the
+       requestedRegion member.  In the normal case this is the whole
+       framebuffer if the client is ready, empty if it's not. */
+
+    RegionRec requestedRegion;
+
+    /* The following members represent the state of the "deferred update" timer
+       - when the framebuffer is modified and the client is ready, in most
+       cases it is more efficient to defer sending the update by a few
+       milliseconds so that several changes to the framebuffer can be combined
+       into a single update. */
+
+    Bool deferredUpdateScheduled;
+    OsTimerPtr deferredUpdateTimer;
+
+    /* translateFn points to the translation function which is used to copy
+       and translate a rectangle from the framebuffer to an output buffer. */
+
+    rfbTranslateFnType translateFn;
+
+    char *translateLookupTable;
+
+    rfbPixelFormat format;
+
+    /* statistics */
+
+    int rfbBytesSent[MAX_ENCODINGS];
+    int rfbRectanglesSent[MAX_ENCODINGS];
+    int rfbLastRectMarkersSent;
+    int rfbLastRectBytesSent;
+    int rfbCursorShapeBytesSent;
+    int rfbCursorShapeUpdatesSent;
+    int rfbCursorPosBytesSent;
+    int rfbCursorPosUpdatesSent;
+    int rfbFramebufferUpdateMessagesSent;
+    int rfbRawBytesEquivalent;
+    int rfbKeyEventsRcvd;
+    int rfbPointerEventsRcvd;
+
+    /* zlib encoding -- necessary compression state info per client */
+
+    struct z_stream_s compStream;
+    Bool compStreamInited;
+
+    CARD32 zlibCompressLevel;
+
+    /* tight encoding -- preserve zlib streams' state for each client */
+
+    z_stream zsStruct[4];
+    Bool zsActive[4];
+    int zsLevel[4];
+    int tightCompressLevel;
+    int tightQualityLevel;
+
+    Bool enableLastRectEncoding;   /* client supports LastRect encoding */
+    Bool enableCursorShapeUpdates; /* client supports cursor shape updates */
+    Bool enableCursorPosUpdates;   /* client supports PointerPos updates */
+#ifdef CHROMIUM
+    Bool enableChromiumEncoding;   /* client supports Chromium encoding */
+#endif
+    Bool useRichCursorEncoding;    /* rfbEncodingRichCursor is preferred */
+    Bool cursorWasChanged;         /* cursor shape update should be sent */
+    Bool cursorWasMoved;           /* cursor position update should be sent */
+
+    int cursorX, cursorY;          /* client's cursor position */
+
+    struct rfbClientRec *next;
+
+    ScreenPtr pScreen;
+    int userAccepted;
+
+#ifdef CHROMIUM
+    unsigned int chromium_port;
+#endif
+} rfbClientRec, *rfbClientPtr;
+
+#ifdef CHROMIUM
+typedef struct CRWindowTable {
+	unsigned long CRwinId;
+	unsigned long XwinId;
+	BoxPtr clipRects;
+	int numRects;
+	struct CRWindowTable *next;
+} CRWindowTable, *CRWindowTablePtr;
+
+extern struct CRWindowTable *windowTable;
+#endif
+
+/*
+ * This macro is used to test whether there is a framebuffer update needing to
+ * be sent to the client.
+ */
+
+#define FB_UPDATE_PENDING(cl)                                           \
+    ((!(cl)->enableCursorShapeUpdates && !pVNC->cursorIsDrawn) ||   \
+     ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) ||      \
+     ((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) ||          \
+     REGION_NOTEMPTY(((cl)->pScreen),&(cl)->copyRegion) ||                    \
+     REGION_NOTEMPTY(((cl)->pScreen),&(cl)->modifiedRegion))
+
+/*
+ * This macro creates an empty region (ie. a region with no areas) if it is
+ * given a rectangle with a width or height of zero. It appears that 
+ * REGION_INTERSECT does not quite do the right thing with zero-width
+ * rectangles, but it should with completely empty regions.
+ */
+
+#define SAFE_REGION_INIT(pscreen, preg, rect, size)          \
+{                                                            \
+      if ( ( (rect) ) &&                                     \
+           ( ( (rect)->x2 == (rect)->x1 ) ||                 \
+	     ( (rect)->y2 == (rect)->y1 ) ) ) {              \
+	  REGION_NULL( (pscreen), (preg) ); 		     \
+      } else {                                               \
+	  REGION_INIT( (pscreen), (preg), (rect), (size) );  \
+      }                                                      \
+}
+
+/*
+ * An rfbGCRec is where we store the pointers to the original GC funcs and ops
+ * which we wrap (NULL means not wrapped).
+ */
+
+typedef struct {
+    GCFuncs *wrapFuncs;
+    GCOps *wrapOps;
+} rfbGCRec, *rfbGCPtr;
+
+
+
+/*
+ * Macros for endian swapping.
+ */
+
+#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
+
+#define Swap32(l) (((l) >> 24) | \
+		   (((l) & 0x00ff0000) >> 8)  | \
+		   (((l) & 0x0000ff00) << 8)  | \
+		   ((l) << 24))
+
+static const int rfbEndianTest = 1;
+
+#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s))
+
+#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l))
+
+
+/*
+ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.130).
+ * Normally, using macros is no good, but this macro saves us from
+ * writing constants twice -- it constructs signature names from codes.
+ * Note that "code_sym" argument should be a single symbol, not an expression.
+ */
+
+#define SetCapInfo(cap_ptr, code_sym, vendor)		\
+{							\
+    rfbCapabilityInfo *pcap;				\
+    pcap = (cap_ptr);					\
+    pcap->code = Swap32IfLE(code_sym);			\
+    memcpy(pcap->vendorSignature, (vendor),		\
+	   sz_rfbCapabilityInfoVendor);			\
+    memcpy(pcap->nameSignature, sig_##code_sym,		\
+	   sz_rfbCapabilityInfoName);			\
+}
+
+
+/* init.c */
+
+extern char *desktopName;
+extern char rfbThisHost[];
+extern Atom VNC_LAST_CLIENT_ID;
+
+extern rfbScreenInfo rfbScreen;
+extern int rfbGCIndex;
+
+extern int inetdSock;
+
+extern int rfbBitsPerPixel(int depth);
+extern void rfbLog(char *format, ...);
+extern void rfbLogPerror(char *str);
+
+
+/* sockets.c */
+
+extern int rfbMaxClientWait;
+
+extern Bool rfbInitSockets(ScreenPtr pScreen);
+extern void rfbDisconnectUDPSock(ScreenPtr pScreen);
+extern void rfbCloseSock(ScreenPtr pScreen, int sock);
+extern void rfbCheckFds(ScreenPtr pScreen);
+extern void rfbWaitForClient(int sock);
+extern int rfbConnect(ScreenPtr pScreen, char *host, int port);
+
+extern int ReadExact(int sock, char *buf, int len);
+extern int WriteExact(int sock, char *buf, int len);
+extern int ListenOnTCPPort(ScreenPtr pScreen, int port);
+extern int ListenOnUDPPort(ScreenPtr pScreen, int port);
+extern int ConnectToTcpAddr(char *host, int port);
+
+
+/* cmap.c */
+
+
+extern int rfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps);
+extern void rfbInstallColormap(ColormapPtr pmap);
+extern void rfbUninstallColormap(ColormapPtr pmap);
+extern void rfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs);
+
+
+/* draw.c */
+
+extern int rfbDeferUpdateTime;
+
+extern void
+rfbComposite(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pMask,
+    PicturePtr pDst,
+    INT16 xSrc,
+    INT16 ySrc,
+    INT16 xMask,
+    INT16 yMask,
+    INT16 xDst,
+    INT16 yDst,
+    CARD16 width,
+    CARD16 height
+);
+
+extern void rfbGlyphs(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pDst,
+    PictFormatPtr maskFormat,
+    INT16 xSrc,
+    INT16 ySrc,
+    int nlistInit,
+    GlyphListPtr listInit,
+    GlyphPtr *glyphsInit
+);
+extern Bool rfbCloseScreen(int,ScreenPtr);
+extern Bool rfbCreateGC(GCPtr);
+extern void rfbPaintWindowBackground(WindowPtr, RegionPtr, int what);
+extern void rfbPaintWindowBorder(WindowPtr, RegionPtr, int what);
+extern void rfbCopyWindow(WindowPtr, DDXPointRec, RegionPtr);
+#ifdef CHROMIUM
+extern Bool rfbRealizeWindow(WindowPtr); 
+extern Bool rfbUnrealizeWindow(WindowPtr); 
+extern Bool rfbDestroyWindow(WindowPtr);
+extern void rfbResizeWindow(WindowPtr, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib);
+extern Bool rfbPositionWindow(WindowPtr, int x, int y);
+extern void rfbClipNotify(WindowPtr, int x, int y);
+#endif
+extern void rfbClearToBackground(WindowPtr, int x, int y, int w,
+				 int h, Bool generateExposures);
+extern RegionPtr rfbRestoreAreas(WindowPtr, RegionPtr);
+
+
+/* cutpaste.c */
+
+extern void rfbSetXCutText(char *str, int len);
+extern void rfbGotXCutText(char *str, int len);
+
+
+/* kbdptr.c */
+
+extern Bool compatibleKbd;
+extern unsigned char ptrAcceleration;
+
+extern void PtrDeviceInit(void);
+extern void PtrDeviceOn(DeviceIntPtr pDev);
+extern void PtrDeviceOff(void);
+extern void PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl);
+extern void PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+
+extern void KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap);
+extern void KbdDeviceOn(void);
+extern void KbdDeviceOff(void);
+extern void KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl);
+extern void KbdReleaseAllKeys(void);
+
+
+/* rfbserver.c */
+
+
+extern rfbClientPtr rfbClientHead;
+extern rfbClientPtr pointerClient;
+
+extern void rfbUserAllow(int sock, int accept);
+
+extern void rfbNewClientConnection(ScreenPtr pScreen, int sock);
+extern rfbClientPtr rfbReverseConnection(ScreenPtr pScreen, char *host, int port);
+extern void rfbRootPropertyChange(ScreenPtr pScreen);
+extern void rfbClientConnectionGone(int sock);
+extern void rfbProcessClientMessage(ScreenPtr pScreen, int sock);
+extern void rfbClientConnFailed(rfbClientPtr cl, char *reason);
+extern void rfbNewUDPConnection(int sock);
+extern void rfbProcessUDPInput(ScreenPtr pScreen, int sock);
+extern Bool rfbSendFramebufferUpdate(ScreenPtr pScreen, rfbClientPtr cl);
+extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h);
+extern Bool rfbSendUpdateBuf(rfbClientPtr cl);
+extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour,
+				       int nColours);
+extern void rfbSendBell(void);
+extern void rfbSendServerCutText(char *str, int len);
+#ifdef CHROMIUM
+extern void rfbSendChromiumWindowShow(unsigned int winid, unsigned int show);
+extern void rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h);
+extern void rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects);
+#endif
+
+/* translate.c */
+
+extern Bool rfbEconomicTranslate;
+
+extern void rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+			     rfbPixelFormat *out,
+			     unsigned char *iptr, char *optr,
+			     int bytesBetweenInputLines,
+			     int width, int height,
+			     int x, int y);
+extern Bool rfbSetTranslateFunction(rfbClientPtr cl);
+extern void rfbSetClientColourMaps(int firstColour, int nColours);
+extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour,
+				  int nColours);
+
+
+/* httpd.c */
+
+extern Bool httpInitSockets(ScreenPtr pScreen);
+extern void httpCheckFds(ScreenPtr pScreen);
+
+
+
+/* auth.c */
+
+extern void rfbAuthNewClient(rfbClientPtr cl);
+extern void rfbProcessClientSecurityType(rfbClientPtr cl);
+extern void rfbProcessClientTunnelingType(rfbClientPtr cl);
+extern void rfbProcessClientAuthType(rfbClientPtr cl);
+extern void rfbVncAuthProcessResponse(rfbClientPtr cl);
+
+/* Functions to prevent too many successive authentication failures */
+extern Bool rfbAuthConsiderBlocking(rfbClientPtr cl);
+extern void rfbAuthUnblock(rfbClientPtr cl);
+extern Bool rfbAuthIsBlocked(rfbClientPtr cl);
+
+/* loginauth.c */
+
+extern void rfbLoginAuthProcessClientMessage(rfbClientPtr cl);
+  
+/* rre.c */
+
+extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* corre.c */
+
+extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* hextile.c */
+
+extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w,
+				       int h);
+
+
+/* zlib.c */
+
+/* Minimum zlib rectangle size in bytes.  Anything smaller will
+ * not compress well due to overhead.
+ */
+#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17)
+
+/* Set maximum zlib rectangle size in pixels.  Always allow at least
+ * two scan lines.
+ */
+#define ZLIB_MAX_RECT_SIZE (128*256)
+#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \
+			    ( min * 2 ) : ZLIB_MAX_RECT_SIZE )
+
+extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
+				    int h);
+
+
+/* tight.c */
+
+#define TIGHT_DEFAULT_COMPRESSION  6
+
+extern Bool rfbTightDisableGradient;
+
+extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h);
+extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* cursor.c */
+
+extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen);
+extern Bool rfbSendCursorPos(rfbClientPtr cl, ScreenPtr pScreen);
+
+
+/* stats.c */
+
+extern void rfbResetStats(rfbClientPtr cl);
+extern void rfbPrintStats(rfbClientPtr cl);
diff -u -rNp a/hw/dmx/vnc/rfbkeyb.c b/hw/dmx/vnc/rfbkeyb.c
--- a/hw/dmx/vnc/rfbkeyb.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rfbkeyb.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,412 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include <stdlib.h>
+
+#if XFREE86VNC
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include <misc.h>
+#include <xf86.h>
+#define NEED_XF86_TYPES
+#if !defined(DGUX)
+#include <xf86_ansic.h>
+#include <xisb.h>
+#endif
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>		/* Needed for InitValuator/Proximity stuff */
+#include <X11/keysym.h>
+#include <mipointer.h>
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+#else
+#include <X11/keysym.h>
+#include <dix.h>
+#include <mipointer.h>
+#endif
+
+#include "rfb.h"
+
+extern Bool noXkbExtension;
+extern void rfbSendBell(void);
+extern DeviceIntPtr kbdDevice;
+
+static const char *DEFAULTS[] = {
+    NULL
+};
+
+#include "keyboard.h"
+
+#ifdef XKB
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+#include <X11/extensions/XKBsrv.h>
+
+#if XFREE86VNC
+    /* 
+     * would like to use an XkbComponentNamesRec here but can't without
+     * pulling in a bunch of header files. :-(
+     */
+static    char *		xkbkeymap;
+static    char *		xkbkeycodes;
+static    char *		xkbtypes;
+static    char *		xkbcompat;
+static    char *		xkbsymbols;
+static    char *		xkbgeometry;
+static    Bool		xkbcomponents_specified;
+static    char *		xkbrules;
+static    char *		xkbmodel;
+static    char *		xkblayout;
+static    char *		xkbvariant;
+static    char *		xkboptions;
+#endif
+#endif
+
+void
+KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap)
+{
+    int i;
+
+    kbdDevice = pDevice;
+
+    for (i = 0; i < MAP_LENGTH; i++)
+	pModMap[i] = NoSymbol;
+
+    pModMap[CONTROL_L_KEY_CODE] = ControlMask;
+    pModMap[CONTROL_R_KEY_CODE] = ControlMask;
+    pModMap[SHIFT_L_KEY_CODE] = ShiftMask;
+    pModMap[SHIFT_R_KEY_CODE] = ShiftMask;
+    pModMap[META_L_KEY_CODE] = Mod1Mask;
+    pModMap[META_R_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_L_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_R_KEY_CODE] = Mod1Mask;
+
+    pKeySyms->minKeyCode = MIN_KEY_CODE;
+    pKeySyms->maxKeyCode = MAX_KEY_CODE;
+    pKeySyms->mapWidth = GLYPHS_PER_KEY;
+
+    pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym)
+				     * MAP_LENGTH * GLYPHS_PER_KEY);
+
+    if (!pKeySyms->map) {
+	ErrorF("xalloc failed in KbdDeviceInit\n");
+	exit(1);
+    }
+
+    for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++)
+	pKeySyms->map[i] = NoSymbol;
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+	pKeySyms->map[i] = map[i];
+    }
+}
+
+void
+KbdDeviceOn(void)
+{
+}
+
+
+void
+KbdDeviceOff(void)
+{
+}
+
+#if XFREE86VNC
+static int
+xf86rfbKeybControlProc(DeviceIntPtr device, int onoff)
+{
+    KeySymsRec		keySyms;
+    CARD8 		modMap[MAP_LENGTH];
+    DevicePtr pDev = (DevicePtr)device;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT: 
+	KbdDeviceInit(device, &keySyms, modMap);
+#ifdef XKB
+	if (noXkbExtension) {
+#endif
+	    InitKeyboardDeviceStruct(pDev, &keySyms, modMap,
+				 (BellProcPtr)rfbSendBell,
+				 (KbdCtrlProcPtr)NoopDDA);
+#ifdef XKB
+	} else {
+ 	    XkbComponentNamesRec names;
+	    if (XkbInitialMap) {
+	    	if ((xkbkeymap = strchr(XkbInitialMap, '/')) != NULL)
+		    xkbkeymap++;
+	    	else
+		    xkbkeymap = XkbInitialMap;
+	    }
+	    if (xkbkeymap) {
+	    	names.keymap = xkbkeymap;
+	    	names.keycodes = NULL;
+	    	names.types = NULL;
+	    	names.compat = NULL;
+	    	names.symbols = NULL;
+	    	names.geometry = NULL;
+	    } else {
+	    	names.keymap = NULL;
+	    	names.keycodes = xkbkeycodes;
+	    	names.types = xkbtypes;
+	    	names.compat = xkbcompat;
+	    	names.symbols = xkbsymbols;
+	    	names.geometry = xkbgeometry;
+	    }
+	if ((xkbkeymap || xkbcomponents_specified)
+	   && (xkbmodel == NULL || xkblayout == NULL)) {
+		xkbrules = NULL;
+	}
+#if 0
+	XkbSetRulesDflts(xkbrules, xkbmodel,
+			 xkblayout, xkbvariant,
+			 xkboptions);
+#endif
+	XkbInitKeyboardDeviceStruct(device, 
+				    &names,
+				    &keySyms, 
+				    modMap, 
+				    (BellProcPtr)rfbSendBell,
+				    (KbdCtrlProcPtr)NoopDDA);
+    }
+#endif /* XKB */
+	break;
+    case DEVICE_ON: 
+	pDev->on = TRUE;
+	KbdDeviceOn();
+	break;
+    case DEVICE_OFF: 
+	pDev->on = FALSE;
+	KbdDeviceOff();
+	break;
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    KbdDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static void
+xf86rfbKeybUninit(InputDriverPtr	drv,
+	       InputInfoPtr	pInfo,
+	       int		flags)
+{
+    xf86rfbKeybControlProc(pInfo->dev, DEVICE_OFF);
+}
+
+static InputInfoPtr
+xf86rfbKeybInit(InputDriverPtr	drv,
+	     IDevPtr		dev,
+	     int		flags)
+{
+    InputInfoPtr pInfo;
+    char *s;
+    Bool from;
+
+    if (!(pInfo = xf86AllocateInput(drv, 0)))
+	return NULL;
+
+    /* Initialise the InputInfoRec. */
+    pInfo->name = dev->identifier;
+    pInfo->type_name = "rfbKeyb";
+    pInfo->flags = XI86_KEYBOARD_CAPABLE;
+    pInfo->device_control = xf86rfbKeybControlProc;
+    pInfo->read_input = NULL;
+    pInfo->motion_history_proc = NULL;
+    pInfo->history_size = 0;
+    pInfo->control_proc = NULL;
+    pInfo->close_proc = NULL;
+    pInfo->switch_mode = NULL;
+    pInfo->conversion_proc = NULL;
+    pInfo->reverse_conversion_proc = NULL;
+    pInfo->fd = -1;
+    pInfo->dev = NULL;
+    pInfo->private_flags = 0;
+    pInfo->always_core_feedback = 0;
+    pInfo->conf_idev = dev;
+
+    /* Collect the options, and process the common options. */
+    xf86CollectInputOptions(pInfo, DEFAULTS, NULL);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    
+    /* Mark the device configured */
+    pInfo->flags |= XI86_CONFIGURED;
+
+#ifdef XKB
+  from = X_DEFAULT;
+  if (noXkbExtension)
+    from = X_CMDLINE;
+  else if (xf86FindOption(dev->commonOptions, "XkbDisable")) {
+    noXkbExtension =
+	xf86SetBoolOption(dev->commonOptions, "XkbDisable", FALSE);
+    from = X_CONFIG;
+  }
+  if (noXkbExtension)
+    xf86Msg(from, "XKB: disabled\n");
+
+#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL))
+
+  if (!noXkbExtension && !XkbInitialMap) {
+    if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeymap", NULL))) {
+      xkbkeymap = NULL_IF_EMPTY(s);
+      xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" "
+		"(overrides other XKB settings)\n", xkbkeymap);
+    } else {
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbCompat", NULL))) {
+	xkbcompat = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbTypes", NULL))) {
+	xkbtypes = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeycodes", NULL))) {
+	xkbkeycodes = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbGeometry", NULL))) {
+	xkbgeometry = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbSymbols", NULL))) {
+	xkbsymbols = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbRules", NULL))) {
+	xkbrules = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbModel", NULL))) {
+	xkbmodel = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbLayout", NULL))) {
+	xkblayout = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbVariant", NULL))) {
+	xkbvariant = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbOptions", NULL))) {
+	xkboptions = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s);
+      }
+    }
+  }
+#undef NULL_IF_EMPTY
+#endif /* XKB */
+
+    /* Return the configured device */
+    return (pInfo);
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec RFBKEYB = {
+    1,				/* driver version */
+    "rfbkeyb",			/* driver name */
+    NULL,			/* identify */
+    xf86rfbKeybInit,		/* pre-init */
+    xf86rfbKeybUninit,		/* un-init */
+    NULL,			/* module */
+    0				/* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+static void
+xf86rfbKeybUnplug(pointer	p)
+{
+}
+
+static pointer
+xf86rfbKeybPlug(pointer	module,
+	    pointer	options,
+	    int		*errmaj,
+	    int		*errmin)
+{
+    xf86AddInputDriver(&RFBKEYB, module, 0);
+
+    return module;
+}
+
+void
+vncInitKeyb(void)
+{
+    xf86AddInputDriver(&RFBKEYB, NULL, 0);
+}
+
+static XF86ModuleVersionInfo xf86rfbKeybVersionRec =
+{
+    "rfbkeyb",
+    "xf4vnc Project, see http://xf4vnc.sf.net",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XF86_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_XINPUT,
+    ABI_XINPUT_VERSION,
+    MOD_CLASS_XINPUT,
+    {0, 0, 0, 0}		/* signature, to be patched into the file by */
+				/* a tool */
+};
+
+XF86ModuleData rfbkeybModuleData = {&xf86rfbKeybVersionRec,
+				  xf86rfbKeybPlug,
+				  xf86rfbKeybUnplug};
+
+#endif /* XFree86LOADER */
+#endif /* XFREE86VNC */
diff -u -rNp a/hw/dmx/vnc/rfbmouse.c b/hw/dmx/vnc/rfbmouse.c
--- a/hw/dmx/vnc/rfbmouse.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rfbmouse.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,243 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#if XFREE86VNC
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include <misc.h>
+#include <xf86.h>
+#define NEED_XF86_TYPES
+#if !defined(DGUX)
+#include <xf86_ansic.h>
+#include <xisb.h>
+#endif
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>		/* Needed for InitValuator/Proximity stuff */
+#include <X11/keysym.h>
+#include <mipointer.h>
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+
+static const char *DEFAULTS[] = {
+    NULL
+};
+#else
+#include <X11/keysym.h>
+#include <dix.h>
+#include <mipointer.h>
+#endif
+
+#include "rfb.h"
+
+
+unsigned char ptrAcceleration = 50;
+
+void
+PtrDeviceOn(DeviceIntPtr pDev)
+{
+#if 0
+    ptrAcceleration = (unsigned char)pDev->ptrfeed->ctrl.num;
+#endif
+}
+
+void
+PtrDeviceInit(void)
+{
+}
+
+void
+PtrDeviceOff(void)
+{
+}
+
+
+void
+PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl)
+{
+#if 0
+    ptrAcceleration = (char)ctrl->num;
+
+    if (udpSockConnected) {
+	if (write(udpSock, &ptrAcceleration, 1) <= 0) {
+	    ErrorF("PtrDeviceControl: UDP input: write");
+	    rfbDisconnectUDPSock();
+	}
+    }
+#endif
+}
+
+#if XFREE86VNC
+static int
+xf86rfbMouseControlProc(DeviceIntPtr device, int onoff)
+{
+    BYTE map[6];
+    DevicePtr pDev = (DevicePtr)device;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT:
+	PtrDeviceInit();
+	map[1] = 1;
+	map[2] = 2;
+	map[3] = 3;
+	map[4] = 4;
+	map[5] = 5;
+	InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents,
+				PtrDeviceControl,
+				miPointerGetMotionBufferSize());
+	break;
+
+    case DEVICE_ON:
+	pDev->on = TRUE;
+	PtrDeviceOn(device);
+        break;
+
+    case DEVICE_OFF:
+	pDev->on = FALSE;
+	PtrDeviceOff();
+	break;
+
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    PtrDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static void
+xf86rfbMouseUninit(InputDriverPtr	drv,
+	       InputInfoPtr	pInfo,
+	       int		flags)
+{
+    xf86rfbMouseControlProc(pInfo->dev, DEVICE_OFF);
+}
+
+static InputInfoPtr
+xf86rfbMouseInit(InputDriverPtr	drv,
+	     IDevPtr		dev,
+	     int		flags)
+{
+    InputInfoPtr pInfo;
+
+    if (!(pInfo = xf86AllocateInput(drv, 0)))
+	return NULL;
+
+    /* Initialise the InputInfoRec. */
+    pInfo->name = dev->identifier;
+    pInfo->type_name = "rfbMouse";
+    pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+    pInfo->device_control = xf86rfbMouseControlProc;
+    pInfo->read_input = NULL;
+    pInfo->motion_history_proc = xf86GetMotionEvents;
+    pInfo->history_size = 0;
+    pInfo->control_proc = NULL;
+    pInfo->close_proc = NULL;
+    pInfo->switch_mode = NULL;
+    pInfo->conversion_proc = NULL;
+    pInfo->reverse_conversion_proc = NULL;
+    pInfo->fd = -1;
+    pInfo->dev = NULL;
+    pInfo->private_flags = 0;
+    pInfo->always_core_feedback = 0;
+    pInfo->conf_idev = dev;
+
+    /* Collect the options, and process the common options. */
+    xf86CollectInputOptions(pInfo, DEFAULTS, NULL);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    
+    /* Mark the device configured */
+    pInfo->flags |= XI86_CONFIGURED;
+
+    /* Return the configured device */
+    return (pInfo);
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec RFBMOUSE = {
+    1,				/* driver version */
+    "rfbmouse",			/* driver name */
+    NULL,			/* identify */
+    xf86rfbMouseInit,		/* pre-init */
+    xf86rfbMouseUninit,		/* un-init */
+    NULL,			/* module */
+    0				/* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+static void
+xf86rfbMouseUnplug(pointer	p)
+{
+}
+
+static pointer
+xf86rfbMousePlug(pointer	module,
+	    pointer	options,
+	    int		*errmaj,
+	    int		*errmin)
+{
+    xf86AddInputDriver(&RFBMOUSE, module, 0);
+
+    return module;
+}
+
+void
+vncInitMouse(void)
+{
+    xf86AddInputDriver(&RFBMOUSE, NULL, 0);
+}
+
+static XF86ModuleVersionInfo xf86rfbMouseVersionRec =
+{
+    "rfbmouse",
+    "xf4vnc Project, see http://xf4vnc.sf.net",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XF86_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_XINPUT,
+    ABI_XINPUT_VERSION,
+    MOD_CLASS_XINPUT,
+    {0, 0, 0, 0}		/* signature, to be patched into the file by */
+				/* a tool */
+};
+
+XF86ModuleData rfbmouseModuleData = {&xf86rfbMouseVersionRec,
+				  xf86rfbMousePlug,
+				  xf86rfbMouseUnplug};
+
+#endif /* XFree86LOADER */
+#endif
diff -u -rNp a/hw/dmx/vnc/rfbproto.h b/hw/dmx/vnc/rfbproto.h
--- a/hw/dmx/vnc/rfbproto.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rfbproto.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1347 @@
+/*
+ *  Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol, versions 3.3, 3.7 and 3.7t
+ * (protocol 3.7t is effectively 3.7 with TightVNC extensions enabled)
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first).  Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data.  The order of definitions in
+ * this file is as follows:
+ *
+ *  (1) Structures used in several types of message.
+ *  (2) Structures used in the initial handshaking.
+ *  (3) Message types.
+ *  (4) Encoding types.
+ *  (5) For each message type, the form of the data following the type byte.
+ *      Sometimes this is defined by a single structure but the more complex
+ *      messages have to be explained by comments.
+ */
+
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle.  This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+
+typedef struct _rfbRectangle {
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct _rfbPixelFormat {
+
+    CARD8 bitsPerPixel;		/* 8,16,32 only */
+
+    CARD8 depth;		/* 8 to 32 */
+
+    CARD8 bigEndian;		/* True if multi-byte pixels are interpreted
+				   as big endian, or if single-bit-per-pixel
+				   has most significant bit of the byte
+				   corresponding to first (leftmost) pixel. Of
+				   course this is meaningless for 8 bits/pix */
+
+    CARD8 trueColour;		/* If false then we need a "colour map" to
+				   convert pixels to RGB.  If true, xxxMax and
+				   xxxShift specify bits used for red, green
+				   and blue */
+
+    /* the following fields are only meaningful if trueColour is true */
+
+    CARD16 redMax;		/* maximum red value (= 2^n - 1 where n is the
+				   number of bits used for red). Note this
+				   value is always in big endian order. */
+
+    CARD16 greenMax;		/* similar for green */
+
+    CARD16 blueMax;		/* and blue */
+
+    CARD8 redShift;		/* number of shifts needed to get the red
+				   value in a pixel to the least significant
+				   bit. To find the red value from a given
+				   pixel, do the following:
+				   1) Swap pixel value according to bigEndian
+				      (e.g. if bigEndian is false and host byte
+				      order is big endian, then swap).
+				   2) Shift right by redShift.
+				   3) AND with redMax (in host byte order).
+				   4) You now have the red value between 0 and
+				      redMax. */
+
+    CARD8 greenShift;		/* similar for green */
+
+    CARD8 blueShift;		/* and blue */
+
+    CARD8 pad1;
+    CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to describe protocol options such as tunneling methods,
+ * authentication schemes and message types (protocol version 3.7t).
+ */
+
+typedef struct _rfbCapabilityInfo {
+
+    CARD32 code;		/* numeric identifier */
+    CARD8 vendorSignature[4];	/* vendor identification */
+    CARD8 nameSignature[8];	/* abbreviated option name */
+
+} rfbCapabilityInfo;
+
+#define sz_rfbCapabilityInfoVendor 4
+#define sz_rfbCapabilityInfoName 8
+#define sz_rfbCapabilityInfo 16
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define rfbStandardVendor "STDV"
+#define rfbTridiaVncVendor "TRDV"
+#define rfbTightVncVendor "TGHT"
+#define rfbTungstenGraphicsVendor "TGIV"
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports.  These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.7
+ * this is "RFB 003.007\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism.  Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent.  For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK.  This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 7
+#define rfbProtocolFallbackMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13];	/* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*
+ * Negotiation of the security type (protocol version 3.7)
+ *
+ * Once the protocol version has been decided, the server either sends a list
+ * of supported security types, or informs the client about an error (when the
+ * number of security types is 0).  Security type rfbSecTypeTight is used to
+ * enable TightVNC-specific protocol extensions.  The value rfbSecTypeVncAuth
+ * stands for classic VNC authentication.
+ *
+ * The client selects a particular security type from the list provided by the
+ * server.
+ */
+
+#define rfbSecTypeInvalid 0
+#define rfbSecTypeNone 1
+#define rfbSecTypeVncAuth 2
+#define rfbSecTypeTight 16
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Tunneling Capabilities (protocol version 3.7t)
+ *
+ * If the chosen security type is rfbSecTypeTight, the server sends a list of
+ * supported tunneling methods ("tunneling" refers to any additional layer of
+ * data transformation, such as encryption or external compression.)
+ *
+ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported tunneling methods in the order of preference.
+ *
+ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
+ * used, and the client should not send a response requesting a tunneling
+ * method.
+ */
+
+typedef struct _rfbTunnelingCapsMsg {
+    CARD32 nTunnelTypes;
+    /* followed by nTunnelTypes * rfbCapabilityInfo structures */
+} rfbTunnelingCapsMsg;
+
+#define sz_rfbTunnelingCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Tunneling Method Request (protocol version 3.7t)
+ *
+ * If the list of tunneling capabilities sent by the server was not empty, the
+ * client should reply with a 32-bit code specifying a particular tunneling
+ * method.  The following code should be used for no tunneling.
+ */
+
+#define rfbNoTunneling 0
+#define sig_rfbNoTunneling "NOTUNNEL"
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Authentication Capabilities (protocol version 3.7t)
+ *
+ * After setting up tunneling, the server sends a list of supported
+ * authentication schemes.
+ *
+ * nAuthTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported authentication schemes in the order of preference.
+ *
+ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is
+ * necessary, and the client should not send a response requesting an
+ * authentication scheme.
+ */
+
+typedef struct _rfbAuthenticationCapsMsg {
+    CARD32 nAuthTypes;
+    /* followed by nAuthTypes * rfbCapabilityInfo structures */
+} rfbAuthenticationCapsMsg;
+
+#define sz_rfbAuthenticationCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Authentication Scheme Request (protocol version 3.7t)
+ *
+ * If the list of authentication capabilities sent by the server was not empty,
+ * the client should reply with a 32-bit code specifying a particular
+ * authentication scheme.  The following codes are supported.
+ */
+
+#define rfbAuthNone 1
+#define rfbAuthVNC 2
+#define rfbAuthUnixLogin 129
+#define rfbAuthExternal 130
+
+#define sig_rfbAuthNone "NOAUTH__"
+#define sig_rfbAuthVNC "VNCAUTH_"
+#define sig_rfbAuthUnixLogin "ULGNAUTH"
+#define sig_rfbAuthExternal "XTRNAUTH"
+
+
+/*-----------------------------------------------------------------------------
+ * Standard VNC Authentication (all protocol versions)
+ *
+ * Standard authentication result codes are defined below.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct _rfbClientInitMsg {
+    CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct _rfbServerInitMsg {
+    CARD16 framebufferWidth;
+    CARD16 framebufferHeight;
+    rfbPixelFormat format;	/* the server's preferred pixel format */
+    CARD32 nameLength;
+    /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*-----------------------------------------------------------------------------
+ * Server Interaction Capabilities Message (protocol version 3.7t)
+ *
+ * In the protocol version 3.7t, the server informs the client what message
+ * types it supports in addition to ones defined in the protocol version 3.7.
+ * Also, the server sends the list of all supported encodings (note that it's
+ * not necessary to advertise the "raw" encoding sinse it MUST be supported in
+ * RFB 3.x protocols).
+ *
+ * This data immediately follows the server initialisation message.
+ */
+
+typedef struct _rfbInteractionCapsMsg {
+    CARD16 nServerMessageTypes;
+    CARD16 nClientMessageTypes;
+    CARD16 nEncodingTypes;
+    CARD16 pad;			/* reserved, must be 0 */
+    /* followed by nServerMessageTypes * rfbCapabilityInfo structures */
+    /* followed by nClientMessageTypes * rfbCapabilityInfo structures */
+} rfbInteractionCapsMsg;
+
+#define sz_rfbInteractionCapsMsg 8
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants.  Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest.  From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages.  The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+/* Chromium extensions, use higher values */
+#define rfbChromiumStart 50 
+#define rfbChromiumMoveResizeWindow 51
+#define rfbChromiumClipList 52
+#define rfbChromiumWindowShow 53
+
+#define rfbFileListData 130
+#define rfbFileDownloadData 131
+#define rfbFileUploadCancel 132
+#define rfbFileDownloadFailed 133
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListData "FTS_LSDT"
+#define sig_rfbFileDownloadData "FTS_DNDT"
+#define sig_rfbFileUploadCancel "FTS_UPCN"
+#define sig_rfbFileDownloadFailed "FTS_DNFL"
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1	/* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+/* Chromium extensions, use higher values */
+#define rfbChromiumStop 50
+#define rfbChromiumExpose 51
+
+#define rfbFileListRequest 130
+#define rfbFileDownloadRequest 131
+#define rfbFileUploadRequest 132
+#define rfbFileUploadData 133
+#define rfbFileDownloadCancel 134
+#define rfbFileUploadFailed 135
+#define rfbFileCreateDirRequest 136
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListRequest "FTC_LSRQ"
+#define sig_rfbFileDownloadRequest "FTC_DNRQ"
+#define sig_rfbFileUploadRequest "FTC_UPRQ"
+#define sig_rfbFileUploadData "FTC_UPDT"
+#define sig_rfbFileDownloadCancel "FTC_DNCN"
+#define sig_rfbFileUploadFailed "FTC_UPFL"
+#define sig_rfbFileCreateDirRequest "FTC_FCDR"
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw       0
+#define rfbEncodingCopyRect  1
+#define rfbEncodingRRE       2
+#define rfbEncodingCoRRE     4
+#define rfbEncodingHextile   5
+#define rfbEncodingZlib      6
+#define rfbEncodingTight     7
+#define rfbEncodingZlibHex   8
+
+/* signatures for basic encoding types */
+#define sig_rfbEncodingRaw       "RAW_____"
+#define sig_rfbEncodingCopyRect  "COPYRECT"
+#define sig_rfbEncodingRRE       "RRE_____"
+#define sig_rfbEncodingCoRRE     "CORRE___"
+#define sig_rfbEncodingHextile   "HEXTILE_"
+#define sig_rfbEncodingZlib      "ZLIB____"
+#define sig_rfbEncodingTight     "TIGHT___"
+#define sig_rfbEncodingZlibHex   "ZLIBHEX_"
+#define sig_rfbEncodingChromium  "CHROMIUM"
+
+/*
+ * Special encoding numbers:
+ *   0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
+ *   0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data;
+ *   0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions;
+ *   0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet;
+ *   0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor;
+ *   0xFFFFFFF0 .. 0xFFFFFFFF -- not allocated yet.
+ */
+
+#define rfbEncodingCompressLevel0  0xFFFFFF00
+#define rfbEncodingCompressLevel1  0xFFFFFF01
+#define rfbEncodingCompressLevel2  0xFFFFFF02
+#define rfbEncodingCompressLevel3  0xFFFFFF03
+#define rfbEncodingCompressLevel4  0xFFFFFF04
+#define rfbEncodingCompressLevel5  0xFFFFFF05
+#define rfbEncodingCompressLevel6  0xFFFFFF06
+#define rfbEncodingCompressLevel7  0xFFFFFF07
+#define rfbEncodingCompressLevel8  0xFFFFFF08
+#define rfbEncodingCompressLevel9  0xFFFFFF09
+
+#define rfbEncodingXCursor         0xFFFFFF10
+#define rfbEncodingRichCursor      0xFFFFFF11
+#define rfbEncodingPointerPos      0xFFFFFF18
+
+#define rfbEncodingLastRect        0xFFFFFF20
+#define rfbEncodingNewFBSize       0xFFFFFF21
+#define rfbEncodingChromium	   0xFFFFFF2F
+#define rfbEncodingChromium2	   0xFFFFFF30
+
+#define rfbEncodingQualityLevel0   0xFFFFFFE0
+#define rfbEncodingQualityLevel1   0xFFFFFFE1
+#define rfbEncodingQualityLevel2   0xFFFFFFE2
+#define rfbEncodingQualityLevel3   0xFFFFFFE3
+#define rfbEncodingQualityLevel4   0xFFFFFFE4
+#define rfbEncodingQualityLevel5   0xFFFFFFE5
+#define rfbEncodingQualityLevel6   0xFFFFFFE6
+#define rfbEncodingQualityLevel7   0xFFFFFFE7
+#define rfbEncodingQualityLevel8   0xFFFFFFE8
+#define rfbEncodingQualityLevel9   0xFFFFFFE9
+
+/* signatures for "fake" encoding types */
+#define sig_rfbEncodingCompressLevel0  "COMPRLVL"
+#define sig_rfbEncodingXCursor         "X11CURSR"
+#define sig_rfbEncodingRichCursor      "RCHCURSR"
+#define sig_rfbEncodingPointerPos      "POINTPOS"
+#define sig_rfbEncodingLastRect        "LASTRECT"
+#define sig_rfbEncodingNewFBSize       "NEWFBSIZ"
+#define sig_rfbEncodingQualityLevel0   "JPEGQLVL"
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves.  The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct _rfbFramebufferUpdateMsg {
+    CARD8 type;			/* always rfbFramebufferUpdate */
+    CARD8 pad;
+    CARD16 nRects;
+    /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data.  Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct _rfbFramebufferUpdateRectHeader {
+    rfbRectangle r;
+    CARD32 encoding;		/* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding.  Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding.  The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct _rfbCopyRect {
+    CARD16 srcX;
+    CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding.  We have an rfbRREHeader structure
+ * giving the number of subrectangles following.  Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct _rfbRREHeader {
+    CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding.  We have an rfbRREHeader structure giving
+ * the number of subrectangles following.  Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>].  This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct _rfbCoRRERectangle {
+    CARD8 x;
+    CARD8 y;
+    CARD8 w;
+    CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding.  The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order.  If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller.  Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller.  Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits.  If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile).  Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes.  The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ *    the background colour for this tile.  The first non-raw tile in a
+ *    rectangle must have this bit set.  If this bit isn't set then the
+ *    background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ *    the foreground colour to be used for all subrectangles in this tile.
+ *    If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ *    subrectangles following.  If not set, there are no subrectangles (i.e.
+ *    the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ *    value giving the colour of that subrectangle.  If not set, all
+ *    subrectangles are the same colour, the foreground colour;  if the
+ *    ForegroundSpecified bit wasn't set then the foreground is the same as
+ *    the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes.  The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw			(1 << 0)
+#define rfbHextileBackgroundSpecified	(1 << 1)
+#define rfbHextileForegroundSpecified	(1 << 2)
+#define rfbHextileAnySubrects		(1 << 3)
+#define rfbHextileSubrectsColoured	(1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZLIB - zlib compression Encoding.  We have an rfbZlibHeader structure
+ * giving the number of bytes to follow.  Finally the data follows in
+ * zlib compressed format.
+ */
+
+typedef struct _rfbZlibHeader {
+    CARD32 nBytes;
+} rfbZlibHeader;
+
+#define sz_rfbZlibHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Tight Encoding.
+ *
+ *-- The first byte of each Tight-encoded rectangle is a "compression control
+ *   byte". Its format is as follows (bit 0 is the least significant one):
+ *
+ *   bit 0:    if 1, then compression stream 0 should be reset;
+ *   bit 1:    if 1, then compression stream 1 should be reset;
+ *   bit 2:    if 1, then compression stream 2 should be reset;
+ *   bit 3:    if 1, then compression stream 3 should be reset;
+ *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
+ *             if 1001 (0x09), then the compression type is "jpeg",
+ *             if 0xxx, then the compression type is "basic",
+ *             values greater than 1001 are not valid.
+ *
+ * If the compression type is "basic", then bits 6..4 of the
+ * compression control byte (those xxx in 0xxx) specify the following:
+ *
+ *   bits 5-4:  decimal representation is the index of a particular zlib
+ *              stream which should be used for decompressing the data;
+ *   bit 6:     if 1, then a "filter id" byte is following this byte.
+ *
+ *-- The data that follows after the compression control byte described
+ * above depends on the compression type ("fill", "jpeg" or "basic").
+ *
+ *-- If the compression type is "fill", then the only pixel value follows, in
+ * client pixel format (see NOTE 1). This value applies to all pixels of the
+ * rectangle.
+ *
+ *-- If the compression type is "jpeg", the following data stream looks like
+ * this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     JPEG image.
+ *
+ * Data size is compactly represented in one, two or three bytes, according
+ * to the following scheme:
+ *
+ *  0xxxxxxx                    (for values 0..127)
+ *  1xxxxxxx 0yyyyyyy           (for values 128..16383)
+ *  1xxxxxxx 1yyyyyyy zzzzzzzz  (for values 16384..4194303)
+ *
+ * Here each character denotes one bit, xxxxxxx are the least significant 7
+ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
+ * most significant 8 bits (bits 14-21). For example, decimal value 10000
+ * should be represented as two bytes: binary 10010000 01001110, or
+ * hexadecimal 90 4E.
+ *
+ *-- If the compression type is "basic" and bit 6 of the compression control
+ * byte was set to 1, then the next (second) byte specifies "filter id" which
+ * tells the decoder what filter type was used by the encoder to pre-process
+ * pixel data before the compression. The "filter id" byte can be one of the
+ * following:
+ *
+ *   0:  no filter ("copy" filter);
+ *   1:  "palette" filter;
+ *   2:  "gradient" filter.
+ *
+ *-- If bit 6 of the compression control byte is set to 0 (no "filter id"
+ * byte), or if the filter id is 0, then raw pixel values in the client
+ * format (see NOTE 1) will be compressed. See below details on the
+ * compression.
+ *
+ *-- The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better. 
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ *   if (P[i,j] < 0) then P[i,j] := 0;
+ *   if (P[i,j] > MAX) then P[i,j] := MAX;
+ *   D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.
+ *
+ *-- The "palette" filter converts true-color pixel data to indexed colors
+ * and a palette which can consist of 2..256 colors. If the number of colors
+ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
+ * encode one pixel. 1-bit encoding is performed such way that the most
+ * significant bits correspond to the leftmost pixels, and each raw of pixels
+ * is aligned to the byte boundary. When "palette" filter is used, the
+ * palette is sent before the pixel data. The palette begins with an unsigned
+ * byte which value is the number of colors in the palette minus 1 (i.e. 1
+ * means 2 colors, 255 means 256 colors in the palette). Then follows the
+ * palette itself which consist of pixel values in client pixel format (see
+ * NOTE 1).
+ *
+ *-- The pixel data is compressed using the zlib library. But if the data
+ * size after applying the filter but before the compression is less then 12,
+ * then the data is sent as is, uncompressed. Four separate zlib streams
+ * (0..3) can be used and the decoder should read the actual stream id from
+ * the compression control byte (see NOTE 2).
+ *
+ * If the compression is not used, then the pixel data is sent as is,
+ * otherwise the data stream looks like this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     zlib-compressed data.
+ *
+ * Data size is compactly represented in one, two or three bytes, just like
+ * in the "jpeg" compression method (see above).
+ *
+ *-- NOTE 1. If the color depth is 24, and all three color components are
+ * 8-bit wide, then one pixel in Tight encoding is always represented by
+ * three bytes, where the first byte is red component, the second byte is
+ * green component, and the third byte is blue component of the pixel color
+ * value. This applies to colors in palettes as well.
+ *
+ *-- NOTE 2. The decoder must reset compression streams' states before
+ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
+ * byte are set to 1. Note that the decoder must reset zlib streams even if
+ * the compression type is "fill" or "jpeg".
+ *
+ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
+ * when bits-per-pixel value is either 16 or 32, not 8.
+ *
+ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
+ * pixels. If a rectangle is wider, it must be split into several rectangles
+ * and each one should be encoded separately.
+ *
+ */
+
+#define rfbTightExplicitFilter         0x04
+#define rfbTightFill                   0x08
+#define rfbTightJpeg                   0x09
+#define rfbTightMaxSubencoding         0x09
+
+/* Filters to improve compression efficiency */
+#define rfbTightFilterCopy             0x00
+#define rfbTightFilterPalette          0x01
+#define rfbTightFilterGradient         0x02
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZLIBHEX - zlib compressed Hextile Encoding.  Essentially, this is the
+ * hextile encoding with zlib compression on the tiles that can not be
+ * efficiently encoded with one of the other hextile subencodings.  The
+ * new zlib subencoding uses two bytes to specify the length of the
+ * compressed tile and then the compressed data follows.  As with the
+ * raw sub-encoding, the zlib subencoding invalidates the other
+ * values, if they are also set.
+ */
+
+#define rfbHextileZlibRaw		(1 << 5)
+#define rfbHextileZlibHex		(1 << 6)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * XCursor encoding. This is a special encoding used to transmit X-style
+ * cursor shapes from server to clients. Note that for this encoding,
+ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot
+ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB
+ * samples are sent after header in the rfbXCursorColors structure. They
+ * denote foreground and background colors of the cursor. If a client
+ * supports only black-and-white cursors, it should ignore these colors and
+ * assume that foreground is black and background is white. Next, two bitmaps
+ * (1 bits per pixel) follow: first one with actual data (value 0 denotes
+ * background color, value 1 denotes foreground color), second one with
+ * transparency data (bits with zero value mean that these pixels are
+ * transparent). Both bitmaps represent cursor data in a byte stream, from
+ * left to right, from top to bottom, and each row is byte-aligned. Most
+ * significant bits correspond to leftmost pixels. The number of bytes in
+ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor
+ * should be hidden (or default local cursor should be set by the client).
+ */
+
+typedef struct _rfbXCursorColors {
+    CARD8 foreRed;
+    CARD8 foreGreen;
+    CARD8 foreBlue;
+    CARD8 backRed;
+    CARD8 backGreen;
+    CARD8 backBlue;
+} rfbXCursorColors;
+
+#define sz_rfbXCursorColors 6
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RichCursor encoding. This is a special encoding used to transmit cursor
+ * shapes from server to clients. It is similar to the XCursor encoding but
+ * uses client pixel format instead of two RGB colors to represent cursor
+ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader
+ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h).
+ * After header, two pixmaps follow: first one with cursor image in current
+ * client pixel format (like in raw encoding), second with transparency data
+ * (1 bit per pixel, exactly the same format as used for transparency bitmap
+ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or
+ * default local cursor should be set by the client).
+ */
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries.  In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest.  So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct _rfbSetColourMapEntriesMsg {
+    CARD8 type;			/* always rfbSetColourMapEntries */
+    CARD8 redIndex;		/* used to be pad, but used for DirectColor */
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct _rfbBellMsg {
+    CARD8 type;			/* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct _rfbServerCutTextMsg {
+    CARD8 type;			/* always rfbServerCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ChromiumStart - a port number for the crserver
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumStart */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 crServerPort;
+    CARD32 mothershipPort;
+} rfbChromiumStartMsg;
+
+#define sz_rfbChromiumStartMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * ChromiumMoveResizeWindow - move a chromium window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumMoveResizeWindow */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 x;
+    CARD32 y;
+    CARD32 w;
+    CARD32 h;
+} rfbChromiumMoveResizeWindowMsg;
+
+#define sz_rfbChromiumMoveResizeWindowMsg 24
+
+/*-----------------------------------------------------------------------------
+ * ChromiumClipList - send clip list
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumClipList */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 length;
+} rfbChromiumClipListMsg;
+
+#define sz_rfbChromiumClipListMsg 12
+
+/*-----------------------------------------------------------------------------
+ * ChromiumWindowShow - map or unmap a window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumWindowShow */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 show;
+} rfbChromiumWindowShowMsg;
+
+#define sz_rfbChromiumWindowShowMsg 12
+
+/*-----------------------------------------------------------------------------
+ * FileListData
+ */
+
+typedef struct _rfbFileListDataMsg {
+    CARD8 type;
+    CARD8 flags;
+    CARD16 numFiles;
+    CARD16 dataSize;
+    CARD16 compressedSize;
+    /* Followed by SizeData[numFiles] */
+    /* Followed by Filenames[compressedSize] */
+} rfbFileListDataMsg;
+
+#define sz_rfbFileListDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadData
+ */
+
+typedef struct _rfbFileDownloadDataMsg {
+    CARD8 type;
+    CARD8 compressLevel;
+    CARD16 realSize;
+    CARD16 compressedSize;
+    /* Followed by File[copressedSize] */
+} rfbFileDownloadDataMsg;
+
+#define sz_rfbFileDownloadDataMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadCancel
+ */
+
+typedef struct _rfbFileUploadCancelMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileUploadCancelMsg;
+
+#define sz_rfbFileUploadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadFailed
+ */
+
+typedef struct _rfbFileDownloadFailedMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileDownloadFailedMsg;
+
+#define sz_rfbFileDownloadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union _rfbServerToClientMsg {
+    CARD8 type;
+    rfbFramebufferUpdateMsg fu;
+    rfbSetColourMapEntriesMsg scme;
+    rfbBellMsg b;
+    rfbServerCutTextMsg sct;
+    rfbFileListDataMsg fld;
+    rfbFileDownloadDataMsg fdd;
+    rfbFileUploadCancelMsg fuc;
+    rfbFileDownloadFailedMsg fdf;
+    rfbChromiumStartMsg scd;
+    rfbChromiumMoveResizeWindowMsg scm;
+    rfbChromiumClipListMsg sccl;
+    rfbChromiumWindowShowMsg scws;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct _rfbSetPixelFormatMsg {
+    CARD8 type;			/* always rfbSetPixelFormat */
+    CARD8 pad1;
+    CARD16 pad2;
+    rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ *    ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct _rfbFixColourMapEntriesMsg {
+    CARD8 type;			/* always rfbFixColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept.  Put them
+ * in order of preference, if we have any.  We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct _rfbSetEncodingsMsg {
+    CARD8 type;			/* always rfbSetEncodings */
+    CARD8 pad;
+    CARD16 nEncodings;
+    /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update.  If incremental
+ * is true then the client just wants the changes since the last update.  If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct _rfbFramebufferUpdateRequestMsg {
+    CARD8 type;			/* always rfbFramebufferUpdateRequest */
+    CARD8 incremental;
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value.  Other common keys are:
+ *
+ * BackSpace		0xff08
+ * Tab			0xff09
+ * Return or Enter	0xff0d
+ * Escape		0xff1b
+ * Insert		0xff63
+ * Delete		0xffff
+ * Home			0xff50
+ * End			0xff57
+ * Page Up		0xff55
+ * Page Down		0xff56
+ * Left			0xff51
+ * Up			0xff52
+ * Right		0xff53
+ * Down			0xff54
+ * F1			0xffbe
+ * F2			0xffbf
+ * ...			...
+ * F12			0xffc9
+ * Shift		0xffe1
+ * Control		0xffe3
+ * Meta			0xffe7
+ * Alt			0xffe9
+ */
+
+typedef struct _rfbKeyEventMsg {
+    CARD8 type;			/* always rfbKeyEvent */
+    CARD8 down;			/* true if down (press), false if up */
+    CARD16 pad;
+    CARD32 key;			/* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct _rfbPointerEventMsg {
+    CARD8 type;			/* always rfbPointerEvent */
+    CARD8 buttonMask;		/* bits 0-7 are buttons 1-8, 0=up, 1=down */
+    CARD16 x;
+    CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+#define rfbButton4Mask 8
+#define rfbButton5Mask 16
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct _rfbClientCutTextMsg {
+    CARD8 type;			/* always rfbClientCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileListRequest
+ */
+
+typedef struct _rfbFileListRequestMsg {
+    CARD8 type;
+    CARD8 flags;
+    CARD16 dirNameSize;
+    /* Followed by char Dirname[dirNameSize] */
+} rfbFileListRequestMsg;
+
+#define sz_rfbFileListRequestMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadRequest
+ */
+
+typedef struct _rfbFileDownloadRequestMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 fNameSize;
+    CARD32 position;
+    /* Followed by char Filename[fNameSize] */
+} rfbFileDownloadRequestMsg;
+
+#define sz_rfbFileDownloadRequestMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileUploadRequest
+ */
+
+typedef struct _rfbFileUploadRequestMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 fNameSize;
+    CARD32 position;
+    /* Followed by char Filename[fNameSize] */
+} rfbFileUploadRequestMsg;
+
+#define sz_rfbFileUploadRequestMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadData
+ */
+
+typedef struct _rfbFileUploadDataMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 realSize;
+    CARD16 compressedSize;
+    /* Followed by File[compressedSize]   */
+} rfbFileUploadDataMsg;
+
+#define sz_rfbFileUploadDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadCancel
+ */
+
+typedef struct _rfbFileDownloadCancelMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileDownloadCancelMsg;
+
+#define sz_rfbFileDownloadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileUploadFailed
+ */
+
+typedef struct _rfbFileUploadFailedMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileUploadFailedMsg;
+
+#define sz_rfbFileUploadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileCreateDirRequest
+ */
+
+typedef struct _rfbFileCreateDirRequestMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 dNameLen;
+    CARD32 dModTime;
+    /* Followed by dName[dNameLen] */
+} rfbFileCreateDirRequestMsg;
+ 
+#define sz_rfbFileCreateDirRequestMsg 8
+ 
+/*-----------------------------------------------------------------------------
+ * ChromiumStop - the client has stopped the GL app.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumStop */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 port;
+} rfbChromiumStopMsg;
+
+#define sz_rfbChromiumStopMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ChromiumExpose - redraw the window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumExpose */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+} rfbChromiumExposeMsg;
+
+#define sz_rfbChromiumExposeMsg 8
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union _rfbClientToServerMsg {
+    CARD8 type;
+    rfbSetPixelFormatMsg spf;
+    rfbFixColourMapEntriesMsg fcme;
+    rfbSetEncodingsMsg se;
+    rfbFramebufferUpdateRequestMsg fur;
+    rfbKeyEventMsg ke;
+    rfbPointerEventMsg pe;
+    rfbClientCutTextMsg cct;
+    rfbFileListRequestMsg flr;
+    rfbFileDownloadRequestMsg fdr;
+    rfbFileUploadRequestMsg fupr;
+    rfbFileUploadDataMsg fud;
+    rfbFileDownloadCancelMsg fdc;
+    rfbFileUploadFailedMsg fuf;
+    rfbFileCreateDirRequestMsg fcdr;
+    rfbChromiumStopMsg csd;
+    rfbChromiumExposeMsg cse;
+} rfbClientToServerMsg;
diff -u -rNp a/hw/dmx/vnc/rfbserver.c b/hw/dmx/vnc/rfbserver.c
--- a/hw/dmx/vnc/rfbserver.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rfbserver.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2265 @@
+/*
+ * rfbserver.c - deal with server-side of the RFB protocol.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000-2004 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* Use ``#define CORBA'' to enable CORBA control interface */
+
+#include "rfb.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "windowstr.h"
+#include "input.h"
+#include "mipointer.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+#ifdef CHROMIUM
+#include "mivalidate.h"
+#endif
+#include "sprite.h"
+#include "propertyst.h"
+#include <X11/Xatom.h>
+#include <mi.h>
+
+#ifdef CORBA
+#include <vncserverctrl.h>
+#endif
+
+#if 0
+extern int GenerateVncConnectedEvent(int sock);
+extern int GenerateVncDisconnectedEvent(int sock);
+#endif
+#ifdef CHROMIUM
+extern int GenerateVncChromiumConnectedEvent(int sock);
+struct CRWindowTable *windowTable = NULL;
+#endif
+
+extern Atom VNC_CONNECT;
+
+rfbClientPtr rfbClientHead = NULL;
+rfbClientPtr pointerClient = NULL;  /* Mutex for pointer events */
+
+static rfbClientPtr rfbNewClient(ScreenPtr pScreen, int sock);
+static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
+static void rfbProcessClientInitMessage(rfbClientPtr cl);
+static void rfbSendInteractionCaps(rfbClientPtr cl);
+static void rfbProcessClientNormalMessage(rfbClientPtr cl);
+static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy);
+static Bool rfbSendLastRectMarker(rfbClientPtr cl);
+
+static char *text = NULL;
+
+void
+rfbRootPropertyChange(ScreenPtr pScreen)
+{
+    PropertyPtr pProp;
+    WindowPtr pWin = WindowTable[pScreen->myNum];
+
+    pProp = wUserProps (pWin);
+
+    while (pProp) {
+        if ((pProp->propertyName == XA_CUT_BUFFER0) && 
+	    (pProp->type == XA_STRING) &&
+	    (pProp->format == 8))
+    	{
+	    /* Ensure we don't keep re-sending cut buffer */
+
+    	    if ( (text && pProp->data && strncmp(text, pProp->data, pProp->size)) || !text)
+	    	rfbGotXCutText(pProp->data, pProp->size);
+
+	    if (text) xfree(text);
+    	    text = xalloc(1 + pProp->size);
+    	    if (! text) return;
+    	    if (pProp->data) memcpy(text, pProp->data, pProp->size);
+    	    text[pProp->size] = '\0';
+
+	    return;
+    	}
+    	if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING)
+	    && (pProp->format == 8) && (pProp->size > 0))
+    	{
+	    int i;
+	    rfbClientPtr cl;
+	    int port = 5500;
+	    char *host = (char *)Xalloc(pProp->size+1);
+	    memcpy(host, pProp->data, pProp->size);
+	    host[pProp->size] = 0;
+	    for (i = 0; i < pProp->size; i++) {
+	    	if (host[i] == ':') {
+		    port = atoi(&host[i+1]);
+		    host[i] = 0;
+	    	}
+	    }
+
+	    cl = rfbReverseConnection(pScreen, host, port);
+
+#ifdef CORBA
+	    if (cl != NULL)
+	    	newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+
+	    ChangeWindowProperty(pWin,
+		 	     pProp->propertyName, pProp->type,
+			     pProp->format, PropModeReplace,
+			     0, NULL,
+			     FALSE
+			     );
+
+	    free(host);
+    	}
+	pProp = pProp->next;
+    }
+}
+
+int
+rfbBitsPerPixel(depth)
+    int depth;
+{
+    if (depth == 1) return 1;
+    else if (depth <= 8) return 8;
+    else if (depth <= 16) return 16;
+    else return 32;
+}
+
+void 
+rfbUserAllow(int sock, int accept)
+{
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (cl->sock == sock) {
+	    cl->userAccepted = accept;
+	}
+    }
+}
+
+/*
+ * rfbNewClientConnection is called from sockets.c when a new connection
+ * comes in.
+ */
+
+void
+rfbNewClientConnection(ScreenPtr pScreen, int sock)
+{
+    rfbClientPtr cl;
+
+    cl = rfbNewClient(pScreen, sock);
+
+#if 0
+    GenerateVncConnectedEvent(sock);
+#endif
+
+#if XFREE86VNC
+    /* Someone is connected - disable VT switching */
+    xf86EnableVTSwitch(FALSE);
+#endif
+
+#ifdef CORBA
+    if (cl != NULL)
+	newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+}
+
+
+/*
+ * rfbReverseConnection is called by the CORBA stuff to make an outward
+ * connection to a "listening" RFB client.
+ */
+
+rfbClientPtr
+rfbReverseConnection(ScreenPtr pScreen, char *host, int port)
+{
+    int sock;
+    rfbClientPtr cl;
+
+    if ((sock = rfbConnect(pScreen, host, port)) < 0)
+	return (rfbClientPtr)NULL;
+
+    cl = rfbNewClient(pScreen, sock);
+
+    if (cl) {
+	cl->reverseConnection = TRUE;
+    }
+
+    return cl;
+}
+
+
+#ifdef CHROMIUM
+/*
+ * rfbSetClip --
+ * 	Generate expose event.
+ * 	This function is overkill and should be cleaned up, but it
+ * 	works for now.
+ */
+
+static void
+rfbSetClip(WindowPtr pWin, BOOL enable)
+{
+    ScreenPtr   pScreen = pWin->drawable.pScreen;
+    WindowPtr	pChild;
+    Bool	WasViewable = (Bool)(pWin->viewable);
+    Bool	anyMarked = FALSE;
+    RegionPtr	pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+    Bool	dosave = FALSE;
+#endif
+    WindowPtr   pLayerWin;
+    BoxRec	box;
+
+    if (WasViewable)
+    {
+	for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+	{
+	    (void) (*pScreen->MarkOverlappedWindows)(pChild,
+						     pChild,
+						     &pLayerWin);
+	}
+	(*pScreen->MarkWindow) (pWin);
+	anyMarked = TRUE;
+	if (pWin->valdata)
+	{
+	    if (HasBorder (pWin))
+	    {
+		RegionPtr	borderVisible;
+
+		borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+		REGION_SUBTRACT(pScreen, borderVisible,
+				&pWin->borderClip, &pWin->winSize);
+		pWin->valdata->before.borderVisible = borderVisible;
+	    }
+	    pWin->valdata->before.resized = TRUE;
+	}
+    }
+    
+    /*
+     * Use REGION_BREAK to avoid optimizations in ValidateTree
+     * that assume the root borderClip can't change well, normally
+     * it doesn't...)
+     */
+    if (enable)
+    {
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = pScreen->width;
+	box.y2 = pScreen->height;
+	REGION_INIT (pScreen, &pWin->winSize, &box, 1);
+	REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
+	if (WasViewable)
+	    REGION_RESET(pScreen, &pWin->borderClip, &box);
+	pWin->drawable.width = pScreen->width;
+	pWin->drawable.height = pScreen->height;
+        REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    else
+    {
+	REGION_EMPTY(pScreen, &pWin->borderClip);
+	REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    
+    ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
+    
+    if (WasViewable)
+    {
+	if (pWin->backStorage)
+	{
+	    pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+	    REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+	}
+
+	if (pWin->firstChild)
+	{
+	    anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
+							   pWin->firstChild,
+							   (WindowPtr *)NULL);
+	}
+	else
+	{
+	    (*pScreen->MarkWindow) (pWin);
+	    anyMarked = TRUE;
+	}
+
+#ifdef DO_SAVE_UNDERS
+	if (DO_SAVE_UNDERS(pWin))
+	{
+	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
+	}
+#endif /* DO_SAVE_UNDERS */
+
+	if (anyMarked)
+	    (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
+    }
+
+    if (pWin->backStorage &&
+	((pWin->backingStore == Always) || WasViewable))
+    {
+	if (!WasViewable)
+	    pOldClip = &pWin->clipList; /* a convenient empty region */
+	bsExposed = (*pScreen->TranslateBackingStore)
+			     (pWin, 0, 0, pOldClip,
+			      pWin->drawable.x, pWin->drawable.y);
+	if (WasViewable)
+	    REGION_DESTROY(pScreen, pOldClip);
+	if (bsExposed)
+	{
+	    RegionPtr	valExposed = NullRegion;
+    
+	    if (pWin->valdata)
+		valExposed = &pWin->valdata->after.exposed;
+	    (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+	    if (valExposed)
+		REGION_EMPTY(pScreen, valExposed);
+	    REGION_DESTROY(pScreen, bsExposed);
+	}
+    }
+    if (WasViewable)
+    {
+	if (anyMarked)
+	    (*pScreen->HandleExposures)(pWin);
+#ifdef DO_SAVE_UNDERS
+	if (dosave)
+	    (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
+#endif /* DO_SAVE_UNDERS */
+	if (anyMarked && pScreen->PostValidateTree)
+	    (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
+    }
+    if (pWin->realized)
+	WindowsRestructured ();
+    FlushAllOutput ();
+}
+#endif /* CHROMIUM */
+
+/*
+ * rfbNewClient is called when a new connection has been made by whatever
+ * means.
+ */
+
+static rfbClientPtr
+rfbNewClient(ScreenPtr pScreen, int sock)
+{
+    rfbProtocolVersionMsg pv;
+    rfbClientPtr cl;
+    BoxRec box;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
+    VNCSCREENPTR(pScreen);
+    int i;
+
+    if (rfbClientHead == NULL) {
+	/* no other clients - make sure we don't think any keys are pressed */
+	KbdReleaseAllKeys();
+    } else {
+	rfbLog("  (other clients");
+	for (cl = rfbClientHead; cl; cl = cl->next) {
+	    rfbLog(" %s",cl->host);
+	}
+	rfbLog(")\n");
+    }
+
+    cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec));
+
+#ifdef CHROMIUM
+    cl->chromium_port = 0; /* no GL application on this port, yet */
+#endif
+    cl->userAccepted = 0; /* user hasn't even approached this yet .... */
+    cl->sock = sock;
+    getpeername(sock, (struct sockaddr *)&addr, &addrlen);
+    cl->host = strdup(inet_ntoa(addr.sin_addr));
+    cl->login = NULL;
+
+    /* Dispatch client input to rfbProcessClientProtocolVersion(). */
+    cl->state = RFB_PROTOCOL_VERSION;
+
+    cl->viewOnly = FALSE;
+    cl->reverseConnection = FALSE;
+    cl->readyForSetColourMapEntries = FALSE;
+    cl->useCopyRect = FALSE;
+    cl->preferredEncoding = rfbEncodingRaw;
+    cl->correMaxWidth = 48;
+    cl->correMaxHeight = 48;
+    cl->pScreen = pScreen;
+
+    REGION_NULL(pScreen,&cl->copyRegion);
+    cl->copyDX = 0;
+    cl->copyDY = 0;
+
+    box.x1 = box.y1 = 0;
+    box.x2 = pVNC->width;
+    box.y2 = pVNC->height;
+    REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
+
+    REGION_NULL(pScreen,&cl->requestedRegion);
+
+    cl->deferredUpdateScheduled = FALSE;
+    cl->deferredUpdateTimer = NULL;
+
+    cl->format = pVNC->rfbServerFormat;
+    cl->translateFn = rfbTranslateNone;
+    cl->translateLookupTable = NULL;
+
+    cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+    cl->tightQualityLevel = -1;
+    for (i = 0; i < 4; i++)
+        cl->zsActive[i] = FALSE;
+
+    cl->enableCursorShapeUpdates = FALSE;
+    cl->enableCursorPosUpdates = FALSE;
+    cl->enableLastRectEncoding = FALSE;
+#ifdef CHROMIUM
+    cl->enableChromiumEncoding = FALSE;
+#endif
+
+    cl->next = rfbClientHead;
+    rfbClientHead = cl;
+
+    rfbResetStats(cl);
+
+    cl->compStreamInited = FALSE;
+    cl->compStream.total_in = 0;
+    cl->compStream.total_out = 0;
+    cl->compStream.zalloc = Z_NULL;
+    cl->compStream.zfree = Z_NULL;
+    cl->compStream.opaque = Z_NULL;
+
+    cl->zlibCompressLevel = 5;
+
+    sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
+	    rfbProtocolMinorVersion);
+
+    if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) {
+	rfbLogPerror("rfbNewClient: write");
+	rfbCloseSock(pScreen, sock);
+	return NULL;
+    }
+
+    return cl;
+}
+
+
+/*
+ * rfbClientConnectionGone is called from sockets.c just after a connection
+ * has gone away.
+ */
+
+void
+rfbClientConnectionGone(sock)
+    int sock;
+{
+    rfbClientPtr cl, prev;
+    int i;
+#if XFREE86VNC
+    int allowvt = TRUE;
+#endif
+
+    for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) {
+	if (sock == cl->sock)
+	    break;
+    }
+
+    if (!cl) {
+	rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock);
+	return;
+    }
+
+    if (cl->login != NULL) {
+	rfbLog("Client %s (%s) gone\n", cl->login, cl->host);
+	free(cl->login);
+    } else {
+	rfbLog("Client %s gone\n", cl->host);
+    }
+    free(cl->host);
+
+    /* Release the compression state structures if any. */
+    if ( cl->compStreamInited == TRUE ) {
+	deflateEnd( &(cl->compStream) );
+    }
+
+    for (i = 0; i < 4; i++) {
+	if (cl->zsActive[i])
+	    deflateEnd(&cl->zsStruct[i]);
+    }
+
+    if (pointerClient == cl)
+	pointerClient = NULL;
+
+#ifdef CORBA
+    destroyConnection(cl);
+#endif
+
+    if (prev)
+	prev->next = cl->next;
+    else
+	rfbClientHead = cl->next;
+
+    REGION_UNINIT(cl->pScreen,&cl->copyRegion);
+    REGION_UNINIT(cl->pScreen,&cl->modifiedRegion);
+    TimerFree(cl->deferredUpdateTimer);
+
+    rfbPrintStats(cl);
+
+    if (cl->translateLookupTable) free(cl->translateLookupTable);
+
+    xfree(cl);
+
+#if 0
+    GenerateVncDisconnectedEvent(sock);
+#endif
+
+#if XFREE86VNC
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	/* still someone connected */
+	allowvt = FALSE;
+    }
+
+    xf86EnableVTSwitch(allowvt);
+#endif
+}
+
+
+/*
+ * rfbProcessClientMessage is called when there is data to read from a client.
+ */
+
+void
+rfbProcessClientMessage(ScreenPtr pScreen, int sock)
+{
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (sock == cl->sock)
+	    break;
+    }
+
+    if (!cl) {
+	rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock);
+	rfbCloseSock(pScreen, sock);
+	return;
+    }
+
+#ifdef CORBA
+    if (isClosePending(cl)) {
+	rfbLog("Closing connection to client %s\n", cl->host);
+	rfbCloseSock(pScreen, sock);
+	return;
+    }
+#endif
+
+    switch (cl->state) {
+    case RFB_PROTOCOL_VERSION:
+	rfbProcessClientProtocolVersion(cl);
+	break;
+    case RFB_SECURITY_TYPE:	/* protocol 3.7 */
+	rfbProcessClientSecurityType(cl);
+	break;
+    case RFB_TUNNELING_TYPE:	/* protocol 3.7t */
+	rfbProcessClientTunnelingType(cl);
+	break;
+    case RFB_AUTH_TYPE:		/* protocol 3.7t */
+	rfbProcessClientAuthType(cl);
+	break;
+    case RFB_AUTHENTICATION:
+	rfbVncAuthProcessResponse(cl);
+	break;
+    case RFB_INITIALISATION:
+	rfbProcessClientInitMessage(cl);
+	break;
+    default:
+	rfbProcessClientNormalMessage(cl);
+    }
+}
+
+
+/*
+ * rfbProcessClientProtocolVersion is called when the client sends its
+ * protocol version.
+ */
+
+static void
+rfbProcessClientProtocolVersion(cl)
+    rfbClientPtr cl;
+{
+    rfbProtocolVersionMsg pv;
+    int n, major, minor;
+
+    if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientProtocolVersion: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientProtocolVersion: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    pv[sz_rfbProtocolVersionMsg] = 0;
+    if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
+	rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    rfbLog("Using protocol version %d.%d\n", major, minor);
+
+    if (major != rfbProtocolMajorVersion) {
+	rfbLog("RFB protocol version mismatch - server %d.%d, client %d.%d\n",
+		rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Always use one of the two standard versions of the RFB protocol. */
+    cl->protocol_minor_ver = minor;
+    if (minor > rfbProtocolMinorVersion) {
+	cl->protocol_minor_ver = rfbProtocolMinorVersion;
+    } else if (minor < rfbProtocolMinorVersion) {
+	cl->protocol_minor_ver = rfbProtocolFallbackMinorVersion;
+    }
+    if (minor != rfbProtocolMinorVersion &&
+	minor != rfbProtocolFallbackMinorVersion) {
+	rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n",
+	       major, minor, rfbProtocolMajorVersion, cl->protocol_minor_ver);
+    }
+ 
+    /* TightVNC protocol extensions are not enabled yet. */
+    cl->protocol_tightvnc = FALSE;
+
+    rfbAuthNewClient(cl);
+}
+
+/*
+ * rfbClientConnFailed is called when a client connection has failed
+ * before the authentication stage.
+ */
+
+void
+rfbClientConnFailed(cl, reason)
+    rfbClientPtr cl;
+    char *reason;
+{
+    int headerLen, reasonLen;
+    char buf[8];
+
+    headerLen = (cl->protocol_minor_ver >= 7) ? 1 : 4;
+    reasonLen = strlen(reason);
+    ((CARD32 *)buf)[0] = 0;
+    ((CARD32 *)buf)[1] = Swap32IfLE(reasonLen);
+
+    if ( WriteExact(cl->sock, buf, headerLen) < 0 ||
+	 WriteExact(cl->sock, buf + 4, 4) < 0 ||
+	 WriteExact(cl->sock, reason, reasonLen) < 0 ) {
+	rfbLogPerror("rfbClientConnFailed: write");
+    }
+
+    rfbCloseSock(cl->pScreen, cl->sock);
+}
+
+
+/*
+ * rfbProcessClientInitMessage is called when the client sends its
+ * initialisation message.
+ */
+
+static void
+rfbProcessClientInitMessage(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbClientInitMsg ci;
+    char buf[256];
+    rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
+    struct passwd *user;
+    int len, n;
+    rfbClientPtr otherCl, nextCl;
+
+    if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientInitMessage: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientInitMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    si->framebufferWidth = Swap16IfLE(pVNC->width);
+    si->framebufferHeight = Swap16IfLE(pVNC->height);
+    si->format = pVNC->rfbServerFormat;
+    si->format.redMax = Swap16IfLE(si->format.redMax);
+    si->format.greenMax = Swap16IfLE(si->format.greenMax);
+    si->format.blueMax = Swap16IfLE(si->format.blueMax);
+
+    user = getpwuid(getuid());
+
+    if (strlen(desktopName) > 128)	/* sanity check on desktop name len */
+	desktopName[128] = 0;
+
+    if (user) {
+	sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)",
+		user->pw_name, desktopName, rfbThisHost, display);
+    } else {
+	sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)",
+		desktopName, rfbThisHost, display);
+    }
+    len = strlen(buf + sz_rfbServerInitMsg);
+    si->nameLength = Swap32IfLE(len);
+
+    if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) {
+	rfbLogPerror("rfbProcessClientInitMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    if (cl->protocol_tightvnc)
+	rfbSendInteractionCaps(cl); /* protocol 3.7t */
+
+    /* Dispatch client input to rfbProcessClientNormalMessage(). */
+    cl->state = RFB_NORMAL;
+
+    if (!cl->reverseConnection &&
+	(pVNC->rfbNeverShared || (!pVNC->rfbAlwaysShared && !ci.shared))) {
+
+	if (pVNC->rfbDontDisconnect) {
+	    for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) {
+		if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+		    rfbLog("-dontdisconnect: Not shared & existing client\n");
+		    rfbLog("  refusing new client %s\n", cl->host);
+		    rfbCloseSock(cl->pScreen, cl->sock);
+		    return;
+		}
+	    }
+	} else {
+	    for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) {
+		nextCl = otherCl->next;
+		if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+		    rfbLog("Not shared - closing connection to client %s\n",
+			   otherCl->host);
+		    rfbCloseSock(otherCl->pScreen, otherCl->sock);
+		}
+	    }
+	}
+    }
+}
+
+
+/*
+ * rfbSendInteractionCaps is called after sending the server
+ * initialisation message, only if the protocol version is 3.130.
+ * In this function, we send the lists of supported protocol messages
+ * and encodings.
+ */
+
+/* Update these constants on changing capability lists below! */
+#define N_SMSG_CAPS  0
+#define N_CMSG_CAPS  0
+#define N_ENC_CAPS  12
+
+void
+rfbSendInteractionCaps(cl)
+    rfbClientPtr cl;
+{
+    rfbInteractionCapsMsg intr_caps;
+    rfbCapabilityInfo enc_list[N_ENC_CAPS];
+    int i;
+
+    /* Fill in the header structure sent prior to capability lists. */
+    intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
+    intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
+    intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
+    intr_caps.pad = 0;
+
+    /* Supported server->client message types. */
+    /* For future file transfer support:
+    i = 0;
+    SetCapInfo(&smsg_list[i++], rfbFileListData,           rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileDownloadData,       rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileUploadCancel,       rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed,     rfbTightVncVendor);
+    if (i != N_SMSG_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    */
+
+    /* Supported client->server message types. */
+    /* For future file transfer support:
+    i = 0;
+    SetCapInfo(&cmsg_list[i++], rfbFileListRequest,        rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest,    rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest,      rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadData,         rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel,     rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed,       rfbTightVncVendor);
+    if (i != N_CMSG_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    */
+
+    /* Encoding types. */
+    i = 0;
+    SetCapInfo(&enc_list[i++],  rfbEncodingCopyRect,       rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingRRE,            rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingCoRRE,          rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingHextile,        rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingZlib,           rfbTridiaVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingTight,          rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingCompressLevel0, rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingQualityLevel0,  rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingXCursor,        rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingRichCursor,     rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingPointerPos,     rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingLastRect,       rfbTightVncVendor);
+    if (i != N_ENC_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Send header and capability lists */
+    if (WriteExact(cl->sock, (char *)&intr_caps,
+		   sz_rfbInteractionCapsMsg) < 0 ||
+	WriteExact(cl->sock, (char *)&enc_list[0],
+		   sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
+	rfbLogPerror("rfbSendInteractionCaps: write");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientNormalMessage(). */
+    cl->state = RFB_NORMAL;
+}
+
+
+/*
+ * rfbProcessClientNormalMessage is called when the client has sent a normal
+ * protocol message.
+ */
+
+static void
+rfbProcessClientNormalMessage(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int n;
+    rfbClientToServerMsg msg;
+    char *str;
+
+#if 0
+    if (pVNC->rfbUserAccept) {
+	/* 
+	 * We've asked for another level of user authentication
+	 * If the user has not validated this connected, don't
+	 * process it.
+	 */
+	/*
+ 	 * NOTE: we do it here, so the vncviewer knows it's
+	 * connected, but waiting for the first screen update
+	 */
+	if (cl->userAccepted == VNC_USER_UNDEFINED)
+	    return;
+	if (cl->userAccepted == VNC_USER_DISCONNECT) {
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+    }
+#endif
+
+    if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) {
+	if (n != 0)
+	    rfbLogPerror("rfbProcessClientNormalMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    switch (msg.type) {
+
+    case rfbSetPixelFormat:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbSetPixelFormatMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
+	cl->format.depth = msg.spf.format.depth;
+	cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0);
+	cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0);
+	cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
+	cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
+	cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
+	cl->format.redShift = msg.spf.format.redShift;
+	cl->format.greenShift = msg.spf.format.greenShift;
+	cl->format.blueShift = msg.spf.format.blueShift;
+
+	cl->readyForSetColourMapEntries = TRUE;
+
+	rfbSetTranslateFunction(cl);
+	return;
+
+
+    case rfbFixColourMapEntries:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+	rfbLog("rfbProcessClientNormalMessage: %s",
+		"FixColourMapEntries unsupported\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+
+
+    case rfbSetEncodings:
+    {
+	int i;
+	CARD32 enc;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbSetEncodingsMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
+
+	cl->preferredEncoding = -1;
+	cl->useCopyRect = FALSE;
+	cl->enableCursorShapeUpdates = FALSE;
+	cl->enableCursorPosUpdates = FALSE;
+	cl->enableLastRectEncoding = FALSE;
+#ifdef CHROMIUM
+	cl->enableChromiumEncoding = FALSE;
+#endif
+	cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+	cl->tightQualityLevel = -1;
+
+	for (i = 0; i < msg.se.nEncodings; i++) {
+	    if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) {
+		if (n != 0)
+		    rfbLogPerror("rfbProcessClientNormalMessage: read");
+		rfbCloseSock(cl->pScreen, cl->sock);
+		return;
+	    }
+	    enc = Swap32IfLE(enc);
+
+	    switch (enc) {
+
+	    case rfbEncodingCopyRect:
+		cl->useCopyRect = TRUE;
+		rfbLog("Using copyrect encoding for client %s\n",
+			   cl->host);
+		break;
+	    case rfbEncodingRaw:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using raw encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingRRE:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using rre encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingCoRRE:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using CoRRE encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingHextile:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using hextile encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingZlib:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using zlib encoding for client %s\n",
+			   cl->host);
+		}
+              break;
+	    case rfbEncodingTight:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using tight encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingXCursor:
+		rfbLog("Enabling X-style cursor updates for client %s\n",
+		       cl->host);
+		cl->enableCursorShapeUpdates = TRUE;
+		cl->useRichCursorEncoding = FALSE;
+		cl->cursorWasChanged = TRUE;
+		break;
+	    case rfbEncodingRichCursor:
+		if (!cl->enableCursorShapeUpdates) {
+		    rfbLog("Enabling full-color cursor updates for client "
+			   "%s\n", cl->host);
+		    cl->enableCursorShapeUpdates = TRUE;
+		    cl->useRichCursorEncoding = TRUE;
+		    cl->cursorWasChanged = TRUE;
+		}
+		break;
+	    case rfbEncodingPointerPos:
+		if (!cl->enableCursorPosUpdates) {
+		    rfbLog("Enabling cursor position updates for client %s\n",
+			   cl->host);
+		    cl->enableCursorPosUpdates = TRUE;
+		    cl->cursorWasMoved = TRUE;
+		    cl->cursorX = -1;
+		    cl->cursorY = -1;
+		}
+	        break;
+	    case rfbEncodingLastRect:
+		if (!cl->enableLastRectEncoding) {
+		    rfbLog("Enabling LastRect protocol extension for client "
+			   "%s\n", cl->host);
+		    cl->enableLastRectEncoding = TRUE;
+		}
+		break;
+#ifdef CHROMIUM
+	    case rfbEncodingChromium:
+		if (!cl->enableChromiumEncoding) {
+    		    WindowPtr	pWin = WindowTable[cl->pScreen->myNum];
+		    rfbLog("Enabling Chromium protocol extension for client "
+			   "%s\n", cl->host);
+		    cl->enableChromiumEncoding = TRUE;
+		    /* Now generate an event, so we can start our GL app */
+    		    GenerateVncChromiumConnectedEvent(cl->sock);
+		    /* Generate exposures for all windows */
+		    rfbSetClip(pWin, 1);
+		}
+		break;
+#endif
+	    default:
+		if ( enc >= (CARD32)rfbEncodingCompressLevel0 &&
+		     enc <= (CARD32)rfbEncodingCompressLevel9 ) {
+		    cl->zlibCompressLevel = enc & 0x0F;
+		    cl->tightCompressLevel = enc & 0x0F;
+		    rfbLog("Using compression level %d for client %s\n",
+			   cl->tightCompressLevel, cl->host);
+		} else if ( enc >= (CARD32)rfbEncodingQualityLevel0 &&
+			    enc <= (CARD32)rfbEncodingQualityLevel9 ) {
+		    cl->tightQualityLevel = enc & 0x0F;
+		    rfbLog("Using image quality level %d for client %s\n",
+			   cl->tightQualityLevel, cl->host);
+		} else {
+		    rfbLog("rfbProcessClientNormalMessage: ignoring unknown "
+			   "encoding 0x%x\n", (int)enc);
+		}
+	    }
+	}
+
+	if (cl->preferredEncoding == -1) {
+	    cl->preferredEncoding = rfbEncodingRaw;
+ 	    rfbLog("No encoding specified - using raw encoding for client %s\n",
+			   cl->host);
+	}
+
+	if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
+	    rfbLog("Disabling cursor position updates for client %s\n",
+		   cl->host);
+	    cl->enableCursorPosUpdates = FALSE;
+	}
+
+#if XFREE86VNC
+	/*
+	 * With XFree86 and the hardware cursor's we need to put up the
+	 * cursor again, and if we've detected a cursor shapeless client
+	 * we need to disable hardware cursors.
+	 */
+	if (!cl->enableCursorShapeUpdates)
+	    pVNC->SWCursor = (Bool *)TRUE;
+	else
+	    pVNC->SWCursor = (Bool *)FALSE;
+
+	{
+		int x, y;
+		miPointerPosition(&x, &y);
+		(*pVNC->spriteFuncs->SetCursor)(cl->pScreen, pVNC->pCurs, x, y);
+	}
+#endif
+
+	return;
+    }
+
+
+    case rfbFramebufferUpdateRequest:
+    {
+	RegionRec tmpRegion;
+	BoxRec box;
+
+#ifdef CORBA
+	addCapability(cl, DISPLAY_DEVICE);
+#endif
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	box.x1 = Swap16IfLE(msg.fur.x);
+	box.y1 = Swap16IfLE(msg.fur.y);
+	box.x2 = box.x1 + Swap16IfLE(msg.fur.w);
+	box.y2 = box.y1 + Swap16IfLE(msg.fur.h);
+	SAFE_REGION_INIT(cl->pScreen,&tmpRegion,&box,0);
+
+	REGION_UNION(cl->pScreen, &cl->requestedRegion, &cl->requestedRegion,
+		     &tmpRegion);
+
+	if (!cl->readyForSetColourMapEntries) {
+	    /* client hasn't sent a SetPixelFormat so is using server's */
+	    cl->readyForSetColourMapEntries = TRUE;
+	    if (!cl->format.trueColour) {
+		if (!rfbSetClientColourMap(cl, 0, 0)) {
+		    REGION_UNINIT(cl->pScreen,&tmpRegion);
+		    return;
+		}
+	    }
+	}
+
+	if (!msg.fur.incremental) {
+	    REGION_UNION(cl->pScreen,&cl->modifiedRegion,&cl->modifiedRegion,
+			 &tmpRegion);
+	    REGION_SUBTRACT(cl->pScreen,&cl->copyRegion,&cl->copyRegion,
+			    &tmpRegion);
+	}
+
+	if (FB_UPDATE_PENDING(cl)) {
+	    rfbSendFramebufferUpdate(cl->pScreen, cl);
+	}
+
+	REGION_UNINIT(cl->pScreen,&tmpRegion);
+	return;
+    }
+
+    case rfbKeyEvent:
+
+	cl->rfbKeyEventsRcvd++;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbKeyEventMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+#ifdef CORBA
+	addCapability(cl, KEYBOARD_DEVICE);
+
+	if (!isKeyboardEnabled(cl))
+	    return;
+#endif
+	if (!pVNC->rfbViewOnly && !cl->viewOnly) {
+	    KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl);
+	}
+	return;
+
+
+    case rfbPointerEvent:
+
+	cl->rfbPointerEventsRcvd++;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbPointerEventMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+#ifdef CORBA
+	addCapability(cl, POINTER_DEVICE);
+
+	if (!isPointerEnabled(cl))
+	    return;
+#endif
+
+	if (pointerClient && (pointerClient != cl))
+	    return;
+
+	if (msg.pe.buttonMask == 0)
+	    pointerClient = NULL;
+	else
+	    pointerClient = cl;
+
+	if (!pVNC->rfbViewOnly && !cl->viewOnly) {
+	    cl->cursorX = (int)Swap16IfLE(msg.pe.x);
+            cl->cursorY = (int)Swap16IfLE(msg.pe.y);
+	    PtrAddEvent(msg.pe.buttonMask, cl->cursorX, cl->cursorY, cl);
+	}
+	return;
+
+
+    case rfbClientCutText:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbClientCutTextMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	msg.cct.length = Swap32IfLE(msg.cct.length);
+
+	str = (char *)xalloc(msg.cct.length);
+
+	if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    xfree(str);
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* NOTE: We do not accept cut text from a view-only client */
+	if (!cl->viewOnly)
+	    rfbSetXCutText(str, msg.cct.length);
+
+	xfree(str);
+	return;
+
+#ifdef CHROMIUM
+    case rfbChromiumStop:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbChromiumStopMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* would we use msg.csd.port ??? */
+
+	cl->chromium_port = 0;
+
+	/* tear down window information */
+    	{
+	    CRWindowTable *wt, *nextWt = NULL;
+
+   	    for (wt = windowTable; wt; wt = nextWt) {
+   	 	nextWt = wt->next;
+		xfree(wt);
+	    }
+
+	    windowTable = NULL;
+	}
+
+	return;
+
+    case rfbChromiumExpose:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbChromiumExposeMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* find the window and re-expose it */
+    	{
+	    CRWindowTable *wt, *nextWt = NULL;
+
+   	    for (wt = windowTable; wt; wt = nextWt) {
+   	 	nextWt = wt->next;
+		if (wt->CRwinId == msg.cse.winid) {
+			WindowPtr pWin;
+	    		pWin = LookupIDByType(wt->XwinId, RT_WINDOW);
+			if (pWin) {
+				miSendExposures(pWin, &pWin->clipList,
+						pWin->drawable.x,
+						pWin->drawable.y);
+				FlushAllOutput();
+			}
+		}
+	    }
+	}
+
+	return;
+#endif
+
+    default:
+
+	rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
+		msg.type);
+	rfbLog(" ... closing connection\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+}
+
+
+
+/*
+ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
+ * the RFB client.
+ */
+
+Bool
+rfbSendFramebufferUpdate(pScreen, cl)
+    ScreenPtr pScreen;
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(pScreen);
+    int i;
+    int nUpdateRegionRects;
+    rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)pVNC->updateBuf;
+    RegionRec updateRegion, updateCopyRegion;
+    int dx, dy;
+    Bool sendCursorShape = FALSE;
+    Bool sendCursorPos = FALSE;
+
+    /*
+     * If this client understands cursor shape updates, cursor should be
+     * removed from the framebuffer. Otherwise, make sure it's put up.
+     */
+
+#if XFREE86VNC
+    if (cl->enableCursorShapeUpdates) {
+	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor(pScreen);
+	if (!pVNC->cursorIsDrawn && cl->cursorWasChanged)
+	    sendCursorShape = TRUE;
+    } else {
+	if (!pVNC->cursorIsDrawn)
+	    rfbSpriteRestoreCursor(pScreen);
+    }
+#else
+    if (cl->enableCursorShapeUpdates)
+	if (cl->cursorWasChanged) 
+	    sendCursorShape = TRUE;
+#endif
+
+    /*
+     * Do we plan to send cursor position update?
+     */
+
+    if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
+	sendCursorPos = TRUE;
+
+    /*
+     * The modifiedRegion may overlap the destination copyRegion.  We remove
+     * any overlapping bits from the copyRegion (since they'd only be
+     * overwritten anyway).
+     */
+
+    REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
+		    &cl->modifiedRegion);
+
+    /*
+     * The client is interested in the region requestedRegion.  The region
+     * which should be updated now is the intersection of requestedRegion
+     * and the union of modifiedRegion and copyRegion.  If it's empty then
+     * no update is needed.
+     */
+
+    REGION_NULL(pScreen,&updateRegion);
+    REGION_UNION(pScreen, &updateRegion, &cl->copyRegion,
+		 &cl->modifiedRegion);
+    REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion,
+		     &updateRegion);
+
+    if ( !REGION_NOTEMPTY(pScreen,&updateRegion) &&
+	 !sendCursorShape && !sendCursorPos ) {
+	REGION_UNINIT(pScreen,&updateRegion);
+	return TRUE;
+    }
+
+    /*
+     * We assume that the client doesn't have any pixel data outside the
+     * requestedRegion.  In other words, both the source and destination of a
+     * copy must lie within requestedRegion.  So the region we can send as a
+     * copy is the intersection of the copyRegion with both the requestedRegion
+     * and the requestedRegion translated by the amount of the copy.  We set
+     * updateCopyRegion to this.
+     */
+
+    REGION_NULL(pScreen,&updateCopyRegion);
+    REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion,
+		     &cl->requestedRegion);
+    REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY);
+    REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion,
+		     &cl->requestedRegion);
+    dx = cl->copyDX;
+    dy = cl->copyDY;
+
+    /*
+     * Next we remove updateCopyRegion from updateRegion so that updateRegion
+     * is the part of this update which is sent as ordinary pixel data (i.e not
+     * a copy).
+     */
+
+    REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion);
+
+    /*
+     * Finally we leave modifiedRegion to be the remainder (if any) of parts of
+     * the screen which are modified but outside the requestedRegion.  We also
+     * empty both the requestedRegion and the copyRegion - note that we never
+     * carry over a copyRegion for a future update.
+     */
+
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		 &cl->copyRegion);
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &updateRegion);
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &updateCopyRegion);
+
+    REGION_EMPTY(pScreen, &cl->requestedRegion);
+    REGION_EMPTY(pScreen, &cl->copyRegion);
+    cl->copyDX = 0;
+    cl->copyDY = 0;
+
+    /*
+     * Now send the update.
+     */
+
+    cl->rfbFramebufferUpdateMessagesSent++;
+
+    if (cl->preferredEncoding == rfbEncodingCoRRE) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1)
+				     * ((h-1) / cl->correMaxHeight + 1));
+	}
+    } else if (cl->preferredEncoding == rfbEncodingZlib) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
+	}
+    } else if (cl->preferredEncoding == rfbEncodingTight) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    int n = rfbNumCodedRectsTight(cl, x, y, w, h);
+	    if (n == 0) {
+		nUpdateRegionRects = 0xFFFF;
+		break;
+	    }
+	    nUpdateRegionRects += n;
+	}
+    } else {
+	nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion);
+    }
+
+    fu->type = rfbFramebufferUpdate;
+    if (nUpdateRegionRects != 0xFFFF) {
+	fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) +
+				nUpdateRegionRects +
+				!!sendCursorShape + !!sendCursorPos);
+    } else {
+	fu->nRects = 0xFFFF;
+    }
+    pVNC->ublen = sz_rfbFramebufferUpdateMsg;
+
+    if (sendCursorShape) {
+	cl->cursorWasChanged = FALSE;
+	if (!rfbSendCursorShape(cl, pScreen))
+	    return FALSE;
+    }
+
+    if (sendCursorPos) {
+	cl->cursorWasMoved = FALSE;
+	if (!rfbSendCursorPos(cl, pScreen))
+ 	    return FALSE;
+    }
+
+    if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) {
+	if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) {
+	    REGION_UNINIT(pScreen,&updateRegion);
+	    REGION_UNINIT(pScreen,&updateCopyRegion);
+	    return FALSE;
+	}
+    }
+
+    REGION_UNINIT(pScreen,&updateCopyRegion);
+
+    for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	int x = REGION_RECTS(&updateRegion)[i].x1;
+	int y = REGION_RECTS(&updateRegion)[i].y1;
+	int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+
+	cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
+				      + w * (cl->format.bitsPerPixel / 8) * h);
+
+	switch (cl->preferredEncoding) {
+	case rfbEncodingRaw:
+	    if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingRRE:
+	    if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingCoRRE:
+	    if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingHextile:
+	    if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingZlib:
+	    if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingTight:
+	    if (!rfbSendRectEncodingTight(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	}
+    }
+
+    REGION_UNINIT(pScreen,&updateRegion);
+
+    if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl))
+	return FALSE;
+
+    if (!rfbSendUpdateBuf(cl))
+	return FALSE;
+
+    return TRUE;
+}
+
+
+
+/*
+ * Send the copy region as a string of CopyRect encoded rectangles.
+ * The only slightly tricky thing is that we should send the messages in
+ * the correct order so that an earlier CopyRect will not corrupt the source
+ * of a later one.
+ */
+
+static Bool
+rfbSendCopyRegion(cl, reg, dx, dy)
+    rfbClientPtr cl;
+    RegionPtr reg;
+    int dx, dy;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand;
+    int x, y, w, h;
+    rfbFramebufferUpdateRectHeader rect;
+    rfbCopyRect cr;
+
+    nrects = REGION_NUM_RECTS(reg);
+
+    if (dx <= 0) {
+	x_inc = 1;
+    } else {
+	x_inc = -1;
+    }
+
+    if (dy <= 0) {
+	thisRect = 0;
+	y_inc = 1;
+    } else {
+	thisRect = nrects - 1;
+	y_inc = -1;
+    }
+
+    while (nrects > 0) {
+
+	firstInNextBand = thisRect;
+	nrectsInBand = 0;
+
+	while ((nrects > 0) &&
+	       (REGION_RECTS(reg)[firstInNextBand].y1
+		== REGION_RECTS(reg)[thisRect].y1))
+	{
+	    firstInNextBand += y_inc;
+	    nrects--;
+	    nrectsInBand++;
+	}
+
+	if (x_inc != y_inc) {
+	    thisRect = firstInNextBand - y_inc;
+	}
+
+	while (nrectsInBand > 0) {
+	    if ((pVNC->ublen + sz_rfbFramebufferUpdateRectHeader
+		 + sz_rfbCopyRect) > UPDATE_BUF_SIZE)
+	    {
+		if (!rfbSendUpdateBuf(cl))
+		    return FALSE;
+	    }
+
+	    x = REGION_RECTS(reg)[thisRect].x1;
+	    y = REGION_RECTS(reg)[thisRect].y1;
+	    w = REGION_RECTS(reg)[thisRect].x2 - x;
+	    h = REGION_RECTS(reg)[thisRect].y2 - y;
+
+	    rect.r.x = Swap16IfLE(x);
+	    rect.r.y = Swap16IfLE(y);
+	    rect.r.w = Swap16IfLE(w);
+	    rect.r.h = Swap16IfLE(h);
+	    rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
+
+	    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+		   sz_rfbFramebufferUpdateRectHeader);
+	    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+	    cr.srcX = Swap16IfLE(x - dx);
+	    cr.srcY = Swap16IfLE(y - dy);
+
+	    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&cr, sz_rfbCopyRect);
+	    pVNC->ublen += sz_rfbCopyRect;
+
+	    cl->rfbRectanglesSent[rfbEncodingCopyRect]++;
+	    cl->rfbBytesSent[rfbEncodingCopyRect]
+		+= sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
+
+	    thisRect += x_inc;
+	    nrectsInBand--;
+	}
+
+	thisRect = firstInNextBand;
+    }
+
+    return TRUE;
+}
+
+
+/*
+ * Send a given rectangle in raw encoding (rfbEncodingRaw).
+ */
+
+Bool
+rfbSendRectEncodingRaw(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    int nlines;
+    int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
+    unsigned char *fbptr = NULL;
+    int newy = 0;
+
+    if (pVNC->useGetImage) {
+	newy = y;
+    } else {
+    	fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+    }
+
+    /* Flush the buffer to guarantee correct alignment for translateFn(). */
+    if (pVNC->ublen > 0) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingRaw);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingRaw]++;
+    cl->rfbBytesSent[rfbEncodingRaw]
+	+= sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
+
+    nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine;
+
+    while (TRUE) {
+	if (nlines > h)
+	    nlines = h;
+
+    	if (pVNC->useGetImage) {
+    	    (*cl->pScreen->GetImage)((DrawablePtr)WindowTable[cl->pScreen->myNum], x, newy, w, nlines, ZPixmap, ~0, &pVNC->updateBuf[pVNC->ublen]);
+	    newy += nlines;
+    	} else {
+	    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+			   &cl->format, fbptr, &pVNC->updateBuf[pVNC->ublen],
+			   pVNC->paddedWidthInBytes, w, nlines, x, y);
+    	}
+
+	pVNC->ublen += nlines * bytesPerLine;
+	h -= nlines;
+
+	if (h == 0)	/* rect fitted in buffer, do next one */
+	    return TRUE;
+
+	/* buffer full - flush partial rect and do another nlines */
+
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+
+	if (!pVNC->useGetImage)
+	    fbptr += (pVNC->paddedWidthInBytes * nlines);
+
+	nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine;
+	if (nlines == 0) {
+	    rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d "
+		   "bytes per line\n", bytesPerLine);
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return FALSE;
+	}
+    }
+}
+
+
+/*
+ * Send an empty rectangle with encoding field set to value of
+ * rfbEncodingLastRect to notify client that this is the last
+ * rectangle in framebuffer update ("LastRect" extension of RFB
+ * protocol).
+ */
+
+static Bool
+rfbSendLastRectMarker(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.encoding = Swap32IfLE(rfbEncodingLastRect);
+    rect.r.x = 0;
+    rect.r.y = 0;
+    rect.r.w = 0;
+    rect.r.h = 0;
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbLastRectMarkersSent++;
+    cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+
+    return TRUE;
+}
+
+
+/*
+ * Send the contents of pVNC->updateBuf.  Returns 1 if successful, -1 if
+ * not (errno should be set).
+ */
+
+Bool
+rfbSendUpdateBuf(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+
+    /*
+    int i;
+    for (i = 0; i < pVNC->ublen; i++) {
+	rfbLog("%02x ",((unsigned char *)pVNC->updateBuf)[i]);
+    }
+    rfbLog("\n");
+    */
+
+    if (pVNC->ublen > 0 && WriteExact(cl->sock, pVNC->updateBuf, pVNC->ublen) < 0) {
+	rfbLogPerror("rfbSendUpdateBuf: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    pVNC->ublen = 0;
+    return TRUE;
+}
+
+
+
+/*
+ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
+ * client, using values from the currently installed colormap.
+ */
+
+Bool
+rfbSendSetColourMapEntries(cl, firstColour, nColours)
+    rfbClientPtr cl;
+    int firstColour;
+    int nColours;
+{
+#if !XFREE86VNC
+    VNCSCREENPTR(cl->pScreen);
+#endif
+    char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+    rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+    CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+    EntryPtr pent;
+    EntryPtr redEntry, greenEntry, blueEntry;
+    unsigned short redPart, greenPart, bluePart;
+    int i, len;
+
+    scme->type = rfbSetColourMapEntries;
+    scme->nColours = Swap16IfLE(nColours);
+
+    len = sz_rfbSetColourMapEntriesMsg;
+
+    /* PseudoColor */
+#if XFREE86VNC
+    if (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor) {
+#else
+    if (pVNC->rfbInstalledColormap->class == PseudoColor) {
+#endif
+      scme->firstColour = Swap16IfLE(firstColour);
+#if XFREE86VNC
+      pent = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[firstColour];
+#else
+      pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[firstColour];
+#endif
+      for (i = 0; i < nColours; i++) {
+  	  if (pent->fShared) {
+	      rgb[i*3] = Swap16IfLE(pent->co.shco.red->color);
+	      rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color);
+	      rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color);
+	  } else {
+	      rgb[i*3] = Swap16IfLE(pent->co.local.red);
+	      rgb[i*3+1] = Swap16IfLE(pent->co.local.green);
+	      rgb[i*3+2] = Swap16IfLE(pent->co.local.blue);
+	  }
+	  pent++;
+      }
+    }
+
+    else {
+
+      /* Break the DirectColor pixel into its r/g/b components */
+#if XFREE86VNC
+      redPart   = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->redMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetRed;
+      greenPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->greenMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetGreen;
+      bluePart  = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->blueMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetBlue;
+#else
+      redPart   = (firstColour & pVNC->rfbInstalledColormap->pVisual->redMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetRed;
+      greenPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->greenMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetGreen;
+      bluePart  = (firstColour & pVNC->rfbInstalledColormap->pVisual->blueMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetBlue;
+#endif
+
+      /*
+       * The firstColour field is only 16 bits. To support 24-bit pixels we
+       * sneak the red component in the 8-bit padding field which we renamed
+       * to redIndex. Green and blue are in firstColour (MSB, LSB respectively).
+       */
+      scme->redIndex    = Swap16IfLE(redPart);
+      scme->firstColour = Swap16IfLE((greenPart << 8) | bluePart);
+
+#if XFREE86VNC
+      redEntry   = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[redPart];
+      greenEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->green[greenPart];
+      blueEntry  = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->blue[bluePart];
+#else
+      redEntry   = (EntryPtr)&pVNC->rfbInstalledColormap->red[redPart];
+      greenEntry = (EntryPtr)&pVNC->rfbInstalledColormap->green[greenPart];
+      blueEntry  = (EntryPtr)&pVNC->rfbInstalledColormap->blue[bluePart];
+#endif
+      for (i = 0; i < nColours; i++) {
+	  if (redEntry->fShared)
+	      rgb[i*3] = Swap16IfLE(redEntry->co.shco.red->color);
+	  else
+	      rgb[i*3] = Swap16IfLE(redEntry->co.local.red);
+
+	  if (greenEntry->fShared)
+	      rgb[i*3+1] = Swap16IfLE(greenEntry->co.shco.green->color);
+	  else
+	      rgb[i*3+1] = Swap16IfLE(greenEntry->co.local.green);
+
+	  if (blueEntry->fShared)
+	      rgb[i*3+2] = Swap16IfLE(blueEntry->co.shco.blue->color);
+	  else
+	      rgb[i*3+2] = Swap16IfLE(blueEntry->co.local.blue);
+
+	  redEntry++;
+	  greenEntry++;
+	  blueEntry++;
+      }
+    }
+
+    len += nColours * 3 * 2;
+
+    if (WriteExact(cl->sock, buf, len) < 0) {
+	rfbLogPerror("rfbSendSetColourMapEntries: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+ * rfbSendBell sends a Bell message to all the clients.
+ */
+
+void
+rfbSendBell()
+{
+    rfbClientPtr cl, nextCl;
+    rfbBellMsg b;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	b.type = rfbBell;
+	if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) {
+	    rfbLogPerror("rfbSendBell: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	}
+    }
+}
+
+#ifdef CHROMIUM
+#ifdef sun
+extern int inet_aton(const char *cp, struct in_addr *inp);
+#endif
+
+/**
+ * Tell the VNC viewers to start a new crserver process.
+ */
+void
+rfbSendChromiumStart(unsigned int ipaddress, unsigned int port)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumStartMsg scd;
+    struct in_addr ip;
+    unsigned int vncipaddress;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	inet_aton(cl->host, &ip);
+	memcpy(&vncipaddress, &ip, sizeof(unsigned int));
+	if (ipaddress == vncipaddress && !cl->chromium_port) {
+	    cl->chromium_port = port;
+    	    scd.type = rfbChromiumStart;
+    	    scd.port = port;
+    	    if (WriteExact(cl->sock, (char *)&scd,
+		       sz_rfbChromiumStartMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumStart: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+    	    }
+	    /* We only start one client at at time, so break now! */
+	    break;
+	}
+    }
+}
+
+/**
+ * Begin tracking the size, position, visibility and cliprect info for the
+ * given Chromium/X window.
+ */
+void
+rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid)
+{
+    CRWindowTable *nextRec;
+    CRWindowTable *wt, *nextWt = NULL;
+
+    /* See if we're already managing this window */
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 /* and if so, update it's window ID */
+	 if (wt->CRwinId == cr_windowid) {
+		wt->XwinId = windowid;
+	 	return;
+	 }
+    }
+
+    /* o.k, new window so create new slot information */
+    nextRec = (CRWindowTable *)xalloc(sizeof(CRWindowTable));
+
+    if (!nextRec)
+    {
+	    rfbLog("OUCH, Chromium can't monitor window ID\n");
+    	    return;
+    }
+    
+    nextRec->next = NULL;
+    nextRec->CRwinId = cr_windowid;
+    nextRec->XwinId = windowid;
+    nextRec->clipRects = NULL;
+    nextRec->numRects = 0;
+
+    if (!windowTable)
+	    windowTable = nextRec;
+    else 
+    {
+    	    for (wt = windowTable; wt; wt = nextWt) {
+	   	 nextWt = wt->next;
+		 if (!wt->next) /* found the next slot */
+	    		wt->next = nextRec;
+	    }
+    }
+}
+
+/**
+ * Send new window position/size info to all VNC clients who want this info.
+ */
+void
+rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumMoveResizeWindowMsg scm;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    scm.type = rfbChromiumMoveResizeWindow;
+	    scm.winid = winid;
+	    scm.x = x;
+	    scm.y = y;
+	    scm.w = w;
+	    scm.h = h;
+    	    if (WriteExact(cl->sock, (char *)&scm,
+		       sz_rfbChromiumMoveResizeWindowMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumMoveResizeWindow: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	}
+    }
+}
+
+/**
+ * Send the new cliprect info for the given window to all VNC clients who
+ * want this info.
+ */
+void
+rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumClipListMsg sccl;
+    int len = sizeof(BoxRec) * numClipRects;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    sccl.type = rfbChromiumClipList;
+	    sccl.winid = winid;
+	    sccl.length = Swap32IfLE(len);
+    	    if (WriteExact(cl->sock, (char *)&sccl,
+		       sz_rfbChromiumClipListMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumClipList: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	    if (WriteExact(cl->sock, (char *)pClipRects, len) < 0) {
+	   	rfbLogPerror("rfbSendChromiumClipList: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+	    }
+	}
+    }
+}
+
+/**
+ * Tell VNC clients about the visibility status of given window.
+ */
+void
+rfbSendChromiumWindowShow(unsigned int winid, unsigned int show)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumWindowShowMsg scws;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    scws.type = rfbChromiumWindowShow;
+	    scws.winid = winid;
+	    scws.show = show;
+    	    if (WriteExact(cl->sock, (char *)&scws,
+		       sz_rfbChromiumWindowShowMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumWindowShow: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	}
+    }
+}
+#endif /* CHROMIUM */
+
+/*
+ * rfbSendServerCutText sends a ServerCutText message to all the clients.
+ */
+
+void
+rfbSendServerCutText(char *str, int len)
+{
+    rfbClientPtr cl, nextCl = NULL;
+    rfbServerCutTextMsg sct;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	if (cl->state != RFB_NORMAL) continue;
+	nextCl = cl->next;
+	sct.type = rfbServerCutText;
+	sct.length = Swap32IfLE(len);
+	if (WriteExact(cl->sock, (char *)&sct,
+		       sz_rfbServerCutTextMsg) < 0) {
+	    rfbLogPerror("rfbSendServerCutText: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    continue;
+	}
+	if (WriteExact(cl->sock, str, len) < 0) {
+	    rfbLogPerror("rfbSendServerCutText: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	}
+    }
+}
+
+
+
+
+/*****************************************************************************
+ *
+ * UDP can be used for keyboard and pointer events when the underlying
+ * network is highly reliable.  This is really here to support ORL's
+ * videotile, whose TCP implementation doesn't like sending lots of small
+ * packets (such as 100s of pen readings per second!).
+ */
+
+void
+rfbNewUDPConnection(sock)
+    int sock;
+{
+    if (write(sock, &ptrAcceleration, 1) < 0) {
+	rfbLogPerror("rfbNewUDPConnection: write");
+    }
+}
+
+/*
+ * Because UDP is a message based service, we can't read the first byte and
+ * then the rest of the packet separately like we do with TCP.  We will always
+ * get a whole packet delivered in one go, so we ask read() for the maximum
+ * number of bytes we can possibly get.
+ */
+
+void
+rfbProcessUDPInput(ScreenPtr pScreen, int sock)
+{
+    VNCSCREENPTR(pScreen);
+    int n;
+    rfbClientToServerMsg msg;
+
+    if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) {
+	if (n < 0) {
+	    rfbLogPerror("rfbProcessUDPInput: read");
+	}
+	rfbDisconnectUDPSock(pScreen);
+	return;
+    }
+
+    switch (msg.type) {
+
+    case rfbKeyEvent:
+	if (n != sz_rfbKeyEventMsg) {
+	    rfbLog("rfbProcessUDPInput: key event incorrect length\n");
+	    rfbDisconnectUDPSock(pScreen);
+	    return;
+	}
+	if (!pVNC->rfbViewOnly) {
+	    KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), 0);
+	}
+	break;
+
+    case rfbPointerEvent:
+	if (n != sz_rfbPointerEventMsg) {
+	    rfbLog("rfbProcessUDPInput: ptr event incorrect length\n");
+	    rfbDisconnectUDPSock(pScreen);
+	    return;
+	}
+	if (!pVNC->rfbViewOnly) {
+	    PtrAddEvent(msg.pe.buttonMask,
+			Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), 0);
+	}
+	break;
+
+    default:
+	rfbLog("rfbProcessUDPInput: unknown message type %d\n",
+	       msg.type);
+	rfbDisconnectUDPSock(pScreen);
+    }
+}
diff -u -rNp a/hw/dmx/vnc/rre.c b/hw/dmx/vnc/rre.c
--- a/hw/dmx/vnc/rre.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/rre.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,325 @@
+/*
+ * rre.c
+ *
+ * Routines to implement Rise-and-Run-length Encoding (RRE).  This
+ * code is based on krw's original javatel rfbserver.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rfb.h"
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version.  If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(CARD8 *data, int w, int h);
+static int subrectEncode16(CARD16 *data, int w, int h);
+static int subrectEncode32(CARD32 *data, int w, int h);
+static CARD32 getBgColour(char *data, int size, int bpp);
+
+
+/*
+ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
+ */
+
+Bool
+rfbSendRectEncodingRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbRREHeader hdr;
+    int nSubrects;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize = (pVNC->width * pVNC->height
+		      * (cl->format.bitsPerPixel / 8));
+
+    if (rreBeforeBufSize < maxRawSize) {
+	rreBeforeBufSize = maxRawSize;
+	if (rreBeforeBuf == NULL)
+	    rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
+	else
+	    rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+    }
+
+    if (rreAfterBufSize < maxRawSize) {
+	rreAfterBufSize = maxRawSize;
+	if (rreAfterBuf == NULL)
+	    rreAfterBuf = (char *)xalloc(rreAfterBufSize);
+	else
+	    rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+    }
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, rreBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
+	break;
+    case 16:
+	nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
+	break;
+    case 32:
+	nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
+	break;
+    default:
+	rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+	exit(1);
+    }
+	
+    if (nSubrects < 0) {
+
+	/* RRE encoding was too large, use raw */
+
+	return rfbSendRectEncodingRaw(cl, x, y, w, h);
+    }
+
+    cl->rfbRectanglesSent[rfbEncodingRRE]++;
+    cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader
+					 + sz_rfbRREHeader + rreAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingRRE);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nSubrects = Swap32IfLE(nSubrects);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader);
+    pVNC->ublen += sz_rfbRREHeader;
+
+    for (i = 0; i < rreAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > rreAfterBufLen) {
+	    bytesToCopy = rreAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background 
+ * colour overwritten by single-coloured rectangles.  It returns the number 
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive 
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp)					      \
+static int								      \
+subrectEncode##bpp(data,w,h)						      \
+    CARD##bpp *data;							      \
+    int w;								      \
+    int h;								      \
+{									      \
+    CARD##bpp cl;							      \
+    rfbRectangle subrect;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp);		      \
+									      \
+    *((CARD##bpp*)rreAfterBuf) = bg;					      \
+									      \
+    rreAfterBufLen = (bpp/8);						      \
+									      \
+    for (y=0; y<h; y++) {						      \
+      line = data+(y*w);						      \
+      for (x=0; x<w; x++) {						      \
+        if (line[x] != bg) {						      \
+          cl = line[x];							      \
+          hy = y-1;							      \
+          hyflag = 1;							      \
+          for (j=y; j<h; j++) {						      \
+            seg = data+(j*w);						      \
+            if (seg[x] != cl) {break;}					      \
+            i = x;							      \
+            while ((seg[i] == cl) && (i < w)) i += 1;			      \
+            i -= 1;							      \
+            if (j == y) vx = hx = i;					      \
+            if (i < vx) vx = i;						      \
+            if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      \
+          }								      \
+          vy = j-1;							      \
+									      \
+          /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  \
+           *  We'll choose the bigger of the two.			      \
+           */								      \
+          hw = hx-x+1;							      \
+          hh = hy-y+1;							      \
+          vw = vx-x+1;							      \
+          vh = vy-y+1;							      \
+									      \
+          thex = x;							      \
+          they = y;							      \
+									      \
+          if ((hw*hh) > (vw*vh)) {					      \
+            thew = hw;							      \
+            theh = hh;							      \
+          } else {							      \
+            thew = vw;							      \
+            theh = vh;							      \
+          }								      \
+									      \
+          subrect.x = Swap16IfLE(thex);					      \
+          subrect.y = Swap16IfLE(they);					      \
+          subrect.w = Swap16IfLE(thew);					      \
+          subrect.h = Swap16IfLE(theh);					      \
+									      \
+	  newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle;		      \
+          if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize))     \
+	    return -1;							      \
+									      \
+	  numsubs += 1;							      \
+	  *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl;		      \
+	  rreAfterBufLen += (bpp/8);					      \
+	  memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle);      \
+	  rreAfterBufLen += sz_rfbRectangle;				      \
+									      \
+          /*								      \
+           * Now mark the subrect as done.				      \
+           */								      \
+          for (j=they; j < (they+theh); j++) {				      \
+            for (i=thex; i < (thex+thew); i++) {			      \
+              data[j*w+i] = bg;						      \
+            }								      \
+          }								      \
+        }								      \
+      }									      \
+    }									      \
+									      \
+    return numsubs;							      \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static CARD32
+getBgColour(data,size,bpp)
+    char *data;
+    int size;
+    int bpp;
+{
+    
+#define NUMCLRS 256
+  
+  static int counts[NUMCLRS];
+  int i,j,k;
+
+  int maxcount = 0;
+  CARD8 maxclr = 0;
+
+  if (bpp != 8) {
+    if (bpp == 16) {
+      return ((CARD16 *)data)[0];
+    } else if (bpp == 32) {
+      return ((CARD32 *)data)[0];
+    } else {
+      rfbLog("getBgColour: bpp %d?\n",bpp);
+      exit(1);
+    }
+  }
+
+  for (i=0; i<NUMCLRS; i++) {
+    counts[i] = 0;
+  }
+
+  for (j=0; j<size; j++) {
+    k = (int)(((CARD8 *)data)[j]);
+    if (k >= NUMCLRS) {
+      rfbLog("getBgColour: unusual colour = %d\n", k);
+      exit(1);
+    }
+    counts[k] += 1;
+    if (counts[k] > maxcount) {
+      maxcount = counts[k];
+      maxclr = ((CARD8 *)data)[j];
+    }
+  }
+  
+  return maxclr;
+}
diff -u -rNp a/hw/dmx/vnc/sockets.c b/hw/dmx/vnc/sockets.c
--- a/hw/dmx/vnc/sockets.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/sockets.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,656 @@
+/*
+ * sockets.c - deal with TCP & UDP sockets.
+ *
+ * This code should be independent of any changes in the RFB protocol.  It just
+ * deals with the X server scheduling stuff, calling rfbNewClientConnection and
+ * rfbProcessClientMessage to actually deal with the protocol.  If a socket
+ * needs to be closed for any reason then rfbCloseSock should be called, and
+ * this in turn will call rfbClientConnectionGone.  To make an active
+ * connection out, call rfbConnect - note that this does _not_ call
+ * rfbNewClientConnection.
+ *
+ * This file is divided into two types of function.  Those beginning with
+ * "rfb" are specific to sockets using the RFB protocol.  Those without the
+ * "rfb" prefix are more general socket routines (which are used by the http
+ * code).
+ *
+ * Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN
+ * not EWOULDBLOCK.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if HAVE_DMX_CONFIG_H
+#include "dmx-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "windowstr.h"
+
+#ifndef USE_LIBWRAP
+#define USE_LIBWRAP 0
+#endif
+#if USE_LIBWRAP
+#include <syslog.h>
+#include <tcpd.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif
+
+#include "rfb.h"
+
+int rfbMaxClientWait = 20000;	/* time (ms) after which we decide client has
+				   gone away - needed to stop us hanging */
+
+static struct sockaddr_in udpRemoteAddr;
+
+/*
+ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB
+ * connections.  It does nothing if called again.
+ */
+
+Bool
+rfbInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (inetdSock != -1) {
+	const int one = 1;
+
+	if (fcntl(inetdSock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("fcntl");
+	    return FALSE;
+	}
+
+	if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("setsockopt");
+	    return FALSE;
+	}
+
+    	AddEnabledDevice(inetdSock);
+    	FD_ZERO(&pVNC->allFds);
+    	FD_SET(inetdSock, &pVNC->allFds);
+    	pVNC->maxFd = inetdSock;
+	return TRUE;
+    }
+
+    if (pVNC->rfbPort == 0) {
+	pVNC->rfbPort = 5900 + atoi(display) + pScreen->myNum;
+    }
+
+    if ((pVNC->rfbListenSock = ListenOnTCPPort(pScreen, pVNC->rfbPort)) < 0) {
+	rfbLogPerror("ListenOnTCPPort");
+	pVNC->rfbPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for VNC connections on TCP port %d\n", pVNC->rfbPort);
+
+    AddEnabledDevice(pVNC->rfbListenSock);
+
+    FD_ZERO(&pVNC->allFds);
+    FD_SET(pVNC->rfbListenSock, &pVNC->allFds);
+    pVNC->maxFd = pVNC->rfbListenSock;
+
+    if (pVNC->udpPort != 0) {
+	rfbLog("rfbInitSockets: listening for input on UDP port %d\n",pVNC->udpPort);
+
+	if ((pVNC->udpSock = ListenOnUDPPort(pScreen, pVNC->udpPort)) < 0) {
+	    rfbLogPerror("ListenOnUDPPort");
+	    return FALSE;
+	}
+	AddEnabledDevice(pVNC->udpSock);
+	FD_SET(pVNC->udpSock, &pVNC->allFds);
+	pVNC->maxFd = max(pVNC->udpSock,pVNC->maxFd);
+    }
+   
+    return TRUE;
+}
+
+
+/*
+ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB
+ * socket(s).  If there is input to process, the appropriate function in the
+ * RFB server code will be called (rfbNewClientConnection,
+ * rfbProcessClientMessage, etc).
+ */
+
+void
+rfbCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+#if XFREE86VNC
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+#endif
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+    char buf[6];
+    const int one = 1;
+    int sock;
+    static Bool inetdInitDone = FALSE;
+
+    if (!inetdInitDone && inetdSock != -1) {
+	rfbNewClientConnection(pScreen, inetdSock); 
+	inetdInitDone = TRUE;
+    }
+
+    memcpy((char *)&fds, (char *)&pVNC->allFds, sizeof(fd_set));
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(pVNC->maxFd + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR)
+		rfbLogPerror("rfbCheckFds: select");
+	return;
+    }
+
+    if (pVNC->rfbListenSock != -1 && FD_ISSET(pVNC->rfbListenSock, &fds)) {
+
+	if ((sock = accept(pVNC->rfbListenSock,
+			   (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("rfbCheckFds: accept");
+	    return;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("rfbCheckFds: fcntl");
+	    close(sock);
+	    return;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("rfbCheckFds: setsockopt");
+	    close(sock);
+	    return;
+	}
+
+	rfbLog("\n");
+
+#if USE_LIBWRAP
+        if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr),
+                       STRING_UNKNOWN)) {
+          rfbLog("Rejected connection from client %s\n",
+                 inet_ntoa(addr.sin_addr));
+          close(sock);
+          return;
+        }
+#endif
+
+	rfbLog("Got VNC connection from client %s\n", inet_ntoa(addr.sin_addr));
+
+	AddEnabledDevice(sock);
+	FD_SET(sock, &pVNC->allFds);
+	pVNC->maxFd = max(sock,pVNC->maxFd);
+
+	rfbNewClientConnection(pScreen, sock);
+
+	FD_CLR(pVNC->rfbListenSock, &fds);
+	if (--nfds == 0)
+	    return;
+    }
+
+    if ((pVNC->udpSock != -1) && FD_ISSET(pVNC->udpSock, &fds)) {
+
+	if (recvfrom(pVNC->udpSock, buf, 1, MSG_PEEK,
+		     (struct sockaddr *)&addr, &addrlen) < 0) {
+
+	    rfbLogPerror("rfbCheckFds: UDP: recvfrom");
+	    rfbDisconnectUDPSock(pScreen);
+
+	} else {
+
+	    if (!pVNC->udpSockConnected ||
+		(memcmp(&addr, &udpRemoteAddr, addrlen) != 0))
+	    {
+		/* new remote end */
+		rfbLog("rfbCheckFds: UDP: got connection\n");
+
+		memcpy(&udpRemoteAddr, &addr, addrlen);
+		pVNC->udpSockConnected = TRUE;
+
+		if (connect(pVNC->udpSock,
+			    (struct sockaddr *)&addr, addrlen) < 0) {
+		    rfbLogPerror("rfbCheckFds: UDP: connect");
+		    rfbDisconnectUDPSock(pScreen);
+		    return;
+		}
+
+		rfbNewUDPConnection(pVNC->udpSock);
+	    }
+
+	    rfbProcessUDPInput(pScreen, pVNC->udpSock);
+	}
+
+	FD_CLR(pVNC->udpSock, &fds);
+	if (--nfds == 0)
+	    return;
+    }
+
+    for (sock = 0; sock <= pVNC->maxFd; sock++) {
+	if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &pVNC->allFds)) {
+#if XFREE86VNC
+	    if (!pScrn->vtSema)
+		rfbCloseSock(pScreen, sock);
+	    else
+#endif
+	    	rfbProcessClientMessage(pScreen, sock);
+	}
+    }
+}
+
+
+void
+rfbDisconnectUDPSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    pVNC->udpSockConnected = FALSE;
+}
+
+
+void
+rfbCloseSock(ScreenPtr pScreen, int sock)
+{
+    VNCSCREENPTR(pScreen);
+    close(sock);
+    RemoveEnabledDevice(sock);
+    FD_CLR(sock, &pVNC->allFds);
+    rfbClientConnectionGone(sock);
+    if (sock == inetdSock)
+	GiveUp(0);
+}
+
+#if 0
+/*
+ * rfbWaitForClient can be called to wait for the RFB client to send us a
+ * message.  When one is received it is processed by calling
+ * rfbProcessClientMessage().
+ */
+
+void
+rfbWaitForClient(sock)
+    int sock;
+{
+    int n;
+    fd_set fds;
+    struct timeval tv;
+
+    FD_ZERO(&fds);
+    FD_SET(sock, &fds);
+    tv.tv_sec = rfbMaxClientWait / 1000;
+    tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
+    n = select(sock+1, &fds, NULL, NULL, &tv);
+    if (n < 0) {
+	rfbLogPerror("rfbWaitForClient: select");
+	exit(1);
+    }
+    if (n == 0) {
+	rfbCloseSock(sock);
+	return;
+    }
+
+    rfbProcessClientMessage(sock);
+}
+#endif
+
+/*
+ * rfbConnect is called to make a connection out to a given TCP address.
+ */
+
+int
+rfbConnect(ScreenPtr pScreen, char *host, int port)
+{
+    VNCSCREENPTR(pScreen);
+    int sock;
+    int one = 1;
+
+    rfbLog("\n");
+    rfbLog("Making connection to client on host %s port %d\n",
+	   host,port);
+
+    if ((sock = ConnectToTcpAddr(host, port)) < 0) {
+	rfbLogPerror("connection failed");
+	return -1;
+    }
+
+    if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	rfbLogPerror("fcntl failed");
+	close(sock);
+	return -1;
+    }
+
+    if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		   (char *)&one, sizeof(one)) < 0) {
+	rfbLogPerror("setsockopt failed");
+	close(sock);
+	return -1;
+    }
+
+    AddEnabledDevice(sock);
+    FD_SET(sock, &pVNC->allFds);
+    pVNC->maxFd = max(sock,pVNC->maxFd);
+
+    return sock;
+}
+
+
+
+
+/*
+ * ReadExact reads an exact number of bytes on a TCP socket.  Returns 1 if
+ * those bytes have been read, 0 if the other end has closed, or -1 if an error
+ * occurred (errno is set to ETIMEDOUT if it timed out).
+ */
+
+int
+ReadExact(sock, buf, len)
+    int sock;
+    char *buf;
+    int len;
+{
+    int n;
+    fd_set fds;
+    int tries = 5;
+    struct timeval tv;
+
+    while (len > 0) {
+	n = read(sock, buf, len);
+
+	if (n > 0) {
+
+	    buf += n;
+	    len -= n;
+
+	} else if (n == 0) {
+
+	    return 0;
+
+	} else {
+	    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+		return n;
+	    }
+
+	    do {
+	   	FD_ZERO(&fds);
+	    	FD_SET(sock, &fds);
+	    	tv.tv_sec = rfbMaxClientWait / 1000;
+	    	tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
+	    	n = select(sock+1, &fds, NULL, NULL, &tv);
+		tries--;
+		
+	    /* We really need to retry if we get EINTR, so spin */
+	    /* If after 5 attempts we're still broke, abort.... */
+
+	    } while ((n < 0 && errno == EINTR) && tries > 0);
+
+	    if (n < 0) {
+		rfbLogPerror("ReadExact: select");
+		return n;
+	    }
+	    if (n == 0) {
+		errno = ETIMEDOUT;
+		return -1;
+	    }
+	}
+    }
+    return 1;
+}
+
+
+
+/*
+ * WriteExact writes an exact number of bytes on a TCP socket.  Returns 1 if
+ * those bytes have been written, or -1 if an error occurred (errno is set to
+ * ETIMEDOUT if it timed out).
+ */
+
+int
+WriteExact(sock, buf, len)
+    int sock;
+    char *buf;
+    int len;
+{
+    int n;
+    fd_set fds;
+    struct timeval tv;
+    int totalTimeWaited = 0;
+
+    while (len > 0) {
+	n = write(sock, buf, len);
+
+	if (n > 0) {
+
+	    buf += n;
+	    len -= n;
+
+	} else if (n == 0) {
+
+	    rfbLog("WriteExact: write returned 0?\n");
+	    return -1;
+
+	} else {
+	    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+		return n;
+	    }
+
+#if 0
+	    /* Retry every 5 seconds until we exceed rfbMaxClientWait.  We
+	       need to do this because select doesn't necessarily return
+	       immediately when the other end has gone away */
+
+	    FD_ZERO(&fds);
+	    FD_SET(sock, &fds);
+	    tv.tv_sec = 5;
+	    tv.tv_usec = 0;
+#else
+	    /* We're in the WakeupHandler now, so don't wait */
+
+	    FD_ZERO(&fds);
+	    FD_SET(sock, &fds);
+	    tv.tv_sec = 0;
+	    tv.tv_usec = 0;
+#endif
+	    n = select(sock+1, NULL, &fds, NULL, &tv);
+#if 0
+	    if (n < 0) {
+		rfbLogPerror("WriteExact: select");
+		return n;
+	    }
+	    if (n == 0) {
+		totalTimeWaited += 5000;
+		if (totalTimeWaited >= rfbMaxClientWait) {
+		    errno = ETIMEDOUT;
+		    return -1;
+		}
+	    } else {
+		totalTimeWaited = 0;
+	    }
+#endif
+	}
+    }
+    return 1;
+}
+
+
+int
+ListenOnTCPPort(ScreenPtr pScreen, int port)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    int sock;
+    int one = 1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = pVNC->interface.s_addr;
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one)) < 0) {
+	close(sock);
+	return -1;
+    }
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	close(sock);
+	return -1;
+    }
+    if (listen(sock, 5) < 0) {
+	close(sock);
+	return -1;
+    }
+
+    return sock;
+}
+
+
+int
+ConnectToTcpAddr(host, port)
+    char *host;
+    int port;
+{
+    struct hostent *hp;
+    int sock, n;
+    struct sockaddr_in addr;
+    int tries = 5;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    if ((addr.sin_addr.s_addr = inet_addr(host)) == -1)
+    {
+	if (!(hp = gethostbyname(host))) {
+	    errno = EINVAL;
+	    return -1;
+	}
+	addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
+    }
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	return -1;
+    }
+
+    do {
+    	sock = socket(AF_INET, SOCK_STREAM, 0);
+	tries--;
+
+	/* We really need to retry if we get EINTR, so spin */
+	/* If after 5 attempts we're still broke, abort.... */
+
+    } while ((sock < 0 && errno == EINTR) && tries > 0);
+
+    if (sock < 0) {
+	return -1;
+    }
+
+    tries = 5;
+
+    do {
+    	n = connect(sock, (struct sockaddr *)&addr, (sizeof(addr)));
+	tries--;
+
+	/* We really need to retry if we get EINTR, so spin */
+	/* If after 5 attempts we're still broke, abort.... */
+
+    } while ((n < 0 && errno == EINTR) && tries > 0);
+
+    if (n < 0) {
+	close(sock);
+	return -1;
+    }
+
+    return sock;
+}
+
+
+int
+ListenOnUDPPort(ScreenPtr pScreen, int port)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    int sock;
+    int one = 1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = pVNC->interface.s_addr;
+
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one)) < 0) {
+	return -1;
+    }
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	return -1;
+    }
+
+    return sock;
+}
+
+#if 0
+/*
+ * rdpInitSockets sets up the TCP for RDP
+ * connections.  It does nothing if called again.
+ */
+
+Bool
+rdpInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if ((pVNC->rdpListenSock = ListenOnTCPPort(pScreen, pVNC->rdpPort)) < 0) {
+	rfbLogPerror("ListenOnTCPPort");
+	pVNC->rdpPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for RDP connections on TCP port %d\n", pVNC->rdpPort);
+
+    AddEnabledDevice(pVNC->rdpListenSock);
+
+    return TRUE;
+}
+#endif
diff -u -rNp a/hw/dmx/vnc/sprite.c b/hw/dmx/vnc/sprite.c
--- a/hw/dmx/vnc/sprite.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/sprite.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2491 @@
+/*
+ * sprite.c
+ *
+ * software sprite routines - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* $XConsortium: misprite.c,v 5.47 94/04/17 20:27:53 dpw Exp $ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#include "rfb.h"
+# include   "X11/X.h"
+# include   "X11/Xproto.h"
+# include   "misc.h"
+# include   "pixmapstr.h"
+# include   "input.h"
+# include   "mi.h"
+# include   "cursorstr.h"
+/*# include   "font.h"*/
+# include   "scrnintstr.h"
+# include   "colormapst.h"
+# include   "windowstr.h"
+# include   "gcstruct.h"
+# include   "mipointer.h"
+# include   "spritest.h"
+# include   "dixfontstr.h"
+/*# include   "fontstruct.h"*/
+#ifdef RENDER
+# include   "mipict.h"
+#endif
+
+/*
+ * screen wrappers
+ */
+
+static int  rfbSpriteScreenIndex;
+static unsigned long rfbSpriteGeneration = 0;
+
+static Bool	    rfbSpriteCloseScreen(int i, ScreenPtr pScreen);
+static void	    rfbSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
+				     int w, int h, unsigned int format,
+				     unsigned long planemask, char *pdstLine);
+static void	    rfbSpriteGetSpans(DrawablePtr pDrawable, int wMax,
+				     DDXPointPtr ppt, int *pwidth, int nspans,
+			     char *pdstStart);
+static void	    rfbSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
+					   int width, int height);
+static Bool	    rfbSpriteCreateGC(GCPtr pGC);
+static void	    rfbSpriteBlockHandler(int i, pointer blockData,
+					 pointer pTimeout,
+					 pointer pReadMask);
+static void	    rfbSpriteInstallColormap(ColormapPtr pMap);
+static void	    rfbSpriteStoreColors(ColormapPtr pMap, int ndef,
+					xColorItem *pdef);
+
+static void	    rfbSpritePaintWindowBackground(WindowPtr pWin,
+						  RegionPtr pRegion, int what);
+static void	    rfbSpritePaintWindowBorder(WindowPtr pWin,
+					      RegionPtr pRegion, int what);
+static void	    rfbSpriteCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
+				       RegionPtr pRegion);
+static void	    rfbSpriteClearToBackground(WindowPtr pWin, int x, int y,
+					      int w, int h,
+					      Bool generateExposures);
+
+#ifdef RENDER
+static void	    rfbSpriteComposite(CARD8	op,
+				      PicturePtr pSrc,
+				      PicturePtr pMask,
+				      PicturePtr pDst,
+				      INT16	xSrc,
+				      INT16	ySrc,
+				      INT16	xMask,
+				      INT16	yMask,
+				      INT16	xDst,
+				      INT16	yDst,
+				      CARD16	width,
+				      CARD16	height);
+
+static void	    rfbSpriteGlyphs(CARD8	op,
+				   PicturePtr	pSrc,
+				   PicturePtr	pDst,
+				   PictFormatPtr maskFormat,
+				   INT16	xSrc,
+				   INT16	ySrc,
+				   int		nlist,
+				   GlyphListPtr	list,
+				   GlyphPtr	*glyphs);
+#endif
+
+static void	    rfbSpriteSaveDoomedAreas(WindowPtr pWin,
+					    RegionPtr pObscured, int dx,
+					    int dy);
+static RegionPtr    rfbSpriteRestoreAreas(WindowPtr pWin, RegionPtr pRgnExposed);
+static void	    rfbSpriteComputeSaved(ScreenPtr pScreen);
+
+#define SCREEN_PROLOGUE(pScreen, field)\
+  ((pScreen)->field = \
+   ((rfbSpriteScreenPtr) (pScreen)->devPrivates[rfbSpriteScreenIndex].ptr)->field) 
+
+#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
+    ((pScreen)->field = wrapper)
+
+/*
+ * GC func wrappers
+ */
+
+static int  rfbSpriteGCIndex;
+
+static void rfbSpriteValidateGC(GCPtr pGC, unsigned long stateChanges,
+			       DrawablePtr pDrawable);
+static void rfbSpriteCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
+static void rfbSpriteDestroyGC(GCPtr pGC);
+static void rfbSpriteChangeGC(GCPtr pGC, unsigned long mask);
+static void rfbSpriteChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
+static void rfbSpriteDestroyClip(GCPtr pGC);
+static void rfbSpriteCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
+
+static GCFuncs	rfbSpriteGCFuncs = {
+    rfbSpriteValidateGC,
+    rfbSpriteChangeGC,
+    rfbSpriteCopyGC,
+    rfbSpriteDestroyGC,
+    rfbSpriteChangeClip,
+    rfbSpriteDestroyClip,
+    rfbSpriteCopyClip,
+};
+
+#define GC_FUNC_PROLOGUE(pGC)					\
+    rfbSpriteGCPtr   pGCPriv =					\
+	(rfbSpriteGCPtr) (pGC)->devPrivates[rfbSpriteGCIndex].ptr;\
+    (pGC)->funcs = pGCPriv->wrapFuncs;				\
+    if (pGCPriv->wrapOps)					\
+	(pGC)->ops = pGCPriv->wrapOps;
+
+#define GC_FUNC_EPILOGUE(pGC)					\
+    pGCPriv->wrapFuncs = (pGC)->funcs;				\
+    (pGC)->funcs = &rfbSpriteGCFuncs;				\
+    if (pGCPriv->wrapOps)					\
+    {								\
+	pGCPriv->wrapOps = (pGC)->ops;				\
+	(pGC)->ops = &rfbSpriteGCOps;				\
+    }
+
+/*
+ * GC op wrappers
+ */
+
+static void	    rfbSpriteFillSpans(DrawablePtr pDrawable, GCPtr pGC,
+				      int nInit, DDXPointPtr pptInit,
+				      int *pwidthInit, int fSorted);
+static void	    rfbSpriteSetSpans(DrawablePtr pDrawable, GCPtr pGC,
+				     char *psrc, DDXPointPtr ppt, int *pwidth,
+				     int nspans, int fSorted);
+static void	    rfbSpritePutImage(DrawablePtr pDrawable, GCPtr pGC,
+				     int depth, int x, int y, int w, int h,
+				     int leftPad, int format, char *pBits);
+static RegionPtr    rfbSpriteCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
+				     GCPtr pGC, int srcx, int srcy, int w,
+				     int h, int dstx, int dsty);
+static RegionPtr    rfbSpriteCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
+				     GCPtr pGC, int srcx, int srcy, int w,
+				     int h, int dstx, int dsty,
+				     unsigned long plane);
+static void	    rfbSpritePolyPoint(DrawablePtr pDrawable, GCPtr pGC,
+				      int mode, int npt, xPoint *pptInit);
+static void	    rfbSpritePolylines(DrawablePtr pDrawable, GCPtr pGC,
+				      int mode, int npt, DDXPointPtr pptInit);
+static void	    rfbSpritePolySegment(DrawablePtr pDrawable, GCPtr pGC,
+					int nseg, xSegment *pSegs);
+static void	    rfbSpritePolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
+					  int nrects, xRectangle *pRects);
+static void	    rfbSpritePolyArc(DrawablePtr pDrawable, GCPtr pGC,
+				    int narcs, xArc *parcs);
+static void	    rfbSpriteFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
+					int shape, int mode, int count,
+					DDXPointPtr pPts);
+static void	    rfbSpritePolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
+					 int nrectFill, xRectangle *prectInit);
+static void	    rfbSpritePolyFillArc(DrawablePtr pDrawable, GCPtr pGC,
+					int narcs, xArc *parcs);
+static int	    rfbSpritePolyText8(DrawablePtr pDrawable, GCPtr pGC,
+				      int x, int y, int count, char *chars);
+static int	    rfbSpritePolyText16(DrawablePtr pDrawable, GCPtr pGC,
+				       int x, int y, int count,
+				       unsigned short *chars);
+static void	    rfbSpriteImageText8(DrawablePtr pDrawable, GCPtr pGC,
+				       int x, int y, int count, char *chars);
+static void	    rfbSpriteImageText16(DrawablePtr pDrawable, GCPtr pGC,
+					int x, int y, int count,
+					unsigned short *chars);
+static void	    rfbSpriteImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+					  int x, int y, unsigned int nglyph,
+					  CharInfoPtr *ppci,
+					  pointer pglyphBase);
+static void	    rfbSpritePolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+					 int x, int y, unsigned int nglyph,
+					 CharInfoPtr *ppci,
+					 pointer pglyphBase);
+static void	    rfbSpritePushPixels(GCPtr pGC, PixmapPtr pBitMap,
+				       DrawablePtr pDst, int w, int h,
+				       int x, int y);
+#ifdef NEED_LINEHELPER
+static void	    rfbSpriteLineHelper();
+#endif
+
+static GCOps rfbSpriteGCOps = {
+    rfbSpriteFillSpans,	    rfbSpriteSetSpans,	    rfbSpritePutImage,	
+    rfbSpriteCopyArea,	    rfbSpriteCopyPlane,	    rfbSpritePolyPoint,
+    rfbSpritePolylines,	    rfbSpritePolySegment,   rfbSpritePolyRectangle,
+    rfbSpritePolyArc,	    rfbSpriteFillPolygon,   rfbSpritePolyFillRect,
+    rfbSpritePolyFillArc,   rfbSpritePolyText8,	    rfbSpritePolyText16,
+    rfbSpriteImageText8,    rfbSpriteImageText16,   rfbSpriteImageGlyphBlt,
+    rfbSpritePolyGlyphBlt,  rfbSpritePushPixels
+#ifdef NEED_LINEHELPER
+    , rfbSpriteLineHelper
+#endif
+};
+
+/*
+ * testing only -- remove cursor for every draw.  Eventually,
+ * each draw operation will perform a bounding box check against
+ * the saved cursor area
+ */
+
+#define GC_SETUP_CHEAP(pDrawable)				    \
+    rfbSpriteScreenPtr	pScreenPriv = (rfbSpriteScreenPtr)	    \
+	(pDrawable)->pScreen->devPrivates[rfbSpriteScreenIndex].ptr; \
+
+#define GC_SETUP(pDrawable, pGC)				    \
+    GC_SETUP_CHEAP(pDrawable)					    \
+    rfbSpriteGCPtr	pGCPrivate = (rfbSpriteGCPtr)		    \
+	(pGC)->devPrivates[rfbSpriteGCIndex].ptr;		    \
+    GCFuncs *oldFuncs = pGC->funcs;
+
+#define GC_SETUP_AND_CHECK(pDrawable, pGC)			    \
+    GC_SETUP(pDrawable, pGC);					    \
+    if (GC_CHECK((WindowPtr)pDrawable))				    \
+	rfbSpriteRemoveCursor (pDrawable->pScreen);
+    
+#define GC_CHECK(pWin)						    \
+    (pVNC->cursorIsDrawn &&					    \
+        (pScreenPriv->pCacheWin == pWin ?			    \
+	    pScreenPriv->isInCacheWin : (			    \
+	    (pScreenPriv->pCacheWin = (pWin)) ,			    \
+	    (pScreenPriv->isInCacheWin =			    \
+		(pWin)->drawable.x < pScreenPriv->saved.x2 &&	    \
+		pScreenPriv->saved.x1 < (pWin)->drawable.x +	    \
+				    (int) (pWin)->drawable.width && \
+		(pWin)->drawable.y < pScreenPriv->saved.y2 &&	    \
+		pScreenPriv->saved.y1 < (pWin)->drawable.y +	    \
+				    (int) (pWin)->drawable.height &&\
+		RECT_IN_REGION((pWin)->drawable.pScreen, &(pWin)->borderClip, \
+			&pScreenPriv->saved) != rgnOUT))))
+
+#define GC_OP_PROLOGUE(pGC) { \
+    (pGC)->funcs = pGCPrivate->wrapFuncs; \
+    (pGC)->ops = pGCPrivate->wrapOps; \
+    }
+
+#define GC_OP_EPILOGUE(pGC) { \
+    pGCPrivate->wrapOps = (pGC)->ops; \
+    (pGC)->funcs = oldFuncs; \
+    (pGC)->ops = &rfbSpriteGCOps; \
+    }
+
+/*
+ * pointer-sprite method table
+ */
+
+static Bool rfbSpriteRealizeCursor (),	rfbSpriteUnrealizeCursor ();
+static void rfbSpriteSetCursor (),	rfbSpriteMoveCursor ();
+
+miPointerSpriteFuncRec rfbSpritePointerFuncs = {
+    rfbSpriteRealizeCursor,
+    rfbSpriteUnrealizeCursor,
+    rfbSpriteSetCursor,
+    rfbSpriteMoveCursor,
+};
+
+/*
+ * other misc functions
+ */
+
+static Bool rfbDisplayCursor (ScreenPtr pScreen, CursorPtr pCursor);
+
+
+/*
+ * rfbSpriteInitialize -- called from device-dependent screen
+ * initialization proc after all of the function pointers have
+ * been stored in the screen structure.
+ */
+
+Bool
+rfbSpriteInitialize (pScreen, cursorFuncs, screenFuncs)
+    ScreenPtr		    pScreen;
+    rfbSpriteCursorFuncPtr   cursorFuncs;
+    miPointerScreenFuncPtr  screenFuncs;
+{
+    rfbSpriteScreenPtr	pPriv;
+    VisualPtr		pVisual;
+#ifdef RENDER
+    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
+#endif
+    
+    if (rfbSpriteGeneration != serverGeneration)
+    {
+	rfbSpriteScreenIndex = AllocateScreenPrivateIndex ();
+	if (rfbSpriteScreenIndex < 0)
+	    return FALSE;
+	rfbSpriteGeneration = serverGeneration;
+	rfbSpriteGCIndex = AllocateGCPrivateIndex ();
+    }
+    if (!AllocateGCPrivate(pScreen, rfbSpriteGCIndex, sizeof(rfbSpriteGCRec)))
+	return FALSE;
+    pPriv = (rfbSpriteScreenPtr) xalloc (sizeof (rfbSpriteScreenRec));
+    if (!pPriv)
+	return FALSE;
+    if (!miPointerInitialize (pScreen, &rfbSpritePointerFuncs, screenFuncs,TRUE))
+    {
+	xfree ((pointer) pPriv);
+	return FALSE;
+    }
+    for (pVisual = pScreen->visuals;
+	 pVisual->vid != pScreen->rootVisual;
+	 pVisual++)
+	;
+    pPriv->pVisual = pVisual;
+    pPriv->CloseScreen = pScreen->CloseScreen;
+    pPriv->GetImage = pScreen->GetImage;
+    pPriv->GetSpans = pScreen->GetSpans;
+    pPriv->SourceValidate = pScreen->SourceValidate;
+    pPriv->CreateGC = pScreen->CreateGC;
+#if 0
+    pPriv->BlockHandler = pScreen->BlockHandler;
+#endif
+    pPriv->InstallColormap = pScreen->InstallColormap;
+    pPriv->StoreColors = pScreen->StoreColors;
+    pPriv->DisplayCursor = pScreen->DisplayCursor;
+
+    pPriv->PaintWindowBackground = pScreen->PaintWindowBackground;
+    pPriv->PaintWindowBorder = pScreen->PaintWindowBorder;
+    pPriv->CopyWindow = pScreen->CopyWindow;
+    pPriv->ClearToBackground = pScreen->ClearToBackground;
+
+    pPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas;
+    pPriv->RestoreAreas = pScreen->RestoreAreas;
+#ifdef RENDER
+    if (ps)
+    {
+	pPriv->Composite = ps->Composite;
+	pPriv->Glyphs = ps->Glyphs;
+    }
+#endif
+
+    pPriv->pCursor = NULL;
+    pPriv->x = 0;
+    pPriv->y = 0;
+    pPriv->shouldBeUp = FALSE;
+    pPriv->pCacheWin = NullWindow;
+    pPriv->isInCacheWin = FALSE;
+    pPriv->checkPixels = TRUE;
+    pPriv->pInstalledMap = NULL;
+    pPriv->pColormap = NULL;
+    pPriv->funcs = cursorFuncs;
+    pPriv->colors[SOURCE_COLOR].red = 0;
+    pPriv->colors[SOURCE_COLOR].green = 0;
+    pPriv->colors[SOURCE_COLOR].blue = 0;
+    pPriv->colors[MASK_COLOR].red = 0;
+    pPriv->colors[MASK_COLOR].green = 0;
+    pPriv->colors[MASK_COLOR].blue = 0;
+    pScreen->devPrivates[rfbSpriteScreenIndex].ptr = (pointer) pPriv;
+    pScreen->CloseScreen = rfbSpriteCloseScreen;
+    pScreen->GetImage = rfbSpriteGetImage;
+    pScreen->GetSpans = rfbSpriteGetSpans;
+    pScreen->SourceValidate = rfbSpriteSourceValidate;
+    pScreen->CreateGC = rfbSpriteCreateGC;
+#if 0
+    pScreen->BlockHandler = rfbSpriteBlockHandler;
+#endif
+    pScreen->InstallColormap = rfbSpriteInstallColormap;
+    pScreen->StoreColors = rfbSpriteStoreColors;
+
+    pScreen->PaintWindowBackground = rfbSpritePaintWindowBackground;
+    pScreen->PaintWindowBorder = rfbSpritePaintWindowBorder;
+    pScreen->CopyWindow = rfbSpriteCopyWindow;
+    pScreen->ClearToBackground = rfbSpriteClearToBackground;
+
+    pScreen->SaveDoomedAreas = rfbSpriteSaveDoomedAreas;
+    pScreen->RestoreAreas = rfbSpriteRestoreAreas;
+
+    pScreen->DisplayCursor = rfbDisplayCursor;
+#ifdef RENDER
+    if (ps)
+    {
+	ps->Composite = rfbSpriteComposite;
+	ps->Glyphs = rfbSpriteGlyphs;
+    }
+#endif
+
+    return TRUE;
+}
+
+/*
+ * Screen wrappers
+ */
+
+/*
+ * CloseScreen wrapper -- unwrap everything, free the private data
+ * and call the wrapped function
+ */
+
+static Bool
+rfbSpriteCloseScreen (i, pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+#ifdef RENDER
+    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
+#endif
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    pScreen->CloseScreen = pScreenPriv->CloseScreen;
+    pScreen->GetImage = pScreenPriv->GetImage;
+    pScreen->GetSpans = pScreenPriv->GetSpans;
+    pScreen->SourceValidate = pScreenPriv->SourceValidate;
+    pScreen->CreateGC = pScreenPriv->CreateGC;
+#if 0
+    pScreen->BlockHandler = pScreenPriv->BlockHandler;
+#endif
+    pScreen->InstallColormap = pScreenPriv->InstallColormap;
+    pScreen->StoreColors = pScreenPriv->StoreColors;
+
+    pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground;
+    pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder;
+    pScreen->CopyWindow = pScreenPriv->CopyWindow;
+    pScreen->ClearToBackground = pScreenPriv->ClearToBackground;
+
+    pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas;
+    pScreen->RestoreAreas = pScreenPriv->RestoreAreas;
+#ifdef RENDER
+    if (ps)
+    {
+	ps->Composite = pScreenPriv->Composite;
+	ps->Glyphs = pScreenPriv->Glyphs;
+    }
+#endif
+
+    xfree ((pointer) pScreenPriv);
+
+    return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+static void
+rfbSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine)
+    DrawablePtr	    pDrawable;
+    int		    sx, sy, w, h;
+    unsigned int    format;
+    unsigned long   planemask;
+    char	    *pdstLine;
+{
+    ScreenPtr	    pScreen = pDrawable->pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, GetImage);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    if (pDrawable->type == DRAWABLE_WINDOW &&
+        pVNC->cursorIsDrawn &&
+	ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h))
+    {
+	rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
+			  format, planemask, pdstLine);
+
+    SCREEN_EPILOGUE (pScreen, GetImage, rfbSpriteGetImage);
+}
+
+static void
+rfbSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart)
+    DrawablePtr	pDrawable;
+    int		wMax;
+    DDXPointPtr	ppt;
+    int		*pwidth;
+    int		nspans;
+    char	*pdstStart;
+{
+    ScreenPtr		    pScreen = pDrawable->pScreen;
+    rfbSpriteScreenPtr	    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, GetSpans);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn)
+    {
+	register DDXPointPtr    pts;
+	register int    	*widths;
+	register int    	nPts;
+	register int    	xorg,
+				yorg;
+
+	xorg = pDrawable->x;
+	yorg = pDrawable->y;
+
+	for (pts = ppt, widths = pwidth, nPts = nspans;
+	     nPts--;
+	     pts++, widths++)
+ 	{
+	    if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg,
+			     pts->x+xorg,*widths))
+	    {
+		rfbSpriteRemoveCursor (pScreen);
+		break;
+	    }
+	}
+    }
+
+    (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+
+    SCREEN_EPILOGUE (pScreen, GetSpans, rfbSpriteGetSpans);
+}
+
+static void
+rfbSpriteSourceValidate (pDrawable, x, y, width, height)
+    DrawablePtr	pDrawable;
+    int		x, y, width, height;
+{
+    ScreenPtr		    pScreen = pDrawable->pScreen;
+    rfbSpriteScreenPtr	    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, SourceValidate);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn &&
+	ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y,
+		    x, y, width, height))
+    {
+	rfbSpriteRemoveCursor (pScreen);
+    }
+
+    if (pScreen->SourceValidate)
+	(*pScreen->SourceValidate) (pDrawable, x, y, width, height);
+
+    SCREEN_EPILOGUE (pScreen, SourceValidate, rfbSpriteSourceValidate);
+}
+
+static Bool
+rfbSpriteCreateGC (pGC)
+    GCPtr   pGC;
+{
+    ScreenPtr	    pScreen = pGC->pScreen;
+    Bool	    ret;
+    rfbSpriteGCPtr   pPriv;
+
+    SCREEN_PROLOGUE (pScreen, CreateGC);
+    
+    pPriv = (rfbSpriteGCPtr)pGC->devPrivates[rfbSpriteGCIndex].ptr;
+
+    ret = (*pScreen->CreateGC) (pGC);
+
+    pPriv->wrapOps = NULL;
+    pPriv->wrapFuncs = pGC->funcs;
+    pGC->funcs = &rfbSpriteGCFuncs;
+
+    SCREEN_EPILOGUE (pScreen, CreateGC, rfbSpriteCreateGC);
+
+    return ret;
+}
+
+static void
+rfbSpriteBlockHandler (i, blockData, pTimeout, pReadmask)
+    int	i;
+    pointer	blockData;
+    pointer	pTimeout;
+    pointer	pReadmask;
+{
+    ScreenPtr		pScreen = screenInfo.screens[i];
+    rfbSpriteScreenPtr	pPriv;
+    VNCSCREENPTR(pScreen);
+
+    pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    SCREEN_PROLOGUE(pScreen, BlockHandler);
+    
+    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+
+    SCREEN_EPILOGUE(pScreen, BlockHandler, rfbSpriteBlockHandler);
+
+    if (!pVNC->cursorIsDrawn && pPriv->shouldBeUp)
+	rfbSpriteRestoreCursor (pScreen);
+}
+
+static void
+rfbSpriteInstallColormap (pMap)
+    ColormapPtr	pMap;
+{
+    ScreenPtr		pScreen = pMap->pScreen;
+    rfbSpriteScreenPtr	pPriv;
+    VNCSCREENPTR(pScreen);
+
+    pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    SCREEN_PROLOGUE(pScreen, InstallColormap);
+    
+    (*pScreen->InstallColormap) (pMap);
+
+    SCREEN_EPILOGUE(pScreen, InstallColormap, rfbSpriteInstallColormap);
+
+    pPriv->pInstalledMap = pMap;
+    if (pPriv->pColormap != pMap)
+    {
+    	pPriv->checkPixels = TRUE;
+	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+}
+
+static void
+rfbSpriteStoreColors (pMap, ndef, pdef)
+    ColormapPtr	pMap;
+    int		ndef;
+    xColorItem	*pdef;
+{
+    ScreenPtr		pScreen = pMap->pScreen;
+    rfbSpriteScreenPtr	pPriv;
+    int			i;
+    int			updated;
+    VisualPtr		pVisual;
+    VNCSCREENPTR(pScreen);
+
+    pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    SCREEN_PROLOGUE(pScreen, StoreColors);
+    
+    (*pScreen->StoreColors) (pMap, ndef, pdef);
+
+    SCREEN_EPILOGUE(pScreen, StoreColors, rfbSpriteStoreColors);
+
+    if (pPriv->pColormap == pMap)
+    {
+	updated = 0;
+	pVisual = pMap->pVisual;
+	if (pVisual->class == DirectColor)
+	{
+	    /* Direct color - match on any of the subfields */
+
+#define MaskMatch(a,b,mask) ((a) & ((pVisual->mask) == (b)) & (pVisual->mask))
+
+#define UpdateDAC(plane,dac,mask) {\
+    if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\
+	pPriv->colors[plane].dac = pdef[i].dac; \
+	updated = 1; \
+    } \
+}
+
+#define CheckDirect(plane) \
+	    UpdateDAC(plane,red,redMask) \
+	    UpdateDAC(plane,green,greenMask) \
+	    UpdateDAC(plane,blue,blueMask)
+
+	    for (i = 0; i < ndef; i++)
+	    {
+		CheckDirect (SOURCE_COLOR)
+		CheckDirect (MASK_COLOR)
+	    }
+	}
+	else
+	{
+	    /* PseudoColor/GrayScale - match on exact pixel */
+	    for (i = 0; i < ndef; i++)
+	    {
+	    	if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel)
+	    	{
+		    pPriv->colors[SOURCE_COLOR] = pdef[i];
+		    if (++updated == 2)
+		    	break;
+	    	}
+	    	if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel)
+	    	{
+		    pPriv->colors[MASK_COLOR] = pdef[i];
+		    if (++updated == 2)
+		    	break;
+	    	}
+	    }
+	}
+    	if (updated)
+    	{
+	    pPriv->checkPixels = TRUE;
+	    if (pVNC->cursorIsDrawn)
+	    	rfbSpriteRemoveCursor (pScreen);
+    	}
+    }
+}
+
+static void
+rfbSpriteFindColors (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr	pScreenPriv = (rfbSpriteScreenPtr)
+			    pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    CursorPtr		pCursor;
+    xColorItem		*sourceColor, *maskColor;
+
+    pCursor = pScreenPriv->pCursor;
+    sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
+    maskColor = &pScreenPriv->colors[MASK_COLOR];
+    if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
+	!(pCursor->foreRed == sourceColor->red &&
+	  pCursor->foreGreen == sourceColor->green &&
+          pCursor->foreBlue == sourceColor->blue &&
+	  pCursor->backRed == maskColor->red &&
+	  pCursor->backGreen == maskColor->green &&
+	  pCursor->backBlue == maskColor->blue))
+    {
+	pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
+	sourceColor->red = pCursor->foreRed;
+	sourceColor->green = pCursor->foreGreen;
+	sourceColor->blue = pCursor->foreBlue;
+	FakeAllocColor (pScreenPriv->pColormap, sourceColor);
+	maskColor->red = pCursor->backRed;
+	maskColor->green = pCursor->backGreen;
+	maskColor->blue = pCursor->backBlue;
+	FakeAllocColor (pScreenPriv->pColormap, maskColor);
+	/* "free" the pixels right away, don't let this confuse you */
+	FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
+	FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
+    }
+    pScreenPriv->checkPixels = FALSE;
+}
+
+/*
+ * BackingStore wrappers
+ */
+
+static void
+rfbSpriteSaveDoomedAreas (pWin, pObscured, dx, dy)
+    WindowPtr	pWin;
+    RegionPtr	pObscured;
+    int		dx, dy;
+{
+    ScreenPtr		pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr   pScreenPriv;
+    BoxRec		cursorBox;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, SaveDoomedAreas);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	cursorBox = pScreenPriv->saved;
+
+	if (dx || dy)
+ 	{
+	    cursorBox.x1 += dx;
+	    cursorBox.y1 += dy;
+	    cursorBox.x2 += dx;
+	    cursorBox.y2 += dy;
+	}
+	if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy);
+
+    SCREEN_EPILOGUE (pScreen, SaveDoomedAreas, rfbSpriteSaveDoomedAreas);
+}
+
+static RegionPtr
+rfbSpriteRestoreAreas (pWin, prgnExposed)
+    WindowPtr	pWin;
+    RegionPtr	prgnExposed;
+{
+    ScreenPtr		pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr   pScreenPriv;
+    RegionPtr		result;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, RestoreAreas);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	if (RECT_IN_REGION( pScreen, prgnExposed, &pScreenPriv->saved) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    result = (*pScreen->RestoreAreas) (pWin, prgnExposed);
+
+    SCREEN_EPILOGUE (pScreen, RestoreAreas, rfbSpriteRestoreAreas);
+
+    return result;
+}
+
+/*
+ * Window wrappers
+ */
+
+static void
+rfbSpritePaintWindowBackground (pWin, pRegion, what)
+    WindowPtr	pWin;
+    RegionPtr	pRegion;
+    int		what;
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, PaintWindowBackground);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	/*
+	 * If the cursor is on the same screen as the window, check the
+	 * region to paint for the cursor and remove it as necessary
+	 */
+	if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
+
+    SCREEN_EPILOGUE (pScreen, PaintWindowBackground, rfbSpritePaintWindowBackground);
+}
+
+static void
+rfbSpritePaintWindowBorder (pWin, pRegion, what)
+    WindowPtr	pWin;
+    RegionPtr	pRegion;
+    int		what;
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, PaintWindowBorder);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	/*
+	 * If the cursor is on the same screen as the window, check the
+	 * region to paint for the cursor and remove it as necessary
+	 */
+	if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
+
+    SCREEN_EPILOGUE (pScreen, PaintWindowBorder, rfbSpritePaintWindowBorder);
+}
+
+static void
+rfbSpriteCopyWindow (pWin, ptOldOrg, pRegion)
+    WindowPtr	pWin;
+    DDXPointRec	ptOldOrg;
+    RegionPtr	pRegion;
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    BoxRec	    cursorBox;
+    int		    dx, dy;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, CopyWindow);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	/*
+	 * check both the source and the destination areas.  The given
+	 * region is source relative, so offset the cursor box by
+	 * the delta position
+	 */
+	cursorBox = pScreenPriv->saved;
+	dx = pWin->drawable.x - ptOldOrg.x;
+	dy = pWin->drawable.y - ptOldOrg.y;
+	cursorBox.x1 -= dx;
+	cursorBox.x2 -= dx;
+	cursorBox.y1 -= dy;
+	cursorBox.y2 -= dy;
+	if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT ||
+	    RECT_IN_REGION( pScreen, pRegion, &cursorBox) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->CopyWindow) (pWin, ptOldOrg, pRegion);
+
+    SCREEN_EPILOGUE (pScreen, CopyWindow, rfbSpriteCopyWindow);
+}
+
+static void
+rfbSpriteClearToBackground (pWin, x, y, w, h, generateExposures)
+    WindowPtr pWin;
+    short x,y;
+    unsigned short w,h;
+    Bool generateExposures;
+{
+    ScreenPtr		pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr	pScreenPriv;
+    int			realw, realh;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, ClearToBackground);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (GC_CHECK(pWin))
+    {
+	if (!(realw = w))
+	    realw = (int) pWin->drawable.width - x;
+	if (!(realh = h))
+	    realh = (int) pWin->drawable.height - y;
+	if (ORG_OVERLAP(&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y,
+			x, y, realw, realh))
+	{
+	    rfbSpriteRemoveCursor (pScreen);
+	}
+    }
+
+    (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+    SCREEN_EPILOGUE (pScreen, ClearToBackground, rfbSpriteClearToBackground);
+}
+
+/*
+ * GC Func wrappers
+ */
+
+static void
+rfbSpriteValidateGC (pGC, changes, pDrawable)
+    GCPtr	pGC;
+    unsigned long	changes;
+    DrawablePtr	pDrawable;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+    
+    pGCPriv->wrapOps = NULL;
+    if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDrawable)->viewable)
+    {
+	WindowPtr   pWin;
+	RegionPtr   pRegion;
+
+	pWin = (WindowPtr) pDrawable;
+	pRegion = &pWin->clipList;
+	if (pGC->subWindowMode == IncludeInferiors)
+	    pRegion = &pWin->borderClip;
+	if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion))
+	    pGCPriv->wrapOps = pGC->ops;
+    }
+
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteChangeGC (pGC, mask)
+    GCPtr	    pGC;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->ChangeGC) (pGC, mask);
+    
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteCopyGC (pGCSrc, mask, pGCDst)
+    GCPtr	    pGCSrc, pGCDst;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE (pGCDst);
+
+    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+    
+    GC_FUNC_EPILOGUE (pGCDst);
+}
+
+static void
+rfbSpriteDestroyGC (pGC)
+    GCPtr   pGC;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->DestroyGC) (pGC);
+    
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteChangeClip (pGC, type, pvalue, nrects)
+    GCPtr   pGC;
+    int		type;
+    pointer	pvalue;
+    int		nrects;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteCopyClip(pgcDst, pgcSrc)
+    GCPtr pgcDst, pgcSrc;
+{
+    GC_FUNC_PROLOGUE (pgcDst);
+
+    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+
+    GC_FUNC_EPILOGUE (pgcDst);
+}
+
+static void
+rfbSpriteDestroyClip(pGC)
+    GCPtr	pGC;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (* pGC->funcs->DestroyClip)(pGC);
+
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+/*
+ * GC Op wrappers
+ */
+
+static void
+rfbSpriteFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nInit;			/* number of spans to fill */
+    DDXPointPtr pptInit;		/* pointer to list of start points */
+    int		*pwidthInit;		/* pointer to list of n widths */
+    int 	fSorted;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register DDXPointPtr    pts;
+	register int    	*widths;
+	register int    	nPts;
+
+	for (pts = pptInit, widths = pwidthInit, nPts = nInit;
+	     nPts--;
+	     pts++, widths++)
+ 	{
+	     if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths))
+	     {
+		 rfbSpriteRemoveCursor (pDrawable->pScreen);
+		 break;
+	     }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted)
+    DrawablePtr		pDrawable;
+    GCPtr		pGC;
+    char		*psrc;
+    register DDXPointPtr ppt;
+    int			*pwidth;
+    int			nspans;
+    int			fSorted;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register DDXPointPtr    pts;
+	register int    	*widths;
+	register int    	nPts;
+
+	for (pts = ppt, widths = pwidth, nPts = nspans;
+	     nPts--;
+	     pts++, widths++)
+ 	{
+	     if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths))
+	     {
+		 rfbSpriteRemoveCursor(pDrawable->pScreen);
+		 break;
+	     }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int		  depth;
+    int	    	  x;
+    int	    	  y;
+    int	    	  w;
+    int	    	  h;
+    int	    	  format;
+    char    	  *pBits;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	if (ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,
+			x,y,w,h))
+ 	{
+	    rfbSpriteRemoveCursor (pDrawable->pScreen);
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static RegionPtr
+rfbSpriteCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    GCPtr   	  pGC;
+    int	    	  srcx;
+    int	    	  srcy;
+    int	    	  w;
+    int	    	  h;
+    int	    	  dstx;
+    int	    	  dsty;
+{
+    RegionPtr rgn;
+    ScreenPtr 		pScreen = pGC->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDst, pGC);
+
+    /* check destination/source overlap. */
+    if (GC_CHECK((WindowPtr) pDst) &&
+	 (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) ||
+	  ((pDst == pSrc) &&
+	   ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h))))
+    {
+	rfbSpriteRemoveCursor (pDst->pScreen);
+    }
+ 
+    GC_OP_PROLOGUE (pGC);
+
+    rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				 dstx, dsty);
+
+    GC_OP_EPILOGUE (pGC);
+
+    return rgn;
+}
+
+static RegionPtr
+rfbSpriteCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    register GCPtr pGC;
+    int     	  srcx,
+		  srcy;
+    int     	  w,
+		  h;
+    int     	  dstx,
+		  dsty;
+    unsigned long  plane;
+{
+    RegionPtr rgn;
+    ScreenPtr 		pScreen = pGC->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDst, pGC);
+
+    /*
+     * check destination/source for overlap.
+     */
+    if (GC_CHECK((WindowPtr) pDst) &&
+	(ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) ||
+	 ((pDst == pSrc) &&
+	  ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h))))
+    {
+	rfbSpriteRemoveCursor (pDst->pScreen);
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx, dsty, plane);
+
+    GC_OP_EPILOGUE (pGC);
+
+    return rgn;
+}
+
+static void
+rfbSpritePolyPoint (pDrawable, pGC, mode, npt, pptInit)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		mode;		/* Origin or Previous */
+    int		npt;
+    xPoint 	*pptInit;
+{
+    xPoint	t;
+    int		n;
+    BoxRec	cursor;
+    register xPoint *pts;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    if (npt && GC_CHECK((WindowPtr) pDrawable))
+    {
+	cursor.x1 = pScreenPriv->saved.x1 - pDrawable->x;
+	cursor.y1 = pScreenPriv->saved.y1 - pDrawable->y;
+	cursor.x2 = pScreenPriv->saved.x2 - pDrawable->x;
+	cursor.y2 = pScreenPriv->saved.y2 - pDrawable->y;
+
+	if (mode == CoordModePrevious)
+	{
+	    t.x = 0;
+	    t.y = 0;
+	    for (pts = pptInit, n = npt; n--; pts++)
+	    {
+		t.x += pts->x;
+		t.y += pts->y;
+		if (cursor.x1 <= t.x && t.x <= cursor.x2 &&
+		    cursor.y1 <= t.y && t.y <= cursor.y2)
+		{
+		    rfbSpriteRemoveCursor (pDrawable->pScreen);
+		    break;
+		}
+	    }
+	}
+	else
+	{
+	    for (pts = pptInit, n = npt; n--; pts++)
+	    {
+		if (cursor.x1 <= pts->x && pts->x <= cursor.x2 &&
+		    cursor.y1 <= pts->y && pts->y <= cursor.y2)
+		{
+		    rfbSpriteRemoveCursor (pDrawable->pScreen);
+		    break;
+		}
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolylines (pDrawable, pGC, mode, npt, pptInit)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int	    	  mode;
+    int	    	  npt;
+    DDXPointPtr	  pptInit;
+{
+    BoxPtr  cursor;
+    register DDXPointPtr pts;
+    int	    n;
+    int	    x, y, x1, y1, x2, y2;
+    int	    lw;
+    int	    extra;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    if (npt && GC_CHECK((WindowPtr) pDrawable))
+    {
+	cursor = &pScreenPriv->saved;
+	lw = pGC->lineWidth;
+	x = pptInit->x + pDrawable->x;
+	y = pptInit->y + pDrawable->y;
+
+	if (npt == 1)
+	{
+	    extra = lw >> 1;
+	    if (LINE_OVERLAP(cursor, x, y, x, y, extra))
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+	}
+	else
+	{
+	    extra = lw >> 1;
+	    /*
+	     * mitered joins can project quite a way from
+	     * the line end; the 11 degree miter limit limits
+	     * this extension to 10.43 * lw / 2, rounded up
+	     * and converted to int yields 6 * lw
+	     */
+	    if (pGC->joinStyle == JoinMiter)
+		extra = 6 * lw;
+	    else if (pGC->capStyle == CapProjecting)
+		extra = lw;
+	    for (pts = pptInit + 1, n = npt - 1; n--; pts++)
+	    {
+		x1 = x;
+		y1 = y;
+		if (mode == CoordModeOrigin)
+		{
+		    x2 = pDrawable->x + pts->x;
+		    y2 = pDrawable->y + pts->y;
+		}
+		else
+		{
+		    x2 = x + pts->x;
+		    y2 = y + pts->y;
+		}
+		x = x2;
+		y = y2;
+		LINE_SORT(x1, y1, x2, y2);
+		if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra))
+		{
+		    rfbSpriteRemoveCursor (pDrawable->pScreen);
+		    break;
+		}
+	    }
+	}
+    }
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, pptInit);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolySegment(pDrawable, pGC, nseg, pSegs)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int		nseg;
+    xSegment	*pSegs;
+{
+    int	    n;
+    register xSegment *segs;
+    BoxPtr  cursor;
+    int	    x1, y1, x2, y2;
+    int	    extra;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (nseg && GC_CHECK((WindowPtr) pDrawable))
+    {
+	cursor = &pScreenPriv->saved;
+	extra = pGC->lineWidth >> 1;
+	if (pGC->capStyle == CapProjecting)
+	    extra = pGC->lineWidth;
+	for (segs = pSegs, n = nseg; n--; segs++)
+	{
+	    x1 = segs->x1 + pDrawable->x;
+	    y1 = segs->y1 + pDrawable->y;
+	    x2 = segs->x2 + pDrawable->x;
+	    y2 = segs->y2 + pDrawable->y;
+	    LINE_SORT(x1, y1, x2, y2);
+	    if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, pSegs);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyRectangle(pDrawable, pGC, nrects, pRects)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*pRects;
+{
+    register xRectangle *rects;
+    BoxPtr  cursor;
+    int	    lw;
+    int	    n;
+    int     x1, y1, x2, y2;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    
+    GC_SETUP (pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	lw = pGC->lineWidth >> 1;
+	cursor = &pScreenPriv->saved;
+	for (rects = pRects, n = nrects; n--; rects++)
+	{
+	    x1 = rects->x + pDrawable->x;
+	    y1 = rects->y + pDrawable->y;
+	    x2 = x1 + (int)rects->width;
+	    y2 = y1 + (int)rects->height;
+	    if (LINE_OVERLAP(cursor, x1, y1, x2, y1, lw) ||
+		LINE_OVERLAP(cursor, x2, y1, x2, y2, lw) ||
+		LINE_OVERLAP(cursor, x1, y2, x2, y2, lw) ||
+		LINE_OVERLAP(cursor, x1, y1, x1, y2, lw))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, pRects);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyArc(pDrawable, pGC, narcs, parcs)
+    DrawablePtr	pDrawable;
+    register GCPtr	pGC;
+    int		narcs;
+    xArc	*parcs;
+{
+    BoxPtr  cursor;
+    int	    lw;
+    int	    n;
+    register xArc *arcs;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    
+    GC_SETUP (pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	lw = pGC->lineWidth >> 1;
+	cursor = &pScreenPriv->saved;
+	for (arcs = parcs, n = narcs; n--; arcs++)
+	{
+	    if (ORG_OVERLAP (cursor, pDrawable->x, pDrawable->y,
+			     arcs->x - lw, arcs->y - lw,
+			     (int) arcs->width + pGC->lineWidth,
+ 			     (int) arcs->height + pGC->lineWidth))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, parcs);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteFillPolygon(pDrawable, pGC, shape, mode, count, pPts)
+    register DrawablePtr pDrawable;
+    register GCPtr	pGC;
+    int			shape, mode;
+    int			count;
+    DDXPointPtr		pPts;
+{
+    int x, y, minx, miny, maxx, maxy;
+    register DDXPointPtr pts;
+    int n;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    if (count && GC_CHECK((WindowPtr) pDrawable))
+    {
+	x = pDrawable->x;
+	y = pDrawable->y;
+	pts = pPts;
+	minx = maxx = pts->x;
+	miny = maxy = pts->y;
+	pts++;
+	n = count - 1;
+
+	if (mode == CoordModeOrigin)
+	{
+	    for (; n--; pts++)
+	    {
+		if (pts->x < minx)
+		    minx = pts->x;
+		else if (pts->x > maxx)
+		    maxx = pts->x;
+		if (pts->y < miny)
+		    miny = pts->y;
+		else if (pts->y > maxy)
+		    maxy = pts->y;
+	    }
+	    minx += x;
+	    miny += y;
+	    maxx += x;
+	    maxy += y;
+	}
+	else
+	{
+	    x += minx;
+	    y += miny;
+	    minx = maxx = x;
+	    miny = maxy = y;
+	    for (; n--; pts++)
+	    {
+		x += pts->x;
+		y += pts->y;
+		if (x < minx)
+		    minx = x;
+		else if (x > maxx)
+		    maxx = x;
+		if (y < miny)
+		    miny = y;
+		else if (y > maxy)
+		    maxy = y;
+	    }
+	}
+	if (BOX_OVERLAP(&pScreenPriv->saved,minx,miny,maxx,maxy))
+	    rfbSpriteRemoveCursor (pDrawable->pScreen);
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pPts);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyFillRect(pDrawable, pGC, nrectFill, prectInit)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nrectFill; 	/* number of rectangles to fill */
+    xRectangle	*prectInit;  	/* Pointer to first rectangle to fill */
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register int	    nRect;
+	register xRectangle *pRect;
+	register int	    xorg, yorg;
+
+	xorg = pDrawable->x;
+	yorg = pDrawable->y;
+
+	for (nRect = nrectFill, pRect = prectInit; nRect--; pRect++) {
+	    if (ORGRECT_OVERLAP(&pScreenPriv->saved,xorg,yorg,pRect)){
+		rfbSpriteRemoveCursor(pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrectFill, prectInit);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyFillArc(pDrawable, pGC, narcs, parcs)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		narcs;
+    xArc	*parcs;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register int	n;
+	BoxPtr		cursor;
+	register xArc *arcs;
+
+	cursor = &pScreenPriv->saved;
+
+	for (arcs = parcs, n = narcs; n--; arcs++)
+	{
+	    if (ORG_OVERLAP(cursor, pDrawable->x, pDrawable->y,
+			    arcs->x, arcs->y,
+ 			    (int) arcs->width, (int) arcs->height))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, parcs);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+/*
+ * general Poly/Image text function.  Extract glyph information,
+ * compute bounding box and remove cursor if it is overlapped.
+ */
+
+static Bool
+rfbSpriteTextOverlap (pDraw, font, x, y, n, charinfo, imageblt, w, cursorBox)
+    DrawablePtr   pDraw;
+    FontPtr	  font;
+    int		  x, y;
+    unsigned int  n;
+    CharInfoPtr   *charinfo;
+    Bool	  imageblt;
+    unsigned int  w;
+    BoxPtr	  cursorBox;
+{
+    ExtentInfoRec extents;
+
+    x += pDraw->x;
+    y += pDraw->y;
+
+    if (FONTMINBOUNDS(font,characterWidth) >= 0)
+    {
+	/* compute an approximate (but covering) bounding box */
+	if (!imageblt || (charinfo[0]->metrics.leftSideBearing < 0))
+	    extents.overallLeft = charinfo[0]->metrics.leftSideBearing;
+	else
+	    extents.overallLeft = 0;
+	if (w)
+	    extents.overallRight = w - charinfo[n-1]->metrics.characterWidth;
+	else
+	    extents.overallRight = FONTMAXBOUNDS(font,characterWidth)
+				    * (n - 1);
+	if (imageblt && (charinfo[n-1]->metrics.characterWidth >
+			 charinfo[n-1]->metrics.rightSideBearing))
+	    extents.overallRight += charinfo[n-1]->metrics.characterWidth;
+	else
+	    extents.overallRight += charinfo[n-1]->metrics.rightSideBearing;
+	if (imageblt && FONTASCENT(font) > FONTMAXBOUNDS(font,ascent))
+	    extents.overallAscent = FONTASCENT(font);
+	else
+	    extents.overallAscent = FONTMAXBOUNDS(font, ascent);
+	if (imageblt && FONTDESCENT(font) > FONTMAXBOUNDS(font,descent))
+	    extents.overallDescent = FONTDESCENT(font);
+	else
+	    extents.overallDescent = FONTMAXBOUNDS(font,descent);
+	if (!BOX_OVERLAP(cursorBox,
+			 x + extents.overallLeft,
+			 y - extents.overallAscent,
+			 x + extents.overallRight,
+			 y + extents.overallDescent))
+	    return FALSE;
+	else if (imageblt && w)
+	    return TRUE;
+	/* if it does overlap, fall through and compute exactly, because
+	 * taking down the cursor is expensive enough to make this worth it
+	 */
+    }
+    QueryGlyphExtents(font, charinfo, n, &extents);
+    if (imageblt)
+    {
+	if (extents.overallWidth > extents.overallRight)
+	    extents.overallRight = extents.overallWidth;
+	if (extents.overallWidth < extents.overallLeft)
+	    extents.overallLeft = extents.overallWidth;
+	if (extents.overallLeft > 0)
+	    extents.overallLeft = 0;
+	if (extents.fontAscent > extents.overallAscent)
+	    extents.overallAscent = extents.fontAscent;
+	if (extents.fontDescent > extents.overallDescent)
+	    extents.overallDescent = extents.fontDescent;
+    }
+    return (BOX_OVERLAP(cursorBox,
+			x + extents.overallLeft,
+			y - extents.overallAscent,
+			x + extents.overallRight,
+			y + extents.overallDescent));
+}
+
+/*
+ * values for textType:
+ */
+#define TT_POLY8   0
+#define TT_IMAGE8  1
+#define TT_POLY16  2
+#define TT_IMAGE16 3
+
+static int 
+rfbSpriteText (pDraw, pGC, x, y, count, chars, fontEncoding, textType, cursorBox)
+    DrawablePtr	    pDraw;
+    GCPtr	    pGC;
+    int		    x,
+		    y;
+    unsigned long    count;
+    char	    *chars;
+    FontEncoding    fontEncoding;
+    Bool	    textType;
+    BoxPtr	    cursorBox;
+{
+    CharInfoPtr *charinfo;
+    register CharInfoPtr *info;
+    unsigned long i;
+    unsigned int  n;
+    int		  w;
+    void   	  (*drawFunc)() = NULL;
+
+    Bool imageblt;
+
+    imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16);
+
+    charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr));
+    if (!charinfo)
+	return x;
+
+    GetGlyphs(pGC->font, count, (unsigned char *)chars,
+	      fontEncoding, &i, charinfo);
+    n = (unsigned int)i;
+    w = 0;
+    if (!imageblt)
+	for (info = charinfo; i--; info++)
+	    w += (*info)->metrics.characterWidth;
+
+    if (n != 0) {
+	if (rfbSpriteTextOverlap(pDraw, pGC->font, x, y, n, charinfo, imageblt, w, cursorBox))
+	    rfbSpriteRemoveCursor(pDraw->pScreen);
+
+#ifdef AVOID_GLYPHBLT
+	/*
+	 * On displays like Apollos, which do not optimize the GlyphBlt functions because they
+	 * convert fonts to their internal form in RealizeFont and optimize text directly, we
+	 * want to invoke the text functions here, not the GlyphBlt functions.
+	 */
+	switch (textType)
+	{
+	case TT_POLY8:
+	    drawFunc = (void (*)())pGC->ops->PolyText8;
+	    break;
+	case TT_IMAGE8:
+	    drawFunc = pGC->ops->ImageText8;
+	    break;
+	case TT_POLY16:
+	    drawFunc = (void (*)())pGC->ops->PolyText16;
+	    break;
+	case TT_IMAGE16:
+	    drawFunc = pGC->ops->ImageText16;
+	    break;
+	}
+	(*drawFunc) (pDraw, pGC, x, y, (int) count, chars);
+#else /* don't AVOID_GLYPHBLT */
+	/*
+	 * On the other hand, if the device does use GlyphBlt ultimately to do text, we
+	 * don't want to slow it down by invoking the text functions and having them call
+	 * GetGlyphs all over again, so we go directly to the GlyphBlt functions here.
+	 */
+	drawFunc = imageblt ? pGC->ops->ImageGlyphBlt : pGC->ops->PolyGlyphBlt;
+	(*drawFunc) (pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font));
+#endif /* AVOID_GLYPHBLT */
+    }
+    DEALLOCATE_LOCAL(charinfo);
+    return x + w;
+}
+
+static int
+rfbSpritePolyText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int 	count;
+    char	*chars;
+{
+    int	ret;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, chars,
+			    Linear8Bit, TT_POLY8, &pScreenPriv->saved);
+    else
+	ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+    return ret;
+}
+
+static int
+rfbSpritePolyText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    int	ret;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count,
+			    (char *)chars,
+			    FONTLASTROW(pGC->font) == 0 ?
+			    Linear16Bit : TwoD16Bit, TT_POLY16, &pScreenPriv->saved);
+    else
+	ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+    return ret;
+}
+
+static void
+rfbSpriteImageText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    char	*chars;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	(void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count,
+			     chars, Linear8Bit, TT_IMAGE8, &pScreenPriv->saved);
+    else
+	(*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteImageText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	(void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count,
+			     (char *)chars,
+			    FONTLASTROW(pGC->font) == 0 ?
+			    Linear16Bit : TwoD16Bit, TT_IMAGE16, &pScreenPriv->saved);
+    else
+	(*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer 	pglyphBase;	/* start of array of glyphs */
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable) &&
+	rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, TRUE, 0, &pScreenPriv->saved))
+    {
+	rfbSpriteRemoveCursor(pDrawable->pScreen);
+    }
+    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer	pglyphBase;	/* start of array of glyphs */
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable) &&
+	rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, FALSE, 0, &pScreenPriv->saved))
+    {
+	rfbSpriteRemoveCursor(pDrawable->pScreen);
+    }
+    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePushPixels(pGC, pBitMap, pDrawable, w, h, x, y)
+    GCPtr	pGC;
+    PixmapPtr	pBitMap;
+    DrawablePtr pDrawable;
+    int		w, h, x, y;
+{
+    VNCSCREENPTR(pGC->pScreen);
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable) &&
+	ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,x,y,w,h))
+    {
+	rfbSpriteRemoveCursor (pDrawable->pScreen);
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+#ifdef NEED_LINEHELPER
+/*
+ * I don't expect this routine will ever be called, as the GC
+ * will have been unwrapped for the line drawing
+ */
+
+static void
+rfbSpriteLineHelper()
+{
+    FatalError("rfbSpriteLineHelper called\n");
+}
+#endif
+
+#ifdef RENDER
+
+# define mod(a,b)	((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
+
+static void
+rfbSpritePictureOverlap (PicturePtr  pPict,
+			INT16	    x,
+			INT16	    y,
+			CARD16	    w,
+			CARD16	    h)
+{
+    VNCSCREENPTR(pPict->pDrawable->pScreen);
+
+    if (pPict->pDrawable->type == DRAWABLE_WINDOW)
+    {
+	WindowPtr		pWin = (WindowPtr) (pPict->pDrawable);
+	rfbSpriteScreenPtr	pScreenPriv = (rfbSpriteScreenPtr)
+	    pPict->pDrawable->pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+	if (GC_CHECK(pWin))
+	{
+	    if (pPict->repeat)
+	    {
+		x = mod(x,pWin->drawable.width);
+		y = mod(y,pWin->drawable.height);
+	    }
+	    if (ORG_OVERLAP (&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y,
+			     x, y, w, h))
+		rfbSpriteRemoveCursor (pWin->drawable.pScreen);
+	}
+    }
+}
+
+#define PICTURE_PROLOGUE(ps, pScreenPriv, field) \
+    ps->field = pScreenPriv->field
+
+#define PICTURE_EPILOGUE(ps, field, wrap) \
+    ps->field = wrap
+
+static void
+rfbSpriteComposite(CARD8	op,
+		  PicturePtr pSrc,
+		  PicturePtr pMask,
+		  PicturePtr pDst,
+		  INT16	xSrc,
+		  INT16	ySrc,
+		  INT16	xMask,
+		  INT16	yMask,
+		  INT16	xDst,
+		  INT16	yDst,
+		  CARD16	width,
+		  CARD16	height)
+{
+    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
+    PictureScreenPtr	ps = GetPictureScreen(pScreen);
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    PICTURE_PROLOGUE(ps, pScreenPriv, Composite);
+    rfbSpritePictureOverlap (pSrc, xSrc, ySrc, width, height);
+    if (pMask)
+	rfbSpritePictureOverlap (pMask, xMask, yMask, width, height);
+    rfbSpritePictureOverlap (pDst, xDst, yDst, width, height);
+
+    (*ps->Composite) (op,
+		       pSrc,
+		       pMask,
+		       pDst,
+		       xSrc,
+		       ySrc,
+		       xMask,
+		       yMask,
+		       xDst,
+		       yDst,
+		       width,
+		       height);
+    
+    PICTURE_EPILOGUE(ps, Composite, rfbSpriteComposite);
+}
+
+static void
+rfbSpriteGlyphs(CARD8		op,
+	       PicturePtr	pSrc,
+	       PicturePtr	pDst,
+	       PictFormatPtr	maskFormat,
+	       INT16		xSrc,
+	       INT16		ySrc,
+	       int		nlist,
+	       GlyphListPtr	list,
+	       GlyphPtr		*glyphs)
+{
+    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    PictureScreenPtr	ps = GetPictureScreen(pScreen);
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    PICTURE_PROLOGUE(ps, pScreenPriv, Glyphs);
+    if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
+    {
+	WindowPtr   pSrcWin = (WindowPtr) (pSrc->pDrawable);
+
+	if (GC_CHECK(pSrcWin))
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+    if (pDst->pDrawable->type == DRAWABLE_WINDOW)
+    {
+	WindowPtr   pDstWin = (WindowPtr) (pDst->pDrawable);
+
+	if (GC_CHECK(pDstWin))
+	{
+	    BoxRec  extents;
+
+	    miGlyphExtents (nlist, list, glyphs, &extents);
+	    if (BOX_OVERLAP(&pScreenPriv->saved,
+			    extents.x1 + pDstWin->drawable.x,
+			    extents.y1 + pDstWin->drawable.y,
+			    extents.x2 + pDstWin->drawable.x,
+			    extents.y2 + pDstWin->drawable.y))
+	    {
+		rfbSpriteRemoveCursor (pScreen);
+	    }
+	}
+    }
+    
+    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+    
+    PICTURE_EPILOGUE (ps, Glyphs, rfbSpriteGlyphs);
+}
+#endif
+
+/*
+ * miPointer interface routines
+ */
+
+#define SPRITE_PAD 8
+
+static Bool
+rfbSpriteRealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pCursor == pScreenPriv->pCursor)
+	pScreenPriv->checkPixels = TRUE;
+    return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor);
+}
+
+static Bool
+rfbSpriteUnrealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor);
+}
+
+static void
+rfbSpriteSetCursor (pScreen, pCursor, x, y)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+    rfbClientPtr cl, nextCl;
+    VNCSCREENPTR(pScreen);
+
+    pScreenPriv
+	= (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (!pCursor)
+    {
+    	pScreenPriv->shouldBeUp = FALSE;
+    	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor (pScreen);
+	pScreenPriv->pCursor = 0;
+	return;
+    }
+    pScreenPriv->shouldBeUp = TRUE;
+    if (pScreenPriv->x == x &&
+	pScreenPriv->y == y &&
+	pScreenPriv->pCursor == pCursor &&
+	!pScreenPriv->checkPixels)
+    {
+	return;
+    }
+    pScreenPriv->x = x;
+    pScreenPriv->y = y;
+    pScreenPriv->pCacheWin = NullWindow;
+    if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor)
+    {
+	pScreenPriv->pCursor = pCursor;
+	rfbSpriteFindColors (pScreen);
+    }
+    if (pVNC->cursorIsDrawn) {
+	int	sx, sy;
+	/*
+	 * check to see if the old saved region
+	 * encloses the new sprite, in which case we use
+	 * the flicker-free MoveCursor primitive.
+	 */
+	sx = pScreenPriv->x - (int)pCursor->bits->xhot;
+	sy = pScreenPriv->y - (int)pCursor->bits->yhot;
+	if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 &&
+	    sx < pScreenPriv->saved.x2 &&
+	    sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 &&
+	    sy < pScreenPriv->saved.y2 &&
+	    (int) pCursor->bits->width + (2 * SPRITE_PAD) ==
+		pScreenPriv->saved.x2 - pScreenPriv->saved.x1 &&
+	    (int) pCursor->bits->height + (2 * SPRITE_PAD) ==
+		pScreenPriv->saved.y2 - pScreenPriv->saved.y1
+	    )
+	{
+	    pVNC->cursorIsDrawn = FALSE;
+	    if (!(sx >= pScreenPriv->saved.x1 &&
+	      	  sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 &&
+	      	  sy >= pScreenPriv->saved.y1 &&
+	      	  sy + (int)pCursor->bits->height < pScreenPriv->saved.y2))
+	    {
+		int oldx1, oldy1, dx, dy;
+
+		oldx1 = pScreenPriv->saved.x1;
+		oldy1 = pScreenPriv->saved.y1;
+		dx = oldx1 - (sx - SPRITE_PAD);
+		dy = oldy1 - (sy - SPRITE_PAD);
+		pScreenPriv->saved.x1 -= dx;
+		pScreenPriv->saved.y1 -= dy;
+		pScreenPriv->saved.x2 -= dx;
+		pScreenPriv->saved.y2 -= dy;
+		(void) (*pScreenPriv->funcs->ChangeSave) (pScreen,
+				pScreenPriv->saved.x1,
+ 				pScreenPriv->saved.y1,
+				pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+				pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
+				dx, dy);
+	    }
+	    (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor,
+				  pScreenPriv->saved.x1,
+ 				  pScreenPriv->saved.y1,
+				  pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+				  pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
+				  sx - pScreenPriv->saved.x1,
+				  sy - pScreenPriv->saved.y1,
+				  pScreenPriv->colors[SOURCE_COLOR].pixel,
+				  pScreenPriv->colors[MASK_COLOR].pixel);
+	    pVNC->cursorIsDrawn = TRUE;
+	}
+	else
+	{
+	    rfbSpriteRemoveCursor (pScreen);
+	}
+    }
+#if 0
+    if (!pVNC->cursorIsDrawn && pScreenPriv->pCursor)
+	rfbSpriteRestoreCursor (pScreen);
+#endif
+    if (pVNC->cursorIsDrawn)
+	rfbSpriteRemoveCursor (pScreen);
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (cl->enableCursorPosUpdates) {
+	    if (x == cl->cursorX && y == cl->cursorY) {
+		cl->cursorWasMoved = FALSE;
+		continue;
+	    }
+	    cl->cursorWasMoved = TRUE;
+	}
+	if (REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) {
+	    /* cursorIsDrawn is guaranteed to be FALSE here, so we definitely
+	       want to send a screen update to the client, even if that's only
+	       putting up the cursor */
+	    rfbSendFramebufferUpdate(pScreen, cl);
+	}
+    }
+}
+
+static void
+rfbSpriteMoveCursor (pScreen, x, y)
+    ScreenPtr	pScreen;
+    int		x, y;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    rfbSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y);
+}
+
+/*
+ * undraw/draw cursor
+ */
+
+void
+rfbSpriteRemoveCursor (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+    VNCSCREENPTR(pScreen);
+
+    if (!pVNC->cursorIsDrawn)
+	return;
+
+    pScreenPriv
+	= (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    pVNC->dontSendFramebufferUpdate = TRUE;
+    pVNC->cursorIsDrawn = FALSE;
+    pScreenPriv->pCacheWin = NullWindow;
+    if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen,
+					 pScreenPriv->saved.x1,
+					 pScreenPriv->saved.y1,
+					 pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+					 pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
+    {
+	pVNC->cursorIsDrawn = TRUE;
+    }
+    pVNC->dontSendFramebufferUpdate = FALSE;
+}
+
+
+void
+rfbSpriteRestoreCursor (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+    int			x, y;
+    CursorPtr		pCursor;
+    VNCSCREENPTR(pScreen);
+
+    pScreenPriv
+	= (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    pCursor = pScreenPriv->pCursor;
+
+    if (pVNC->cursorIsDrawn || !pCursor)
+	return;
+
+    pVNC->dontSendFramebufferUpdate = TRUE;
+
+    rfbSpriteComputeSaved (pScreen);
+
+    x = pScreenPriv->x - (int)pCursor->bits->xhot;
+    y = pScreenPriv->y - (int)pCursor->bits->yhot;
+    if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen,
+				      pScreenPriv->saved.x1,
+				      pScreenPriv->saved.y1,
+				      pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+				      pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
+    {
+	if (pScreenPriv->checkPixels)
+	    rfbSpriteFindColors (pScreen);
+	if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y,
+				  pScreenPriv->colors[SOURCE_COLOR].pixel,
+				  pScreenPriv->colors[MASK_COLOR].pixel))
+	    pVNC->cursorIsDrawn = TRUE;
+    }
+
+    pVNC->dontSendFramebufferUpdate = FALSE;
+}
+
+/*
+ * compute the desired area of the screen to save
+ */
+
+static void
+rfbSpriteComputeSaved (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+    int		    x, y, w, h;
+    int		    wpad, hpad;
+    CursorPtr	    pCursor;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    pCursor = pScreenPriv->pCursor;
+    x = pScreenPriv->x - (int)pCursor->bits->xhot;
+    y = pScreenPriv->y - (int)pCursor->bits->yhot;
+    w = pCursor->bits->width;
+    h = pCursor->bits->height;
+    wpad = SPRITE_PAD;
+    hpad = SPRITE_PAD;
+    pScreenPriv->saved.x1 = x - wpad;
+    pScreenPriv->saved.y1 = y - hpad;
+    pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2;
+    pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2;
+}
+
+
+/*
+ * this function is called when the cursor shape is being changed
+ */
+
+static Bool
+rfbDisplayCursor(pScreen, pCursor)
+    ScreenPtr pScreen;
+    CursorPtr pCursor;
+{
+    rfbClientPtr cl;
+    rfbSpriteScreenPtr pPriv;
+
+    for (cl = rfbClientHead; cl ; cl = cl->next) {
+	if (cl->enableCursorShapeUpdates)
+	    cl->cursorWasChanged = TRUE;
+    }
+
+    pPriv = (rfbSpriteScreenPtr)pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    return (*pPriv->DisplayCursor)(pScreen, pCursor);
+}
+
+
+/*
+ * obtain current cursor pointer
+ */
+
+CursorPtr
+rfbSpriteGetCursorPtr (pScreen)
+    ScreenPtr pScreen;
+{
+    rfbSpriteScreenPtr pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr)
+	pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    return pScreenPriv->pCursor;
+}
+
+/*
+ * obtain current cursor position
+ */
+
+void
+rfbSpriteGetCursorPos (pScreen, px, py)
+    ScreenPtr pScreen;
+    int *px, *py;
+{
+    rfbSpriteScreenPtr pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr)
+	pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    *px = pScreenPriv->x;
+    *py = pScreenPriv->y;
+}
+
diff -u -rNp a/hw/dmx/vnc/sprite.h b/hw/dmx/vnc/sprite.h
--- a/hw/dmx/vnc/sprite.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/sprite.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,141 @@
+/*
+ * sprite.h
+ *
+ * software-sprite/sprite drawing - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+typedef struct {
+    Bool	(*RealizeCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/
+);
+    Bool	(*UnrealizeCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/
+);
+    Bool	(*PutUpCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/,
+		int /*x*/,
+		int /*y*/,
+		unsigned long /*source*/,
+		unsigned long /*mask*/
+);
+    Bool	(*SaveUnderCursor)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/
+);
+    Bool	(*RestoreUnderCursor)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/
+);
+    Bool	(*MoveCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/,
+		int /*dx*/,
+		int /*dy*/,
+		unsigned long /*source*/,
+		unsigned long /*mask*/
+);
+    Bool	(*ChangeSave)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/,
+		int /*dx*/,
+		int /*dy*/
+);
+
+} rfbSpriteCursorFuncRec, *rfbSpriteCursorFuncPtr;
+
+extern Bool rfbSpriteInitialize(
+#if NeedFunctionPrototypes
+    ScreenPtr /*pScreen*/,
+    rfbSpriteCursorFuncPtr /*cursorFuncs*/,
+    miPointerScreenFuncPtr /*screenFuncs*/
+#endif
+);
+
+extern void rfbSpriteRestoreCursor(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern void rfbSpriteRemoveCursor(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern CursorPtr rfbSpriteGetCursorPtr(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern void rfbSpriteGetCursorPos(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/,
+    int *       /*px*/,
+    int *       /*py*/
+#endif
+);
diff -u -rNp a/hw/dmx/vnc/spritest.h b/hw/dmx/vnc/spritest.h
--- a/hw/dmx/vnc/spritest.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/spritest.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,138 @@
+/*
+ * spritest.h
+ *
+ * sprite structures - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+# include   "sprite.h"
+
+#ifdef RENDER
+# include   "picturestr.h"
+#endif
+
+/*
+ * per screen information
+ */
+
+typedef struct {
+    CloseScreenProcPtr			CloseScreen;
+    GetImageProcPtr			GetImage;
+    GetSpansProcPtr			GetSpans;
+    SourceValidateProcPtr		SourceValidate;
+    CreateGCProcPtr			CreateGC;
+    ScreenBlockHandlerProcPtr		BlockHandler;
+    InstallColormapProcPtr		InstallColormap;
+    StoreColorsProcPtr			StoreColors;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    SaveDoomedAreasProcPtr		SaveDoomedAreas;
+    RestoreAreasProcPtr			RestoreAreas;
+    DisplayCursorProcPtr		DisplayCursor;
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+    GlyphsProcPtr			Glyphs;
+#endif
+
+    CursorPtr	    pCursor;
+    int		    x;
+    int		    y;
+    Bool	    shouldBeUp;
+    BoxRec	    saved;
+    WindowPtr	    pCacheWin;
+    Bool	    isInCacheWin;
+    Bool	    checkPixels;
+    xColorItem	    colors[2];
+    ColormapPtr	    pInstalledMap;
+    ColormapPtr	    pColormap;
+    VisualPtr	    pVisual;
+    rfbSpriteCursorFuncPtr    funcs;
+} rfbSpriteScreenRec, *rfbSpriteScreenPtr;
+
+#define SOURCE_COLOR	0
+#define MASK_COLOR	1
+
+typedef struct {
+    GCFuncs		*wrapFuncs;
+    GCOps		*wrapOps;
+} rfbSpriteGCRec, *rfbSpriteGCPtr;
+
+/*
+ * Overlap BoxPtr and Box elements
+ */
+#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
+ 	(((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
+	 ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
+
+/*
+ * Overlap BoxPtr, origins, and rectangle
+ */
+#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
+    BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
+
+/*
+ * Overlap BoxPtr, origins and RectPtr
+ */
+#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
+    ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
+		(int)((pRect)->width), (int)((pRect)->height))
+/*
+ * Overlap BoxPtr and horizontal span
+ */
+#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
+
+#define LINE_SORT(x1,y1,x2,y2) \
+{ int _t; \
+  if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
+  if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
+
+#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
+    BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
diff -u -rNp a/hw/dmx/vnc/stats.c b/hw/dmx/vnc/stats.c
--- a/hw/dmx/vnc/stats.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/stats.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * stats.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "rfb.h"
+
+static char* encNames[] = {
+    "raw", "copyRect", "RRE", "[encoding 3]", "CoRRE", "hextile",
+    "zlib", "tight", "[encoding 8]", "[encoding 9]"
+};
+
+
+void
+rfbResetStats(rfbClientPtr cl)
+{
+    int i;
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	cl->rfbBytesSent[i] = 0;
+	cl->rfbRectanglesSent[i] = 0;
+    }
+    cl->rfbLastRectMarkersSent = 0;
+    cl->rfbLastRectBytesSent = 0;
+    cl->rfbCursorShapeBytesSent = 0;
+    cl->rfbCursorShapeUpdatesSent = 0;
+    cl->rfbCursorPosBytesSent = 0;
+    cl->rfbCursorPosUpdatesSent = 0;
+    cl->rfbFramebufferUpdateMessagesSent = 0;
+    cl->rfbRawBytesEquivalent = 0;
+    cl->rfbKeyEventsRcvd = 0;
+    cl->rfbPointerEventsRcvd = 0;
+}
+
+void
+rfbPrintStats(rfbClientPtr cl)
+{
+    int i;
+    int totalRectanglesSent = 0;
+    int totalBytesSent = 0;
+
+    rfbLog("Statistics:\n");
+
+    if ((cl->rfbKeyEventsRcvd != 0) || (cl->rfbPointerEventsRcvd != 0))
+	rfbLog("  key events received %d, pointer events %d\n",
+		cl->rfbKeyEventsRcvd, cl->rfbPointerEventsRcvd);
+
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	totalRectanglesSent += cl->rfbRectanglesSent[i];
+	totalBytesSent += cl->rfbBytesSent[i];
+    }
+    totalRectanglesSent += (cl->rfbCursorShapeUpdatesSent +
+			    cl->rfbCursorPosUpdatesSent +
+			    cl->rfbLastRectMarkersSent);
+    totalBytesSent += (cl->rfbCursorShapeBytesSent +
+		       cl->rfbCursorPosBytesSent +
+		       cl->rfbLastRectBytesSent);
+
+    rfbLog("  framebuffer updates %d, rectangles %d, bytes %d\n",
+	    cl->rfbFramebufferUpdateMessagesSent, totalRectanglesSent,
+	    totalBytesSent);
+
+    if (cl->rfbLastRectMarkersSent != 0)
+	rfbLog("    LastRect markers %d, bytes %d\n",
+		cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent);
+
+    if (cl->rfbCursorShapeUpdatesSent != 0)
+	rfbLog("    cursor shape updates %d, bytes %d\n",
+		cl->rfbCursorShapeUpdatesSent, cl->rfbCursorShapeBytesSent);
+
+    if (cl->rfbCursorPosUpdatesSent != 0)
+	rfbLog("    cursor position updates %d, bytes %d\n",
+	       cl->rfbCursorPosUpdatesSent, cl->rfbCursorPosBytesSent);
+
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	if (cl->rfbRectanglesSent[i] != 0)
+	    rfbLog("    %s rectangles %d, bytes %d\n",
+		   encNames[i], cl->rfbRectanglesSent[i], cl->rfbBytesSent[i]);
+    }
+
+    if ((totalBytesSent - cl->rfbBytesSent[rfbEncodingCopyRect]) != 0) {
+	rfbLog("  raw bytes equivalent %d, compression ratio %f\n",
+		cl->rfbRawBytesEquivalent,
+		(double)cl->rfbRawBytesEquivalent
+		/ (double)(totalBytesSent -
+			   cl->rfbBytesSent[rfbEncodingCopyRect] -
+			   cl->rfbCursorShapeBytesSent -
+			   cl->rfbCursorPosBytesSent -
+			   cl->rfbLastRectBytesSent));
+    }
+}
diff -u -rNp a/hw/dmx/vnc/tableinitcmtemplate.c b/hw/dmx/vnc/tableinitcmtemplate.c
--- a/hw/dmx/vnc/tableinitcmtemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/tableinitcmtemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,89 @@
+/*
+ * tableinitcmtemplate.c - template for initialising lookup tables for
+ * translation from a colour map to true colour.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines a function which allocates an
+ * appropriately sized lookup table and initialises it.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT2E(CARD,OUT)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitColourMapSingleTableOUT \
+				CONCAT2E(rfbInitColourMapSingleTable,OUT)
+
+static void
+rfbInitColourMapSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				rfbPixelFormat *out)
+{
+    VNCSCREENPTR(pScreen);
+    int i, r, g, b;
+    OUT_T *t;
+    EntryPtr pent;
+    int nEntries = 1 << in->bitsPerPixel;
+
+    if (*table) free(*table);
+    *table = (char *)malloc(nEntries * sizeof(OUT_T));
+    t = (OUT_T *)*table;
+
+#if XFREE86VNC
+    pent = (EntryPtr)&miInstalledMaps[pScreen->myNum]->red[0];
+#else
+    pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[0];
+#endif
+
+    for (i = 0; i < nEntries; i++) {
+	if (pent->fShared) {
+	    r = pent->co.shco.red->color;
+	    g = pent->co.shco.green->color;
+	    b = pent->co.shco.blue->color;
+	} else {
+	    r = pent->co.local.red;
+	    g = pent->co.local.green;
+	    b = pent->co.local.blue;
+	}
+	t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) |
+		(((g * out->greenMax + 32767) / 65535) << out->greenShift) |
+		(((b * out->blueMax + 32767) / 65535) << out->blueShift));
+#if (OUT != 8)
+	if (out->bigEndian != in->bigEndian) {
+	    t[i] = SwapOUT(t[i]);
+	}
+#endif
+	pent++;
+    }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitColourMapSingleTableOUT
diff -u -rNp a/hw/dmx/vnc/tableinittctemplate.c b/hw/dmx/vnc/tableinittctemplate.c
--- a/hw/dmx/vnc/tableinittctemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/tableinittctemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ * tableinittctemplate.c - template for initialising lookup tables for
+ * truecolour to truecolour translation.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines two functions for initialising
+ * lookup tables.  One is for truecolour translation using a single lookup
+ * table, the other is for truecolour translation using three separate
+ * lookup tables for the red, green and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT2E(CARD,OUT)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitTrueColourSingleTableOUT \
+				CONCAT2E(rfbInitTrueColourSingleTable,OUT)
+#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT)
+#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT)
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+		       int swap);
+
+
+/*
+ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
+ * translation.
+ */
+
+static void
+rfbInitTrueColourSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				 rfbPixelFormat *out)
+{
+    int i;
+    int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
+    OUT_T *t;
+    int nEntries = 1 << in->bitsPerPixel;
+
+    if (*table) free(*table);
+    *table = (char *)malloc(nEntries * sizeof(OUT_T));
+    t = (OUT_T *)*table;
+
+    for (i = 0; i < nEntries; i++) {
+	inRed   = (i >> in->redShift)   & in->redMax;
+	inGreen = (i >> in->greenShift) & in->greenMax;
+	inBlue  = (i >> in->blueShift)  & in->blueMax;
+
+	outRed   = (inRed   * out->redMax   + in->redMax / 2)   / in->redMax;
+	outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
+	outBlue  = (inBlue  * out->blueMax  + in->blueMax / 2)  / in->blueMax;
+
+	t[i] = ((outRed   << out->redShift)   |
+		(outGreen << out->greenShift) |
+		(outBlue  << out->blueShift));
+#if (OUT != 8)
+	if (out->bigEndian != in->bigEndian) {
+	    t[i] = SwapOUT(t[i]);
+	}
+#endif
+    }
+}
+
+
+/*
+ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the
+ * red, green and blue values.
+ */
+
+static void
+rfbInitTrueColourRGBTablesOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+			       rfbPixelFormat *out)
+{
+    OUT_T *redTable;
+    OUT_T *greenTable;
+    OUT_T *blueTable;
+
+    if (*table) free(*table);
+    *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
+			    * sizeof(OUT_T));
+    redTable = (OUT_T *)*table;
+    greenTable = redTable + in->redMax + 1;
+    blueTable = greenTable + in->greenMax + 1;
+
+    rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax,
+			   out->redShift, (out->bigEndian != in->bigEndian));
+    rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax,
+			   out->greenShift, (out->bigEndian != in->bigEndian));
+    rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax,
+			   out->blueShift, (out->bigEndian != in->bigEndian));
+}
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+		       int swap)
+{
+    int i;
+    int nEntries = inMax + 1;
+
+    for (i = 0; i < nEntries; i++) {
+	table[i] = ((i * outMax + inMax / 2) / inMax) << outShift;
+#if (OUT != 8)
+	if (swap) {
+	    table[i] = SwapOUT(table[i]);
+	}
+#endif
+    }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitTrueColourSingleTableOUT
+#undef rfbInitTrueColourRGBTablesOUT
+#undef rfbInitOneRGBTableOUT
diff -u -rNp a/hw/dmx/vnc/tabletranstemplate.c b/hw/dmx/vnc/tabletranstemplate.c
--- a/hw/dmx/vnc/tabletranstemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/tabletranstemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,119 @@
+/*
+ * tabletranstemplate.c - template for translation using lookup tables.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with different definitions of the macros IN and OUT.
+ *
+ * For each pair of values IN and OUT, this file defines two functions for
+ * translating a given rectangle of pixel data.  One uses a single lookup
+ * table, and the other uses three separate lookup tables for the red, green
+ * and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(IN) || !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define IN_T CONCAT2E(CARD,IN)
+#define OUT_T CONCAT2E(CARD,OUT)
+#define rfbTranslateWithSingleTableINtoOUT \
+				CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT)
+#define rfbTranslateWithRGBTablesINtoOUT \
+				CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT)
+
+/*
+ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTableINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+				    rfbPixelFormat *out,
+				    unsigned char *iptr, char *optr,
+				    int bytesBetweenInputLines,
+				    int width, int height,
+				    int x, int y)
+{
+    IN_T *ip = (IN_T *)iptr;
+    OUT_T *op = (OUT_T *)optr;
+    int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+    OUT_T *opLineEnd;
+    OUT_T *t = (OUT_T *)table;
+
+    while (height > 0) {
+	opLineEnd = op + width;
+
+	while (op < opLineEnd) {
+	    *(op++) = t[*(ip++)];
+	}
+
+	ip += ipextra;
+	height--;
+    }
+}
+
+
+/*
+ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTablesINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+				  rfbPixelFormat *out,
+				  unsigned char *iptr, char *optr,
+				  int bytesBetweenInputLines,
+				  int width, int height,
+				  int x, int y)
+{
+    IN_T *ip = (IN_T *)iptr;
+    OUT_T *op = (OUT_T *)optr;
+    int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+    OUT_T *opLineEnd;
+    OUT_T *redTable = (OUT_T *)table;
+    OUT_T *greenTable = redTable + in->redMax + 1;
+    OUT_T *blueTable = greenTable + in->greenMax + 1;
+
+    while (height > 0) {
+	opLineEnd = op + width;
+
+	while (op < opLineEnd) {
+	    *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] |
+		       greenTable[(*ip >> in->greenShift) & in->greenMax] |
+		       blueTable[(*ip >> in->blueShift) & in->blueMax]);
+	    ip++;
+	}
+	ip += ipextra;
+	height--;
+    }
+}
+
+#undef IN_T
+#undef OUT_T
+#undef rfbTranslateWithSingleTableINtoOUT
+#undef rfbTranslateWithRGBTablesINtoOUT
diff -u -rNp a/hw/dmx/vnc/tight.c b/hw/dmx/vnc/tight.c
--- a/hw/dmx/vnc/tight.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/tight.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1827 @@
+/*
+ * tight.c
+ *
+ * Routines to implement Tight Encoding
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "rfb.h"
+#include <jpeglib.h>
+
+
+/* Note: The following constant should not be changed. */
+#define TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define MIN_SPLIT_RECT_SIZE     4096
+#define MIN_SOLID_SUBRECT_SIZE  2048
+#define MAX_SPLIT_TILE_SIZE       16
+
+/* May be set to TRUE with "-lazytight" Xvnc option. */
+Bool rfbTightDisableGradient = FALSE;
+
+/* This variable is set on every rfbSendRectEncodingTight() call. */
+static Bool usePixelFormat24;
+
+
+/* Compression level stuff. The following array contains various
+   encoder parameters for each of 10 compression levels (0..9).
+   Last three parameters correspond to JPEG quality levels (0..9). */
+
+typedef struct TIGHT_CONF_s {
+    int maxRectSize, maxRectWidth;
+    int monoMinRectSize, gradientMinRectSize;
+    int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel;
+    int gradientThreshold, gradientThreshold24;
+    int idxMaxColorsDivisor;
+    int jpegQuality, jpegThreshold, jpegThreshold24;
+} TIGHT_CONF;
+
+static TIGHT_CONF tightConf[10] = {
+    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
+    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
+    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
+    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
+    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
+    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
+    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
+    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
+    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
+    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
+};
+
+/* Stuff dealing with palettes. */
+
+typedef struct COLOR_LIST_s {
+    struct COLOR_LIST_s *next;
+    int idx;
+    CARD32 rgb;
+} COLOR_LIST;
+
+typedef struct PALETTE_ENTRY_s {
+    COLOR_LIST *listNode;
+    int numPixels;
+} PALETTE_ENTRY;
+
+typedef struct PALETTE_s {
+    PALETTE_ENTRY entry[256];
+    COLOR_LIST *hash[256];
+    COLOR_LIST list[256];
+} PALETTE;
+
+static int paletteNumColors, paletteMaxColors;
+static CARD32 monoBackground, monoForeground;
+static PALETTE palette;
+
+/* Pointers to dynamically-allocated buffers. */
+
+static int tightBeforeBufSize = 0;
+static char *tightBeforeBuf = NULL;
+
+static int tightAfterBufSize = 0;
+static char *tightAfterBuf = NULL;
+
+static int *prevRowBuf = NULL;
+
+
+/* Prototypes for static functions. */
+
+static void FindBestSolidArea (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 colorValue, int *w_ptr, int *h_ptr);
+static void ExtendSolidArea   (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 colorValue,
+                               int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
+static Bool CheckSolidTile    (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile8   (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile16  (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile32  (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+
+static Bool SendRectSimple    (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendSubrect       (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendTightHeader   (rfbClientPtr cl, int x, int y, int w, int h);
+
+static Bool SendSolidRect     (rfbClientPtr cl);
+static Bool SendMonoRect      (rfbClientPtr cl, int w, int h);
+static Bool SendIndexedRect   (rfbClientPtr cl, int w, int h);
+static Bool SendFullColorRect (rfbClientPtr cl, int w, int h);
+static Bool SendGradientRect  (rfbClientPtr cl, int w, int h);
+
+static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen,
+                         int zlibLevel, int zlibStrategy);
+static Bool SendCompressedData(rfbClientPtr cl, int compressedLen);
+
+static void FillPalette8(int count);
+static void FillPalette16(int count);
+static void FillPalette32(int count);
+
+static void PaletteReset(void);
+static int PaletteInsert(CARD32 rgb, int numPixels, int bpp);
+
+static void Pack24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int count);
+
+static void EncodeIndexedRect16(CARD8 *buf, int count);
+static void EncodeIndexedRect32(CARD8 *buf, int count);
+
+static void EncodeMonoRect8(CARD8 *buf, int w, int h);
+static void EncodeMonoRect16(CARD8 *buf, int w, int h);
+static void EncodeMonoRect32(CARD8 *buf, int w, int h);
+
+static void FilterGradient24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient16(ScreenPtr pScreen, CARD16 *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient32(ScreenPtr pScreen, CARD32 *buf, rfbPixelFormat *fmt, int w, int h);
+
+static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+
+static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
+                         int quality);
+static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+
+static void JpegInitDestination(j_compress_ptr cinfo);
+static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo);
+static void JpegTermDestination(j_compress_ptr cinfo);
+static void JpegSetDstManager(j_compress_ptr cinfo);
+
+
+/*
+ * Tight encoding implementation.
+ */
+
+int
+rfbNumCodedRectsTight(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    int maxRectSize, maxRectWidth;
+    int subrectMaxWidth, subrectMaxHeight;
+
+    /* No matter how many rectangles we will send if LastRect markers
+       are used to terminate rectangle stream. */
+    if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
+      return 0;
+
+    maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+    maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+    if (w > maxRectWidth || w * h > maxRectSize) {
+        subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        subrectMaxHeight = maxRectSize / subrectMaxWidth;
+        return (((w - 1) / maxRectWidth + 1) *
+                ((h - 1) / subrectMaxHeight + 1));
+    } else {
+        return 1;
+    }
+}
+
+Bool
+rfbSendRectEncodingTight(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int nMaxRows;
+    CARD32 colorValue;
+    int dx, dy, dw, dh;
+    int x_best, y_best, w_best, h_best;
+    unsigned char *fbptr;
+
+    if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
+         cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
+        usePixelFormat24 = TRUE;
+    } else {
+        usePixelFormat24 = FALSE;
+    }
+
+    if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
+        return SendRectSimple(cl, x, y, w, h);
+
+    /* Make sure we can write at least one pixel into tightBeforeBuf. */
+
+    if (tightBeforeBufSize < 4) {
+        tightBeforeBufSize = 4;
+        if (tightBeforeBuf == NULL)
+            tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+        else
+            tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+                                              tightBeforeBufSize);
+    }
+
+    /* Calculate maximum number of rows in one non-solid rectangle. */
+
+    {
+        int maxRectSize, maxRectWidth, nMaxWidth;
+
+        maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+        maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+        nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        nMaxRows = maxRectSize / nMaxWidth;
+    }
+
+    /* Try to find large solid-color areas and send them separately. */
+
+    for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+        /* If a rectangle becomes too large, send its upper part now. */
+
+        if (dy - y >= nMaxRows) {
+            if (!SendRectSimple(cl, x, y, w, nMaxRows))
+                return 0;
+            y += nMaxRows;
+            h -= nMaxRows;
+        }
+
+        dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+            MAX_SPLIT_TILE_SIZE : (y + h - dy);
+
+        for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
+
+            dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
+                MAX_SPLIT_TILE_SIZE : (x + w - dx);
+
+            if (CheckSolidTile(cl->pScreen, dx, dy, dw, dh, &colorValue, FALSE)) {
+
+                /* Get dimensions of solid-color area. */
+
+                FindBestSolidArea(cl->pScreen, dx, dy, w - (dx - x), h - (dy - y),
+				  colorValue, &w_best, &h_best);
+
+                /* Make sure a solid rectangle is large enough
+                   (or the whole rectangle is of the same color). */
+
+                if ( w_best * h_best != w * h &&
+                     w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
+                    continue;
+
+                /* Try to extend solid rectangle to maximum size. */
+
+                x_best = dx; y_best = dy;
+                ExtendSolidArea(cl->pScreen, x, y, w, h, colorValue,
+                                &x_best, &y_best, &w_best, &h_best);
+
+                /* Send rectangles at top and left to solid-color area. */
+
+                if ( y_best != y &&
+                     !SendRectSimple(cl, x, y, w, y_best-y) )
+                    return FALSE;
+                if ( x_best != x &&
+                     !rfbSendRectEncodingTight(cl, x, y_best,
+                                               x_best-x, h_best) )
+                    return FALSE;
+
+                /* Send solid-color rectangle. */
+
+                if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
+                    return FALSE;
+
+                fbptr = (pVNC->pfbMemory +
+                         (pVNC->paddedWidthInBytes * y_best) +
+                         (x_best * (pVNC->bitsPerPixel / 8)));
+
+                (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+				   &pVNC->rfbServerFormat,
+                                   &cl->format, fbptr, tightBeforeBuf,
+                                   pVNC->paddedWidthInBytes, 1, 1, 
+				   x_best, y_best);
+
+                if (!SendSolidRect(cl))
+                    return FALSE;
+
+                /* Send remaining rectangles (at right and bottom). */
+
+                if ( x_best + w_best != x + w &&
+                     !rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
+                                               w-(x_best-x)-w_best, h_best) )
+                    return FALSE;
+                if ( y_best + h_best != y + h &&
+                     !rfbSendRectEncodingTight(cl, x, y_best+h_best,
+                                               w, h-(y_best-y)-h_best) )
+                    return FALSE;
+
+                /* Return after all recursive calls are done. */
+
+                return TRUE;
+            }
+
+        }
+
+    }
+
+    /* No suitable solid-color rectangles found. */
+
+    return SendRectSimple(cl, x, y, w, h);
+}
+
+static void
+FindBestSolidArea(pScreen, x, y, w, h, colorValue, w_ptr, h_ptr)
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 colorValue;
+    int *w_ptr, *h_ptr;
+{
+    int dx, dy, dw, dh;
+    int w_prev;
+    int w_best = 0, h_best = 0;
+
+    w_prev = w;
+
+    for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+        dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+            MAX_SPLIT_TILE_SIZE : (y + h - dy);
+        dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
+            MAX_SPLIT_TILE_SIZE : w_prev;
+
+        if (!CheckSolidTile(pScreen, x, dy, dw, dh, &colorValue, TRUE))
+            break;
+
+        for (dx = x + dw; dx < x + w_prev;) {
+            dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
+                MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
+            if (!CheckSolidTile(pScreen, dx, dy, dw, dh, &colorValue, TRUE))
+                break;
+	    dx += dw;
+        }
+
+        w_prev = dx - x;
+        if (w_prev * (dy + dh - y) > w_best * h_best) {
+            w_best = w_prev;
+            h_best = dy + dh - y;
+        }
+    }
+
+    *w_ptr = w_best;
+    *h_ptr = h_best;
+}
+
+static void
+ExtendSolidArea(pScreen, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr)
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 colorValue;
+    int *x_ptr, *y_ptr, *w_ptr, *h_ptr;
+{
+    int cx, cy;
+
+    /* Try to extend the area upwards. */
+    for ( cy = *y_ptr - 1;
+          cy >= y && CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+          cy-- );
+    *h_ptr += *y_ptr - (cy + 1);
+    *y_ptr = cy + 1;
+
+    /* ... downwards. */
+    for ( cy = *y_ptr + *h_ptr;
+          cy < y + h &&
+              CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+          cy++ );
+    *h_ptr += cy - (*y_ptr + *h_ptr);
+
+    /* ... to the left. */
+    for ( cx = *x_ptr - 1;
+          cx >= x && CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+          cx-- );
+    *w_ptr += *x_ptr - (cx + 1);
+    *x_ptr = cx + 1;
+
+    /* ... to the right. */
+    for ( cx = *x_ptr + *w_ptr;
+          cx < x + w &&
+              CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+          cx++ );
+    *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successfull, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+static Bool
+CheckSolidTile(pScreen, x, y, w, h, colorPtr, needSameColor) 
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 *colorPtr;
+    Bool needSameColor;
+{
+    VNCSCREENPTR(pScreen);
+    switch(pVNC->rfbServerFormat.bitsPerPixel) {
+    case 32:
+        return CheckSolidTile32(pScreen, x, y, w, h, colorPtr, needSameColor);
+    case 16:
+        return CheckSolidTile16(pScreen, x, y, w, h, colorPtr, needSameColor);
+    default:
+        return CheckSolidTile8(pScreen, x, y, w, h, colorPtr, needSameColor);
+    }
+}
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                      \
+                                                                              \
+static Bool                                                                   \
+CheckSolidTile##bpp(pScreen, x, y, w, h, colorPtr, needSameColor)             \
+    ScreenPtr pScreen;							      \
+    int x, y;                                                                 \
+    CARD32 *colorPtr;                                                         \
+    Bool needSameColor;                                                       \
+{                                                                             \
+    VNCSCREENPTR(pScreen);						      \
+    CARD##bpp *fbptr;                                                         \
+    CARD##bpp colorValue;                                                     \
+    int dx, dy;                                                               \
+                                                                              \
+    fbptr = (CARD##bpp *)                                                     \
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * (bpp/8)]; \
+                                                                              \
+    colorValue = *fbptr;                                                      \
+    if (needSameColor && (CARD32)colorValue != *colorPtr)                     \
+        return FALSE;                                                         \
+                                                                              \
+    for (dy = 0; dy < h; dy++) {                                              \
+        for (dx = 0; dx < w; dx++) {                                          \
+            if (colorValue != fbptr[dx])                                      \
+                return FALSE;                                                 \
+        }                                                                     \
+        fbptr = (CARD##bpp *)((CARD8 *)fbptr + pVNC->paddedWidthInBytes);     \
+    }                                                                         \
+                                                                              \
+    *colorPtr = (CARD32)colorValue;                                           \
+    return TRUE;                                                              \
+}
+
+DEFINE_CHECK_SOLID_FUNCTION(8)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(32)
+
+static Bool
+SendRectSimple(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    int maxBeforeSize, maxAfterSize;
+    int maxRectSize, maxRectWidth;
+    int subrectMaxWidth, subrectMaxHeight;
+    int dx, dy;
+    int rw, rh;
+
+    maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+    maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+    maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
+    maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
+
+    if (tightBeforeBufSize < maxBeforeSize) {
+        tightBeforeBufSize = maxBeforeSize;
+        if (tightBeforeBuf == NULL)
+            tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+        else
+            tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+                                              tightBeforeBufSize);
+    }
+
+    if (tightAfterBufSize < maxAfterSize) {
+        tightAfterBufSize = maxAfterSize;
+        if (tightAfterBuf == NULL)
+            tightAfterBuf = (char *)xalloc(tightAfterBufSize);
+        else
+            tightAfterBuf = (char *)xrealloc(tightAfterBuf,
+                                             tightAfterBufSize);
+    }
+
+    if (w > maxRectWidth || w * h > maxRectSize) {
+        subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        subrectMaxHeight = maxRectSize / subrectMaxWidth;
+
+        for (dy = 0; dy < h; dy += subrectMaxHeight) {
+            for (dx = 0; dx < w; dx += maxRectWidth) {
+                rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
+                rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+                if (!SendSubrect(cl, x+dx, y+dy, rw, rh))
+                    return FALSE;
+            }
+        }
+    } else {
+        if (!SendSubrect(cl, x, y, w, h))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+SendSubrect(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    unsigned char *fbptr;
+    Bool success = FALSE;
+
+    /* Send pending data if there is more than 128 bytes. */
+    if (pVNC->ublen > 128) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    if (!SendTightHeader(cl, x, y, w, h))
+        return FALSE;
+
+    fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+             + (x * (pVNC->bitsPerPixel / 8)));
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+                       &cl->format, fbptr, tightBeforeBuf,
+                       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    paletteMaxColors = w * h / tightConf[cl->tightCompressLevel].idxMaxColorsDivisor;
+    if ( paletteMaxColors < 2 &&
+         w * h >= tightConf[cl->tightCompressLevel].monoMinRectSize ) {
+        paletteMaxColors = 2;
+    }
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+        FillPalette8(w * h);
+        break;
+    case 16:
+        FillPalette16(w * h);
+        break;
+    default:
+        FillPalette32(w * h);
+    }
+
+    switch (paletteNumColors) {
+    case 0:
+        /* Truecolor image */
+        if (DetectSmoothImage(cl, &cl->format, w, h)) {
+            if (cl->tightQualityLevel != -1) {
+                success = SendJpegRect(cl, x, y, w, h,
+                                  tightConf[cl->tightQualityLevel].jpegQuality);
+            } else {
+                success = SendGradientRect(cl, w, h);
+            }
+        } else {
+            success = SendFullColorRect(cl, w, h);
+        }
+        break;
+    case 1:
+        /* Solid rectangle */
+        success = SendSolidRect(cl);
+        break;
+    case 2:
+        /* Two-color rectangle */
+        success = SendMonoRect(cl, w, h);
+        break;
+    default:
+        /* Up to 256 different colors */
+        if ( paletteNumColors > 96 &&
+             cl->tightQualityLevel != -1 && cl->tightQualityLevel <= 3 &&
+             DetectSmoothImage(cl, &cl->format, w, h) ) {
+            success = SendJpegRect(cl, x, y, w, h,
+                                  tightConf[cl->tightQualityLevel].jpegQuality);
+        } else {
+            success = SendIndexedRect(cl, w, h);
+        }
+    }
+    return success;
+}
+
+static Bool
+SendTightHeader(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingTight);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+           sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingTight]++;
+    cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
+
+    return TRUE;
+}
+
+/*
+ * Subencoding implementations.
+ */
+
+static Bool
+SendSolidRect(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int len;
+
+    if (usePixelFormat24) {
+        Pack24(cl->pScreen, tightBeforeBuf, &cl->format, 1);
+        len = 3;
+    } else
+        len = cl->format.bitsPerPixel / 8;
+
+    if (pVNC->ublen + 1 + len > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightFill << 4);
+    memcpy (&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, len);
+    pVNC->ublen += len;
+
+    cl->rfbBytesSent[rfbEncodingTight] += len + 1;
+
+    return TRUE;
+}
+
+static Bool
+SendMonoRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 1;
+    int paletteLen, dataLen;
+
+    if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+          2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    /* Prepare tight encoding header. */
+    dataLen = (w + 7) / 8;
+    dataLen *= h;
+
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette;
+    pVNC->updateBuf[pVNC->ublen++] = 1;
+
+    /* Prepare palette, convert image. */
+    switch (cl->format.bitsPerPixel) {
+
+    case 32:
+        EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h);
+
+        ((CARD32 *)tightAfterBuf)[0] = monoBackground;
+        ((CARD32 *)tightAfterBuf)[1] = monoForeground;
+        if (usePixelFormat24) {
+            Pack24(cl->pScreen, tightAfterBuf, &cl->format, 2);
+            paletteLen = 6;
+        } else
+            paletteLen = 8;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteLen);
+        pVNC->ublen += paletteLen;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen;
+        break;
+
+    case 16:
+        EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h);
+
+        ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground;
+        ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, 4);
+        pVNC->ublen += 4;
+        cl->rfbBytesSent[rfbEncodingTight] += 7;
+        break;
+
+    default:
+        EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h);
+
+        pVNC->updateBuf[pVNC->ublen++] = (char)monoBackground;
+        pVNC->updateBuf[pVNC->ublen++] = (char)monoForeground;
+        cl->rfbBytesSent[rfbEncodingTight] += 5;
+    }
+
+    return CompressData(cl, streamId, dataLen,
+                        tightConf[cl->tightCompressLevel].monoZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendIndexedRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 2;
+    int i, entryLen;
+
+    if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+          paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    /* Prepare tight encoding header. */
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette;
+    pVNC->updateBuf[pVNC->ublen++] = (char)(paletteNumColors - 1);
+
+    /* Prepare palette, convert image. */
+    switch (cl->format.bitsPerPixel) {
+
+    case 32:
+        EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h);
+
+        for (i = 0; i < paletteNumColors; i++) {
+            ((CARD32 *)tightAfterBuf)[i] =
+                palette.entry[i].listNode->rgb;
+        }
+        if (usePixelFormat24) {
+            Pack24(cl->pScreen, tightAfterBuf, &cl->format, paletteNumColors);
+            entryLen = 3;
+        } else
+            entryLen = 4;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * entryLen);
+        pVNC->ublen += paletteNumColors * entryLen;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
+        break;
+
+    case 16:
+        EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h);
+
+        for (i = 0; i < paletteNumColors; i++) {
+            ((CARD16 *)tightAfterBuf)[i] =
+                (CARD16)palette.entry[i].listNode->rgb;
+        }
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * 2);
+        pVNC->ublen += paletteNumColors * 2;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
+        break;
+
+    default:
+        return FALSE;           /* Should never happen. */
+    }
+
+    return CompressData(cl, streamId, w * h,
+                        tightConf[cl->tightCompressLevel].idxZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendFullColorRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 0;
+    int len;
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = 0x00;  /* stream id = 0, no flushing, no filter */
+    cl->rfbBytesSent[rfbEncodingTight]++;
+
+    if (usePixelFormat24) {
+        Pack24(cl->pScreen, tightBeforeBuf, &cl->format, w * h);
+        len = 3;
+    } else
+        len = cl->format.bitsPerPixel / 8;
+
+    return CompressData(cl, streamId, w * h * len,
+                        tightConf[cl->tightCompressLevel].rawZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendGradientRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 3;
+    int len;
+
+    if (cl->format.bitsPerPixel == 8)
+        return SendFullColorRect(cl, w, h);
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    if (prevRowBuf == NULL)
+        prevRowBuf = (int *)xalloc(2048 * 3 * sizeof(int));
+
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterGradient;
+    cl->rfbBytesSent[rfbEncodingTight] += 2;
+
+    if (usePixelFormat24) {
+        FilterGradient24(cl->pScreen, tightBeforeBuf, &cl->format, w, h);
+        len = 3;
+    } else if (cl->format.bitsPerPixel == 32) {
+        FilterGradient32(cl->pScreen, (CARD32 *)tightBeforeBuf, &cl->format, w, h);
+        len = 4;
+    } else {
+        FilterGradient16(cl->pScreen, (CARD16 *)tightBeforeBuf, &cl->format, w, h);
+        len = 2;
+    }
+
+    return CompressData(cl, streamId, w * h * len,
+                        tightConf[cl->tightCompressLevel].gradientZlibLevel,
+                        Z_FILTERED);
+}
+
+static Bool
+CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy)
+    rfbClientPtr cl;
+    int streamId, dataLen, zlibLevel, zlibStrategy;
+{
+    VNCSCREENPTR(cl->pScreen);
+    z_streamp pz;
+    int err;
+
+    if (dataLen < TIGHT_MIN_TO_COMPRESS) {
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, dataLen);
+        pVNC->ublen += dataLen;
+        cl->rfbBytesSent[rfbEncodingTight] += dataLen;
+        return TRUE;
+    }
+
+    pz = &cl->zsStruct[streamId];
+
+    /* Initialize compression stream if needed. */
+    if (!cl->zsActive[streamId]) {
+        pz->zalloc = Z_NULL;
+        pz->zfree = Z_NULL;
+        pz->opaque = Z_NULL;
+
+        err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
+                            MAX_MEM_LEVEL, zlibStrategy);
+        if (err != Z_OK)
+            return FALSE;
+
+        cl->zsActive[streamId] = TRUE;
+        cl->zsLevel[streamId] = zlibLevel;
+    }
+
+    /* Prepare buffer pointers. */
+    pz->next_in = (Bytef *)tightBeforeBuf;
+    pz->avail_in = dataLen;
+    pz->next_out = (Bytef *)tightAfterBuf;
+    pz->avail_out = tightAfterBufSize;
+
+    /* Change compression parameters if needed. */
+    if (zlibLevel != cl->zsLevel[streamId]) {
+        if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
+            return FALSE;
+        }
+        cl->zsLevel[streamId] = zlibLevel;
+    }
+
+    /* Actual compression. */
+    if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK ||
+         pz->avail_in != 0 || pz->avail_out == 0 ) {
+        return FALSE;
+    }
+
+    return SendCompressedData(cl, tightAfterBufSize - pz->avail_out);
+}
+
+static Bool SendCompressedData(cl, compressedLen)
+    rfbClientPtr cl;
+    int compressedLen;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int i, portionLen;
+
+    pVNC->updateBuf[pVNC->ublen++] = compressedLen & 0x7F;
+    cl->rfbBytesSent[rfbEncodingTight]++;
+    if (compressedLen > 0x7F) {
+        pVNC->updateBuf[pVNC->ublen-1] |= 0x80;
+        pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 7 & 0x7F;
+        cl->rfbBytesSent[rfbEncodingTight]++;
+        if (compressedLen > 0x3FFF) {
+            pVNC->updateBuf[pVNC->ublen-1] |= 0x80;
+            pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 14 & 0xFF;
+            cl->rfbBytesSent[rfbEncodingTight]++;
+        }
+    }
+
+    portionLen = UPDATE_BUF_SIZE;
+    for (i = 0; i < compressedLen; i += portionLen) {
+        if (i + portionLen > compressedLen) {
+            portionLen = compressedLen - i;
+        }
+        if (pVNC->ublen + portionLen > UPDATE_BUF_SIZE) {
+            if (!rfbSendUpdateBuf(cl))
+                return FALSE;
+        }
+        memcpy(&pVNC->updateBuf[pVNC->ublen], &tightAfterBuf[i], portionLen);
+        pVNC->ublen += portionLen;
+    }
+    cl->rfbBytesSent[rfbEncodingTight] += compressedLen;
+    return TRUE;
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+
+static void
+FillPalette8(count)
+    int count;
+{
+    CARD8 *data = (CARD8 *)tightBeforeBuf;
+    CARD8 c0, c1;
+    int i, n0, n1;
+
+    paletteNumColors = 0;
+
+    c0 = data[0];
+    for (i = 1; i < count && data[i] == c0; i++);
+    if (i == count) {
+        paletteNumColors = 1;
+        return;                 /* Solid rectangle */
+    }
+
+    if (paletteMaxColors < 2)
+        return;
+
+    n0 = i;
+    c1 = data[i];
+    n1 = 0;
+    for (i++; i < count; i++) {
+        if (data[i] == c0) {
+            n0++;
+        } else if (data[i] == c1) {
+            n1++;
+        } else
+            break;
+    }
+    if (i == count) {
+        if (n0 > n1) {
+            monoBackground = (CARD32)c0;
+            monoForeground = (CARD32)c1;
+        } else {
+            monoBackground = (CARD32)c1;
+            monoForeground = (CARD32)c0;
+        }
+        paletteNumColors = 2;   /* Two colors */
+    }
+}
+
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
+                                                                        \
+static void                                                             \
+FillPalette##bpp(count)                                                 \
+    int count;                                                          \
+{                                                                       \
+    CARD##bpp *data = (CARD##bpp *)tightBeforeBuf;                      \
+    CARD##bpp c0, c1, ci = 0;                                           \
+    int i, n0, n1, ni;                                                  \
+                                                                        \
+    c0 = data[0];                                                       \
+    for (i = 1; i < count && data[i] == c0; i++);                       \
+    if (i >= count) {                                                   \
+        paletteNumColors = 1;   /* Solid rectangle */                   \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    if (paletteMaxColors < 2) {                                         \
+        paletteNumColors = 0;   /* Full-color encoding preferred */     \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    n0 = i;                                                             \
+    c1 = data[i];                                                       \
+    n1 = 0;                                                             \
+    for (i++; i < count; i++) {                                         \
+        ci = data[i];                                                   \
+        if (ci == c0) {                                                 \
+            n0++;                                                       \
+        } else if (ci == c1) {                                          \
+            n1++;                                                       \
+        } else                                                          \
+            break;                                                      \
+    }                                                                   \
+    if (i >= count) {                                                   \
+        if (n0 > n1) {                                                  \
+            monoBackground = (CARD32)c0;                                \
+            monoForeground = (CARD32)c1;                                \
+        } else {                                                        \
+            monoBackground = (CARD32)c1;                                \
+            monoForeground = (CARD32)c0;                                \
+        }                                                               \
+        paletteNumColors = 2;   /* Two colors */                        \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    PaletteReset();                                                     \
+    PaletteInsert (c0, (CARD32)n0, bpp);                                \
+    PaletteInsert (c1, (CARD32)n1, bpp);                                \
+                                                                        \
+    ni = 1;                                                             \
+    for (i++; i < count; i++) {                                         \
+        if (data[i] == ci) {                                            \
+            ni++;                                                       \
+        } else {                                                        \
+            if (!PaletteInsert (ci, (CARD32)ni, bpp))                   \
+                return;                                                 \
+            ci = data[i];                                               \
+            ni = 1;                                                     \
+        }                                                               \
+    }                                                                   \
+    PaletteInsert (ci, (CARD32)ni, bpp);                                \
+}
+
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+
+/*
+ * Functions to operate with palette structures.
+ */
+
+#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF))
+#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF))
+
+static void
+PaletteReset(void)
+{
+    paletteNumColors = 0;
+    memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
+}
+
+static int
+PaletteInsert(CARD32 rgb, int numPixels, int bpp)
+{
+    COLOR_LIST *pnode;
+    COLOR_LIST *prev_pnode = NULL;
+    int hash_key, idx, new_idx, count;
+
+    hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+    pnode = palette.hash[hash_key];
+
+    while (pnode != NULL) {
+        if (pnode->rgb == rgb) {
+            /* Such palette entry already exists. */
+            new_idx = idx = pnode->idx;
+            count = palette.entry[idx].numPixels + numPixels;
+            if (new_idx && palette.entry[new_idx-1].numPixels < count) {
+                do {
+                    palette.entry[new_idx] = palette.entry[new_idx-1];
+                    palette.entry[new_idx].listNode->idx = new_idx;
+                    new_idx--;
+                }
+                while (new_idx && palette.entry[new_idx-1].numPixels < count);
+                palette.entry[new_idx].listNode = pnode;
+                pnode->idx = new_idx;
+            }
+            palette.entry[new_idx].numPixels = count;
+            return paletteNumColors;
+        }
+        prev_pnode = pnode;
+        pnode = pnode->next;
+    }
+
+    /* Check if palette is full. */
+    if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
+        paletteNumColors = 0;
+        return 0;
+    }
+
+    /* Move palette entries with lesser pixel counts. */
+    for ( idx = paletteNumColors;
+          idx > 0 && palette.entry[idx-1].numPixels < numPixels;
+          idx-- ) {
+        palette.entry[idx] = palette.entry[idx-1];
+        palette.entry[idx].listNode->idx = idx;
+    }
+
+    /* Add new palette entry into the freed slot. */
+    pnode = &palette.list[paletteNumColors];
+    if (prev_pnode != NULL) {
+        prev_pnode->next = pnode;
+    } else {
+        palette.hash[hash_key] = pnode;
+    }
+    pnode->next = NULL;
+    pnode->idx = idx;
+    pnode->rgb = rgb;
+    palette.entry[idx].listNode = pnode;
+    palette.entry[idx].numPixels = numPixels;
+
+    return (++paletteNumColors);
+}
+
+
+/*
+ * Converting 32-bit color samples into 24-bit colors.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void Pack24(pScreen, buf, fmt, count)
+    ScreenPtr pScreen;
+    char *buf;
+    rfbPixelFormat *fmt;
+    int count;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *buf32;
+    CARD32 pix;
+    int r_shift, g_shift, b_shift;
+
+    buf32 = (CARD32 *)buf;
+
+    if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+        r_shift = fmt->redShift;
+        g_shift = fmt->greenShift;
+        b_shift = fmt->blueShift;
+    } else {
+        r_shift = 24 - fmt->redShift;
+        g_shift = 24 - fmt->greenShift;
+        b_shift = 24 - fmt->blueShift;
+    }
+
+    while (count--) {
+        pix = *buf32++;
+        *buf++ = (char)(pix >> r_shift);
+        *buf++ = (char)(pix >> g_shift);
+        *buf++ = (char)(pix >> b_shift);
+    }
+}
+
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
+                                                                        \
+static void                                                             \
+EncodeIndexedRect##bpp(buf, count)                                      \
+    CARD8 *buf;                                                         \
+    int count;                                                          \
+{                                                                       \
+    COLOR_LIST *pnode;                                                  \
+    CARD##bpp *src;                                                     \
+    CARD##bpp rgb;                                                      \
+    int rep = 0;                                                        \
+                                                                        \
+    src = (CARD##bpp *) buf;                                            \
+                                                                        \
+    while (count--) {                                                   \
+        rgb = *src++;                                                   \
+        while (count && *src == rgb) {                                  \
+            rep++, src++, count--;                                      \
+        }                                                               \
+        pnode = palette.hash[HASH_FUNC##bpp(rgb)];                      \
+        while (pnode != NULL) {                                         \
+            if ((CARD##bpp)pnode->rgb == rgb) {                         \
+                *buf++ = (CARD8)pnode->idx;                             \
+                while (rep) {                                           \
+                    *buf++ = (CARD8)pnode->idx;                         \
+                    rep--;                                              \
+                }                                                       \
+                break;                                                  \
+            }                                                           \
+            pnode = pnode->next;                                        \
+        }                                                               \
+    }                                                                   \
+}
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
+                                                                        \
+static void                                                             \
+EncodeMonoRect##bpp(buf, w, h)                                          \
+    CARD8 *buf;                                                         \
+    int w, h;                                                           \
+{                                                                       \
+    CARD##bpp *ptr;                                                     \
+    CARD##bpp bg;                                                       \
+    unsigned int value, mask;                                           \
+    int aligned_width;                                                  \
+    int x, y, bg_bits;                                                  \
+                                                                        \
+    ptr = (CARD##bpp *) buf;                                            \
+    bg = (CARD##bpp) monoBackground;                                    \
+    aligned_width = w - w % 8;                                          \
+                                                                        \
+    for (y = 0; y < h; y++) {                                           \
+        for (x = 0; x < aligned_width; x += 8) {                        \
+            for (bg_bits = 0; bg_bits < 8; bg_bits++) {                 \
+                if (*ptr++ != bg)                                       \
+                    break;                                              \
+            }                                                           \
+            if (bg_bits == 8) {                                         \
+                *buf++ = 0;                                             \
+                continue;                                               \
+            }                                                           \
+            mask = 0x80 >> bg_bits;                                     \
+            value = mask;                                               \
+            for (bg_bits++; bg_bits < 8; bg_bits++) {                   \
+                mask >>= 1;                                             \
+                if (*ptr++ != bg) {                                     \
+                    value |= mask;                                      \
+                }                                                       \
+            }                                                           \
+            *buf++ = (CARD8)value;                                      \
+        }                                                               \
+                                                                        \
+        mask = 0x80;                                                    \
+        value = 0;                                                      \
+        if (x >= w)                                                     \
+            continue;                                                   \
+                                                                        \
+        for (; x < w; x++) {                                            \
+            if (*ptr++ != bg) {                                         \
+                value |= mask;                                          \
+            }                                                           \
+            mask >>= 1;                                                 \
+        }                                                               \
+        *buf++ = (CARD8)value;                                          \
+    }                                                                   \
+}
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+
+/*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+FilterGradient24(pScreen, buf, fmt, w, h)
+    ScreenPtr pScreen;
+    char *buf;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *buf32;
+    CARD32 pix32;
+    int *prevRowPtr;
+    int shiftBits[3];
+    int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];
+    int prediction;
+    int x, y, c;
+
+    buf32 = (CARD32 *)buf;
+    memset (prevRowBuf, 0, w * 3 * sizeof(int));
+
+    if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+        shiftBits[0] = fmt->redShift;
+        shiftBits[1] = fmt->greenShift;
+        shiftBits[2] = fmt->blueShift;
+    } else {
+        shiftBits[0] = 24 - fmt->redShift;
+        shiftBits[1] = 24 - fmt->greenShift;
+        shiftBits[2] = 24 - fmt->blueShift;
+    }
+
+    for (y = 0; y < h; y++) {
+        for (c = 0; c < 3; c++) {
+            pixUpper[c] = 0;
+            pixHere[c] = 0;
+        }
+        prevRowPtr = prevRowBuf;
+        for (x = 0; x < w; x++) {
+            pix32 = *buf32++;
+            for (c = 0; c < 3; c++) {
+                pixUpperLeft[c] = pixUpper[c];
+                pixLeft[c] = pixHere[c];
+                pixUpper[c] = *prevRowPtr;
+                pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF);
+                *prevRowPtr++ = pixHere[c];
+
+                prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c];
+                if (prediction < 0) {
+                    prediction = 0;
+                } else if (prediction > 0xFF) {
+                    prediction = 0xFF;
+                }
+                *buf++ = (char)(pixHere[c] - prediction);
+            }
+        }
+    }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                             \
+                                                                         \
+static void                                                              \
+FilterGradient##bpp(pScreen, buf, fmt, w, h)                             \
+    ScreenPtr pScreen;							 \
+    CARD##bpp *buf;                                                      \
+    rfbPixelFormat *fmt;                                                 \
+    int w, h;                                                            \
+{                                                                        \
+    VNCSCREENPTR(pScreen);						 \
+    CARD##bpp pix, diff;                                                 \
+    Bool endianMismatch;                                                 \
+    int *prevRowPtr;                                                     \
+    int maxColor[3], shiftBits[3];                                       \
+    int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];            \
+    int prediction;                                                      \
+    int x, y, c;                                                         \
+                                                                         \
+    memset (prevRowBuf, 0, w * 3 * sizeof(int));                         \
+                                                                         \
+    endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian);    \
+                                                                         \
+    maxColor[0] = fmt->redMax;                                           \
+    maxColor[1] = fmt->greenMax;                                         \
+    maxColor[2] = fmt->blueMax;                                          \
+    shiftBits[0] = fmt->redShift;                                        \
+    shiftBits[1] = fmt->greenShift;                                      \
+    shiftBits[2] = fmt->blueShift;                                       \
+                                                                         \
+    for (y = 0; y < h; y++) {                                            \
+        for (c = 0; c < 3; c++) {                                        \
+            pixUpper[c] = 0;                                             \
+            pixHere[c] = 0;                                              \
+        }                                                                \
+        prevRowPtr = prevRowBuf;                                         \
+        for (x = 0; x < w; x++) {                                        \
+            pix = *buf;                                                  \
+            if (endianMismatch) {                                        \
+                pix = Swap##bpp(pix);                                    \
+            }                                                            \
+            diff = 0;                                                    \
+            for (c = 0; c < 3; c++) {                                    \
+                pixUpperLeft[c] = pixUpper[c];                           \
+                pixLeft[c] = pixHere[c];                                 \
+                pixUpper[c] = *prevRowPtr;                               \
+                pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]);   \
+                *prevRowPtr++ = pixHere[c];                              \
+                                                                         \
+                prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \
+                if (prediction < 0) {                                    \
+                    prediction = 0;                                      \
+                } else if (prediction > maxColor[c]) {                   \
+                    prediction = maxColor[c];                            \
+                }                                                        \
+                diff |= ((pixHere[c] - prediction) & maxColor[c])        \
+                    << shiftBits[c];                                     \
+            }                                                            \
+            if (endianMismatch) {                                        \
+                diff = Swap##bpp(diff);                                  \
+            }                                                            \
+            *buf++ = diff;                                               \
+        }                                                                \
+    }                                                                    \
+}
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+
+/*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+#define JPEG_MIN_RECT_SIZE  4096
+
+#define DETECT_SUBROW_WIDTH    7
+#define DETECT_MIN_WIDTH       8
+#define DETECT_MIN_HEIGHT      8
+
+static int
+DetectSmoothImage (cl, fmt, w, h)
+    rfbClientPtr cl;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    unsigned long avgError;
+
+    if ( pVNC->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 ||
+         w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) {
+        return 0;
+    }
+
+    if (cl->tightQualityLevel != -1) {
+        if (w * h < JPEG_MIN_RECT_SIZE) {
+            return 0;
+        }
+    } else {
+        if ( rfbTightDisableGradient ||
+             w * h < tightConf[cl->tightCompressLevel].gradientMinRectSize ) {
+            return 0;
+        }
+    }
+
+    if (fmt->bitsPerPixel == 32) {
+        if (usePixelFormat24) {
+            avgError = DetectSmoothImage24(cl, fmt, w, h);
+            if (cl->tightQualityLevel != -1) {
+                return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold24);
+            }
+            return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold24);
+        } else {
+            avgError = DetectSmoothImage32(cl, fmt, w, h);
+        }
+    } else {
+        avgError = DetectSmoothImage16(cl, fmt, w, h);
+    }
+    if (cl->tightQualityLevel != -1) {
+        return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold);
+    }
+    return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold);
+}
+
+static unsigned long
+DetectSmoothImage24 (cl, fmt, w, h)
+    rfbClientPtr cl;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    int off;
+    int x, y, d, dx, c;
+    int diffStat[256];
+    int pixelCount = 0;
+    int pix, left[3];
+    unsigned long avgError;
+
+    /* If client is big-endian, color samples begin from the second
+       byte (offset 1) of a 32-bit pixel value. */
+    off = (fmt->bigEndian != 0);
+
+    memset(diffStat, 0, 256*sizeof(int));
+
+    y = 0, x = 0;
+    while (y < h && x < w) {
+        for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {
+            for (c = 0; c < 3; c++) {
+                left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+            }
+            for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {
+                for (c = 0; c < 3; c++) {
+                    pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+                    diffStat[abs(pix - left[c])]++;
+                    left[c] = pix;
+                }
+                pixelCount++;
+            }
+        }
+        if (w > h) {
+            x += h;
+            y = 0;
+        } else {
+            x = 0;
+            y += w;
+        }
+    }
+
+    if (diffStat[0] * 33 / pixelCount >= 95)
+        return 0;
+
+    avgError = 0;
+    for (c = 1; c < 8; c++) {
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+        if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)
+            return 0;
+    }
+    for (; c < 256; c++) {
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+    }
+    avgError /= (pixelCount * 3 - diffStat[0]);
+
+    return avgError;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp)                                          \
+                                                                             \
+static unsigned long                                                         \
+DetectSmoothImage##bpp (cl, fmt, w, h)                                       \
+    rfbClientPtr cl;							     \
+    rfbPixelFormat *fmt;                                                     \
+    int w, h;                                                                \
+{                                                                            \
+    VNCSCREENPTR(cl->pScreen);						     \
+    Bool endianMismatch;                                                     \
+    CARD##bpp pix;                                                           \
+    int maxColor[3], shiftBits[3];                                           \
+    int x, y, d, dx, c;                                                      \
+    int diffStat[256];                                                       \
+    int pixelCount = 0;                                                      \
+    int sample, sum, left[3];                                                \
+    unsigned long avgError;                                                  \
+                                                                             \
+    endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian);        \
+                                                                             \
+    maxColor[0] = fmt->redMax;                                               \
+    maxColor[1] = fmt->greenMax;                                             \
+    maxColor[2] = fmt->blueMax;                                              \
+    shiftBits[0] = fmt->redShift;                                            \
+    shiftBits[1] = fmt->greenShift;                                          \
+    shiftBits[2] = fmt->blueShift;                                           \
+                                                                             \
+    memset(diffStat, 0, 256*sizeof(int));                                    \
+                                                                             \
+    y = 0, x = 0;                                                            \
+    while (y < h && x < w) {                                                 \
+        for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {     \
+            pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d];                \
+            if (endianMismatch) {                                            \
+                pix = Swap##bpp(pix);                                        \
+            }                                                                \
+            for (c = 0; c < 3; c++) {                                        \
+                left[c] = (int)(pix >> shiftBits[c] & maxColor[c]);          \
+            }                                                                \
+            for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {                  \
+                pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d+dx];         \
+                if (endianMismatch) {                                        \
+                    pix = Swap##bpp(pix);                                    \
+                }                                                            \
+                sum = 0;                                                     \
+                for (c = 0; c < 3; c++) {                                    \
+                    sample = (int)(pix >> shiftBits[c] & maxColor[c]);       \
+                    sum += abs(sample - left[c]);                            \
+                    left[c] = sample;                                        \
+                }                                                            \
+                if (sum > 255)                                               \
+                    sum = 255;                                               \
+                diffStat[sum]++;                                             \
+                pixelCount++;                                                \
+            }                                                                \
+        }                                                                    \
+        if (w > h) {                                                         \
+            x += h;                                                          \
+            y = 0;                                                           \
+        } else {                                                             \
+            x = 0;                                                           \
+            y += w;                                                          \
+        }                                                                    \
+    }                                                                        \
+                                                                             \
+    if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90)                \
+        return 0;                                                            \
+                                                                             \
+    avgError = 0;                                                            \
+    for (c = 1; c < 8; c++) {                                                \
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);     \
+        if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)             \
+            return 0;                                                        \
+    }                                                                        \
+    for (; c < 256; c++) {                                                   \
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);     \
+    }                                                                        \
+    avgError /= (pixelCount - diffStat[0]);                                  \
+                                                                             \
+    return avgError;                                                         \
+}
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+
+/*
+ * JPEG compression stuff.
+ */
+
+static struct jpeg_destination_mgr jpegDstManager;
+static Bool jpegError;
+static int jpegDstDataLen;
+
+static Bool
+SendJpegRect(cl, x, y, w, h, quality)
+    rfbClientPtr cl;
+    int x, y, w, h;
+    int quality;
+{
+    VNCSCREENPTR(cl->pScreen);
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    CARD8 *srcBuf;
+    JSAMPROW rowPointer[1];
+    int dy;
+
+    if (pVNC->rfbServerFormat.bitsPerPixel == 8)
+        return SendFullColorRect(cl, w, h);
+
+    srcBuf = (CARD8 *)xalloc(w * 3);
+    if (srcBuf == NULL) {
+        return SendFullColorRect(cl, w, h);
+    }
+    rowPointer[0] = srcBuf;
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+
+    cinfo.image_width = w;
+    cinfo.image_height = h;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, TRUE);
+
+    JpegSetDstManager (&cinfo);
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    for (dy = 0; dy < h; dy++) {
+        PrepareRowForJpeg(cl->pScreen, srcBuf, x, y + dy, w);
+        jpeg_write_scanlines(&cinfo, rowPointer, 1);
+        if (jpegError)
+            break;
+    }
+
+    if (!jpegError)
+        jpeg_finish_compress(&cinfo);
+
+    jpeg_destroy_compress(&cinfo);
+    xfree((char *)srcBuf);
+
+    if (jpegError)
+        return SendFullColorRect(cl, w, h);
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightJpeg << 4);
+    cl->rfbBytesSent[rfbEncodingTight]++;
+
+    return SendCompressedData(cl, jpegDstDataLen);
+}
+
+static void
+PrepareRowForJpeg(pScreen, dst, x, y, count)
+    ScreenPtr pScreen;
+    CARD8 *dst;
+    int x, y, count;
+{
+    VNCSCREENPTR(pScreen);
+    if (pVNC->rfbServerFormat.bitsPerPixel == 32) {
+        if ( pVNC->rfbServerFormat.redMax == 0xFF &&
+             pVNC->rfbServerFormat.greenMax == 0xFF &&
+             pVNC->rfbServerFormat.blueMax == 0xFF ) {
+            PrepareRowForJpeg24(pScreen, dst, x, y, count);
+        } else {
+            PrepareRowForJpeg32(pScreen, dst, x, y, count);
+        }
+    } else {
+        /* 16 bpp assumed. */
+        PrepareRowForJpeg16(pScreen, dst, x, y, count);
+    }
+}
+
+static void
+PrepareRowForJpeg24(pScreen, dst, x, y, count)
+    ScreenPtr pScreen;
+    CARD8 *dst;
+    int x, y, count;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *fbptr;
+    CARD32 pix;
+
+    fbptr = (CARD32 *)
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * 4];
+
+    while (count--) {
+        pix = *fbptr++;
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift);
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift);
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift);
+    }
+}
+
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                                   \
+                                                                            \
+static void                                                                 \
+PrepareRowForJpeg##bpp(pScreen, dst, x, y, count)                           \
+    ScreenPtr pScreen;							    \
+    CARD8 *dst;                                                             \
+    int x, y, count;                                                        \
+{                                                                           \
+    VNCSCREENPTR(pScreen);						    \
+    CARD##bpp *fbptr;                                                       \
+    CARD##bpp pix;                                                          \
+    int inRed, inGreen, inBlue;                                             \
+                                                                            \
+    fbptr = (CARD##bpp *)                                                   \
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes +                        \
+                             x * (bpp / 8)];                                \
+                                                                            \
+    while (count--) {                                                       \
+        pix = *fbptr++;                                                     \
+                                                                            \
+        inRed = (int)                                                       \
+            (pix >> pVNC->rfbServerFormat.redShift   & pVNC->rfbServerFormat.redMax);   \
+        inGreen = (int)                                                     \
+            (pix >> pVNC->rfbServerFormat.greenShift & pVNC->rfbServerFormat.greenMax); \
+        inBlue  = (int)                                                     \
+            (pix >> pVNC->rfbServerFormat.blueShift  & pVNC->rfbServerFormat.blueMax);  \
+                                                                            \
+	*dst++ = (CARD8)((inRed   * 255 + pVNC->rfbServerFormat.redMax / 2) /     \
+                         pVNC->rfbServerFormat.redMax);                           \
+	*dst++ = (CARD8)((inGreen * 255 + pVNC->rfbServerFormat.greenMax / 2) /   \
+                         pVNC->rfbServerFormat.greenMax);                         \
+	*dst++ = (CARD8)((inBlue  * 255 + pVNC->rfbServerFormat.blueMax / 2) /    \
+                         pVNC->rfbServerFormat.blueMax);                          \
+    }                                                                       \
+}
+
+DEFINE_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+static void
+JpegInitDestination(j_compress_ptr cinfo)
+{
+    jpegError = FALSE;
+    jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+    jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+}
+
+static boolean
+JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+    jpegError = TRUE;
+    jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+    jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+
+    return TRUE;
+}
+
+static void
+JpegTermDestination(j_compress_ptr cinfo)
+{
+    jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer;
+}
+
+static void
+JpegSetDstManager(j_compress_ptr cinfo)
+{
+    jpegDstManager.init_destination = JpegInitDestination;
+    jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+    jpegDstManager.term_destination = JpegTermDestination;
+    cinfo->dest = &jpegDstManager;
+}
+
diff -u -rNp a/hw/dmx/vnc/translate.c b/hw/dmx/vnc/translate.c
--- a/hw/dmx/vnc/translate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/translate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,496 @@
+/*
+ * translate.c - translate between different pixel formats
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+
+static void PrintPixelFormat(rfbPixelFormat *pf);
+static Bool rfbSetClientColourMapBGR233();
+
+Bool rfbEconomicTranslate = FALSE;
+
+/*
+ * Some standard pixel formats.
+ */
+
+static const rfbPixelFormat BGR233Format = {
+    8, 8, 0, 1, 7, 7, 3, 0, 3, 6
+};
+
+
+/*
+ * Macro to compare pixel formats.
+ */
+
+#define PF_EQ(x,y)							\
+	((x.bitsPerPixel == y.bitsPerPixel) &&				\
+	 (x.depth == y.depth) &&					\
+	 ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) &&	\
+	 (x.trueColour == y.trueColour) &&				\
+	 (!x.trueColour || ((x.redMax == y.redMax) &&			\
+			    (x.greenMax == y.greenMax) &&		\
+			    (x.blueMax == y.blueMax) &&			\
+			    (x.redShift == y.redShift) &&		\
+			    (x.greenShift == y.greenShift) &&		\
+			    (x.blueShift == y.blueShift))))
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+
+#define OUT 8
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 16
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 32
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+typedef void (*rfbInitTableFnType)(ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				   rfbPixelFormat *out);
+
+rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = {
+    rfbInitTrueColourSingleTable8,
+    rfbInitTrueColourSingleTable16,
+    rfbInitTrueColourSingleTable32
+};
+
+rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = {
+    rfbInitColourMapSingleTable8,
+    rfbInitColourMapSingleTable16,
+    rfbInitColourMapSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = {
+    rfbInitTrueColourRGBTables8,
+    rfbInitTrueColourRGBTables16,
+    rfbInitTrueColourRGBTables32
+};
+
+rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = {
+    { rfbTranslateWithSingleTable8to8,
+      rfbTranslateWithSingleTable8to16,
+      rfbTranslateWithSingleTable8to32 },
+    { rfbTranslateWithSingleTable16to8,
+      rfbTranslateWithSingleTable16to16,
+      rfbTranslateWithSingleTable16to32 },
+    { rfbTranslateWithSingleTable32to8,
+      rfbTranslateWithSingleTable32to16,
+      rfbTranslateWithSingleTable32to32 }
+};
+
+rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = {
+    { rfbTranslateWithRGBTables8to8,
+      rfbTranslateWithRGBTables8to16,
+      rfbTranslateWithRGBTables8to32 },
+    { rfbTranslateWithRGBTables16to8,
+      rfbTranslateWithRGBTables16to16,
+      rfbTranslateWithRGBTables16to32 },
+    { rfbTranslateWithRGBTables32to8,
+      rfbTranslateWithRGBTables32to16,
+      rfbTranslateWithRGBTables32to32 }
+};
+
+
+
+/*
+ * rfbTranslateNone is used when no translation is required.
+ */
+
+void
+rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, rfbPixelFormat *out,
+		 unsigned char *iptr, char *optr, int bytesBetweenInputLines,
+		 int width, int height, int x, int y)
+{
+    VNCSCREENPTR(pScreen);
+    int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
+
+    if (pVNC->useGetImage) {
+    	DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum];
+
+    	/* catch all for other TranslateNone cases - hextile, corre, rre, etc.*/
+    	(*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, optr);
+    } else {
+    	while (height > 0) {
+	    memcpy(optr, iptr, bytesPerOutputLine);
+	    iptr += bytesBetweenInputLines;
+	    optr += bytesPerOutputLine;
+	    height--;
+     	}
+    }
+}
+
+
+/*
+ * rfbSetTranslateFunction sets the translation function.
+ */
+
+Bool
+rfbSetTranslateFunction(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbLog("Pixel format for client %s:\n",cl->host);
+    PrintPixelFormat(&cl->format);
+
+    /*
+     * Check that bits per pixel values are valid
+     */
+
+    if ((pVNC->rfbServerFormat.bitsPerPixel != 8) &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 16) &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 32))
+    {
+	rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
+		"rfbSetTranslateFunction");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if ((cl->format.bitsPerPixel != 8) &&
+	(cl->format.bitsPerPixel != 16) &&
+	(cl->format.bitsPerPixel != 32))
+    {
+	rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
+		"rfbSetTranslateFunction");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if (!pVNC->rfbServerFormat.trueColour &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 8) &&
+#if XFREE86VNC
+	(miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) {
+#else
+	(pVNC->rfbInstalledColormap->class == PseudoColor)) {
+#endif
+	rfbLog("rfbSetTranslateFunction: server has colour map "
+		"but %d-bit - can only cope with 8-bit colour maps\n",
+		pVNC->rfbServerFormat.bitsPerPixel);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if (!cl->format.trueColour &&
+	(cl->format.bitsPerPixel != 8) &&
+#if XFREE86VNC
+	(miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) {
+#else
+	(pVNC->rfbInstalledColormap->class == PseudoColor) ) {
+#endif
+	rfbLog("rfbSetTranslateFunction: client has colour map "
+		"but %d-bit - can only cope with 8-bit colour maps\n",
+		cl->format.bitsPerPixel);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    /*
+     * bpp is valid, now work out how to translate
+     */
+
+    if (!cl->format.trueColour) {
+
+	/* ? -> colour map */
+
+	if (!pVNC->rfbServerFormat.trueColour) {
+
+	    /* colour map -> colour map */
+
+#if XFREE86VNC
+	    if (miInstalledMaps[cl->pScreen->myNum]->class == DirectColor) {
+#else
+	    if (pVNC->rfbInstalledColormap->class == DirectColor) {
+#endif
+	      rfbLog("rfbSetTranslateFunction: client is %d-bit DirectColor,"
+ 		     " client has colour map\n",cl->format.bitsPerPixel);
+
+	      cl->translateFn = rfbTranslateWithRGBTablesFns
+			          [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+  	      (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16])
+		   (cl->pScreen, &cl->translateLookupTable,
+		   &pVNC->rfbServerFormat, &cl->format);
+
+	      return rfbSetClientColourMap(cl, 0, 0);
+
+	    /* PseudoColor colormap */
+
+	    } else {
+	      rfbLog("rfbSetTranslateFunction: both 8-bit colour map: "
+		     "no translation needed\n");
+	      cl->translateFn = rfbTranslateNone;
+	      return rfbSetClientColourMap(cl, 0, 0);
+	    }
+	}
+
+	/*
+	 * truecolour -> colour map
+	 *
+	 * Set client's colour map to BGR233, then effectively it's
+	 * truecolour as well
+	 */
+
+	if (!rfbSetClientColourMapBGR233(cl))
+	    return FALSE;
+
+	cl->format = BGR233Format;
+    }
+
+    /* ? -> truecolour */
+
+    if (!pVNC->rfbServerFormat.trueColour) {
+
+	/* colour map -> truecolour */
+
+	rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour,"
+		" server has colour map\n",cl->format.bitsPerPixel);
+
+	cl->translateFn = rfbTranslateWithSingleTableFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	return rfbSetClientColourMap(cl, 0, 0);
+    }
+
+    /* truecolour -> truecolour */
+
+    if (PF_EQ(cl->format,pVNC->rfbServerFormat)) {
+
+	/* client & server the same */
+
+	rfbLog("  no translation needed\n");
+	cl->translateFn = rfbTranslateNone;
+	return TRUE;
+    }
+
+    if ((pVNC->rfbServerFormat.bitsPerPixel < 16) ||
+	(!rfbEconomicTranslate && (pVNC->rfbServerFormat.bitsPerPixel == 16))) {
+
+	/* we can use a single lookup table for <= 16 bpp */
+
+	cl->translateFn = rfbTranslateWithSingleTableFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	(*rfbInitTrueColourSingleTableFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+
+    } else {
+
+	/* otherwise we use three separate tables for red, green and blue */
+
+	cl->translateFn = rfbTranslateWithRGBTablesFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	(*rfbInitTrueColourRGBTablesFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
+ * just like an 8-bit BGR233 true colour client.
+ */
+
+static Bool
+rfbSetClientColourMapBGR233(cl)
+    rfbClientPtr cl;
+{
+    char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+    rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+    CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+    int i, len;
+    int r, g, b;
+
+    if (cl->format.bitsPerPixel != 8) {
+	rfbLog("%s: client not 8 bits per pixel\n",
+		"rfbSetClientColourMapBGR233");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    scme->type = rfbSetColourMapEntries;
+
+    scme->firstColour = Swap16IfLE(0);
+    scme->nColours = Swap16IfLE(256);
+
+    len = sz_rfbSetColourMapEntriesMsg;
+
+    i = 0;
+
+    for (b = 0; b < 4; b++) {
+	for (g = 0; g < 8; g++) {
+	    for (r = 0; r < 8; r++) {
+		rgb[i++] = Swap16IfLE(r * 65535 / 7);
+		rgb[i++] = Swap16IfLE(g * 65535 / 7);
+		rgb[i++] = Swap16IfLE(b * 65535 / 3);
+	    }
+	}
+    }
+
+    len += 256 * 3 * 2;
+
+    if (WriteExact(cl->sock, buf, len) < 0) {
+	rfbLogPerror("rfbSetClientColourMapBGR233: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+ * rfbSetClientColourMap is called to set the client's colour map.  If the
+ * client is a true colour client, we simply update our own translation table
+ * and mark the whole screen as having been modified.
+ */
+
+Bool
+rfbSetClientColourMap(cl, firstColour, nColours)
+    rfbClientPtr cl;
+    int firstColour;
+    int nColours;
+{
+    VNCSCREENPTR(cl->pScreen);
+    BoxRec box;
+
+    if (nColours == 0) {
+#if XFREE86VNC
+	nColours = miInstalledMaps[cl->pScreen->myNum]->pVisual->ColormapEntries;
+#else
+	nColours = pVNC->rfbInstalledColormap->pVisual->ColormapEntries;
+#endif
+    }
+
+    if (pVNC->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
+	return TRUE;
+    }
+
+    if (cl->format.trueColour) {
+	(*rfbInitColourMapSingleTableFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+
+	REGION_UNINIT(cl->pScreen,&cl->modifiedRegion);
+	box.x1 = box.y1 = 0;
+	box.x2 = pVNC->width;
+	box.y2 = pVNC->height;
+	REGION_INIT(cl->pScreen,&cl->modifiedRegion,&box,0);
+
+	return TRUE;
+    }
+
+    return rfbSendSetColourMapEntries(cl, firstColour, nColours);
+}
+
+
+/*
+ * rfbSetClientColourMaps sets the colour map for each RFB client.
+ */
+
+void
+rfbSetClientColourMaps(firstColour, nColours)
+    int firstColour;
+    int nColours;
+{
+    rfbClientPtr cl, nextCl;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	rfbSetClientColourMap(cl, firstColour, nColours);
+    }
+}
+
+
+static void
+PrintPixelFormat(pf)
+    rfbPixelFormat *pf;
+{
+    if (pf->bitsPerPixel == 1) {
+	rfbLog("  1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
+	       (pf->bigEndian ? "most" : "least"));
+    } else {
+	rfbLog("  %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
+	       ((pf->bitsPerPixel == 8) ? ""
+		: (pf->bigEndian ? ", big endian" : ", little endian")));
+	if (pf->trueColour) {
+	    rfbLog("  true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
+		   pf->redMax, pf->greenMax, pf->blueMax,
+		   pf->redShift, pf->greenShift, pf->blueShift);
+	} else {
+	    rfbLog("  uses a colour map (not true colour).\n");
+	}
+    }
+}
diff -u -rNp a/hw/dmx/vnc/vncauth.c b/hw/dmx/vnc/vncauth.c
--- a/hw/dmx/vnc/vncauth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/vncauth.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,239 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * vncauth.c - Functions for VNC password management and authentication.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "vncauth.h"
+#include "d3des.h"
+
+
+/*
+ * Make sure we call srandom() only once.
+ */
+
+static int s_srandom_called = 0;
+
+/*
+ * We use a fixed key to store passwords, since we assume that our local
+ * file system is secure but nonetheless don't want to store passwords
+ * as plaintext.
+ */
+
+static unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7};
+
+
+/*
+ * Encrypt a password and store it in a file.  Returns 0 if successful,
+ * 1 if the file could not be written.
+ *
+ * NOTE: This function is preserved only for compatibility with the original
+ * AT&T VNC software.  Use vncEncryptAndStorePasswd2() instead.
+ */
+
+int
+vncEncryptAndStorePasswd(char *passwd, char *fname)
+{
+    return (vncEncryptAndStorePasswd2(passwd, NULL, fname) == 0);
+}
+
+/*
+ * Encrypt one or two passwords and store them in a file.  Returns 1 if
+ * successful, 0 if the file could not be written (note that the original
+ * vncEncryptAndStorePasswd() function returns inverse values).  The
+ * passwdViewOnly pointer may be NULL.
+ */
+
+int
+vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname)
+{
+    FILE *fp;
+    int i, bytesToWrite, bytesWrote;
+    unsigned char encryptedPasswd[16] = {
+	0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0
+    };
+
+    fp = fopen(fname,"w");
+    if (fp == NULL)
+	return 0;
+
+    chmod(fname, S_IRUSR|S_IWUSR);
+
+    strncpy(encryptedPasswd, passwd, 8);
+    if (passwdViewOnly != NULL)
+	strncpy(encryptedPasswd + 8, passwdViewOnly, 8);
+
+    /* Do encryption in-place - this way we overwrite our copies of
+       plaintext passwords. */
+
+    deskey(s_fixedkey, EN0);
+    des(encryptedPasswd, encryptedPasswd);
+    if (passwdViewOnly != NULL)
+	des(encryptedPasswd + 8, encryptedPasswd + 8);
+
+    bytesToWrite = (passwdViewOnly == NULL) ? 8 : 16;
+    bytesWrote = fwrite(encryptedPasswd, 1, bytesToWrite, fp);
+  
+    fclose(fp);
+    return (bytesWrote == bytesToWrite);
+}
+
+
+/*
+ * Decrypt a password from a file.  Returns a pointer to a newly allocated
+ * string containing the password or a null pointer if the password could
+ * not be retrieved for some reason.
+ *
+ * NOTE: This function is preserved only for compatibility with the original
+ * AT&T VNC software.  Use vncDecryptPasswdFromFile2() instead.
+ */
+
+char *
+vncDecryptPasswdFromFile(char *fname)
+{
+    char *passwd;
+
+    passwd = malloc(9);
+
+    if (passwd != NULL) {
+	if (vncDecryptPasswdFromFile2(fname, passwd, NULL) == 0) {
+	    free(passwd);
+	    passwd = NULL;
+	}
+    }
+
+    return passwd;
+}
+
+/*
+ * Decrypt one or two passwords from a file.  Returns the number of
+ * passwords read (1, 2, or 0 on error).  On success, the passwords are
+ * written into buffers passwdFullControl[] and passwdViewOnly[] if
+ * they are not NULL.  If the pointers to buffers are not NULL, then
+ * the buffers should be at least of 9 bytes length.
+ */
+
+int
+vncDecryptPasswdFromFile2(char *fname,
+			  char *passwdFullControl, char *passwdViewOnly)
+{
+    FILE *fp;
+    int i, ch;
+    char passwd[16];
+
+    if (strcmp(fname, "-") != 0) {
+	if ((fp = fopen(fname,"r")) == NULL)
+	    return 0;		/* Could not open the file */
+    } else {
+	fp = stdin;
+    }
+
+    for (i = 0; i < 16; i++) {
+	ch = getc(fp);
+	if (ch == EOF)
+	    break;
+	passwd[i] = ch;
+    }
+
+    if (fp != stdin)
+	fclose(fp);
+
+    if (i < 8)
+	return 0;		/* Could not read eight bytes */
+
+    deskey(s_fixedkey, DE1);
+
+    /* Decoding first (full-control) password */
+    if (passwdFullControl != NULL) {
+	des(passwd, passwd);
+	memcpy(passwdFullControl, passwd, 8);
+	passwdFullControl[8] = '\0';
+    }
+
+    /* Decoding second (view-only) password if available */
+    if (i == 16 && passwdViewOnly != NULL) {
+	des(&passwd[8], &passwd[8]);
+	memcpy(passwdViewOnly, &passwd[8], 8);
+	passwdViewOnly[8] = '\0';
+    }
+
+    /* Destroying our copy of clear-text passwords */
+    memset(passwd, 0, 16);
+
+    return (i < 16) ? 1 : 2;
+}
+
+
+/*
+ * Generate CHALLENGESIZE random bytes for use in challenge-response
+ * authentication.
+ */
+
+void
+vncRandomBytes(unsigned char *bytes)
+{
+    int i;
+    unsigned int seed;
+
+    if (!s_srandom_called) {
+      seed = (unsigned int)time(0) ^ (unsigned int)getpid();
+      srandom(seed);
+      s_srandom_called = 1;
+    }
+
+    for (i = 0; i < CHALLENGESIZE; i++) {
+	bytes[i] = (unsigned char)(random() & 255);    
+    }
+}
+
+
+/*
+ * Encrypt CHALLENGESIZE bytes in memory using a password.
+ */
+
+void
+vncEncryptBytes(unsigned char *bytes, char *passwd)
+{
+    unsigned char key[8];
+    int i;
+
+    /* key is simply password padded with nulls */
+
+    for (i = 0; i < 8; i++) {
+	if (i < strlen(passwd)) {
+	    key[i] = passwd[i];
+	} else {
+	    key[i] = 0;
+	}
+    }
+
+    deskey(key, EN0);
+
+    for (i = 0; i < CHALLENGESIZE; i += 8) {
+	des(bytes+i, bytes+i);
+    }
+}
diff -u -rNp a/hw/dmx/vnc/vncauth.h b/hw/dmx/vnc/vncauth.h
--- a/hw/dmx/vnc/vncauth.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/vncauth.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* 
+ * vncauth.h - describes the functions provided by the vncauth library.
+ */
+
+#define MAXPWLEN 8
+#define CHALLENGESIZE 16
+
+extern int vncEncryptAndStorePasswd(char *passwd, char *fname);
+extern char *vncDecryptPasswdFromFile(char *fname);
+extern void vncRandomBytes(unsigned char *bytes);
+extern void vncEncryptBytes(unsigned char *bytes, char *passwd);
+
+extern int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname);
+extern int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly);
+
diff -u -rNp a/hw/dmx/vnc/vncext.c b/hw/dmx/vnc/vncext.c
--- a/hw/dmx/vnc/vncext.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/vncext.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,689 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include "rfb.h"
+#include "extnsionst.h"
+#define _VNC_SERVER
+#include <X11/extensions/vncstr.h>
+#include "../dmx.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef CHROMIUM
+extern void rfbSendChromiumStart(unsigned int ipaddress, unsigned int port);
+extern void rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid);
+int GenerateVncChromiumConnectedEvent(int sock);
+#endif
+
+/*extern void rfbUserAllow(int sock, int accept);*/
+
+int VncSelectNotify(ClientPtr client, BOOL onoff);
+int GenerateVncConnectedEvent(int sock);
+int GenerateVncDisconnectedEvent(int sock);
+void VncExtensionInit(void);
+
+static int VncErrorBase;  /* first vnc error number */
+static int VncEventBase;  /* first vnc event number */
+
+unsigned long VncResourceGeneration = 0;
+
+static RESTYPE VncNotifyList;
+
+static XID faked;
+
+typedef struct _VncNotifyListRec {
+  struct _VncNotifyListRec *next;
+  ClientPtr client;
+} VncNotifyListRec, *VncNotifyListPtr;
+
+static int
+ProcVncQueryVersion(ClientPtr client)
+{
+    xVncQueryVersionReply 	rep;
+
+    REQUEST_SIZE_MATCH(xVncQueryVersionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.majorVersion  	= VNC_MAJOR_VERSION;
+    rep.minorVersion  	= VNC_MINOR_VERSION;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.majorVersion, n);
+	swaps(&rep.minorVersion, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncQueryVersionReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncQueryVersion */
+
+static int
+ProcVncConnection(ClientPtr client)
+{
+    REQUEST(xVncConnectionReq);
+    xVncConnectionReply 	rep;
+
+    rfbUserAllow( stuff->sock, stuff->accept );
+
+    REQUEST_SIZE_MATCH(xVncConnectionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.sock  		= 0;
+    rep.accept  	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.sock, n);
+	swaps(&rep.accept, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncConnectionReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncConnection */
+
+static int
+ProcVncSelectNotify(ClientPtr client)
+{
+    REQUEST(xVncSelectNotifyReq);
+    xVncSelectNotifyReply 	rep;
+
+    VncSelectNotify(client, stuff->onoff);
+
+    REQUEST_SIZE_MATCH(xVncSelectNotifyReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncSelectNotifyReply),
+			(char *)&rep);
+    return (client->noClientException);
+
+}
+
+static int
+ProcVncListConnections(ClientPtr client)
+{
+    xVncListConnectionsReply 	rep;
+    rfbClientPtr cl;
+    int count = 0;
+    struct in_addr ipaddress;
+    xVncConnectionListInfo Info;
+
+    /* count connections */
+    for (cl = rfbClientHead; cl; cl = cl->next)
+#ifdef CHROMIUM
+    /* 
+     * Fix this, as it should be generic, but we're only using it
+     * for Chromium at the moment, so we only list the connections
+     * that have a valid chromium encoding. We should be able to list
+     * any type requested. FIXME! XXXX
+     * See furthur down this function too!!!
+     */
+	    if (cl->enableChromiumEncoding)
+#endif
+	    	count++;
+
+    REQUEST_SIZE_MATCH(xVncListConnectionsReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.count		= count;
+    rep.length 		= count * sizeof(xVncConnectionListInfo) >> 2;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    	swaps(&rep.count, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncListConnectionsReply),
+			(char *)&rep);
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+#ifdef CHROMIUM
+        /* 
+         * Fix this, as it should be generic, but we're only using it
+         * for Chromium at the moment, so we only list the connections
+         * that have a valid chromium encoding. We should be able to list
+         * any type requested. FIXME! XXXX
+         */
+	if (!cl->enableChromiumEncoding)
+	    continue;
+#endif
+	inet_aton(cl->host, &ipaddress);
+	memcpy(&Info, &ipaddress, sizeof(struct in_addr));
+	WriteToClient(client, SIZEOF(xVncConnectionListInfo), (char*)&Info);
+    }
+
+    return (client->noClientException);
+} /* ProcVncListConnections */
+
+#ifdef CHROMIUM
+static int
+ProcVncChromiumStart(ClientPtr client)
+{
+    REQUEST(xVncChromiumStartReq);
+    xVncChromiumStartReply 	rep;
+
+    rfbSendChromiumStart(stuff->ipaddress, stuff->port);
+
+    REQUEST_SIZE_MATCH(xVncChromiumStartReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncChromiumStartReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncChromiumStart */
+
+static int
+ProcVncChromiumMonitor(ClientPtr client)
+{
+    REQUEST(xVncChromiumMonitorReq);
+    xVncChromiumMonitorReply 	rep;
+
+    rfbChromiumMonitorWindowID(stuff->cr_windowid, stuff->windowid);
+
+    REQUEST_SIZE_MATCH(xVncChromiumMonitorReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncChromiumMonitorReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncChromiumMonitor */
+#endif /* CHROMIUM */
+
+static int
+ProcVncDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_VncQueryVersion:
+	    return ProcVncQueryVersion(client);
+	case X_VncSelectNotify:
+	    return ProcVncSelectNotify(client);
+	case X_VncConnection:
+	    return ProcVncConnection(client);
+	case X_VncListConnections:
+	    return ProcVncListConnections(client);
+#ifdef CHROMIUM
+	case X_VncChromiumStart:
+	    return ProcVncChromiumStart(client);
+	case X_VncChromiumMonitor:
+	    return ProcVncChromiumMonitor(client);
+#endif
+	default:
+	    return BadRequest;
+    }
+} /* ProcVncDispatch */
+
+static int
+SProcVncQueryVersion(ClientPtr client)
+{
+    REQUEST(xVncQueryVersionReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncQueryVersionReq);
+    swaps(&stuff->majorVersion, n);
+    swaps(&stuff->minorVersion,n);
+    return ProcVncQueryVersion(client);
+} /* SProcVncQueryVersion */
+
+static int
+SProcVncSelectNotify(ClientPtr client)
+{
+    REQUEST(xVncSelectNotifyReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncSelectNotifyReq);
+    return ProcVncSelectNotify(client);
+} /* SProcVncSelectNotify */
+
+static int
+SProcVncListConnections(ClientPtr client)
+{
+    REQUEST(xVncListConnectionsReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncListConnectionsReq);
+    return ProcVncListConnections(client);
+} /* SProcVncListConnections */
+
+#ifdef CHROMIUM
+static int
+SProcVncChromiumStart(ClientPtr client)
+{
+    REQUEST(xVncChromiumStartReq);
+    register char 	n;
+
+    swaps(&stuff->ipaddress, n);
+    swaps(&stuff->port, n);
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncChromiumStartReq);
+    return ProcVncChromiumStart(client);
+} /* SProcVncChromiumStart */
+
+static int
+SProcVncChromiumMonitor(ClientPtr client)
+{
+    REQUEST(xVncChromiumMonitorReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    swaps(&stuff->windowid, n);
+    swaps(&stuff->cr_windowid, n);
+    REQUEST_SIZE_MATCH(xVncChromiumMonitorReq);
+    return ProcVncChromiumMonitor(client);
+} /* SProcVncChromiumMonitor */
+#endif /* CHROMIUM */
+
+static int
+SProcVncConnection(ClientPtr client)
+{
+    REQUEST(xVncConnectionReq);
+    register char 	n;
+
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncConnectionReq);
+    swaps(&stuff->sock, n);
+    swaps(&stuff->accept,n);
+    return ProcVncConnection(client);
+} /* SProcVncConnection */
+
+static int
+SProcVncDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_VncQueryVersion:
+	    return SProcVncQueryVersion(client);
+	case X_VncSelectNotify:
+	    return SProcVncSelectNotify(client);
+	case X_VncConnection:
+	    return SProcVncConnection(client);
+	case X_VncListConnections:
+	    return SProcVncListConnections(client);
+#ifdef CHROMIUM
+	case X_VncChromiumStart:
+	    return SProcVncChromiumStart(client);
+	case X_VncChromiumMonitor:
+	    return SProcVncChromiumMonitor(client);
+#endif
+	default:
+	    return BadRequest;
+    }
+} /* SProcVncDispatch */
+
+static void 
+SwapVncConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+
+#ifdef CHROMIUM
+static void 
+SwapVncChromiumConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+#endif
+
+static void 
+SwapVncDisconnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+
+int
+GenerateVncConnectedEvent(int sock)
+{
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncConnectedEvent conn;
+    	  SOCKLEN_T peer_len;
+    	  struct sockaddr_in peer;
+
+    	  conn.type = VncEventBase + XVncConnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+
+    	  peer_len = sizeof(peer);
+    	  if (getpeername(sock, (struct sockaddr *) &peer, &peer_len) == -1)
+		conn.ipaddress = 0;
+   	  else
+		conn.ipaddress = (CARD32)peer.sin_addr.s_addr;
+
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+
+#ifdef CHROMIUM
+int
+GenerateVncChromiumConnectedEvent(int sock)
+{
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncConnectedEvent conn;
+    	  SOCKLEN_T peer_len;
+    	  struct sockaddr_in peer;
+
+    	  conn.type = VncEventBase + XVncChromiumConnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+
+    	  peer_len = sizeof(peer);
+    	  if (getpeername(sock, (struct sockaddr *)&peer, &peer_len) == -1)
+		conn.ipaddress = 0;
+   	  else
+		conn.ipaddress = (CARD32)peer.sin_addr.s_addr;
+
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+#endif /* CHROMIUM */
+
+int
+GenerateVncDisconnectedEvent(int sock)
+{
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncDisconnectedEvent conn;
+    	  conn.type = VncEventBase + XVncDisconnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+
+static void
+VncResetProc(ExtensionEntry *extEntry)
+{
+} /* VncResetProc */
+
+int
+VncSelectNotify(
+  ClientPtr client,
+  BOOL onoff
+){
+  VncNotifyListPtr pn,tpn,fpn;
+
+  if (!faked)
+	faked = FakeClientID(client->index);
+
+  pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+
+  if (!onoff && !pn) return Success;
+
+  if (!pn) 
+    {
+      if (!(tpn = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec))))
+	return BadAlloc;
+      tpn->next = (VncNotifyListPtr)NULL;
+      tpn->client = (ClientPtr)NULL;
+      if (!AddResource(faked, VncNotifyList, tpn))
+	{
+	  xfree(tpn);
+	  return BadAlloc;
+	}
+    }
+  else
+    {
+      fpn = (VncNotifyListPtr)NULL;
+      tpn = pn;
+
+      /* FIXME - NEED TO HAVE AN OPTION FOR SINGLE CLIENT ONLY!!! */
+
+      while (tpn)
+	{
+	  if (tpn->client == client) 
+	    {
+	      if (!onoff) tpn->client = (ClientPtr)NULL;
+	      return Success;
+	    }
+	  if (!tpn->client) fpn = tpn; /* TAKE NOTE OF FREE ENTRY */
+	  tpn = tpn->next;
+	}
+
+      /* IF TUNNING OFF, THEN JUST RETURN */
+
+      if (!onoff) return Success;
+
+      /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */
+
+      if (fpn)
+	{
+	  tpn = fpn;
+	}
+      else
+	{
+	  if (!(tpn = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec))))
+	    return BadAlloc;
+	  tpn->next = pn->next;
+	  pn->next = tpn;
+	}
+    }
+
+  /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */
+  /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */
+
+  tpn->client = (ClientPtr)NULL;
+
+  AddResource(faked, VncNotifyList, tpn);
+
+  tpn->client = client;
+  return Success;
+
+}
+
+static int
+VncDestroyNotifyList(pointer pn, XID id)
+{
+  VncNotifyListPtr cpn = (VncNotifyListPtr) pn;
+
+  cpn->client = NULL;
+
+  return Success;
+}
+
+static Bool
+CreateResourceTypes(void)
+{
+  if (VncResourceGeneration == serverGeneration) return TRUE;
+
+  VncResourceGeneration = serverGeneration;
+
+  if (!(VncNotifyList = CreateNewResourceType(VncDestroyNotifyList)))
+    {
+      ErrorF("CreateResourceTypes: failed to allocate vnc notify list resource.\n");
+      return FALSE;
+    }
+
+  return TRUE;
+
+}
+
+static unsigned long vncCreateScreenResourcesIndex;
+static unsigned long vncExtGeneration = 0;
+extern Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart);
+
+/* copied from miscrinit.c */
+typedef struct
+{
+    pointer pbits; /* pointer to framebuffer */
+    int width;    /* delta to add to a framebuffer addr to move one row down */
+} miScreenInitParmsRec, *miScreenInitParmsPtr;
+
+#if 0
+static Bool
+vncCreateScreenResources(ScreenPtr pScreen)
+{
+  int ret = TRUE;
+  CreateScreenResourcesProcPtr CreateScreenResources =
+    (CreateScreenResourcesProcPtr)(pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr);
+  miScreenInitParmsPtr pScrInitParms;
+
+  pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate;
+
+  if ( pScreen->CreateScreenResources != vncCreateScreenResources ) {
+    /* Can't find hook we are hung on */
+	xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */,
+		  "vncCreateScreenResources %p called when not in pScreen->CreateScreenResources %p n",
+		   vncCreateScreenResources, pScreen->CreateScreenResources );
+  }
+
+  /* Now do our stuff */
+  VNCInit(pScreen, pScrInitParms->pbits);
+
+  /* Unhook this function ... */
+  pScreen->CreateScreenResources = CreateScreenResources;
+  pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr = NULL;
+
+  /* ... and call the previous CreateScreenResources fuction, if any */
+  if (NULL!=pScreen->CreateScreenResources) {
+    ret = (*pScreen->CreateScreenResources)(pScreen);
+  }
+
+#ifdef DEBUG
+  ErrorF("vncCreateScreenResources() returns %d\n", ret);
+#endif
+  return (ret);
+}
+#endif
+
+void
+VncExtensionInit(void)
+{
+    ExtensionEntry	*extEntry;
+
+ErrorF("INIT1\n");
+    if (vncExtGeneration != serverGeneration) {
+	unsigned int i;
+
+	vncExtGeneration = serverGeneration;
+
+    	if ( ((vncCreateScreenResourcesIndex = AllocateScreenPrivateIndex()) < 0) )
+		return;
+
+#if 0
+    	for (i = 0 ; i < screenInfo.numScreens; i++) 
+	{
+      	    screenInfo.screens[i]->devPrivates[vncCreateScreenResourcesIndex].ptr
+	 		= (void*)(&dmxScreens[i]->pScreen->CreateScreenResources);
+      	    dmxScreens[i].pScreen->CreateScreenResources = vncCreateScreenResources;
+    	}
+#endif
+
+	gethostname(rfbThisHost, 255);
+    }
+
+ErrorF("INIT2\n");
+    if (!CreateResourceTypes())
+	    return;
+ErrorF("INIT3\n");
+
+    extEntry = AddExtension(VNC_EXTENSION_NAME,
+			    XVncNumberEvents, XVncNumberErrors,
+			    ProcVncDispatch, SProcVncDispatch,
+                            VncResetProc, StandardMinorOpcode);
+
+    VncErrorBase = extEntry->errorBase;
+    VncEventBase = extEntry->eventBase;
+
+    EventSwapVector[VncEventBase + XVncConnected] =
+	(EventSwapPtr)SwapVncConnectedEvent;
+    EventSwapVector[VncEventBase + XVncDisconnected] =
+	(EventSwapPtr)SwapVncDisconnectedEvent;
+#ifdef CHROMIUM
+    EventSwapVector[VncEventBase + XVncChromiumConnected] =
+	(EventSwapPtr)SwapVncChromiumConnectedEvent;
+#endif
+ErrorF("INIT EXT\n");
+} /* VncExtensionInit */
diff -u -rNp a/hw/dmx/vnc/vncInit.c b/hw/dmx/vnc/vncInit.c
--- a/hw/dmx/vnc/vncInit.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/vncInit.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,436 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include "rfb.h"
+
+#if DMXVNC
+#include "../dmx.h"
+#include "../dmxcb.h"
+#endif
+
+#include <time.h>
+#include "fb.h"
+
+#include "dixstruct.h"
+#include "compiler.h"
+
+#include "mipointer.h"
+#include "mibstore.h"
+
+#include "globals.h"
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include <netinet/in.h>
+
+int vncScreenPrivateIndex = -1;
+int rfbGCIndex = -1;
+int inetdSock = -1;
+Atom VNC_LAST_CLIENT_ID = 0;
+Atom VNC_CONNECT = 0;
+char *desktopName = "x11";
+char rfbThisHost[256];
+
+extern void VncExtensionInit(void);
+
+extern void vncInitMouse(void);
+extern void vncInitKeyb(void);
+Bool VNCInit(ScreenPtr pScreen, DMXScreenInfo *dmxScreen);
+
+#ifndef XFree86LOADER
+static unsigned long VNCGeneration = 0;
+#endif
+static void rfbWakeupHandler (int i, pointer blockData, unsigned long err, pointer pReadmask);
+
+/*
+ * rfbLog prints a time-stamped message to the log file (stderr).
+ */
+
+void rfbLog(char *format, ...)
+{
+    va_list args;
+    char buf[256];
+    time_t clock;
+
+    va_start(args, format);
+
+    time(&clock);
+    strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock));
+    fprintf(stderr, buf);
+
+    vfprintf(stderr, format, args);
+    fflush(stderr);
+
+    va_end(args);
+}
+
+void rfbLogPerror(char *str)
+{
+    rfbLog("");
+    perror(str);
+}
+
+
+static ScreenPtr TheVNCScreen = NULL;
+
+
+static void
+nopGetImage(DrawablePtr pDrawable, int sx, int sy,
+            int w, int h, unsigned int format,
+            unsigned long planemask, char *pdstLine)
+{
+   int i, j;
+
+   for (i = 0; i < 1; i++) {
+      unsigned int *dst = (unsigned int *) pdstLine;
+      for (j = 0; j < w*h; j++) {
+         dst[j] = 0xff00ff;
+      }
+   }
+
+   /* Eventually, call the DMX/Xinerama GetImage function */
+}
+
+/*
+ * Called by DMX's InitOutput()
+ */
+void
+VNCInit2(void)
+{
+    vncScreenPtr pScreenPriv;
+    VisualPtr v = NULL;
+    int i;
+
+    rfbLog("DMXVNC: Enter VNCInit2\n");
+
+    pScreenPriv = xalloc(sizeof(vncScreenRec));
+    pScreenPriv->width = dmxGlobalWidth;
+    pScreenPriv->height = dmxGlobalHeight;
+    pScreenPriv->rfbAuthTries = 0;
+    pScreenPriv->rfbAuthTooManyTries = FALSE;
+    pScreenPriv->timer = NULL;
+    pScreenPriv->udpPort = 0;
+    pScreenPriv->rfbListenSock = -1;
+    pScreenPriv->udpSock = -1;
+    pScreenPriv->udpSockConnected = FALSE;
+    pScreenPriv->httpListenSock = -1;
+    pScreenPriv->httpSock = -1;
+    pScreenPriv->maxFd = 0;
+    pScreenPriv->rfbAuthPasswdFile = NULL;
+    pScreenPriv->httpDir = NULL;
+    pScreenPriv->rfbInstalledColormap = NULL;
+    pScreenPriv->interface.s_addr = htonl (INADDR_ANY);
+
+    pScreenPriv->rfbPort = 0;
+    pScreenPriv->httpPort = 0;
+    pScreenPriv->rfbAuthPasswdFile = NULL;
+    pScreenPriv->httpDir = NULL;
+    pScreenPriv->rfbAlwaysShared = FALSE;
+    pScreenPriv->rfbNeverShared = FALSE;
+    pScreenPriv->rfbUserAccept = FALSE;
+    pScreenPriv->useGetImage = TRUE; /* For DMX */
+    pScreenPriv->rfbViewOnly = FALSE;
+    pScreenPriv->rfbDontDisconnect = FALSE;
+    pScreenPriv->loginAuthEnabled = FALSE;
+
+    /* Find the root window's visual.
+     * XXX this might be the wrong info to use below.
+     */
+    for (i = 0; i < screenInfo.screens[0]->numVisuals; i++) {
+        v = screenInfo.screens[0]->visuals + i;
+        if (v->vid == screenInfo.screens[0]->rootVisual) {
+            break;
+        }
+    }
+
+    /* XXX is this the right depth and bpp? */
+    /* With DMX, screenInfo.screens[0]->rootDepth is 24 and that doesn't
+     * work in translate.c!  We're just using 32.
+     */
+    pScreenPriv->rfbServerFormat.bitsPerPixel = 32;
+    pScreenPriv->rfbServerFormat.depth = 32;
+    pScreenPriv->rfbServerFormat.bigEndian = 0;
+    pScreenPriv->rfbServerFormat.trueColour = (v->class == TrueColor);
+    if (pScreenPriv->rfbServerFormat.trueColour) {
+	pScreenPriv->rfbServerFormat.redMax = v->redMask >> v->offsetRed;
+	pScreenPriv->rfbServerFormat.greenMax = v->greenMask >> v->offsetGreen;
+	pScreenPriv->rfbServerFormat.blueMax = v->blueMask >> v->offsetBlue;
+	pScreenPriv->rfbServerFormat.redShift = v->offsetRed;
+	pScreenPriv->rfbServerFormat.greenShift = v->offsetGreen;
+	pScreenPriv->rfbServerFormat.blueShift = v->offsetBlue;
+    } else {
+	pScreenPriv->rfbServerFormat.redMax
+	    = pScreenPriv->rfbServerFormat.greenMax 
+	    = pScreenPriv->rfbServerFormat.blueMax = 0;
+	pScreenPriv->rfbServerFormat.redShift
+	    = pScreenPriv->rfbServerFormat.greenShift 
+	    = pScreenPriv->rfbServerFormat.blueShift = 0;
+    }
+
+    /* Allocate/init TheVNCScreen object */
+    vncScreenPrivateIndex = 0;
+    assert(!TheVNCScreen);
+    TheVNCScreen = (ScreenPtr) Xcalloc(1, sizeof(struct _Screen));
+    TheVNCScreen->devPrivates = (DevUnion *) Xcalloc(1, sizeof(DevUnion));
+    TheVNCScreen->devPrivates[vncScreenPrivateIndex].ptr = pScreenPriv;
+    TheVNCScreen->GetImage = nopGetImage;
+
+    rfbInitSockets(TheVNCScreen);
+    if (inetdSock == -1)
+       httpInitSockets(TheVNCScreen);
+}
+
+
+Bool
+VNCInit(ScreenPtr pScreen, DMXScreenInfo *pScrn)
+{
+    VisualPtr visual;
+    vncScreenPtr pScreenPriv;
+#if 0
+    char *interface_str = NULL;
+#endif
+#ifdef RENDER
+    PictureScreenPtr	ps;
+#endif
+
+    rfbLog("DMXVNC: Enter VNCInit\n");
+
+#ifndef XFree86LOADER
+    if (VNCGeneration != serverGeneration) {
+	VNCGeneration = serverGeneration;
+	if ( ((vncScreenPrivateIndex = AllocateScreenPrivateIndex()) < 0) ||
+	    ((rfbGCIndex = AllocateGCPrivateIndex()) < 0) )
+		return FALSE;
+    }
+#endif
+
+    if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec))) {
+	ErrorF("VNCInit(): failed to allocate GCIndex\n");
+	return FALSE;
+    }
+
+    if (!(pScreenPriv = xalloc(sizeof(vncScreenRec))))
+	return FALSE;
+
+    pScreen->devPrivates[vncScreenPrivateIndex].ptr = (pointer)pScreenPriv;
+
+    pScreenPriv->rfbAuthTries = 0;
+    pScreenPriv->rfbAuthTooManyTries = FALSE;
+    pScreenPriv->timer = NULL;
+    pScreenPriv->udpPort = 0;
+    pScreenPriv->rfbListenSock = -1;
+    pScreenPriv->udpSock = -1;
+    pScreenPriv->udpSockConnected = FALSE;
+    pScreenPriv->httpListenSock = -1;
+    pScreenPriv->httpSock = -1;
+    pScreenPriv->maxFd = 0;
+    pScreenPriv->rfbAuthPasswdFile = NULL;
+    pScreenPriv->httpDir = NULL;
+    pScreenPriv->rfbInstalledColormap = NULL;
+    pScreenPriv->interface.s_addr = htonl (INADDR_ANY);
+
+    pScreenPriv->rfbPort = 0;
+    pScreenPriv->httpPort = 0;
+    pScreenPriv->rfbAuthPasswdFile = NULL;
+    pScreenPriv->httpDir = NULL;
+    pScreenPriv->rfbAlwaysShared = FALSE;
+    pScreenPriv->rfbNeverShared = FALSE;
+    pScreenPriv->rfbUserAccept = FALSE;
+    pScreenPriv->useGetImage = TRUE; /* For DMX */
+    pScreenPriv->rfbViewOnly = FALSE;
+    pScreenPriv->rfbDontDisconnect = FALSE;
+    pScreenPriv->loginAuthEnabled = FALSE;
+
+#if 0
+    if (xf86ReturnOptValBool(options, OPTION_LOCALHOST, FALSE))
+	pScreenPriv->interface.s_addr = htonl (INADDR_LOOPBACK);
+
+    interface_str = xf86GetOptValString(options, OPTION_INTERFACE);
+
+    if (interface_str && pScreenPriv->interface.s_addr == htonl(INADDR_ANY)) {
+	Bool failed = FALSE;
+	struct in_addr got;
+	unsigned long octet;
+	char *p = interface_str, *end;
+	int q;
+
+	for (q = 0; q < 4; q++) {
+	    octet = strtoul (p, &end, 10);
+
+	    if (p == end || octet > 255)
+		failed = TRUE;
+
+	    if ((q < 3 && *end != '.') ||
+	        (q == 3 && *end != '\0'))
+		failed = TRUE;
+
+	    got.s_addr = (got.s_addr << 8) | octet;
+	    p = end + 1;
+	}
+
+	if (!failed)
+	    pScreenPriv->interface.s_addr = htonl (got.s_addr);
+	else
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VNC interface option malformed, not using.\n");
+    }
+#endif
+
+    if (!VNC_LAST_CLIENT_ID)
+    	VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID",
+				  strlen("VNC_LAST_CLIENT_ID"), TRUE);
+    if (!VNC_CONNECT)
+    	VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE);
+
+    rfbInitSockets(pScreen);
+    if (inetdSock == -1)
+    	httpInitSockets(pScreen);
+   
+#ifdef CORBA
+    initialiseCORBA(argc, argv, desktopName);
+#endif
+
+    pScreenPriv->width = pScrn->scrnWidth;
+    pScreenPriv->height = pScrn->scrnHeight;
+    pScreenPriv->depth = pScrn->beDepth;
+    pScreenPriv->paddedWidthInBytes = PixmapBytePad(pScrn->scrnWidth, pScrn->beDepth);
+    pScreenPriv->bitsPerPixel = rfbBitsPerPixel(pScrn->beDepth);
+    pScreenPriv->pfbMemory = NULL;
+    pScreenPriv->oldpfbMemory = NULL;
+
+    pScreenPriv->cursorIsDrawn = TRUE;
+    pScreenPriv->dontSendFramebufferUpdate = FALSE;
+
+    pScreenPriv->CloseScreen = pScreen->CloseScreen;
+    pScreenPriv->CreateGC = pScreen->CreateGC;
+    pScreenPriv->PaintWindowBackground = pScreen->PaintWindowBackground;
+    pScreenPriv->PaintWindowBorder = pScreen->PaintWindowBorder;
+    pScreenPriv->CopyWindow = pScreen->CopyWindow;
+    pScreenPriv->ClearToBackground = pScreen->ClearToBackground;
+    pScreenPriv->RestoreAreas = pScreen->RestoreAreas;
+    pScreenPriv->WakeupHandler = pScreen->WakeupHandler;
+    pScreenPriv->InstallColormap = pScreen->InstallColormap;
+    pScreenPriv->UninstallColormap = pScreen->UninstallColormap;
+    pScreenPriv->ListInstalledColormaps = pScreen->ListInstalledColormaps;
+    pScreenPriv->StoreColors = pScreen->StoreColors;
+#ifdef CHROMIUM
+    pScreenPriv->RealizeWindow = pScreen->RealizeWindow;
+    pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow;
+    pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
+    pScreenPriv->PositionWindow = pScreen->PositionWindow;
+    pScreenPriv->ResizeWindow = pScreen->ResizeWindow;
+    pScreenPriv->ClipNotify = pScreen->ClipNotify;
+#endif
+#ifdef RENDER
+    ps = GetPictureScreenIfSet(pScreen);
+    if (ps)
+    	pScreenPriv->Composite = ps->Composite;
+#endif
+    pScreen->CloseScreen = rfbCloseScreen;
+    pScreen->CreateGC = rfbCreateGC;
+    pScreen->PaintWindowBackground = rfbPaintWindowBackground;
+    pScreen->PaintWindowBorder = rfbPaintWindowBorder;
+    pScreen->CopyWindow = rfbCopyWindow;
+    pScreen->ClearToBackground = rfbClearToBackground;
+    pScreen->RestoreAreas = rfbRestoreAreas;
+    pScreen->WakeupHandler = rfbWakeupHandler;
+    pScreen->InstallColormap = rfbInstallColormap;
+    pScreen->UninstallColormap = rfbUninstallColormap;
+    pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
+    pScreen->StoreColors = rfbStoreColors;
+
+#ifdef CHROMIUM
+    pScreen->RealizeWindow = rfbRealizeWindow;
+    pScreen->UnrealizeWindow = rfbUnrealizeWindow;
+    pScreen->DestroyWindow = rfbDestroyWindow;
+    pScreen->PositionWindow = rfbPositionWindow;
+    pScreen->ResizeWindow = rfbResizeWindow;
+    pScreen->ClipNotify = rfbClipNotify;
+#endif
+#ifdef RENDER
+    if (ps)
+    	ps->Composite = rfbComposite;
+#endif
+
+    for (visual = pScreen->visuals; visual->vid != pScreen->rootVisual; visual++)
+	;
+
+    if (!visual) {
+	ErrorF("rfbScreenInit: couldn't find root visual\n");
+	return FALSE;
+    }
+
+    pScreenPriv->rfbServerFormat.bitsPerPixel = pScrn->beBPP;
+    pScreenPriv->rfbServerFormat.depth = pScrn->beDepth;
+    pScreenPriv->rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest);
+    pScreenPriv->rfbServerFormat.trueColour = (visual->class == TrueColor);
+    if (pScreenPriv->rfbServerFormat.trueColour) {
+	pScreenPriv->rfbServerFormat.redMax = visual->redMask >> visual->offsetRed;
+	pScreenPriv->rfbServerFormat.greenMax = visual->greenMask >> visual->offsetGreen;
+	pScreenPriv->rfbServerFormat.blueMax = visual->blueMask >> visual->offsetBlue;
+	pScreenPriv->rfbServerFormat.redShift = visual->offsetRed;
+	pScreenPriv->rfbServerFormat.greenShift = visual->offsetGreen;
+	pScreenPriv->rfbServerFormat.blueShift = visual->offsetBlue;
+    } else {
+	pScreenPriv->rfbServerFormat.redMax
+	    = pScreenPriv->rfbServerFormat.greenMax 
+	    = pScreenPriv->rfbServerFormat.blueMax = 0;
+	pScreenPriv->rfbServerFormat.redShift
+	    = pScreenPriv->rfbServerFormat.greenShift 
+	    = pScreenPriv->rfbServerFormat.blueShift = 0;
+    }
+
+    return TRUE;
+}
+
+static void
+rfbWakeupHandler (
+    int 	i,	
+    pointer     blockData,
+    unsigned long err,
+    pointer     pReadmask
+){
+    ScreenPtr      pScreen = screenInfo.screens[i];
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+    /*DMXScreenInfo *pScrn = &dmxScreens[pScreen->myNum];*/
+
+    rfbRootPropertyChange(pScreen); /* Check clipboard */
+
+    rfbCheckFds(pScreen);
+    httpCheckFds(pScreen);
+#ifdef CORBA
+    corbaCheckFds();
+#endif
+
+    pScreen->WakeupHandler = pScreenPriv->WakeupHandler;
+    (*pScreen->WakeupHandler) (i, blockData, err, pReadmask);
+    pScreen->WakeupHandler = rfbWakeupHandler;
+}
+
+
+/*BP*/
+void
+rfbWakeupHandler2(void)
+{
+    ScreenPtr      pScreen = TheVNCScreen;
+    rfbRootPropertyChange(pScreen); /* Check clipboard */
+    rfbCheckFds(pScreen);
+    httpCheckFds(pScreen);
+}
diff -u -rNp a/hw/dmx/vnc/vncint.h b/hw/dmx/vnc/vncint.h
--- a/hw/dmx/vnc/vncint.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/vncint.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,154 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#ifndef _VNCINT_H_
+#define _VNCINT_H_
+
+#include <netinet/in.h>
+
+extern int vncScreenPrivateIndex;
+
+#define VNCPTR(pScreen)\
+   (vncScreenPtr)((pScreen)->devPrivates[vncScreenPrivateIndex].ptr)
+
+typedef struct {
+    int			rfbPort;
+    int			rdpPort;
+    int			udpPort;
+    int			rfbListenSock;
+    int			rdpListenSock;
+    int			udpSock;
+    int			httpPort;
+    int			httpListenSock;
+    int			httpSock;
+    char *		httpDir;
+    char		buf[HTTP_BUF_SIZE];
+    Bool		udpSockConnected;
+    char *		rfbAuthPasswdFile;
+    size_t		buf_filled;
+    int			maxFd;
+    fd_set		allFds;
+    unsigned char *	oldpfbMemory;
+    Bool		useGetImage;
+    Bool		rfbAlwaysShared;
+    Bool		rfbNeverShared;
+    Bool		rfbDontDisconnect;
+    Bool		rfbUserAccept;
+    Bool		rfbViewOnly;
+    unsigned char *	pfbMemory;
+    int 		paddedWidthInBytes;
+    ColormapPtr 	rfbInstalledColormap;
+    ColormapPtr		savedColormap;
+    rfbPixelFormat	rfbServerFormat;
+    Bool		rfbAuthTooManyTries;
+    int			rfbAuthTries;
+    Bool		loginAuthEnabled;
+    struct in_addr	interface;
+    OsTimerPtr 		timer;
+    char 		updateBuf[UPDATE_BUF_SIZE];
+    int 		ublen;
+    int 		width;
+    int 		height;
+    int 		depth;
+    int 		bitsPerPixel;
+
+    /* The following two members are used to minimise the amount of unnecessary
+       drawing caused by cursor movement.  Whenever any drawing affects the
+       part of the screen where the cursor is, the cursor is removed first and
+       then the drawing is done (this is what the sprite routines test for).
+       Afterwards, however, we do not replace the cursor, even when the cursor
+       is logically being moved across the screen.  We only draw the cursor
+       again just as we are about to send the client a framebuffer update.
+
+       We need to be careful when removing and drawing the cursor because of
+       their relationship with the normal drawing routines.  The drawing
+       routines can invoke the cursor routines, but also the cursor routines
+       themselves end up invoking drawing routines.
+
+       Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by
+       doing a CopyArea from a pixmap to the screen, where the pixmap contains
+       the saved contents of the screen under the cursor.  Before doing this,
+       however, we set cursorIsDrawn to FALSE.  Then, when CopyArea is called,
+       it sees that cursorIsDrawn is FALSE and so doesn't feel the need to
+       (recursively!) remove the cursor before doing it.
+
+       Putting up the cursor (rfbSpriteRestoreCursor) involves a call to
+       PushPixels.  While this is happening, cursorIsDrawn must be FALSE so
+       that PushPixels doesn't think it has to remove the cursor first.
+       Obviously cursorIsDrawn is set to TRUE afterwards.
+
+       Another problem we face is that drawing routines sometimes cause a
+       framebuffer update to be sent to the RFB client.  When the RFB client is
+       already waiting for a framebuffer update and some drawing to the
+       framebuffer then happens, the drawing routine sees that the client is
+       ready, so it calls rfbSendFramebufferUpdate.  If the cursor is not drawn
+       at this stage, it must be put up, and so rfbSpriteRestoreCursor is
+       called.  However, if the original drawing routine was actually called
+       from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't
+       want this to happen.  So both the cursor routines set
+       dontSendFramebufferUpdate to TRUE, and all the drawing routines check
+       this before calling rfbSendFramebufferUpdate. */
+
+    Bool cursorIsDrawn;		    /* TRUE if the cursor is currently drawn */
+    Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the
+				       cursor */
+
+    /* wrapped screen functions */
+
+    CloseScreenProcPtr			CloseScreen;
+    CreateGCProcPtr			CreateGC;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    RestoreAreasProcPtr			RestoreAreas;
+    ScreenWakeupHandlerProcPtr 		WakeupHandler;
+    InstallColormapProcPtr		InstallColormap;
+    UninstallColormapProcPtr		UninstallColormap;
+    ListInstalledColormapsProcPtr 	ListInstalledColormaps;
+    StoreColorsProcPtr			StoreColors;
+    DisplayCursorProcPtr		DisplayCursor;
+    CursorPtr				pCurs;
+    Bool				(*UseHWCursor)(ScreenPtr, CursorPtr);
+    Bool				(*UseHWCursorARGB)(ScreenPtr, CursorPtr);
+    Bool				*SWCursor;
+#ifdef CHROMIUM
+    RealizeWindowProcPtr		RealizeWindow;
+    UnrealizeWindowProcPtr		UnrealizeWindow;
+    DestroyWindowProcPtr		DestroyWindow;
+    ResizeWindowProcPtr			ResizeWindow;
+    PositionWindowProcPtr		PositionWindow;
+    ClipNotifyProcPtr			ClipNotify;
+#endif
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+#endif
+
+} vncScreenRec, *vncScreenPtr;
+
+extern Bool vncUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs);
+extern Bool vncUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs);
+
+extern void
+rfbSendChromiumStart(unsigned int ipaddress, unsigned int port);
+
+#endif /* _VNCINT_H_ */
+
diff -u -rNp a/hw/dmx/vnc/xistubs.c b/hw/dmx/vnc/xistubs.c
--- a/hw/dmx/vnc/xistubs.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/xistubs.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,319 @@
+/* $Xorg: stubs.c,v 1.4 2001/02/09 02:04:35 xorgcvs Exp $ */
+
+/************************************************************
+
+Copyright 1989, 1998  The Open Group
+
+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
+OPEN GROUP 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 Open Group 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 Open Group.
+
+Copyright 1989 by Hewlett-Packard Company, Palo Alto, California.
+
+			All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Hewlett-Packard not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+********************************************************/
+/* $XFree86: xc/programs/Xserver/Xi/stubs.c,v 3.3 2001/01/17 22:13:26 dawes Exp $ */
+
+/*
+ * stubs.c -- stub routines for the X server side of the XINPUT
+ * extension.  This file is mainly to be used only as documentation.
+ * There is not much code here, and you can't get a working XINPUT
+ * server just using this.
+ * The Xvfb server uses this file so it will compile with the same
+ * object files as the real X server for a platform that has XINPUT.
+ * Xnest could do the same thing.
+ */
+
+#define	 NEED_EVENTS
+#include "X11/X.h"
+#include "X11/Xproto.h"
+#include "inputstr.h"
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+/*#include "XIstubs.h"*/
+
+/***********************************************************************
+ *
+ * Caller:	ProcXChangeKeyboardDevice
+ *
+ * This procedure does the implementation-dependent portion of the work
+ * needed to change the keyboard device.
+ *
+ * The X keyboard device has a FocusRec.  If the device that has been 
+ * made into the new X keyboard did not have a FocusRec, 
+ * ProcXChangeKeyboardDevice will allocate one for it.
+ *
+ * If you do not want clients to be able to focus the old X keyboard
+ * device, call DeleteFocusClassDeviceStruct to free the FocusRec.
+ *
+ * If you support input devices with keys that you do not want to be 
+ * used as the X keyboard, you need to check for them here and return 
+ * a BadDevice error.
+ *
+ * The default implementation is to do nothing (assume you do want
+ * clients to be able to focus the old X keyboard).  The commented-out
+ * sample code shows what you might do if you don't want the default.
+ *
+ */
+
+int
+ChangeKeyboardDevice (old_dev, new_dev)
+    DeviceIntPtr	old_dev;
+    DeviceIntPtr	new_dev;
+    {
+    /***********************************************************************
+     DeleteFocusClassDeviceStruct(old_dev);	 * defined in xchgptr.c *
+    **********************************************************************/
+    return BadMatch;
+    }
+
+
+/***********************************************************************
+ *
+ * Caller:	ProcXChangePointerDevice
+ *
+ * This procedure does the implementation-dependent portion of the work
+ * needed to change the pointer device.
+ *
+ * The X pointer device does not have a FocusRec.  If the device that
+ * has been made into the new X pointer had a FocusRec, 
+ * ProcXChangePointerDevice will free it.
+ *
+ * If you want clients to be able to focus the old pointer device that
+ * has now become accessible through the input extension, you need to 
+ * add a FocusRec to it here.
+ *
+ * The XChangePointerDevice protocol request also allows the client
+ * to choose which axes of the new pointer device are used to move 
+ * the X cursor in the X- and Y- directions.  If the axes are different
+ * than the default ones, you need to keep track of that here.
+ *
+ * If you support input devices with valuators that you do not want to be 
+ * used as the X pointer, you need to check for them here and return a 
+ * BadDevice error.
+ *
+ * The default implementation is to do nothing (assume you don't want
+ * clients to be able to focus the old X pointer).  The commented-out
+ * sample code shows what you might do if you don't want the default.
+ *
+ */
+
+int
+#if NeedFunctionPrototypes
+ChangePointerDevice (
+    DeviceIntPtr	old_dev,
+    DeviceIntPtr	new_dev,
+    unsigned char	x,
+    unsigned char	y)
+#else
+ChangePointerDevice (old_dev, new_dev, x, y)
+    DeviceIntPtr	old_dev, new_dev;
+    unsigned char	x, y;
+#endif
+    {
+    /***********************************************************************
+    InitFocusClassDeviceStruct(old_dev);	* allow focusing old ptr*
+
+    x_axis = x;					* keep track of new x-axis*
+    y_axis = y;					* keep track of new y-axis*
+    if (x_axis != 0 || y_axis != 1)
+	axes_changed = TRUE;			* remember axes have changed*
+    else
+	axes_changed = FALSE;
+    *************************************************************************/
+    return BadMatch;
+    }
+
+/***********************************************************************
+ *
+ * Caller:	ProcXCloseDevice
+ *
+ * Take care of implementation-dependent details of closing a device.
+ * Some implementations may actually close the device, others may just
+ * remove this clients interest in that device.
+ *
+ * The default implementation is to do nothing (assume all input devices
+ * are initialized during X server initialization and kept open).
+ *
+ */
+
+void
+CloseInputDevice (d, client)
+    DeviceIntPtr d;
+    ClientPtr client;
+    {
+    }
+
+/***********************************************************************
+ *
+ * Caller:	ProcXListInputDevices
+ *
+ * This is the implementation-dependent routine to initialize an input 
+ * device to the point that information about it can be listed.
+ * Some implementations open all input devices when the server is first
+ * initialized, and never close them.  Other implementations open only
+ * the X pointer and keyboard devices during server initialization,
+ * and only open other input devices when some client makes an
+ * XOpenDevice request.  If some other process has the device open, the
+ * server may not be able to get information about the device to list it.
+ *
+ * This procedure should be used by implementations that do not initialize
+ * all input devices at server startup.  It should do device-dependent
+ * initialization for any devices not previously initialized, and call
+ * AddInputDevice for each of those devices so that a DeviceIntRec will be 
+ * created for them.
+ *
+ * The default implementation is to do nothing (assume all input devices
+ * are initialized during X server initialization and kept open).
+ * The commented-out sample code shows what you might do if you don't want 
+ * the default.
+ *
+ */
+
+void
+AddOtherInputDevices ()
+    {
+    /**********************************************************************
+     for each uninitialized device, do something like: 
+
+    DeviceIntPtr dev;
+    DeviceProc deviceProc;
+    pointer private;
+
+    dev = (DeviceIntPtr) AddInputDevice(deviceProc, TRUE);
+    dev->public.devicePrivate = private;
+    RegisterOtherDevice(dev);
+    dev->inited = ((*dev->deviceProc)(dev, DEVICE_INIT) == Success);
+    ************************************************************************/
+
+    }
+
+/***********************************************************************
+ *
+ * Caller:	ProcXOpenDevice
+ *
+ * This is the implementation-dependent routine to open an input device.
+ * Some implementations open all input devices when the server is first
+ * initialized, and never close them.  Other implementations open only
+ * the X pointer and keyboard devices during server initialization,
+ * and only open other input devices when some client makes an
+ * XOpenDevice request.  This entry point is for the latter type of 
+ * implementation.
+ *
+ * If the physical device is not already open, do it here.  In this case,
+ * you need to keep track of the fact that one or more clients has the
+ * device open, and physically close it when the last client that has
+ * it open does an XCloseDevice.
+ *
+ * The default implementation is to do nothing (assume all input devices
+ * are opened during X server initialization and kept open).
+ *
+ */
+
+void
+OpenInputDevice (dev, client, status)
+    DeviceIntPtr dev;
+    ClientPtr client;
+    int *status;
+    {
+    }
+
+/****************************************************************************
+ *
+ * Caller:	ProcXSetDeviceMode
+ *
+ * Change the mode of an extension device.
+ * This function is used to change the mode of a device from reporting
+ * relative motion to reporting absolute positional information, and
+ * vice versa.
+ * The default implementation below is that no such devices are supported.
+ *
+ */
+
+int
+SetDeviceMode (client, dev, mode)
+    register	ClientPtr	client;
+    DeviceIntPtr dev;
+    int		mode;
+    {
+    return BadMatch;
+    }
+
+/****************************************************************************
+ *
+ * Caller:	ProcXSetDeviceValuators
+ *
+ * Set the value of valuators on an extension input device.
+ * This function is used to set the initial value of valuators on
+ * those input devices that are capable of reporting either relative
+ * motion or an absolute position, and allow an initial position to be set.
+ * The default implementation below is that no such devices are supported.
+ *
+ */
+
+int
+SetDeviceValuators (client, dev, valuators, first_valuator, num_valuators)
+    register	ClientPtr	client;
+    DeviceIntPtr dev;
+    int		*valuators;
+    int		first_valuator;
+    int		num_valuators;
+    {
+    return BadMatch;
+    }
+
+/****************************************************************************
+ *
+ * Caller:	ProcXChangeDeviceControl
+ *
+ * Change the specified device controls on an extension input device.
+ *
+ */
+
+int
+ChangeDeviceControl (client, dev, control)
+    register	ClientPtr	client;
+    DeviceIntPtr dev;
+    xDeviceCtl	*control;
+    {
+    switch (control->control)
+	{
+	case DEVICE_RESOLUTION:
+	    return (BadMatch);
+	default:
+	    return (BadMatch);
+	}
+    }
diff -u -rNp a/hw/dmx/vnc/zlib.c b/hw/dmx/vnc/zlib.c
--- a/hw/dmx/vnc/zlib.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/dmx/vnc/zlib.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,306 @@
+/*
+ * zlib.c
+ *
+ * Routines to implement zlib based encoding (deflate).
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ * For the latest source code, please check:
+ *
+ * http://www.developVNC.org/
+ *
+ * or send email to feedback@developvnc.org.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rfb.h"
+
+/*
+ * zlibBeforeBuf contains pixel data in the client's format.
+ * zlibAfterBuf contains the zlib (deflated) encoding version.
+ * If the zlib compressed/encoded version is
+ * larger than the raw data or if it exceeds zlibAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int zlibBeforeBufSize = 0;
+static char *zlibBeforeBuf = NULL;
+
+static int zlibAfterBufSize = 0;
+static char *zlibAfterBuf = NULL;
+static int zlibAfterBufLen;
+
+/*
+ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
+ *                              rectangle encoding.
+ */
+
+static Bool
+rfbSendOneRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h)
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbZlibHeader hdr;
+    int deflateResult;
+    int previousOut;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+    	   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize;
+    int maxCompSize;
+
+    maxRawSize = (pVNC->width * pVNC->height
+                  * (cl->format.bitsPerPixel / 8));
+
+    if (zlibBeforeBufSize < maxRawSize) {
+	zlibBeforeBufSize = maxRawSize;
+	if (zlibBeforeBuf == NULL)
+	    zlibBeforeBuf = (char *)xalloc(zlibBeforeBufSize);
+	else
+	    zlibBeforeBuf = (char *)xrealloc(zlibBeforeBuf, zlibBeforeBufSize);
+    }
+
+    /* zlib compression is not useful for very small data sets.
+     * So, we just send these raw without any compression.
+     */
+    if (( w * h * (pVNC->bitsPerPixel / 8)) <
+          VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
+
+        int result;
+
+        /* The translation function (used also by the in raw encoding)
+         * requires 4/2/1 byte alignment in the output buffer (which is
+         * pVNC->updateBuf for the raw encoding) based on the bitsPerPixel of
+         * the viewer/client.  This prevents SIGBUS errors on some
+         * architectures like SPARC, PARISC...
+         */
+        if (( cl->format.bitsPerPixel > 8 ) &&
+            ( pVNC->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
+            if (!rfbSendUpdateBuf(cl))
+                return FALSE;
+        }
+
+        result = rfbSendRectEncodingRaw(cl, x, y, w, h);
+
+        return result;
+
+    }
+
+    /*
+     * zlib requires output buffer to be slightly larger than the input
+     * buffer, in the worst case.
+     */
+    maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
+
+    if (zlibAfterBufSize < maxCompSize) {
+	zlibAfterBufSize = maxCompSize;
+	if (zlibAfterBuf == NULL)
+	    zlibAfterBuf = (char *)xalloc(zlibAfterBufSize);
+	else
+	    zlibAfterBuf = (char *)xrealloc(zlibAfterBuf, zlibAfterBufSize);
+    }
+
+    /* 
+     * Convert pixel data to client format.
+     */
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, zlibBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    cl->compStream.next_in = ( Bytef * )zlibBeforeBuf;
+    cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
+    cl->compStream.next_out = ( Bytef * )zlibAfterBuf;
+    cl->compStream.avail_out = maxCompSize;
+    cl->compStream.data_type = Z_BINARY;
+
+    /* Initialize the deflation state. */
+    if ( cl->compStreamInited == FALSE ) {
+
+        cl->compStream.total_in = 0;
+        cl->compStream.total_out = 0;
+        cl->compStream.zalloc = Z_NULL;
+        cl->compStream.zfree = Z_NULL;
+        cl->compStream.opaque = Z_NULL;
+
+        deflateInit2( &(cl->compStream),
+                        cl->zlibCompressLevel,
+                        Z_DEFLATED,
+                        MAX_WBITS,
+                        MAX_MEM_LEVEL,
+                        Z_DEFAULT_STRATEGY );
+        /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
+        /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
+        cl->compStreamInited = TRUE;
+
+    }
+
+    previousOut = cl->compStream.total_out;
+
+    /* Perform the compression here. */
+    deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
+
+    /* Find the total size of the resulting compressed data. */
+    zlibAfterBufLen = cl->compStream.total_out - previousOut;
+
+    if ( deflateResult != Z_OK ) {
+        rfbLog("zlib deflation error: %s\n", cl->compStream.msg);
+        return FALSE;
+    }
+
+    /* Note that it is not possible to switch zlib parameters based on
+     * the results of the compression pass.  The reason is
+     * that we rely on the compressor and decompressor states being
+     * in sync.  Compressing and then discarding the results would
+     * cause lose of synchronization.
+     */
+
+    /* Update statics */
+    cl->rfbRectanglesSent[rfbEncodingZlib]++;
+    cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
+					 + sz_rfbZlibHeader + zlibAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingZlib);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbZlibHeader);
+    pVNC->ublen += sz_rfbZlibHeader;
+
+    for (i = 0; i < zlibAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > zlibAfterBufLen) {
+	    bytesToCopy = zlibAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &zlibAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+
+}
+
+
+/*
+ * rfbSendRectEncodingZlib - send a given rectangle using one or more
+ *                           Zlib encoding rectangles.
+ */
+
+Bool
+rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h)
+{
+    VNCSCREENPTR(cl->pScreen);
+    int  maxLines;
+    int  linesRemaining;
+    rfbRectangle partialRect;
+
+    partialRect.x = x;
+    partialRect.y = y;
+    partialRect.w = w;
+    partialRect.h = h;
+
+    /* Determine maximum pixel/scan lines allowed per rectangle. */
+    maxLines = ( ZLIB_MAX_SIZE(w) / w );
+
+    /* Initialize number of scan lines left to do. */
+    linesRemaining = h;
+
+    /* Loop until all work is done. */
+    while ( linesRemaining > 0 ) {
+
+        int linesToComp;
+
+        if ( maxLines < linesRemaining )
+            linesToComp = maxLines;
+        else
+            linesToComp = linesRemaining;
+
+        partialRect.h = linesToComp;
+
+        /* Encode (compress) and send the next rectangle. */
+        if ( ! rfbSendOneRectEncodingZlib( cl,
+                                           partialRect.x,
+                                           partialRect.y,
+                                           partialRect.w,
+                                           partialRect.h )) {
+
+            return FALSE;
+        }
+
+        /* Technically, flushing the buffer here is not extrememly
+         * efficient.  However, this improves the overall throughput
+         * of the system over very slow networks.  By flushing
+         * the buffer with every maximum size zlib rectangle, we
+         * improve the pipelining usage of the server CPU, network,
+         * and viewer CPU components.  Insuring that these components
+         * are working in parallel actually improves the performance
+         * seen by the user.
+         * Since, zlib is most useful for slow networks, this flush
+         * is appropriate for the desired behavior of the zlib encoding.
+         */
+        if (( pVNC->ublen > 0 ) &&
+            ( linesToComp == maxLines )) {
+            if (!rfbSendUpdateBuf(cl)) {
+
+                return FALSE;
+            }
+        }
+
+        /* Update remaining and incremental rectangle location. */
+        linesRemaining -= linesToComp;
+        partialRect.y += linesToComp;
+
+    }
+
+    return TRUE;
+
+}
+
+
diff -u -rNp a/hw/Makefile.am b/hw/Makefile.am
--- a/hw/Makefile.am	2006-12-01 16:15:53.000000000 +0000
+++ b/hw/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -30,6 +30,10 @@ if XPRINT
 XPRINT_SUBDIRS = xprint
 endif
 
+if XVNC
+VNC_SUBDIRS = vnc
+endif
+
 # need to add darwin support here
 
 SUBDIRS =			\
@@ -40,9 +44,10 @@ SUBDIRS =			\
 	$(XNEST_SUBDIRS)	\
 	$(DMX_SUBDIRS)          \
         $(KDRIVE_SUBDIRS)	\
+	$(VNC_SUBDIRS)		\
 	$(XPRINT_SUBDIRS)
 
-DIST_SUBDIRS = dmx xfree86 vfb xnest xwin darwin kdrive xgl xprint
+DIST_SUBDIRS = dmx xfree86 vfb xnest xwin darwin kdrive xgl xprint vnc
 
 relink:
 	for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink ; done
diff -u -rNp a/hw/vnc/auth.c b/hw/vnc/auth.c
--- a/hw/vnc/auth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/auth.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,562 @@
+/*
+ * auth.c - deal with authentication.
+ *
+ * This file implements authentication when setting up an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003-2004 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include "rfb.h"
+#include "windowstr.h"
+
+static void rfbSendSecurityType(rfbClientPtr cl, int securityType);
+static void rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType);
+static void rfbSendTunnelingCaps(rfbClientPtr cl);
+static void rfbSendAuthCaps(rfbClientPtr cl);
+static void rfbVncAuthSendChallenge(rfbClientPtr cl);
+
+/*
+ * rfbAuthNewClient is called right after negotiating the protocol
+ * version. Depending on the protocol version, we send either a code
+ * for authentication scheme to be used (protocol 3.3), or a list of
+ * possible "security types" (protocol 3.7).
+ */
+
+void
+rfbAuthNewClient(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int securityType = rfbSecTypeInvalid;
+ 
+    if ((!pVNC->rfbAuthPasswdFile && !pVNC->loginAuthEnabled) || cl->reverseConnection) {
+	securityType = rfbSecTypeNone;
+    } else {
+	if (rfbAuthIsBlocked(cl)) {
+	    rfbLog("Too many authentication failures - client rejected\n");
+	    rfbClientConnFailed(cl, "Too many authentication failures");
+	    return;
+	}
+	if (pVNC->rfbAuthPasswdFile)
+	    securityType = rfbSecTypeVncAuth;
+    }
+ 
+    if (cl->protocol_minor_ver < 7) {
+	/* Make sure we use only RFB 3.3 compatible security types. */
+	if (securityType == rfbSecTypeInvalid) {
+	    rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
+	    rfbClientConnFailed(cl, "Your viewer cannot handle required "
+				"authentication methods");
+	    return;
+	}
+	rfbSendSecurityType(cl, securityType);
+    } else {
+	/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
+	rfbSendSecurityTypeList(cl, securityType);
+    }
+}
+ 
+
+/*
+ * Tell the client what security type will be used (protocol 3.3).
+ */
+
+static void
+rfbSendSecurityType(cl, securityType)
+    rfbClientPtr cl;
+    int securityType;
+{
+    CARD32 value32;
+
+    /* Send the value. */
+    value32 = Swap32IfLE(securityType);
+    if (WriteExact(cl->sock, (char *)&value32, 4) < 0) {
+	rfbLogPerror("rfbSendSecurityType: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Decide what to do next. */
+    switch (securityType) {
+    case rfbSecTypeNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbSecTypeVncAuth:
+	/* Begin the standard VNC authentication procedure. */
+	rfbVncAuthSendChallenge(cl);
+	break;
+    default:
+	/* Impossible case (hopefully). */
+	rfbLogPerror("rfbSendSecurityType: assertion failed");
+	rfbCloseSock(cl->pScreen, cl->sock);
+    }
+}
+
+
+/*
+ * Advertise our supported security types (protocol 3.7). The list
+ * will include one standard security type (if primaryType is not set
+ * to rfbSecTypeInvalid), and then one more value telling the client
+ * that we support TightVNC protocol extensions. Thus, currently,
+ * there will be either 1 or 2 items in the list.
+ */
+
+static void
+rfbSendSecurityTypeList(cl, primaryType)
+    rfbClientPtr cl;
+    int primaryType;
+{
+    int count = 1;
+
+    /* Fill in the list of security types in the client structure. */
+    if (primaryType != rfbSecTypeInvalid) {
+	cl->securityTypes[count++] = (CARD8)primaryType;
+    }
+    cl->securityTypes[count] = (CARD8)rfbSecTypeTight;
+    cl->securityTypes[0] = (CARD8)count++;
+
+    /* Send the list. */
+    if (WriteExact(cl->sock, (char *)cl->securityTypes, count) < 0) {
+	rfbLogPerror("rfbSendSecurityTypeList: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientSecurityType. */
+    cl->state = RFB_SECURITY_TYPE;
+}
+
+
+/*
+ * Read the security type chosen by the client (protocol 3.7).
+ */
+
+void
+rfbProcessClientSecurityType(cl)
+    rfbClientPtr cl;
+{
+    int n, count, i;
+    CARD8 chosenType;
+
+    /* Read the security type. */
+    n = ReadExact(cl->sock, (char *)&chosenType, 1);
+    if (n <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientSecurityType: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientSecurityType: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Make sure it was present in the list sent by the server. */
+    count = (int)cl->securityTypes[0];
+    for (i = 1; i <= count; i++) {
+	if (chosenType == cl->securityTypes[i])
+	    break;
+    }
+    if (i > count) {
+	rfbLog("rfbProcessClientSecurityType: "
+	       "wrong security type requested\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Now go to the proper authentication procedure. */
+    switch (chosenType) {
+    case rfbSecTypeNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbSecTypeVncAuth:
+	/* Begin the standard VNC authentication procedure. */
+	rfbVncAuthSendChallenge(cl);
+	break;
+    case rfbSecTypeTight:
+	/* We are lucky: the viewer supports TightVNC extensions. */
+	rfbLog("Enabling TightVNC protocol extensions\n");
+	/* Switch to the protocol 3.7t. */
+	cl->protocol_tightvnc = TRUE;
+	/* Advertise our tunneling capabilities. */
+	rfbSendTunnelingCaps(cl);
+	break;
+    default:
+	/* Impossible case (hopefully). */
+	rfbLog("rfbProcessClientSecurityType: "
+	       "unknown authentication scheme\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+    }
+}
+
+
+/*
+ * Send the list of our tunneling capabilities (protocol 3.7t).
+ */
+
+static void
+rfbSendTunnelingCaps(cl)
+    rfbClientPtr cl;
+{
+    rfbTunnelingCapsMsg caps;
+    CARD32 nTypes = 0;		/* we don't support tunneling yet */
+
+    caps.nTunnelTypes = Swap32IfLE(nTypes);
+    if (WriteExact(cl->sock, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) {
+	rfbLogPerror("rfbSendTunnelingCaps: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    if (nTypes) {
+	/* Dispatch client input to rfbProcessClientTunnelingType(). */
+	cl->state = RFB_TUNNELING_TYPE;
+    } else {
+	rfbSendAuthCaps(cl);
+    }
+}
+
+
+/*
+ * Read tunneling type requested by the client (protocol 3.7t).
+ * NOTE: Currently, we don't support tunneling, and this function
+ *       can never be called.
+ */
+
+void
+rfbProcessClientTunnelingType(cl)
+    rfbClientPtr cl;
+{
+    /* If we were called, then something's really wrong. */
+    rfbLog("rfbProcessClientTunnelingType: not implemented\n");
+    rfbCloseSock(cl->pScreen, cl->sock);
+    return;
+}
+
+
+/*
+ * Send the list of our authentication capabilities to the client
+ * (protocol 3.7t).
+ */
+
+static void
+rfbSendAuthCaps(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    Bool authRequired;
+    rfbAuthenticationCapsMsg caps;
+    rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
+    int count = 0;
+
+    authRequired = ((pVNC->rfbAuthPasswdFile != NULL || pVNC->loginAuthEnabled) &&
+		    !cl->reverseConnection);
+
+    if (authRequired) {
+	if (pVNC->loginAuthEnabled) {
+	    SetCapInfo(&caplist[count], rfbAuthUnixLogin, rfbTightVncVendor);
+	    cl->authCaps[count++] = rfbAuthUnixLogin;
+	}
+	if (pVNC->rfbAuthPasswdFile != NULL) {
+	    SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
+	    cl->authCaps[count++] = rfbAuthVNC;
+	}
+	if (count == 0) {
+	    /* Should never happen. */
+	    rfbLog("rfbSendAuthCaps: assertion failed\n");
+     	    rfbCloseSock(cl->pScreen, cl->sock);
+ 	    return;
+ 	}
+    }
+ 
+    cl->nAuthCaps = count;
+    caps.nAuthTypes = Swap32IfLE((CARD32)count);
+    if (WriteExact(cl->sock, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
+	rfbLogPerror("rfbSendAuthCaps: write");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+ 
+    if (count) {
+	if (WriteExact(cl->sock, (char *)&caplist[0],
+		       count * sz_rfbCapabilityInfo) < 0) {
+	    rfbLogPerror("rfbSendAuthCaps: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+	/* Dispatch client input to rfbProcessClientAuthType. */
+	cl->state = RFB_AUTH_TYPE;
+     } else {
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+    }
+}
+ 
+
+/*
+ * Read client's preferred authentication type (protocol 3.7t).
+ */
+
+void
+rfbProcessClientAuthType(cl)
+    rfbClientPtr cl;
+{
+    CARD32 auth_type;
+    int n, i;
+
+    /* Read authentication type selected by the client. */
+    n = ReadExact(cl->sock, (char *)&auth_type, sizeof(auth_type));
+    if (n <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientAuthType: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientAuthType: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    auth_type = Swap32IfLE(auth_type);
+
+    /* Make sure it was present in the list sent by the server. */
+    for (i = 0; i < cl->nAuthCaps; i++) {
+	if (auth_type == cl->authCaps[i])
+	    break;
+    }
+    if (i >= cl->nAuthCaps) {
+	rfbLog("rfbProcessClientAuthType: "
+	       "wrong authentication type requested\n");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    switch (auth_type) {
+    case rfbAuthNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+ 	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbAuthVNC:
+	rfbVncAuthSendChallenge(cl);
+	break;
+    case rfbAuthUnixLogin:
+	/* FIXME: Do (cl->state = RFB_LOGIN_AUTH) instead? */
+	rfbLoginAuthProcessClientMessage(cl);
+	break;
+    default:
+	rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+     }
+}
+ 
+
+/*
+ * Send the authentication challenge.
+ */
+
+static void
+rfbVncAuthSendChallenge(cl)
+    rfbClientPtr cl;
+{
+    vncRandomBytes(cl->authChallenge);
+    if (WriteExact(cl->sock, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
+	rfbLogPerror("rfbVncAuthSendChallenge: write");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+ 	return;
+     }
+
+    /* Dispatch client input to rfbVncAuthProcessResponse. */
+    cl->state = RFB_AUTHENTICATION;
+}
+
+/*
+ * rfbVncAuthProcessResponse is called when the client sends its
+ * authentication response.
+ */
+
+void
+rfbVncAuthProcessResponse(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    char passwdFullControl[9];
+    char passwdViewOnly[9];
+    int numPasswords;
+    Bool ok;
+    int n;
+    CARD8 encryptedChallenge1[CHALLENGESIZE];
+    CARD8 encryptedChallenge2[CHALLENGESIZE];
+    CARD8 response[CHALLENGESIZE];
+    CARD32 authResult;
+
+    n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE);
+    if (n <= 0) {
+	if (n != 0)
+	    rfbLogPerror("rfbVncAuthProcessResponse: read");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    numPasswords = vncDecryptPasswdFromFile2(pVNC->rfbAuthPasswdFile,
+					     passwdFullControl,
+					     passwdViewOnly);
+    if (numPasswords == 0) {
+	rfbLog("rfbVncAuthProcessResponse: could not get password from %s\n",
+	       pVNC->rfbAuthPasswdFile);
+
+	authResult = Swap32IfLE(rfbVncAuthFailed);
+
+	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	    rfbLogPerror("rfbVncAuthProcessResponse: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    memcpy(encryptedChallenge1, cl->authChallenge, CHALLENGESIZE);
+    vncEncryptBytes(encryptedChallenge1, passwdFullControl);
+    memcpy(encryptedChallenge2, cl->authChallenge, CHALLENGESIZE);
+    vncEncryptBytes(encryptedChallenge2,
+		    (numPasswords == 2) ? passwdViewOnly : passwdFullControl);
+
+    /* Lose the passwords from memory */
+    memset(passwdFullControl, 0, 9);
+    memset(passwdViewOnly, 0, 9);
+
+    ok = FALSE;
+    if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) {
+	rfbLog("Full-control authentication passed by %s\n", cl->host);
+	ok = TRUE;
+	cl->viewOnly = FALSE;
+    } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) {
+	rfbLog("View-only authentication passed by %s\n", cl->host);
+	ok = TRUE;
+	cl->viewOnly = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	    rfbLogPerror("rfbVncAuthProcessResponse: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	rfbLogPerror("rfbVncAuthProcessResponse: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientInitMessage(). */
+    cl->state = RFB_INITIALISATION;
+}
+
+
+/*
+ * Functions to prevent too many successive authentication failures.
+ * FIXME: This should be performed separately per each client IP.
+ */
+
+/* Maximum authentication failures before blocking connections */
+#define MAX_AUTH_TRIES 5
+
+/* Delay in ms, doubles for each failure over MAX_AUTH_TRIES */
+#define AUTH_TOO_MANY_BASE_DELAY 10 * 1000
+
+/*
+ * This function should not be called directly, it is called by
+ * setting a timer in rfbAuthConsiderBlocking().
+ */
+
+static CARD32
+rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+    rfbClientPtr cl = (rfbClientPtr) arg;
+    VNCSCREENPTR(cl->pScreen);
+    pVNC->rfbAuthTooManyTries = FALSE;
+    return 0;
+}
+
+/*
+ * This function should be called after each authentication failure.
+ * The return value will be true if there was too many failures.
+ */
+
+Bool
+rfbAuthConsiderBlocking(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    int i;
+
+    pVNC->rfbAuthTries++;
+
+    if (pVNC->rfbAuthTries >= MAX_AUTH_TRIES) {
+	CARD32 delay = AUTH_TOO_MANY_BASE_DELAY;
+	for (i = MAX_AUTH_TRIES; i < pVNC->rfbAuthTries; i++)
+	    delay *= 2;
+	pVNC->timer = TimerSet(pVNC->timer, 0, delay, rfbAuthReenable, NULL);
+	pVNC->rfbAuthTooManyTries = TRUE;
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * This function should be called after successful authentication.
+ * It resets the counter of authentication failures. Note that it's
+ * not necessary to clear the rfbAuthTooManyTries flag as it will be
+ * reset by the timer function.
+ */
+
+void
+rfbAuthUnblock(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    pVNC->rfbAuthTries = 0;
+}
+
+/*
+ * This function should be called before authentication process.
+ * The return value will be true if there was too many authentication
+ * failures, and the server should not allow another try.
+ */
+
+Bool
+rfbAuthIsBlocked(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    return pVNC->rfbAuthTooManyTries;
+}
+
diff -u -rNp a/hw/vnc/cmap.c b/hw/vnc/cmap.c
--- a/hw/vnc/cmap.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/cmap.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,163 @@
+/*
+ * cmap.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1993  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+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 X CONSORTIUM 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 X Consortium 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 X Consortium.
+
+*/
+
+#include "rfb.h"
+
+int
+rfbListInstalledColormaps(pScreen, pmaps)
+    ScreenPtr	pScreen;
+    Colormap	*pmaps;
+{
+    VNCSCREENPTR(pScreen);
+    /* By the time we are processing requests, we can guarantee that there
+     * is always a colormap installed */
+    if (pVNC->rfbInstalledColormap)
+    	*pmaps = pVNC->rfbInstalledColormap->mid;
+
+#if XFREE86VNC
+    pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps;
+    (*pScreen->ListInstalledColormaps)(pScreen, pmaps);
+    pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
+#endif
+
+    return (1);
+}
+
+
+void
+rfbInstallColormap(pmap)
+    ColormapPtr	pmap;
+{
+    VNCSCREENPTR(pmap->pScreen);
+
+    if (pmap != pVNC->rfbInstalledColormap) {
+
+	if(pVNC->rfbInstalledColormap != (ColormapPtr)None)
+	    WalkTree(pmap->pScreen, TellLostMap,
+				 (char *)&pVNC->rfbInstalledColormap->mid);
+	/* Install pmap */
+	pVNC->rfbInstalledColormap = pmap;
+	WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+	rfbSetClientColourMaps(0, 0);
+    }
+#if XFREE86VNC
+    pmap->pScreen->InstallColormap = pVNC->InstallColormap;
+    (*pmap->pScreen->InstallColormap)(pmap);
+    pmap->pScreen->InstallColormap = rfbInstallColormap;
+#endif
+}
+
+void
+rfbUninstallColormap(pmap)
+    ColormapPtr	pmap;
+{
+    VNCSCREENPTR(pmap->pScreen);
+
+    if(pmap == pVNC->rfbInstalledColormap)
+    {
+	if (pmap->mid != pmap->pScreen->defColormap)
+	{
+	    pVNC->rfbInstalledColormap = 
+			(ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+						   RT_COLORMAP);
+	    (*pmap->pScreen->InstallColormap)(pVNC->rfbInstalledColormap);
+	}
+    }
+#if XFREE86VNC
+    pmap->pScreen->UninstallColormap = pVNC->UninstallColormap;
+    (*pmap->pScreen->UninstallColormap)(pmap);
+    pmap->pScreen->UninstallColormap = rfbUninstallColormap;
+#endif
+}
+
+
+/*
+ * rfbStoreColors.  We have a set of pixels but they may be in any order.
+ * If some of them happen to be in continuous ascending order then we can
+ * group them together into a single call to rfbSetClientColourMaps.
+ */
+
+void
+rfbStoreColors(pmap, ndef, pdefs)
+    ColormapPtr pmap;
+    int         ndef;
+    xColorItem  *pdefs;
+{
+    VNCSCREENPTR(pmap->pScreen);
+    int i;
+    int first = -1;
+    int n = 0;
+
+    if (pmap == pVNC->rfbInstalledColormap) {
+	for (i = 0; i < ndef; i++) {
+	    if ((first != -1) && (first + n == pdefs[i].pixel)) {
+		n++;
+	    } else {
+		if (first != -1) {
+		    rfbSetClientColourMaps(first, n);
+		}
+		first = pdefs[i].pixel;
+		n = 1;
+	    }
+	}
+	rfbSetClientColourMaps(first, n);
+    }
+#if XFREE86VNC
+    pmap->pScreen->StoreColors = pVNC->StoreColors;
+    (*pmap->pScreen->StoreColors)(pmap, ndef, pdefs);
+    pmap->pScreen->StoreColors = rfbStoreColors;
+#endif
+}
diff -u -rNp a/hw/vnc/corre.c b/hw/vnc/corre.c
--- a/hw/vnc/corre.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/corre.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,353 @@
+/*
+ * corre.c
+ *
+ * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE).  This
+ * code is based on krw's original javatel rfbserver.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version.  If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(CARD8 *data, int w, int h);
+static int subrectEncode16(CARD16 *data, int w, int h);
+static int subrectEncode32(CARD32 *data, int w, int h);
+static CARD32 getBgColour(char *data, int size, int bpp);
+static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
+					  int w, int h);
+
+
+/*
+ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
+ * encoding.
+ */
+
+Bool
+rfbSendRectEncodingCoRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    if (h > cl->correMaxHeight) {
+	return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
+		rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight,
+					 w, h - cl->correMaxHeight));
+    }
+
+    if (w > cl->correMaxWidth) {
+	return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
+		rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
+					 w - cl->correMaxWidth, h));
+    }
+
+    return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
+}
+
+
+
+/*
+ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
+ * rectangle using CoRRE encoding.
+ */
+
+static Bool
+rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbRREHeader hdr;
+    int nSubrects;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize = (pVNC->width * pVNC->height
+		      * (cl->format.bitsPerPixel / 8));
+
+    if (rreBeforeBufSize < maxRawSize) {
+	rreBeforeBufSize = maxRawSize;
+	if (rreBeforeBuf == NULL)
+	    rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
+	else
+	    rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+    }
+
+    if (rreAfterBufSize < maxRawSize) {
+	rreAfterBufSize = maxRawSize;
+	if (rreAfterBuf == NULL)
+	    rreAfterBuf = (char *)xalloc(rreAfterBufSize);
+	else
+	    rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+    }
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, rreBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
+	break;
+    case 16:
+	nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
+	break;
+    case 32:
+	nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
+	break;
+    default:
+	rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+	exit(1);
+    }
+	
+    if (nSubrects < 0) {
+
+	/* RRE encoding was too large, use raw */
+
+	return rfbSendRectEncodingRaw(cl, x, y, w, h);
+    }
+
+    cl->rfbRectanglesSent[rfbEncodingCoRRE]++;
+    cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
+					   + sz_rfbRREHeader + rreAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nSubrects = Swap32IfLE(nSubrects);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader);
+    pVNC->ublen += sz_rfbRREHeader;
+
+    for (i = 0; i < rreAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > rreAfterBufLen) {
+	    bytesToCopy = rreAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background 
+ * colour overwritten by single-coloured rectangles.  It returns the number 
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive 
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp)					      \
+static int								      \
+subrectEncode##bpp(data,w,h)						      \
+    CARD##bpp *data;							      \
+    int w;								      \
+    int h;								      \
+{									      \
+    CARD##bpp cl;							      \
+    rfbCoRRERectangle subrect;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp);		      \
+									      \
+    *((CARD##bpp*)rreAfterBuf) = bg;					      \
+									      \
+    rreAfterBufLen = (bpp/8);						      \
+									      \
+    for (y=0; y<h; y++) {						      \
+      line = data+(y*w);						      \
+      for (x=0; x<w; x++) {						      \
+        if (line[x] != bg) {						      \
+          cl = line[x];							      \
+          hy = y-1;							      \
+          hyflag = 1;							      \
+          for (j=y; j<h; j++) {						      \
+            seg = data+(j*w);						      \
+            if (seg[x] != cl) {break;}					      \
+            i = x;							      \
+            while ((seg[i] == cl) && (i < w)) i += 1;			      \
+            i -= 1;							      \
+            if (j == y) vx = hx = i;					      \
+            if (i < vx) vx = i;						      \
+            if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      \
+          }								      \
+          vy = j-1;							      \
+									      \
+          /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  \
+           *  We'll choose the bigger of the two.			      \
+           */								      \
+          hw = hx-x+1;							      \
+          hh = hy-y+1;							      \
+          vw = vx-x+1;							      \
+          vh = vy-y+1;							      \
+									      \
+          thex = x;							      \
+          they = y;							      \
+									      \
+          if ((hw*hh) > (vw*vh)) {					      \
+            thew = hw;							      \
+            theh = hh;							      \
+          } else {							      \
+            thew = vw;							      \
+            theh = vh;							      \
+          }								      \
+									      \
+          subrect.x = thex;						      \
+          subrect.y = they;						      \
+          subrect.w = thew;						      \
+          subrect.h = theh;						      \
+									      \
+	  newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle;	      \
+          if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize))     \
+	    return -1;							      \
+									      \
+	  numsubs += 1;							      \
+	  *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl;		      \
+	  rreAfterBufLen += (bpp/8);					      \
+	  memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
+	  rreAfterBufLen += sz_rfbCoRRERectangle;			      \
+									      \
+          /*								      \
+           * Now mark the subrect as done.				      \
+           */								      \
+          for (j=they; j < (they+theh); j++) {				      \
+            for (i=thex; i < (thex+thew); i++) {			      \
+              data[j*w+i] = bg;						      \
+            }								      \
+          }								      \
+        }								      \
+      }									      \
+    }									      \
+									      \
+    return numsubs;							      \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static CARD32
+getBgColour(data,size,bpp)
+    char *data;
+    int size;
+    int bpp;
+{
+    
+#define NUMCLRS 256
+  
+  static int counts[NUMCLRS];
+  int i,j,k;
+
+  int maxcount = 0;
+  CARD8 maxclr = 0;
+
+  if (bpp != 8) {
+    if (bpp == 16) {
+      return ((CARD16 *)data)[0];
+    } else if (bpp == 32) {
+      return ((CARD32 *)data)[0];
+    } else {
+      rfbLog("getBgColour: bpp %d?\n",bpp);
+      exit(1);
+    }
+  }
+
+  for (i=0; i<NUMCLRS; i++) {
+    counts[i] = 0;
+  }
+
+  for (j=0; j<size; j++) {
+    k = (int)(((CARD8 *)data)[j]);
+    if (k >= NUMCLRS) {
+      rfbLog("getBgColour: unusual colour = %d\n", k);
+      exit(1);
+    }
+    counts[k] += 1;
+    if (counts[k] > maxcount) {
+      maxcount = counts[k];
+      maxclr = ((CARD8 *)data)[j];
+    }
+  }
+  
+  return maxclr;
+}
diff -u -rNp a/hw/vnc/cursor.c b/hw/vnc/cursor.c
--- a/hw/vnc/cursor.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/cursor.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,404 @@
+/*
+ * cursor.c - support for cursor shape updates.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+#include "mipointer.h"
+#include "sprite.h"
+#include "cursorstr.h"
+#include "servermd.h"
+
+
+/* Copied from Xvnc/lib/font/util/utilbitmap.c */
+static unsigned char _reverse_byte[0x100] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+
+static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt,
+				  CursorPtr pCursor);
+static int EncodeRichCursorData16 (ScreenPtr pScreen,
+				   char *buf, rfbPixelFormat *fmt,
+				   CursorPtr pCursor);
+static int EncodeRichCursorData32 (ScreenPtr pScreen,
+				   char *buf, rfbPixelFormat *fmt,
+				   CursorPtr pCursor);
+
+
+/*
+ * Send cursor shape either in X-style format or in client pixel format.
+ */
+
+Bool
+rfbSendCursorShape(cl, pScreen)
+    rfbClientPtr cl;
+    ScreenPtr pScreen;
+{
+    VNCSCREENPTR(pScreen);
+    CursorPtr pCursor;
+    rfbFramebufferUpdateRectHeader rect;
+    rfbXCursorColors colors;
+    int saved_ublen;
+    int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes;
+    int i, j;
+    CARD8 *bitmapData;
+    CARD8 bitmapByte;
+
+    if (cl->useRichCursorEncoding) {
+	rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
+    } else {
+	rect.encoding = Swap32IfLE(rfbEncodingXCursor);
+    }
+
+#if XFREE86VNC
+    pCursor = pVNC->pCurs;
+#else
+    pCursor = rfbSpriteGetCursorPtr(pScreen);
+#endif
+
+    /* If there is no cursor, send update with empty cursor data. */
+
+    if ( pCursor != NULL &&
+	 pCursor->bits->width == 1 &&
+	 pCursor->bits->height == 1 &&
+	 pCursor->bits->mask[0] == 0 ) {
+	pCursor = NULL;
+    }
+
+    if (pCursor == NULL) {
+	if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+	rect.r.x = rect.r.y = 0;
+	rect.r.w = rect.r.h = 0;
+	memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	       sz_rfbFramebufferUpdateRectHeader);
+	pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+	cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
+	cl->rfbCursorShapeUpdatesSent++;
+
+	return TRUE;
+    }
+
+    /* Calculate data sizes. */
+
+    bitmapRowBytes = (pCursor->bits->width + 7) / 8;
+    paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1);
+    maskBytes = bitmapRowBytes * pCursor->bits->height;
+    dataBytes = (cl->useRichCursorEncoding) ?
+	(pCursor->bits->width * pCursor->bits->height *
+	 (cl->format.bitsPerPixel / 8)) : maskBytes;
+
+    /* Send buffer contents if needed. */
+
+    if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader +
+	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader +
+	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+	return FALSE;		/* FIXME. */
+    }
+
+    saved_ublen = pVNC->ublen;
+
+    /* Prepare rectangle header. */
+
+    rect.r.x = Swap16IfLE(pCursor->bits->xhot);
+    rect.r.y = Swap16IfLE(pCursor->bits->yhot);
+    rect.r.w = Swap16IfLE(pCursor->bits->width);
+    rect.r.h = Swap16IfLE(pCursor->bits->height);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    /* Prepare actual cursor data (depends on encoding used). */
+
+    if (!cl->useRichCursorEncoding) {
+	/* XCursor encoding. */
+	colors.foreRed   = (char)(pCursor->foreRed   >> 8);
+	colors.foreGreen = (char)(pCursor->foreGreen >> 8);
+	colors.foreBlue  = (char)(pCursor->foreBlue  >> 8);
+	colors.backRed   = (char)(pCursor->backRed   >> 8);
+	colors.backGreen = (char)(pCursor->backGreen >> 8);
+	colors.backBlue  = (char)(pCursor->backBlue  >> 8);
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&colors, sz_rfbXCursorColors);
+	pVNC->ublen += sz_rfbXCursorColors;
+
+	bitmapData = (CARD8 *)pCursor->bits->source;
+
+	for (i = 0; i < pCursor->bits->height; i++) {
+	    for (j = 0; j < bitmapRowBytes; j++) {
+		bitmapByte = bitmapData[i * paddedRowBytes + j];
+		if (screenInfo.bitmapBitOrder == LSBFirst) {
+		    bitmapByte = _reverse_byte[bitmapByte];
+		}
+		pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte;
+	    }
+	}
+    } else {
+	/* RichCursor encoding. */
+	switch (cl->format.bitsPerPixel) {
+	case 8:
+	    pVNC->ublen += EncodeRichCursorData8(&pVNC->updateBuf[pVNC->ublen],
+					   &cl->format, pCursor);
+	    break;
+	case 16:
+	    pVNC->ublen += EncodeRichCursorData16(pScreen, &pVNC->updateBuf[pVNC->ublen],
+					    &cl->format, pCursor);
+	    break;
+	case 32:
+	    pVNC->ublen += EncodeRichCursorData32(pScreen, &pVNC->updateBuf[pVNC->ublen],
+					    &cl->format, pCursor);
+	    break;
+	default:
+	    return FALSE;
+	}
+    }
+
+    /* Prepare transparency mask. */
+
+    bitmapData = (CARD8 *)pCursor->bits->mask;
+
+    for (i = 0; i < pCursor->bits->height; i++) {
+	for (j = 0; j < bitmapRowBytes; j++) {
+	    bitmapByte = bitmapData[i * paddedRowBytes + j];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte;
+	}
+    }
+
+    /* Update statistics. */
+
+    cl->rfbCursorShapeBytesSent += (pVNC->ublen - saved_ublen);
+    cl->rfbCursorShapeUpdatesSent++;
+
+    return TRUE;
+}
+
+/*
+ * Send cursor position (PointerPos pseudo-encoding).
+ */
+Bool
+rfbSendCursorPos(cl, pScreen)
+    rfbClientPtr cl;
+    ScreenPtr pScreen;
+{
+    VNCSCREENPTR(pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+#if XFREE86VNC
+    ScreenPtr   pCursorScreen = miPointerCurrentScreen();
+#endif
+    int x, y;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+#if XFREE86VNC
+    if (pScreen == pCursorScreen) 
+        miPointerPosition(&x, &y);
+#else
+    rfbSpriteGetCursorPos(pScreen, &x, &y);
+#endif
+
+    rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
+    rect.r.x = Swap16IfLE((CARD16)x);
+    rect.r.y = Swap16IfLE((CARD16)y);
+    rect.r.w = 0;
+    rect.r.h = 0;
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
+    cl->rfbCursorPosUpdatesSent++;
+
+    if (!rfbSendUpdateBuf(cl))
+	return FALSE;
+
+    cl->cursorX = x;
+    cl->cursorY = y;
+
+    return TRUE;
+}
+
+/*
+ * Code to convert cursor source bitmap to the desired pixel format.
+ */
+
+#define RGB48_TO_PIXEL(fmt,r,g,b)					\
+    (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift |	\
+     ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift |	\
+     ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift)
+
+static int
+EncodeRichCursorData8(buf, fmt, pCursor)
+    char *buf;
+    rfbPixelFormat *fmt;
+    CursorPtr pCursor;
+{
+    int widthPixels, widthBytes;
+    int x, y, b;
+    CARD8 *src;
+    char pix[2];
+    CARD8 bitmapByte;
+
+    pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen,
+				  pCursor->backBlue);
+    pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen,
+				  pCursor->foreBlue);
+
+    src = (CARD8 *)pCursor->bits->source;
+    widthPixels = pCursor->bits->width;
+    widthBytes = PixmapBytePad(widthPixels, 1);
+
+    for (y = 0; y < pCursor->bits->height; y++) {
+	for (x = 0; x < widthPixels / 8; x++) {
+	    bitmapByte = src[y * widthBytes + x];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    for (b = 7; b >= 0; b--) {
+		*buf++ = pix[bitmapByte >> b & 1];
+	    }
+	}
+	if (widthPixels % 8) {
+	    bitmapByte = src[y * widthBytes + x];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    for (b = 7; b > 7 - widthPixels % 8; b--) {
+		*buf++ = pix[bitmapByte >> b & 1];
+	    }
+	}
+    }
+
+    return (widthPixels * pCursor->bits->height);
+}
+
+#define DEFINE_RICH_ENCODE(bpp)						 \
+									 \
+static int								 \
+EncodeRichCursorData##bpp(pScreen, buf, fmt, pCursor)			 \
+    ScreenPtr pScreen;							 \
+    char *buf;								 \
+    rfbPixelFormat *fmt;						 \
+    CursorPtr pCursor;							 \
+{									 \
+    VNCSCREENPTR(pScreen);						 \
+    int widthPixels, widthBytes;					 \
+    int x, y, b;							 \
+    CARD8 *src;								 \
+    CARD##bpp pix[2];							 \
+    CARD8 bitmapByte;							 \
+									 \
+    pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed,		 \
+				       pCursor->backGreen,		 \
+				       pCursor->backBlue);		 \
+    pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed,		 \
+				       pCursor->foreGreen,		 \
+				       pCursor->foreBlue);		 \
+    if (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian) {		 \
+	pix[0] = Swap##bpp(pix[0]);					 \
+	pix[1] = Swap##bpp(pix[1]);					 \
+    }									 \
+									 \
+    src = (CARD8 *)pCursor->bits->source;				 \
+    widthPixels = pCursor->bits->width;					 \
+    widthBytes = PixmapBytePad(widthPixels, 1);				 \
+									 \
+    for (y = 0; y < pCursor->bits->height; y++) {			 \
+	for (x = 0; x < widthPixels / 8; x++) {				 \
+	    bitmapByte = src[y * widthBytes + x];			 \
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {		 \
+		bitmapByte = _reverse_byte[bitmapByte];			 \
+	    }								 \
+	    for (b = 7; b >= 0; b--) {					 \
+		memcpy (buf, (char *)&pix[bitmapByte >> b & 1],		 \
+			sizeof(CARD##bpp));				 \
+		buf += sizeof(CARD##bpp);				 \
+	    }								 \
+	}								 \
+	if (widthPixels % 8) {						 \
+	    bitmapByte = src[y * widthBytes + x];			 \
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {		 \
+		bitmapByte = _reverse_byte[bitmapByte];			 \
+	    }								 \
+	    for (b = 7; b > 7 - widthPixels % 8; b--) {			 \
+		memcpy (buf, (char *)&pix[bitmapByte >> b & 1],		 \
+			sizeof(CARD##bpp));				 \
+		buf += sizeof(CARD##bpp);				 \
+	    }								 \
+	}								 \
+    }									 \
+									 \
+    return (widthPixels * pCursor->bits->height * (bpp / 8));		 \
+}
+
+DEFINE_RICH_ENCODE(16)
+DEFINE_RICH_ENCODE(32)
+
diff -u -rNp a/hw/vnc/cutpaste.c b/hw/vnc/cutpaste.c
--- a/hw/vnc/cutpaste.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/cutpaste.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,87 @@
+/*
+ * cutpaste.c - routines to deal with cut & paste buffers / selection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include "rfb.h"
+#include "selection.h"
+#include "input.h"
+
+extern Selection *CurrentSelections;
+extern int NumCurrentSelections;
+
+
+static Bool inSetXCutText = FALSE;
+
+/*
+ * rfbSetXCutText sets the cut buffer to be the given string.  We also clear
+ * the primary selection.  Ideally we'd like to set it to the same thing, but I
+ * can't work out how to do that without some kind of helper X client.
+ */
+
+void
+rfbSetXCutText(char *str, int len)
+{
+    int i = 0;
+
+    inSetXCutText = TRUE;
+    ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING,
+			 8, PropModeReplace, len,
+			 (pointer)str, TRUE);
+    
+    while ((i < NumCurrentSelections) && 
+	   CurrentSelections[i].selection != XA_PRIMARY)
+	i++;
+
+    if (i < NumCurrentSelections) {
+	xEvent event;
+
+	if (CurrentSelections[i].client) {
+	    event.u.u.type = SelectionClear;
+	    event.u.selectionClear.time = GetTimeInMillis();
+	    event.u.selectionClear.window = CurrentSelections[i].window;
+	    event.u.selectionClear.atom = CurrentSelections[i].selection;
+	    (void) TryClientEvents (CurrentSelections[i].client, &event, 1,
+				NoEventMask, NoEventMask /* CantBeFiltered */,
+				NullGrab);
+	}
+
+	CurrentSelections[i].window = None;
+	CurrentSelections[i].pWin = NULL;
+	CurrentSelections[i].client = NullClient;
+    }
+
+    inSetXCutText = FALSE;
+}
+
+
+void rfbGotXCutText(char *str, int len)
+{
+    if (!inSetXCutText)
+	rfbSendServerCutText(str, len);
+}
diff -u -rNp a/hw/vnc/d3des.c b/hw/vnc/d3des.c
--- a/hw/vnc/d3des.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/d3des.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,434 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static unsigned short bytebit[8]	= {
+	01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static unsigned long bigbyte[24] = {
+	0x800000L,	0x400000L,	0x200000L,	0x100000L,
+	0x80000L,	0x40000L,	0x20000L,	0x10000L,
+	0x8000L,	0x4000L,	0x2000L,	0x1000L,
+	0x800L, 	0x400L, 	0x200L, 	0x100L,
+	0x80L,		0x40L,		0x20L,		0x10L,
+	0x8L,		0x4L,		0x2L,		0x1L	};
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
+	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
+
+static unsigned char totrot[16] = {
+	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+void deskey(key, edf)	/* Thanks to James Gillogly & Phil Karn! */
+unsigned char *key;
+int edf;
+{
+	register int i, j, l, m, n;
+	unsigned char pc1m[56], pcr[56];
+	unsigned long kn[32];
+
+	for ( j = 0; j < 56; j++ ) {
+		l = pc1[j];
+		m = l & 07;
+		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+		}
+	for( i = 0; i < 16; i++ ) {
+		if( edf == DE1 ) m = (15 - i) << 1;
+		else m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for( j = 0; j < 28; j++ ) {
+			l = j + totrot[i];
+			if( l < 28 ) pcr[j] = pc1m[l];
+			else pcr[j] = pc1m[l - 28];
+			}
+		for( j = 28; j < 56; j++ ) {
+		    l = j + totrot[i];
+		    if( l < 56 ) pcr[j] = pc1m[l];
+		    else pcr[j] = pc1m[l - 28];
+		    }
+		for( j = 0; j < 24; j++ ) {
+			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+			}
+		}
+	cookey(kn);
+	return;
+	}
+
+static void cookey(raw1)
+register unsigned long *raw1;
+{
+	register unsigned long *cook, *raw0;
+	unsigned long dough[32];
+	register int i;
+
+	cook = dough;
+	for( i = 0; i < 16; i++, raw1++ ) {
+		raw0 = raw1++;
+		*cook	 = (*raw0 & 0x00fc0000L) << 6;
+		*cook	|= (*raw0 & 0x00000fc0L) << 10;
+		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook	 = (*raw0 & 0x0003f000L) << 12;
+		*cook	|= (*raw0 & 0x0000003fL) << 16;
+		*cook	|= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+		}
+	usekey(dough);
+	return;
+	}
+
+void cpkey(into)
+register unsigned long *into;
+{
+	register unsigned long *from, *endp;
+
+	from = KnL, endp = &KnL[32];
+	while( from < endp ) *into++ = *from++;
+	return;
+	}
+
+void usekey(from)
+register unsigned long *from;
+{
+	register unsigned long *to, *endp;
+
+	to = KnL, endp = &KnL[32];
+	while( to < endp ) *to++ = *from++;
+	return;
+	}
+
+void des(inblock, outblock)
+unsigned char *inblock, *outblock;
+{
+	unsigned long work[2];
+
+	scrunch(inblock, work);
+	desfunc(work, KnL);
+	unscrun(work, outblock);
+	return;
+	}
+
+static void scrunch(outof, into)
+register unsigned char *outof;
+register unsigned long *into;
+{
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into++ |= (*outof++ & 0xffL);
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into	|= (*outof   & 0xffL);
+	return;
+	}
+
+static void unscrun(outof, into)
+register unsigned long *outof;
+register unsigned char *into;
+{
+	*into++ = (*outof >> 24) & 0xffL;
+	*into++ = (*outof >> 16) & 0xffL;
+	*into++ = (*outof >>  8) & 0xffL;
+	*into++ =  *outof++	 & 0xffL;
+	*into++ = (*outof >> 24) & 0xffL;
+	*into++ = (*outof >> 16) & 0xffL;
+	*into++ = (*outof >>  8) & 0xffL;
+	*into	=  *outof	 & 0xffL;
+	return;
+	}
+
+static unsigned long SP1[64] = {
+	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(block, keys)
+register unsigned long *block, *keys;
+{
+	register unsigned long fval, work, right, leftt;
+	register int round;
+
+	leftt = block[0];
+	right = block[1];
+	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+	work = ((right >> 2) ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+	for( round = 0; round < 8; round++ ) {
+		work  = (right << 28) | (right >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		leftt ^= fval;
+		work  = (leftt << 28) | (leftt >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		right ^= fval;
+		}
+
+	right = (right << 31) | (right >> 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = (leftt << 31) | (leftt >> 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+	*block++ = right;
+	*block = leftt;
+	return;
+	}
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff -u -rNp a/hw/vnc/dispcur.c b/hw/vnc/dispcur.c
--- a/hw/vnc/dispcur.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/dispcur.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,804 @@
+/*
+ * dispcur.c
+ *
+ * cursor display routines - based on midispcur.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#if HAVE_DIX_CONFIG_H
+#include "dix-config.h"
+#endif
+
+#define NEED_EVENTS
+# include   <X11/X.h>
+# include   "misc.h"
+# include   "input.h"
+# include   "cursorstr.h"
+# include   "windowstr.h"
+# include   "regionstr.h"
+# include   "dixstruct.h"
+# include   "scrnintstr.h"
+# include   "servermd.h"
+# include   "mipointer.h"
+# include   "sprite.h"
+# include   "gcstruct.h"
+
+#ifdef ARGB_CURSOR
+# include   "picturestr.h"
+#endif
+
+/* per-screen private data */
+
+static int	rfbDCScreenIndex;
+static unsigned long rfbDCGeneration = 0;
+
+static Bool	rfbDCCloseScreen(int index, ScreenPtr pScreen);
+
+typedef struct {
+    GCPtr	    pSourceGC, pMaskGC;
+    GCPtr	    pSaveGC, pRestoreGC;
+    GCPtr	    pMoveGC;
+    GCPtr	    pPixSourceGC, pPixMaskGC;
+    CloseScreenProcPtr CloseScreen;
+    PixmapPtr	    pSave, pTemp;
+#ifdef ARGB_CURSOR
+    PicturePtr      pRootPicture;
+    PicturePtr      pTempPicture;
+#endif
+} rfbDCScreenRec, *rfbDCScreenPtr;
+
+/* per-cursor per-screen private data */
+typedef struct {
+    PixmapPtr		sourceBits;	    /* source bits */
+    PixmapPtr		maskBits;	    /* mask bits */
+#ifdef ARGB_CURSOR
+    PicturePtr          pPicture;
+#endif
+} rfbDCCursorRec, *rfbDCCursorPtr;
+
+/*
+ * sprite/cursor method table
+ */
+
+static Bool	rfbDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool	rfbDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor);
+static Bool	rfbDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor,
+				int x, int y, unsigned long source,
+				unsigned long mask);
+static Bool	rfbDCSaveUnderCursor(ScreenPtr pScreen, int x, int y,
+				    int w, int h);
+static Bool	rfbDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y,
+				       int w, int h);
+static Bool	rfbDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor,
+			       int x, int y, int w, int h, int dx, int dy,
+			       unsigned long source, unsigned long mask);
+static Bool	rfbDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h,	
+			       int dx, int dy);
+
+static rfbSpriteCursorFuncRec rfbDCFuncs = {
+    rfbDCRealizeCursor,
+    rfbDCUnrealizeCursor,
+    rfbDCPutUpCursor,
+    rfbDCSaveUnderCursor,
+    rfbDCRestoreUnderCursor,
+    rfbDCMoveCursor,
+    rfbDCChangeSave,
+};
+
+Bool
+rfbDCInitialize (pScreen, screenFuncs)
+    ScreenPtr		    pScreen;
+    miPointerScreenFuncPtr  screenFuncs;
+{
+    rfbDCScreenPtr   pScreenPriv;
+
+    if (rfbDCGeneration != serverGeneration)
+    {
+	rfbDCScreenIndex = AllocateScreenPrivateIndex ();
+	if (rfbDCScreenIndex < 0)
+	    return FALSE;
+	rfbDCGeneration = serverGeneration;
+    }
+    pScreenPriv = (rfbDCScreenPtr) xalloc (sizeof (rfbDCScreenRec));
+    if (!pScreenPriv)
+	return FALSE;
+
+    /*
+     * initialize the entire private structure to zeros
+     */
+
+    pScreenPriv->pSourceGC =
+	pScreenPriv->pMaskGC =
+	pScreenPriv->pSaveGC =
+ 	pScreenPriv->pRestoreGC =
+	pScreenPriv->pMoveGC =
+ 	pScreenPriv->pPixSourceGC =
+	pScreenPriv->pPixMaskGC = NULL;
+#ifdef ARGB_CURSOR
+    pScreenPriv->pRootPicture = NULL;
+    pScreenPriv->pTempPicture = NULL;
+#endif
+    
+    pScreenPriv->pSave = pScreenPriv->pTemp = NULL;
+
+    pScreenPriv->CloseScreen = pScreen->CloseScreen;
+    pScreen->CloseScreen = rfbDCCloseScreen;
+    
+    pScreen->devPrivates[rfbDCScreenIndex].ptr = (pointer) pScreenPriv;
+
+    if (!rfbSpriteInitialize (pScreen, &rfbDCFuncs, screenFuncs))
+    {
+	xfree ((pointer) pScreenPriv);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+#define tossGC(gc)  (gc ? FreeGC (gc, (GContext) 0) : 0)
+#define tossPix(pix)	(pix ? (*pScreen->DestroyPixmap) (pix) : TRUE)
+#define tossPict(pict)  (pict ? FreePicture (pict, 0) : 0)
+
+static Bool
+rfbDCCloseScreen (index, pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbDCScreenPtr   pScreenPriv;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pScreen->CloseScreen = pScreenPriv->CloseScreen;
+    tossGC (pScreenPriv->pSourceGC);
+    tossGC (pScreenPriv->pMaskGC);
+    tossGC (pScreenPriv->pSaveGC);
+    tossGC (pScreenPriv->pRestoreGC);
+    tossGC (pScreenPriv->pMoveGC);
+    tossGC (pScreenPriv->pPixSourceGC);
+    tossGC (pScreenPriv->pPixMaskGC);
+    tossPix (pScreenPriv->pSave);
+    tossPix (pScreenPriv->pTemp);
+#ifdef ARGB_CURSOR
+    tossPict (pScreenPriv->pRootPicture);
+    tossPict (pScreenPriv->pTempPicture);
+#endif
+    xfree ((pointer) pScreenPriv);
+    return (*pScreen->CloseScreen) (index, pScreen);
+}
+
+static Bool
+rfbDCRealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    if (pCursor->bits->refcnt <= 1)
+	pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
+    return TRUE;
+}
+
+#ifdef ARGB_CURSOR
+#define EnsurePicture(picture,draw,win) (picture || rfbDCMakePicture(&picture,draw,win))
+
+static VisualPtr
+rfbDCGetWindowVisual (WindowPtr pWin)
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    VisualID	    vid = wVisual (pWin);
+    int		    i;
+
+    for (i = 0; i < pScreen->numVisuals; i++)
+	if (pScreen->visuals[i].vid == vid)
+	    return &pScreen->visuals[i];
+    return 0;
+}
+
+static PicturePtr
+rfbDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin)
+{
+    ScreenPtr	    pScreen = pDraw->pScreen;
+    VisualPtr	    pVisual;
+    PictFormatPtr   pFormat;
+    XID		    subwindow_mode = IncludeInferiors;
+    PicturePtr	    pPicture;
+    int		    error;
+    
+    pVisual = rfbDCGetWindowVisual (pWin);
+    if (!pVisual)
+	return 0;
+    pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual);
+    if (!pFormat)
+	return 0;
+    pPicture = CreatePicture (0, pDraw, pFormat,
+			      CPSubwindowMode, &subwindow_mode,
+			      serverClient, &error);
+    *ppPicture = pPicture;
+    return pPicture;
+}
+#endif
+
+static rfbDCCursorPtr
+rfbDCRealize (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbDCCursorPtr   pPriv;
+    GCPtr	    pGC;
+    XID		    gcvals[3];
+
+    pPriv = (rfbDCCursorPtr) xalloc (sizeof (rfbDCCursorRec));
+    if (!pPriv)
+	return (rfbDCCursorPtr)NULL;
+#ifdef ARGB_CURSOR
+    if (pCursor->bits->argb)
+    {
+	PixmapPtr	pPixmap;
+	PictFormatPtr	pFormat;
+	int		error;
+	
+	pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
+	if (!pFormat)
+	{
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	
+	pPriv->sourceBits = 0;
+	pPriv->maskBits = 0;
+	pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width,
+					    pCursor->bits->height, 32);
+	if (!pPixmap)
+	{
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	pGC = GetScratchGC (32, pScreen);
+	if (!pGC)
+	{
+	    (*pScreen->DestroyPixmap) (pPixmap);
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	ValidateGC (&pPixmap->drawable, pGC);
+	(*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32,
+			       0, 0, pCursor->bits->width,
+			       pCursor->bits->height,
+			       0, ZPixmap, (char *) pCursor->bits->argb);
+	FreeScratchGC (pGC);
+	pPriv->pPicture = CreatePicture (0, &pPixmap->drawable,
+					pFormat, 0, 0, serverClient, &error);
+        (*pScreen->DestroyPixmap) (pPixmap);
+	if (!pPriv->pPicture)
+	{
+	    xfree ((pointer) pPriv);
+	    return (rfbDCCursorPtr)NULL;
+	}
+	pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
+	return pPriv;
+    }
+    pPriv->pPicture = 0;
+#endif
+    pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
+    if (!pPriv->sourceBits)
+    {
+	xfree ((pointer) pPriv);
+	return (rfbDCCursorPtr)NULL;
+    }
+    pPriv->maskBits =  (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1);
+    if (!pPriv->maskBits)
+    {
+	(*pScreen->DestroyPixmap) (pPriv->sourceBits);
+	xfree ((pointer) pPriv);
+	return (rfbDCCursorPtr)NULL;
+    }
+    pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv;
+
+    /* create the two sets of bits, clipping as appropriate */
+
+    pGC = GetScratchGC (1, pScreen);
+    if (!pGC)
+    {
+	(void) rfbDCUnrealizeCursor (pScreen, pCursor);
+	return (rfbDCCursorPtr)NULL;
+    }
+
+    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->source);
+    gcvals[0] = GXand;
+    ChangeGC (pGC, GCFunction, gcvals);
+    ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->mask);
+
+    /* mask bits -- pCursor->mask & ~pCursor->source */
+    gcvals[0] = GXcopy;
+    ChangeGC (pGC, GCFunction, gcvals);
+    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->mask);
+    gcvals[0] = GXandInverted;
+    ChangeGC (pGC, GCFunction, gcvals);
+    ValidateGC ((DrawablePtr)pPriv->maskBits, pGC);
+    (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1,
+			   0, 0, pCursor->bits->width, pCursor->bits->height,
+ 			   0, XYPixmap, (char *)pCursor->bits->source);
+    FreeScratchGC (pGC);
+    return pPriv;
+}
+
+static Bool
+rfbDCUnrealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbDCCursorPtr   pPriv;
+
+    pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+    if (pPriv && (pCursor->bits->refcnt <= 1))
+    {
+	if (pPriv->sourceBits)
+	    (*pScreen->DestroyPixmap) (pPriv->sourceBits);
+	if (pPriv->maskBits)
+	    (*pScreen->DestroyPixmap) (pPriv->maskBits);
+#ifdef ARGB_CURSOR
+	if (pPriv->pPicture)
+	    FreePicture (pPriv->pPicture, 0);
+#endif
+	xfree ((pointer) pPriv);
+	pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL;
+    }
+    return TRUE;
+}
+
+static void
+rfbDCPutBits (pDrawable, pPriv, sourceGC, maskGC, x, y, w, h, source, mask)
+    DrawablePtr	    pDrawable;
+    GCPtr	    sourceGC, maskGC;
+    int             x, y;
+    unsigned        w, h;
+    rfbDCCursorPtr   pPriv;
+    unsigned long   source, mask;
+{
+    XID	    gcvals[1];
+
+    if (sourceGC->fgPixel != source)
+    {
+	gcvals[0] = source;
+	DoChangeGC (sourceGC, GCForeground, gcvals, 0);
+    }
+    if (sourceGC->serialNumber != pDrawable->serialNumber)
+	ValidateGC (pDrawable, sourceGC);
+    (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y);
+    if (maskGC->fgPixel != mask)
+    {
+	gcvals[0] = mask;
+	DoChangeGC (maskGC, GCForeground, gcvals, 0);
+    }
+    if (maskGC->serialNumber != pDrawable->serialNumber)
+	ValidateGC (pDrawable, maskGC);
+    (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y);
+}
+
+#define EnsureGC(gc,win) (gc || rfbDCMakeGC(&gc, win))
+
+static GCPtr
+rfbDCMakeGC(ppGC, pWin)
+    GCPtr	*ppGC;
+    WindowPtr	pWin;
+{
+    GCPtr pGC;
+    int   status;
+    XID   gcvals[2];
+
+    gcvals[0] = IncludeInferiors;
+    gcvals[1] = FALSE;
+    pGC = CreateGC((DrawablePtr)pWin,
+		   GCSubwindowMode|GCGraphicsExposures, gcvals, &status);
+    if (pGC && pWin->drawable.pScreen->DrawGuarantee)
+	(*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack);
+    *ppGC = pGC;
+    return pGC;
+}
+
+static Bool
+rfbDCPutUpCursor (pScreen, pCursor, x, y, source, mask)
+    ScreenPtr	    pScreen;
+    CursorPtr	    pCursor;
+    int		    x, y;
+    unsigned long   source, mask;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    rfbDCCursorPtr   pPriv;
+    WindowPtr	    pWin;
+
+    pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+    if (!pPriv)
+    {
+	pPriv = rfbDCRealize(pScreen, pCursor);
+	if (!pPriv)
+	    return FALSE;
+    }
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pWin = WindowTable[pScreen->myNum];
+#ifdef ARGB_CURSOR
+    if (pPriv->pPicture)
+    {
+	if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin))
+	    return FALSE;
+	CompositePicture (PictOpOver,
+			  pPriv->pPicture,
+			  NULL,
+			  pScreenPriv->pRootPicture,
+			  0, 0, 0, 0, 
+			  x, y, 
+			  pCursor->bits->width,
+			  pCursor->bits->height);
+    }
+    else
+#endif
+    {
+	if (!EnsureGC(pScreenPriv->pSourceGC, pWin))
+	    return FALSE;
+	if (!EnsureGC(pScreenPriv->pMaskGC, pWin))
+	{
+	    FreeGC (pScreenPriv->pSourceGC, (GContext) 0);
+	    pScreenPriv->pSourceGC = 0;
+	    return FALSE;
+	}
+	rfbDCPutBits ((DrawablePtr)pWin, pPriv,
+		     pScreenPriv->pSourceGC, pScreenPriv->pMaskGC,
+		     x, y, pCursor->bits->width, pCursor->bits->height,
+		     source, mask);
+    }
+    return TRUE;
+}
+
+static Bool
+rfbDCSaveUnderCursor (pScreen, x, y, w, h)
+    ScreenPtr	pScreen;
+    int		x, y, w, h;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    PixmapPtr	    pSave;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pSave = pScreenPriv->pSave;
+    pWin = WindowTable[pScreen->myNum];
+    if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h)
+    {
+	if (pSave)
+	    (*pScreen->DestroyPixmap) (pSave);
+	pScreenPriv->pSave = pSave =
+		(*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth);
+	if (!pSave)
+	    return FALSE;
+    }
+    if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pSaveGC;
+    if (pSave->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pSave, pGC);
+    (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			    x, y, w, h, 0, 0);
+    return TRUE;
+}
+
+static Bool
+rfbDCRestoreUnderCursor (pScreen, x, y, w, h)
+    ScreenPtr	pScreen;
+    int		x, y, w, h;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    PixmapPtr	    pSave;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pSave = pScreenPriv->pSave;
+    pWin = WindowTable[pScreen->myNum];
+    if (!pSave)
+	return FALSE;
+    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pRestoreGC;
+    if (pWin->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pWin, pGC);
+    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			    0, 0, w, h, x, y);
+    return TRUE;
+}
+
+static Bool
+rfbDCChangeSave (pScreen, x, y, w, h, dx, dy)
+    ScreenPtr	    pScreen;
+    int		    x, y, w, h, dx, dy;
+{
+    rfbDCScreenPtr   pScreenPriv;
+    PixmapPtr	    pSave;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+    int		    sourcex, sourcey, destx, desty, copyw, copyh;
+
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pSave = pScreenPriv->pSave;
+    pWin = WindowTable[pScreen->myNum];
+    /*
+     * restore the bits which are about to get trashed
+     */
+    if (!pSave)
+	return FALSE;
+    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pRestoreGC;
+    if (pWin->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pWin, pGC);
+    /*
+     * copy the old bits to the screen.
+     */
+    if (dy > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       0, h - dy, w, dy, x + dx, y + h);
+    }
+    else if (dy < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       0, 0, w, -dy, x + dx, y + dy);
+    }
+    if (dy >= 0)
+    {
+	desty = y + dy;
+	sourcey = 0;
+	copyh = h - dy;
+    }
+    else
+    {
+	desty = y;
+	sourcey = - dy;
+	copyh = h + dy;
+    }
+    if (dx > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       w - dx, sourcey, dx, copyh, x + w, desty);
+    }
+    else if (dx < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC,
+			       0, sourcey, -dx, copyh, x + dx, desty);
+    }
+    if (!EnsureGC(pScreenPriv->pSaveGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pSaveGC;
+    if (pSave->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pSave, pGC);
+    /*
+     * move the bits that are still valid within the pixmap
+     */
+    if (dx >= 0)
+    {
+	sourcex = 0;
+	destx = dx;
+	copyw = w - dx;
+    }
+    else
+    {
+	destx = 0;
+	sourcex = - dx;
+	copyw = w + dx;
+    }
+    if (dy >= 0)
+    {
+	sourcey = 0;
+	desty = dy;
+	copyh = h - dy;
+    }
+    else
+    {
+	desty = 0;
+	sourcey = -dy;
+	copyh = h + dy;
+    }
+    (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC,
+			   sourcex, sourcey, copyw, copyh, destx, desty);
+    /*
+     * copy the new bits from the screen into the remaining areas of the
+     * pixmap
+     */
+    if (dy > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x, y, w, dy, 0, 0);
+    }
+    else if (dy < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x, y + h + dy, w, -dy, 0, h + dy);
+    }
+    if (dy >= 0)
+    {
+	desty = dy;
+	sourcey = y + dy;
+	copyh = h - dy;
+    }
+    else
+    {
+	desty = 0;
+	sourcey = y;
+	copyh = h + dy;
+    }
+    if (dx > 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x, sourcey, dx, copyh, 0, desty);
+    }
+    else if (dx < 0)
+    {
+	(*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC,
+			       x + w + dx, sourcey, -dx, copyh, w + dx, desty);
+    }
+    return TRUE;
+}
+
+static Bool
+rfbDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask)
+    ScreenPtr	    pScreen;
+    CursorPtr	    pCursor;
+    int		    x, y, w, h, dx, dy;
+    unsigned long   source, mask;
+{
+    rfbDCCursorPtr   pPriv;
+    rfbDCScreenPtr   pScreenPriv;
+    int		    status;
+    WindowPtr	    pWin;
+    GCPtr	    pGC;
+    XID		    gcval = FALSE;
+    PixmapPtr	    pTemp;
+
+    pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
+    if (!pPriv)
+    {
+	pPriv = rfbDCRealize(pScreen, pCursor);
+	if (!pPriv)
+	    return FALSE;
+    }
+    pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr;
+    pWin = WindowTable[pScreen->myNum];
+    pTemp = pScreenPriv->pTemp;
+    if (!pTemp ||
+	pTemp->drawable.width != pScreenPriv->pSave->drawable.width ||
+	pTemp->drawable.height != pScreenPriv->pSave->drawable.height)
+    {
+	if (pTemp)
+	    (*pScreen->DestroyPixmap) (pTemp);
+#ifdef ARGB_CURSOR
+	if (pScreenPriv->pTempPicture)
+	{
+	    FreePicture (pScreenPriv->pTempPicture, 0);
+	    pScreenPriv->pTempPicture = 0;
+	}
+#endif
+	pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap)
+	    (pScreen, w, h, pScreenPriv->pSave->drawable.depth);
+	if (!pTemp)
+	    return FALSE;
+    }
+    if (!pScreenPriv->pMoveGC)
+    {
+	pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp,
+	    GCGraphicsExposures, &gcval, &status);
+	if (!pScreenPriv->pMoveGC)
+	    return FALSE;
+    }
+    /*
+     * copy the saved area to a temporary pixmap
+     */
+    pGC = pScreenPriv->pMoveGC;
+    if (pGC->serialNumber != pTemp->drawable.serialNumber)
+	ValidateGC ((DrawablePtr) pTemp, pGC);
+    (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave,
+			  (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0);
+    
+    /*
+     * draw the cursor in the temporary pixmap
+     */
+#ifdef ARGB_CURSOR
+    if (pPriv->pPicture)
+    {
+	if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin))
+	    return FALSE;
+	CompositePicture (PictOpOver,
+			  pPriv->pPicture,
+			  NULL,
+			  pScreenPriv->pTempPicture,
+			  0, 0, 0, 0, 
+			  dx, dy, 
+			  pCursor->bits->width,
+			  pCursor->bits->height);
+    }
+    else
+#endif
+    {
+	if (!pScreenPriv->pPixSourceGC)
+	{
+	    pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp,
+		GCGraphicsExposures, &gcval, &status);
+	    if (!pScreenPriv->pPixSourceGC)
+		return FALSE;
+	}
+	if (!pScreenPriv->pPixMaskGC)
+	{
+	    pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp,
+		GCGraphicsExposures, &gcval, &status);
+	    if (!pScreenPriv->pPixMaskGC)
+		return FALSE;
+	}
+	rfbDCPutBits ((DrawablePtr)pTemp, pPriv,
+		     pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC,
+		     dx, dy, pCursor->bits->width, pCursor->bits->height,
+		     source, mask);
+    }
+
+    /*
+     * copy the temporary pixmap onto the screen
+     */
+
+    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
+	return FALSE;
+    pGC = pScreenPriv->pRestoreGC;
+    if (pWin->drawable.serialNumber != pGC->serialNumber)
+	ValidateGC ((DrawablePtr) pWin, pGC);
+
+    (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin,
+			    pGC,
+			    0, 0, w, h, x, y);
+    return TRUE;
+}
diff -u -rNp a/hw/vnc/dpmsstubs.c b/hw/vnc/dpmsstubs.c
--- a/hw/vnc/dpmsstubs.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/dpmsstubs.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,48 @@
+/* $Xorg: dpmsstubs.c,v 1.3 2000/08/17 19:47:56 cpqbld Exp $ */
+/*****************************************************************
+
+Copyright (c) 1996 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+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
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL 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 Digital Equipment Corporation 
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital 
+Equipment Corporation.
+
+******************************************************************/
+/* $XFree86: xc/programs/Xserver/Xext/dpmsstubs.c,v 3.3 1999/12/16 02:26:23 robin Exp $ */
+
+typedef int Bool;
+
+#define FALSE 0
+
+Bool DPMSSupported(void)
+{
+    return FALSE;
+}
+
+int DPSMGet(int *level)
+{
+    return -1;
+}
+
+void DPMSSet(int level)
+{
+
+}
diff -u -rNp a/hw/vnc/draw.c b/hw/vnc/draw.c
--- a/hw/vnc/draw.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/draw.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2108 @@
+/*
+ * draw.c - drawing routines for the RFB X server.  This is a set of
+ * wrappers around the standard MI/MFB/CFB drawing routines which work out
+ * to a fair approximation the region of the screen being modified by the
+ * drawing.  If the RFB client is ready then the modified region of the screen
+ * is sent to the client, otherwise the modified region will simply grow with
+ * each drawing request until the client is ready.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#include "rfb.h"
+
+int rfbDeferUpdateTime = 40; /* ms */
+
+
+/****************************************************************************/
+/*
+ * Macro definitions
+ */
+/****************************************************************************/
+
+#define TRC(x) /* (rfbLog x) */
+
+/* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each
+   client */
+
+#define ADD_TO_MODIFIED_REGION(pScreen,reg)				      \
+  {									      \
+      rfbClientPtr cl;							      \
+      for (cl = rfbClientHead; cl; cl = cl->next) {			      \
+	  REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\
+      }									      \
+  }
+
+/* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an
+   update to be sent to each client if there is one pending and the client is
+   ready for it.  */
+
+#define SCHEDULE_FB_UPDATE(pScreen,pVNC)				\
+  if (!pVNC->dontSendFramebufferUpdate) {				\
+      rfbClientPtr cl, nextCl;						\
+      for (cl = rfbClientHead; cl; cl = nextCl) {			\
+	  nextCl = cl->next;						\
+	  if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && 	\
+	      REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) 		\
+	  {								\
+	      rfbScheduleDeferredUpdate(pScreen, cl);			\
+	  }								\
+      }									\
+  }
+
+/* function prototypes */
+
+static void rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl);
+static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl,
+			  RegionPtr src, RegionPtr dst, int dx, int dy);
+#ifdef DEBUG
+static void PrintRegion(ScreenPtr pScreen, RegionPtr reg);
+#endif
+
+/* GC funcs */
+
+static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr);
+static void rfbChangeGC(GCPtr, unsigned long /*mask*/);
+static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/);
+static void rfbDestroyGC(GCPtr);
+static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/,
+			  int /*nrects*/);
+static void rfbDestroyClip(GCPtr);
+static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/);
+
+/* GC ops */
+
+static void rfbFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted);
+static void rfbSetSpans(DrawablePtr 		pDrawable, 
+	    		GCPtr			pGC, 
+	    		char			*psrc, 
+	    		register DDXPointPtr	ppt, 
+	    		int			*pwidth, 
+	    		int			nspans, 
+	    		int			fSorted);
+static void rfbPutImage();
+static RegionPtr rfbCopyArea();
+static RegionPtr rfbCopyPlane();
+static void rfbPolyPoint();
+static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts);
+static void rfbPolySegment();
+static void rfbPolyRectangle();
+static void rfbPolyArc();
+static void rfbFillPolygon();
+static void rfbPolyFillRect();
+static void rfbPolyFillArc();
+static int rfbPolyText8();
+static int rfbPolyText16();
+static void rfbImageText8();
+static void rfbImageText16();
+static void rfbImageGlyphBlt();
+static void rfbPolyGlyphBlt();
+static void rfbPushPixels();
+
+
+static GCFuncs rfbGCFuncs = {
+    rfbValidateGC,
+    rfbChangeGC,
+    rfbCopyGC,
+    rfbDestroyGC,
+    rfbChangeClip,
+    rfbDestroyClip,
+    rfbCopyClip,
+};
+
+
+static GCOps rfbGCOps = {
+    rfbFillSpans,	rfbSetSpans,	rfbPutImage,	
+    rfbCopyArea,	rfbCopyPlane,	rfbPolyPoint,
+    rfbPolylines,	rfbPolySegment,	rfbPolyRectangle,
+    rfbPolyArc,		rfbFillPolygon,	rfbPolyFillRect,
+    rfbPolyFillArc,	rfbPolyText8,	rfbPolyText16,
+    rfbImageText8,	rfbImageText16,	rfbImageGlyphBlt,
+    rfbPolyGlyphBlt,	rfbPushPixels
+};
+
+
+
+/****************************************************************************/
+/*
+ * Screen functions wrapper stuff
+ */
+/****************************************************************************/
+
+#define SCREEN_PROLOGUE(scrn, field)		\
+    ScreenPtr pScreen = scrn;			\
+    VNCSCREENPTR(pScreen); 		\
+    pScreen->field = pVNC->field;
+
+#define SCREEN_EPILOGUE(field, wrapper) \
+    pScreen->field = wrapper;
+
+
+/*
+ * CloseScreen wrapper -- unwrap everything, free the private data
+ * and call the wrapped CloseScreen function.
+ */
+
+Bool
+rfbCloseScreen (int i, ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+#if XFREE86VNC
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+#endif
+    int sock;
+
+    for (sock = 0; sock <= pVNC->maxFd; sock++) {
+	if (FD_ISSET(sock, &pVNC->allFds))
+	    if (sock != pVNC->rfbListenSock && sock != pVNC->httpListenSock) {
+	    	rfbCloseSock(pScreen, sock);
+	    }
+    }
+
+    if (pVNC->rfbListenSock > 0)
+    	if (close(pVNC->rfbListenSock))
+		ErrorF("Close of port %d failed\n",pVNC->rfbPort);
+
+    if (pVNC->httpListenSock > 0)
+    	if (close(pVNC->httpListenSock))
+		ErrorF("Close of port %d failed\n",pVNC->httpPort);
+
+    pScreen->CloseScreen = pVNC->CloseScreen;
+    pScreen->CreateGC = pVNC->CreateGC;
+    pScreen->PaintWindowBackground = pVNC->PaintWindowBackground;
+    pScreen->PaintWindowBorder = pVNC->PaintWindowBorder;
+    pScreen->CopyWindow = pVNC->CopyWindow;
+    pScreen->ClearToBackground = pVNC->ClearToBackground;
+    pScreen->RestoreAreas = pVNC->RestoreAreas;
+    pScreen->WakeupHandler = pVNC->WakeupHandler;
+
+#if XFREE86VNC
+    pScreen->InstallColormap = pVNC->InstallColormap;
+    pScreen->UninstallColormap = pVNC->UninstallColormap;
+    pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps;
+    pScreen->StoreColors = pVNC->StoreColors;
+    pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess;
+
+    xfree(pVNC);
+#endif
+
+    TRC((stderr,"Unwrapped screen functions\n"));
+
+    return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+#if XFREE86VNC
+void
+rfbEnableDisableFBAccess (int index, Bool enable)
+{
+    ScrnInfoPtr pScrn = xf86Screens[index];
+    VNCSCREENPTR(pScrn->pScreen);
+
+    /* 
+     * Blank the screen for security while inputs are disabled.
+     * When VT switching is fixed, we might be able to allow
+     * control even when switched away. 
+     */
+    if (!enable) {
+	WindowPtr pWin = WindowTable[index];
+    	ScreenPtr pScreen = pWin->drawable.pScreen;
+    	GCPtr pGC;
+    	xRectangle rect;
+
+    	rect.x = 0;
+    	rect.y = 0;
+    	rect.width = pScrn->virtualX;
+    	rect.height = pScrn->virtualY;
+
+    	if (!(pGC = GetScratchGC(pScreen->rootDepth, pScreen))) {
+    	    ErrorF("Couldn't blank screen");
+    	} else {
+	    CARD32 attributes[2];
+	    attributes[0] = pScreen->whitePixel;
+	    attributes[1] = pScreen->blackPixel;
+	    (void)ChangeGC(pGC, GCForeground | GCBackground, attributes);
+
+	    ValidateGC((DrawablePtr)pWin, pGC);
+
+  	    (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, 1, &rect);
+
+   	    FreeScratchGC(pGC);
+    	
+	    /* Flush pending packets */
+	    rfbCheckFds(pScreen);
+	    httpCheckFds(pScreen);
+    	}
+    }
+
+    pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess;
+    (*pScrn->EnableDisableFBAccess)(index, enable);
+    pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess;
+}
+#endif
+
+/*
+ * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC
+ * func "ValidateGC" is called).
+ */
+
+Bool
+rfbCreateGC (GCPtr pGC)
+{
+    Bool ret;
+    rfbGCPtr pGCPriv;
+
+    SCREEN_PROLOGUE(pGC->pScreen,CreateGC);
+
+    pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr;
+
+    ret = (*pScreen->CreateGC) (pGC);
+
+    TRC((stderr,"rfbCreateGC called\n"));
+
+    pGCPriv->wrapOps = NULL;
+    pGCPriv->wrapFuncs = pGC->funcs;
+    pGC->funcs = &rfbGCFuncs;
+
+    SCREEN_EPILOGUE(CreateGC,rfbCreateGC);
+
+    return ret;
+}
+
+/*
+ * PaintWindowBackground - the region being modified is just the given region.
+ */
+
+void
+rfbPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground);
+
+    TRC((stderr,"rfbPaintWindowBackground called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen,pRegion);
+
+    (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground);
+}
+
+/*
+ * PaintWindowBorder - the region being modified is just the given region.
+ */
+
+void
+rfbPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder);
+
+    TRC((stderr,"rfbPaintWindowBorder called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen,pRegion);
+
+    (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder);
+}
+
+#ifdef CHROMIUM
+Bool
+rfbRealizeWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,RealizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 1);
+	 }
+    }
+
+    ret = (*pScreen->RealizeWindow)(pWin);
+
+    SCREEN_EPILOGUE(RealizeWindow,rfbRealizeWindow);
+
+    return ret;
+}
+
+Bool
+rfbUnrealizeWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,UnrealizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 0);
+	 }
+    }
+
+    ret = (*pScreen->UnrealizeWindow)(pWin);
+
+    SCREEN_EPILOGUE(UnrealizeWindow,rfbUnrealizeWindow);
+
+    return ret;
+}
+
+Bool
+rfbDestroyWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 0);
+	 }
+    }
+
+    ret = (*pScreen->DestroyWindow)(pWin);
+
+    SCREEN_EPILOGUE(DestroyWindow,rfbDestroyWindow);
+
+    return ret;
+}
+
+void
+rfbResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ResizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	     rfbSendChromiumMoveResizeWindow(wt->CRwinId, pWin->drawable.x, pWin->drawable.y, w, h);
+	 }
+    }
+
+    (*pScreen->ResizeWindow)(pWin, x, y, w, h, pSib);
+
+    SCREEN_EPILOGUE(ResizeWindow,rfbResizeWindow);
+}
+
+Bool
+rfbPositionWindow(WindowPtr pWin, int x, int y)
+{
+    Bool ret;
+    CRWindowTable *wt, *nextWt;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PositionWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	     rfbSendChromiumMoveResizeWindow(wt->CRwinId, x, y, pWin->drawable.width, pWin->drawable.height);
+	 }
+    }
+
+    ret = (*pScreen->PositionWindow)(pWin, x, y);
+
+    SCREEN_EPILOGUE(PositionWindow,rfbPositionWindow);
+
+    return ret;
+}
+
+void
+rfbClipNotify(WindowPtr pWin, int x, int y)
+{
+    CRWindowTable *wt, *nextWt;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ClipNotify);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    int numClipRects = REGION_NUM_RECTS(&pWin->clipList);
+	    BoxPtr pClipRects = REGION_RECTS(&pWin->clipList);
+
+	    /* Possible optimization - has the cliplist really? changed */
+
+	    rfbSendChromiumClipList(wt->CRwinId, pClipRects, numClipRects);
+	 }
+    }
+
+    if (*pScreen->ClipNotify) 
+    	(*pScreen->ClipNotify)(pWin, x, y);
+
+    SCREEN_EPILOGUE(ClipNotify,rfbClipNotify);
+}
+#endif /* CHROMIUM */
+
+/*
+ * CopyWindow - the region being modified is the translation of the old
+ * region, clipped to the border clip region of the window.  Note that any
+ * parts of the window which have become newly-visible will not be affected by
+ * this call - a separate PaintWindowBackground/Border will be called to do
+ * that.  If the client will accept CopyRect messages then use rfbCopyRegion to
+ * optimise the pending screen changes into a single "copy region" plus the
+ * ordinary modified region.
+ */
+
+void
+rfbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion)
+{
+    rfbClientPtr cl;
+    RegionRec srcRegion, dstRegion;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow);
+
+    TRC((stderr,"rfbCopyWindow called\n"));
+
+    REGION_NULL(pScreen,&dstRegion);
+    REGION_COPY(pScreen,&dstRegion,pOldRegion);
+    REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion,
+		     pWin->drawable.x - ptOldOrg.x,
+		     pWin->drawable.y - ptOldOrg.y);
+    REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion,
+		     &pWin->borderClip);
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (cl->useCopyRect) {
+	    REGION_NULL(pScreen,&srcRegion);
+	    REGION_COPY(pScreen,&srcRegion,pOldRegion);
+
+	    rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion,
+			  pWin->drawable.x - ptOldOrg.x,
+			  pWin->drawable.y - ptOldOrg.y);
+
+	    REGION_UNINIT(pScreen, &srcRegion);
+
+	} else {
+
+	    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			 &dstRegion);
+	}
+    }
+
+    REGION_UNINIT(pScreen, &dstRegion);
+
+    (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow);
+}
+
+/*
+ * ClearToBackground - when generateExposures is false, the region being
+ * modified is the given rectangle (clipped to the "window clip region").
+ */
+
+void
+rfbClearToBackground (WindowPtr pWin, int x, int y, int w, int h, 
+		      Bool generateExposures)
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground);
+
+    TRC((stderr,"rfbClearToBackground called\n"));
+
+    if (!generateExposures) {
+	box.x1 = x + pWin->drawable.x;
+	box.y1 = y + pWin->drawable.y;
+	box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
+	box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
+
+	SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList);
+
+	ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
+
+	REGION_UNINIT(pScreen, &tmpRegion);
+    }
+
+    (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+    if (!generateExposures) {
+	SCHEDULE_FB_UPDATE(pScreen, pVNC);
+    }
+
+    SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground);
+}
+
+/*
+ * RestoreAreas - just be safe here - the region being modified is the whole
+ * exposed region.
+ */
+
+RegionPtr
+rfbRestoreAreas (WindowPtr pWin, RegionPtr prgnExposed)
+{
+    RegionPtr result;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas);
+
+    TRC((stderr,"rfbRestoreAreas called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen, prgnExposed);
+
+    result = (*pScreen->RestoreAreas) (pWin, prgnExposed);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas);
+
+    return result;
+}
+
+
+
+/****************************************************************************/
+/*
+ * GC funcs wrapper stuff
+ *
+ * We only really want to wrap the GC ops, but to do this we need to wrap
+ * ValidateGC and so all the other GC funcs must be wrapped as well.
+ */
+/****************************************************************************/
+
+#define GC_FUNC_PROLOGUE(pGC)						\
+    rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr;	\
+    (pGC)->funcs = pGCPriv->wrapFuncs;					\
+    if (pGCPriv->wrapOps)						\
+	(pGC)->ops = pGCPriv->wrapOps;
+
+#define GC_FUNC_EPILOGUE(pGC)		\
+    pGCPriv->wrapFuncs = (pGC)->funcs;	\
+    (pGC)->funcs = &rfbGCFuncs;		\
+    if (pGCPriv->wrapOps) {		\
+	pGCPriv->wrapOps = (pGC)->ops;	\
+	(pGC)->ops = &rfbGCOps;		\
+    }
+
+
+/*
+ * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if
+ * the drawing will be to a viewable window.
+ */
+
+static void
+rfbValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+    VNCSCREENPTR(pGC->pScreen);
+    GC_FUNC_PROLOGUE(pGC);
+
+    TRC((stderr,"rfbValidateGC called\n"));
+
+    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+    
+    pGCPriv->wrapOps = NULL;
+    if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable)
+    {
+	WindowPtr   pWin = (WindowPtr) pDrawable;
+	RegionPtr   pRegion = &pWin->clipList;
+
+	if (pGC->subWindowMode == IncludeInferiors)
+	    pRegion = &pWin->borderClip;
+	if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
+	    pGCPriv->wrapOps = pGC->ops;
+	    TRC((stderr,"rfbValidateGC: wrapped GC ops\n"));
+	}
+    }
+
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+/*
+ * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped
+ * function and then rewrap the funcs and ops.
+ */
+
+static void
+rfbChangeGC (pGC, mask)
+    GCPtr	    pGC;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->ChangeGC) (pGC, mask);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbCopyGC (pGCSrc, mask, pGCDst)
+    GCPtr	    pGCSrc, pGCDst;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE(pGCDst);
+    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+    GC_FUNC_EPILOGUE(pGCDst);
+}
+
+static void
+rfbDestroyGC (pGC)
+    GCPtr   pGC;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->DestroyGC) (pGC);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbChangeClip (pGC, type, pvalue, nrects)
+    GCPtr   pGC;
+    int		type;
+    pointer	pvalue;
+    int		nrects;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbDestroyClip(pGC)
+    GCPtr	pGC;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (* pGC->funcs->DestroyClip)(pGC);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbCopyClip(pgcDst, pgcSrc)
+    GCPtr pgcDst, pgcSrc;
+{
+    GC_FUNC_PROLOGUE(pgcDst);
+    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+    GC_FUNC_EPILOGUE(pgcDst);
+}
+
+
+/****************************************************************************/
+/*
+ * GC ops wrapper stuff
+ *
+ * Note that these routines will only have been wrapped for drawing to
+ * viewable windows so we don't need to check each time that the drawable
+ * is a viewable window.
+ */
+/****************************************************************************/
+
+#define GC_OP_PROLOGUE(pDrawable,pGC) \
+    ScreenPtr pScreen = pGC->pScreen;			\
+    VNCSCREENPTR(pScreen);			\
+    rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \
+    GCFuncs *oldFuncs = pGC->funcs; \
+    (void) pScreen; /* silence compiler */ \
+    (pGC)->funcs = pGCPrivate->wrapFuncs; \
+    (pGC)->ops = pGCPrivate->wrapOps;
+
+#define GC_OP_EPILOGUE(pGC) \
+    pGCPrivate->wrapOps = (pGC)->ops; \
+    (pGC)->funcs = oldFuncs; \
+    (pGC)->ops = &rfbGCOps;
+
+
+/*
+ * FillSpans - being very safe - the region being modified is the border clip
+ * region of the window.
+ */
+
+static void
+rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nInit;			/* number of spans to fill */
+    DDXPointPtr pptInit;		/* pointer to list of start points */
+    int		*pwidthInit;		/* pointer to list of n widths */
+    int 	fSorted;
+{
+    GC_OP_PROLOGUE(pDrawable,pGC);
+
+    TRC((stderr,"rfbFillSpans called\n"));
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
+			   &((WindowPtr)pDrawable)->borderClip);
+
+    (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * SetSpans - being very safe - the region being modified is the border clip
+ * region of the window.
+ */
+
+static void
+rfbSetSpans(DrawablePtr 		pDrawable, 
+	    GCPtr			pGC, 
+	    char			*psrc, 
+	    register DDXPointPtr	ppt, 
+	    int				*pwidth, 
+	    int				nspans, 
+	    int				fSorted)
+{
+    GC_OP_PROLOGUE(pDrawable,pGC);
+
+    TRC((stderr,"rfbSetSpans called\n"));
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
+			   &((WindowPtr)pDrawable)->borderClip);
+
+    (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PutImage - the region being modified is the rectangle of the
+ * PutImage (clipped to the window clip region).
+ */
+
+static void
+rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int		  depth;
+    int	    	  x;
+    int	    	  y;
+    int	    	  w;
+    int	    	  h;
+    int		  leftPad;
+    int	    	  format;
+    char    	  *pBits;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPutImage called\n"));
+
+    box.x1 = x + pDrawable->x;
+    box.y1 = y + pDrawable->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+
+    (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h,
+			   leftPad, format, pBits);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * CopyArea - the region being modified is the destination rectangle (clipped
+ * to the window clip region).
+ * If the client will accept CopyRect messages then use rfbCopyRegion
+ * to optimise the pending screen changes into a single "copy region" plus
+ * the ordinary modified region.
+ */
+
+static RegionPtr
+rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    GCPtr   	  pGC;
+    int	    	  srcx;
+    int	    	  srcy;
+    int	    	  w;
+    int	    	  h;
+    int	    	  dstx;
+    int	    	  dsty;
+{
+    rfbClientPtr cl;
+    RegionPtr rgn;
+    RegionRec srcRegion, dstRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDst, pGC);
+
+    TRC((stderr,"rfbCopyArea called\n"));
+
+    box.x1 = dstx + pDst->x;
+    box.y1 = dsty + pDst->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0);
+    REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion,
+		     					pGC->pCompositeClip);
+
+    if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) {
+	box.x1 = srcx + pSrc->x;
+	box.y1 = srcy + pSrc->y;
+	box.x2 = box.x1 + w;
+	box.y2 = box.y1 + h;
+
+	for (cl = rfbClientHead; cl; cl = cl->next) {
+	    if (cl->useCopyRect) {
+		SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0);
+		REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion,
+				 &((WindowPtr)pSrc)->clipList);
+
+		rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion,
+			      dstx + pDst->x - srcx - pSrc->x,
+			      dsty + pDst->y - srcy - pSrc->y);
+
+		REGION_UNINIT(pSrc->pScreen, &srcRegion);
+
+	    } else {
+
+		REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			     &dstRegion);
+	    }
+	}
+
+    } else {
+
+	ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion);
+    }
+
+    REGION_UNINIT(pDst->pScreen, &dstRegion);
+
+    rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				 dstx, dsty);
+
+    SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+
+    return rgn;
+}
+
+
+/*
+ * CopyPlane - the region being modified is the destination rectangle (clipped
+ * to the window clip region).
+ */
+
+static RegionPtr
+rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    register GCPtr pGC;
+    int     	  srcx,
+		  srcy;
+    int     	  w,
+		  h;
+    int     	  dstx,
+		  dsty;
+    unsigned long  plane;
+{
+    RegionPtr rgn;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDst, pGC);
+
+    TRC((stderr,"rfbCopyPlane called\n"));
+
+    box.x1 = dstx + pDst->x;
+    box.y1 = dsty + pDst->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDst->pScreen, &tmpRegion);
+
+    rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx, dsty, plane);
+
+    SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+
+    return rgn;
+}
+
+/*
+ * PolyPoint - find the smallest rectangle which encloses the points drawn
+ * (and clip).
+ */
+
+static void
+rfbPolyPoint (pDrawable, pGC, mode, npt, pts)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		mode;		/* Origin or Previous */
+    int		npt;
+    xPoint 	*pts;
+{
+    int i;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyPoint called\n"));
+
+    if (npt) {
+	int minX = pts[0].x, maxX = pts[0].x;
+	int minY = pts[0].y, maxY = pts[0].y;
+
+	if (mode == CoordModePrevious)
+	{
+	    int x = pts[0].x, y = pts[0].y;
+
+	    for (i = 1; i < npt; i++) {
+		x += pts[i].x;
+		y += pts[i].y;
+		if (x < minX) minX = x;
+		if (x > maxX) maxX = x;
+		if (y < minY) minY = y;
+		if (y > maxY) maxY = y;
+	    }
+	}
+	else
+	{
+	    for (i = 1; i < npt; i++) {
+		if (pts[i].x < minX) minX = pts[i].x;
+		if (pts[i].x > maxX) maxX = pts[i].x;
+		if (pts[i].y < minY) minY = pts[i].y;
+		if (pts[i].y > maxY) maxY = pts[i].y;
+	    }
+	}
+
+	box.x1 = minX + pDrawable->x;
+	box.y1 = minY + pDrawable->y;
+	box.x2 = maxX + 1 + pDrawable->x;
+	box.y2 = maxY + 1 + pDrawable->y;
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+
+    if (npt) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyLines - take the union of bounding boxes around each line (and clip).
+ */
+
+static void
+rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts)
+{
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    int i, extra, nlines, lw;
+    int x1, x2, y1, y2;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolylines called\n"));
+
+    if (npt) {
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	if (npt == 1)
+	{
+	    nlines = 1;
+	    rects = (xRectangle *)xalloc(sizeof(xRectangle));
+	    if (!rects) {
+		FatalError("rfbPolylines: xalloc failed\n");
+	    }
+
+	    rects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe here */
+	    rects[0].y = ppts[0].y - lw + pDrawable->y;
+	    rects[0].width = 2*lw;
+	    rects[0].height = 2*lw;
+	}
+	else
+	{
+	    nlines = npt - 1;
+	    rects = (xRectangle *)xalloc(nlines*sizeof(xRectangle));
+	    if (!rects) {
+		FatalError("rfbPolylines: xalloc failed\n");
+	    }
+
+	    /*
+	     * mitered joins can project quite a way from
+	     * the line end; the 11 degree miter limit limits
+	     * this extension to lw / (2 * tan(11/2)), rounded up
+	     * and converted to int yields 6 * lw
+	     */
+
+	    if (pGC->joinStyle == JoinMiter) {
+		extra = 6 * lw;
+	    } else {
+		extra = lw / 2;
+	    }
+
+	    x1 = ppts[0].x + pDrawable->x;
+	    y1 = ppts[0].y + pDrawable->y;
+
+	    for (i = 0; i < nlines; i++) {
+		if (mode == CoordModeOrigin) {
+		    x2 = pDrawable->x + ppts[i+1].x;
+		    y2 = pDrawable->y + ppts[i+1].y;
+		} else {
+		    x2 = x1 + ppts[i+1].x;
+		    y2 = y1 + ppts[i+1].y;
+		}
+
+		if (x1 > x2) {
+		    rects[i].x = x2 - extra;
+		    rects[i].width = x1 - x2 + 1 + 2 * extra;
+		} else {
+		    rects[i].x = x1 - extra;
+		    rects[i].width = x2 - x1 + 1 + 2 * extra;
+		}
+
+		if (y1 > y2) {
+		    rects[i].y = y2 - extra;
+		    rects[i].height = y1 - y2 + 1 + 2 * extra;
+		} else {
+		    rects[i].y = y1 - extra;
+		    rects[i].height = y2 - y1 + 1 + 2 * extra;
+		}
+
+		x1 = x2;
+		y1 = y2;
+	    }
+	}
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nlines, rects,CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+
+    if (npt) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolySegment - take the union of bounding boxes around each segment (and
+ * clip).
+ */
+
+static void
+rfbPolySegment(pDrawable, pGC, nseg, segs)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int		nseg;
+    xSegment	*segs;
+{
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    int i, extra, lw;
+
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolySegment called\n"));
+
+    if (nseg) {
+	rects = (xRectangle *)xalloc(nseg*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolySegment: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < nseg; i++)
+	{
+	    if (segs[i].x1 > segs[i].x2) {
+		rects[i].x = segs[i].x2 - extra + pDrawable->x;
+		rects[i].width = segs[i].x1 - segs[i].x2 + 1 + 2 * extra;
+	    } else {
+		rects[i].x = segs[i].x1 - extra + pDrawable->x;
+		rects[i].width = segs[i].x2 - segs[i].x1 + 1 + 2 * extra;
+	    }
+
+	    if (segs[i].y1 > segs[i].y2) {
+		rects[i].y = segs[i].y2 - extra + pDrawable->y;
+		rects[i].height = segs[i].y1 - segs[i].y2 + 1 + 2 * extra;
+	    } else {
+		rects[i].y = segs[i].y1 - extra + pDrawable->y;
+		rects[i].height = segs[i].y2 - segs[i].y1 + 1 + 2 * extra;
+	    }
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nseg, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+
+    if (nseg) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyRectangle (rectangle outlines) - take the union of bounding boxes
+ * around each line (and clip).
+ */
+
+static void
+rfbPolyRectangle(pDrawable, pGC, nrects, rects)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*rects;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *regRects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyRectangle called\n"));
+
+    if (nrects) {
+	regRects = (xRectangle *)xalloc(nrects*4*sizeof(xRectangle));
+	if (!regRects) {
+	    FatalError("rfbPolyRectangle: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < nrects; i++)
+	{
+	    regRects[i*4].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4].width = rects[i].width + 1 + 2 * extra;
+	    regRects[i*4].height = 1 + 2 * extra;
+
+	    regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4+1].width = 1 + 2 * extra;
+	    regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
+
+	    regRects[i*4+2].x
+		= rects[i].x + rects[i].width - extra + pDrawable->x;
+	    regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4+2].width = 1 + 2 * extra;
+	    regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
+
+	    regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4+3].y
+		= rects[i].y + rects[i].height - extra + pDrawable->y;
+	    regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
+	    regRects[i*4+3].height = 1 + 2 * extra;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects*4,
+				    regRects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)regRects);
+    }
+
+    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+
+    if (nrects) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyArc - take the union of bounding boxes around each arc (and clip).
+ * Bounding boxes assume each is a full circle / ellipse.
+ */
+
+static void
+rfbPolyArc(pDrawable, pGC, narcs, arcs)
+    DrawablePtr	pDrawable;
+    register GCPtr	pGC;
+    int		narcs;
+    xArc	*arcs;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyArc called\n"));
+
+    if (narcs) {
+	rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolyArc: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < narcs; i++)
+	{
+	    rects[i].x = arcs[i].x - extra + pDrawable->x;
+	    rects[i].y = arcs[i].y - extra + pDrawable->y;
+	    rects[i].width = arcs[i].width + lw;
+	    rects[i].height = arcs[i].height + lw;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+
+    if (narcs) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * FillPolygon - take bounding box around polygon (and clip).
+ */
+
+static void
+rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts)
+    register DrawablePtr pDrawable;
+    register GCPtr	pGC;
+    int			shape, mode;
+    int			count;
+    DDXPointPtr		pts;
+{
+    int i;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbFillPolygon called\n"));
+
+    if (count) {
+	int minX = pts[0].x, maxX = pts[0].x;
+	int minY = pts[0].y, maxY = pts[0].y;
+
+	if (mode == CoordModePrevious)
+	{
+	    int x = pts[0].x, y = pts[0].y;
+
+	    for (i = 1; i < count; i++) {
+		x += pts[i].x;
+		y += pts[i].y;
+		if (x < minX) minX = x;
+		if (x > maxX) maxX = x;
+		if (y < minY) minY = y;
+		if (y > maxY) maxY = y;
+	    }
+	}
+	else
+	{
+	    for (i = 1; i < count; i++) {
+		if (pts[i].x < minX) minX = pts[i].x;
+		if (pts[i].x > maxX) maxX = pts[i].x;
+		if (pts[i].y < minY) minY = pts[i].y;
+		if (pts[i].y > maxY) maxY = pts[i].y;
+	    }
+	}
+
+	box.x1 = minX + pDrawable->x;
+	box.y1 = minY + pDrawable->y;
+	box.x2 = maxX + 1 + pDrawable->x;
+	box.y2 = maxY + 1 + pDrawable->y;
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyFillRect - take the union of the given rectangles (and clip).
+ */
+
+static void
+rfbPolyFillRect(pDrawable, pGC, nrects, rects)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*rects;
+{
+    RegionPtr tmpRegion;
+    xRectangle *regRects;
+    int i;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyFillRect called\n"));
+
+    if (nrects) {
+	regRects = (xRectangle *)xalloc(nrects*sizeof(xRectangle));
+	if (!regRects) {
+	    FatalError("rfbPolyFillRect: xalloc failed\n");
+	}
+
+	for (i = 0; i < nrects; i++) {
+	    regRects[i].x = rects[i].x + pDrawable->x;
+	    regRects[i].y = rects[i].y + pDrawable->y;
+	    regRects[i].width = rects[i].width;
+	    regRects[i].height = rects[i].height;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects, regRects,
+				    CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)regRects);
+    }
+
+    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+
+    if (nrects) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyFillArc - take the union of bounding boxes around each arc (and clip).
+ * Bounding boxes assume each is a full circle / ellipse.
+ */
+
+static void
+rfbPolyFillArc(pDrawable, pGC, narcs, arcs)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		narcs;
+    xArc	*arcs;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyFillArc called\n"));
+
+    if (narcs) {
+	rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolyFillArc: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < narcs; i++)
+	{
+	    rects[i].x = arcs[i].x - extra + pDrawable->x;
+	    rects[i].y = arcs[i].y - extra + pDrawable->y;
+	    rects[i].width = arcs[i].width + lw;
+	    rects[i].height = arcs[i].height + lw;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+
+    if (narcs) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * Get a rough bounding box around n characters of the given font.
+ */
+
+static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox)
+    DrawablePtr pDrawable;
+    FontPtr font;
+    int x, y, n;
+    BoxPtr pbox;
+{
+    int maxAscent, maxDescent, maxCharWidth;
+
+    if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent))
+	maxAscent = FONTASCENT(font);
+    else
+	maxAscent = FONTMAXBOUNDS(font,ascent);
+
+    if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent))
+	maxDescent = FONTDESCENT(font);
+    else
+	maxDescent = FONTMAXBOUNDS(font,descent);
+
+    if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth))
+	maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing);
+    else
+	maxCharWidth = FONTMAXBOUNDS(font,characterWidth);
+
+    pbox->x1 = pDrawable->x + x;
+    pbox->y1 = pDrawable->y + y - maxAscent;
+    pbox->x2 = pbox->x1 + maxCharWidth * n;
+    pbox->y2 = pbox->y1 + maxAscent + maxDescent;
+
+    if (FONTMINBOUNDS(font,leftSideBearing) < 0) {
+	pbox->x1 += FONTMINBOUNDS(font,leftSideBearing);
+    }
+}
+
+
+/*
+ * PolyText8 - use rough bounding box.
+ */
+
+static int
+rfbPolyText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int 	count;
+    char	*chars;
+{
+    int	ret;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyText8 called '%.*s'\n",count,chars));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+    return ret;
+}
+
+/*
+ * PolyText16 - use rough bounding box.
+ */
+
+static int
+rfbPolyText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    int	ret;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyText16 called\n"));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+    return ret;
+}
+
+/*
+ * ImageText8 - use rough bounding box.
+ */
+
+static void
+rfbImageText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    char	*chars;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageText8 called '%.*s'\n",count,chars));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * ImageText16 - use rough bounding box.
+ */
+
+static void
+rfbImageText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageText16 called\n"));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * ImageGlyphBlt - use rough bounding box.
+ */
+
+static void
+rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer 	pglyphBase;	/* start of array of glyphs */
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageGlyphBlt called\n"));
+
+    if (nglyph) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+
+    if (nglyph) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyGlyphBlt - use rough bounding box.
+ */
+
+static void
+rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer	pglyphBase;	/* start of array of glyphs */
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyGlyphBlt called\n"));
+
+    if (nglyph) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    if (nglyph) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PushPixels - be fairly safe - region modified is intersection of the given
+ * rectangle with the window clip region.
+ */
+
+static void
+rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y)
+    GCPtr	pGC;
+    PixmapPtr	pBitMap;
+    DrawablePtr pDrawable;
+    int		w, h, x, y;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPushPixels called\n"));
+
+    box.x1 = x + pDrawable->x;
+    box.y1 = y + pDrawable->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+
+    (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+#ifdef RENDER
+void
+rfbComposite(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pMask,
+    PicturePtr pDst,
+    INT16 xSrc,
+    INT16 ySrc,
+    INT16 xMask,
+    INT16 yMask,
+    INT16 xDst,
+    INT16 yDst,
+    CARD16 width,
+    CARD16 height
+){
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    RegionRec tmpRegion;
+    BoxRec box;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+    box.x1 = pDst->pDrawable->x + xDst;
+    box.y1 = pDst->pDrawable->y + yDst;
+    box.x2 = box.x1 + width;
+    box.y2 = box.y1 + height;
+
+    REGION_INIT(pScreen, &tmpRegion, &box, 0);
+
+    ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
+
+    ps->Composite = pVNC->Composite;
+    (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
+		     xMask, yMask, xDst, yDst, width, height);
+    ps->Composite = rfbComposite;
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    REGION_UNINIT(pScreen, &tmpRegion);
+}
+#endif /* RENDER */
+
+/****************************************************************************/
+/*
+ * Other functions
+ */
+/****************************************************************************/
+
+/*
+ * rfbCopyRegion.  Args are src and dst regions plus a translation (dx,dy).
+ * Takes these args together with the existing modified region and possibly an
+ * existing copy region and translation.  Produces a combined modified region
+ * plus copy region and translation.  Note that the copy region is the
+ * destination of the copy.
+ *
+ * First we trim parts of src which are invalid (ie in the modified region).
+ * Then we see if there is any overlap between the src and the existing copy
+ * region.  If not then the two copies cannot be combined, so we choose
+ * whichever is bigger to form the basis of a new copy, while the other copy is
+ * just done the hard way by being added to the modified region.  So if the
+ * existing copy is bigger then we simply add the destination of the new copy
+ * to the modified region and we're done.  If the new copy is bigger, we add
+ * the old copy region to the modified region and behave as though there is no
+ * existing copy region.
+ * 
+ * At this stage we now know that either the two copies can be combined, or
+ * that there is no existing copy.  We temporarily add both the existing copy
+ * region and dst to the modified region (this is the entire area of the screen
+ * affected in any way).  Finally we calculate the new copy region, and remove
+ * it from the modified region.
+ *
+ * Note:
+ *   1. The src region is modified by this routine.
+ *   2. When the copy region is empty, copyDX and copyDY MUST be set to zero.
+ */
+
+static void
+rfbCopyRegion(pScreen, cl, src, dst, dx, dy)
+    ScreenPtr pScreen;
+    rfbClientPtr cl;
+    RegionPtr src;
+    RegionPtr dst;
+    int dx, dy;
+{
+    RegionRec tmp;
+
+    /* src = src - modifiedRegion */
+
+    REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion);
+
+    if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+
+	REGION_NULL(pScreen, &tmp);
+	REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion);
+
+	if (REGION_NOTEMPTY(pScreen, &tmp)) {
+
+	    /* if src and copyRegion overlap:
+	         src = src intersect copyRegion */
+
+	    REGION_COPY(pScreen, src, &tmp);
+
+	} else {
+
+	    /* if no overlap, find bigger region */
+
+	    int newArea = (((REGION_EXTENTS(pScreen,src))->x2
+			    - (REGION_EXTENTS(pScreen,src))->x1)
+			   * ((REGION_EXTENTS(pScreen,src))->y2
+			      - (REGION_EXTENTS(pScreen,src))->y1));
+
+	    int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2
+			    - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1)
+			   * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2
+			     - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1));
+
+	    if (oldArea > newArea) {
+
+		/* existing copy is bigger:
+		     modifiedRegion = modifiedRegion union dst
+		     copyRegion = copyRegion - dst
+		     return */
+
+		REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			     dst);
+		REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
+				dst);
+		if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+		    cl->copyDX = 0;
+		    cl->copyDY = 0;
+		}
+		return;
+	    }
+
+	    /* new copy is bigger:
+	         modifiedRegion = modifiedRegion union copyRegion
+		 copyRegion = empty */
+
+	    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			 &cl->copyRegion);
+	    REGION_EMPTY(pScreen, &cl->copyRegion);
+	    cl->copyDX = cl->copyDY = 0;
+	}
+    }
+
+
+    /* modifiedRegion = modifiedRegion union dst union copyRegion */
+
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst);
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		 &cl->copyRegion);
+
+    /* copyRegion = T(src) intersect dst */
+
+    REGION_TRANSLATE(pScreen, src, dx, dy);
+    REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst);
+
+    /* modifiedRegion = modifiedRegion - copyRegion */
+
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &cl->copyRegion);
+
+    /* combine new translation T with existing translation */
+
+    if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+	cl->copyDX += dx;
+	cl->copyDY += dy;
+    } else {
+	cl->copyDX = 0;
+	cl->copyDY = 0;
+    }
+}
+
+
+/*
+ * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer
+ * goes off.
+ */
+
+static CARD32
+rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+  rfbClientPtr cl = (rfbClientPtr)arg;
+
+  rfbSendFramebufferUpdate(cl->pScreen, cl);
+
+  cl->deferredUpdateScheduled = FALSE;
+  return 0;
+}
+
+
+/*
+ * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro
+ * to schedule an update.
+ */
+
+static void
+rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl)
+{
+    if (rfbDeferUpdateTime != 0) {
+	cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0,
+					   rfbDeferUpdateTime,
+					   rfbDeferredUpdateCallback, cl);
+	cl->deferredUpdateScheduled = TRUE;
+    } else {
+	rfbSendFramebufferUpdate(pScreen, cl);
+    }
+}
+
+
+/*
+ * PrintRegion is useful for debugging.
+ */
+
+#ifdef DEBUG
+static void
+PrintRegion(ScreenPtr pScreen, RegionPtr reg)
+{
+    int nrects = REGION_NUM_RECTS(reg);
+    int i;
+
+    ErrorF("Region num rects %d extents %d,%d %d,%d\n",nrects,
+	   (REGION_EXTENTS(pScreen,reg))->x1,
+	   (REGION_EXTENTS(pScreen,reg))->y1,
+	   (REGION_EXTENTS(pScreen,reg))->x2,
+	   (REGION_EXTENTS(pScreen,reg))->y2);
+
+    for (i = 0; i < nrects; i++) {
+	ErrorF("    rect %d,%d %dx%d\n",
+	       REGION_RECTS(reg)[i].x1,
+	       REGION_RECTS(reg)[i].y1,
+	       REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1,
+	       REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1);
+    }
+}
+#endif
+
+
+/**
+ * Allow scheduling updates from other functions in other files.
+ */
+void
+rfbScheduleUpdate(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+}
diff -u -rNp a/hw/vnc/hextile.c b/hw/vnc/hextile.c
--- a/hw/vnc/hextile.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/hextile.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,351 @@
+/*
+ * hextile.c
+ *
+ * Routines to implement Hextile Encoding
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+
+static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
+static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
+static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
+
+
+/*
+ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
+ */
+
+Bool
+rfbSendRectEncodingHextile(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingHextile);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingHextile]++;
+    cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader;
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	return sendHextiles8(cl, x, y, w, h);
+    case 16:
+	return sendHextiles16(cl, x, y, w, h);
+    case 32:
+	return sendHextiles32(cl, x, y, w, h);
+    }
+
+    rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
+    return FALSE;
+}
+
+
+#define PUT_PIXEL8(pix) (pVNC->updateBuf[pVNC->ublen++] = (pix))
+
+#define PUT_PIXEL16(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1])
+
+#define PUT_PIXEL32(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[2], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[3])
+
+
+#define DEFINE_SEND_HEXTILES(bpp)					      \
+									      \
+									      \
+static Bool subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w,     \
+			       int h, CARD##bpp bg,   			      \
+			       CARD##bpp fg, Bool mono);		      \
+static void testColours##bpp(CARD##bpp *data, int size, Bool *mono,	      \
+			     Bool *solid, CARD##bpp *bg, CARD##bpp *fg);      \
+									      \
+									      \
+/*									      \
+ * rfbSendHextiles							      \
+ */									      \
+									      \
+static Bool								      \
+sendHextiles##bpp(cl, rx, ry, rw, rh)					      \
+    rfbClientPtr cl;							      \
+    int rx, ry, rw, rh;							      \
+{									      \
+    VNCSCREENPTR(cl->pScreen);						      \
+    int x, y, w, h;							      \
+    int startUblen;							      \
+    unsigned char *fbptr;						      \
+    CARD##bpp bg = 0, fg = 0, newBg, newFg;				      \
+    Bool mono, solid;							      \
+    Bool validBg = FALSE;						      \
+    Bool validFg = FALSE;						      \
+    CARD##bpp clientPixelData[16*16*(bpp/8)];				      \
+									      \
+    for (y = ry; y < ry+rh; y += 16) {					      \
+	for (x = rx; x < rx+rw; x += 16) {				      \
+	    w = h = 16;							      \
+	    if (rx+rw - x < 16)						      \
+		w = rx+rw - x;						      \
+	    if (ry+rh - y < 16)						      \
+		h = ry+rh - y;						      \
+									      \
+	    if ((pVNC->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \
+		if (!rfbSendUpdateBuf(cl))				      \
+		    return FALSE;					      \
+	    }								      \
+									      \
+	    fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)	      \
+		     + (x * (pVNC->bitsPerPixel / 8)));		      	      \
+									      \
+	    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,	      \
+			       &pVNC->rfbServerFormat,			      \
+			       &cl->format, fbptr, (char *)clientPixelData,   \
+			       pVNC->paddedWidthInBytes, w, h, x, y); 	      \
+									      \
+	    startUblen = pVNC->ublen;					      \
+	    pVNC->updateBuf[startUblen] = 0;				      \
+	    pVNC->ublen++;						      \
+									      \
+	    testColours##bpp(clientPixelData, w * h,			      \
+			     &mono, &solid, &newBg, &newFg);		      \
+									      \
+	    if (!validBg || (newBg != bg)) {				      \
+		validBg = TRUE;						      \
+		bg = newBg;						      \
+		pVNC->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
+		PUT_PIXEL##bpp(bg);					      \
+	    }								      \
+									      \
+	    if (solid) {						      \
+		cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen;  \
+		continue;						      \
+	    }								      \
+									      \
+	    pVNC->updateBuf[startUblen] |= rfbHextileAnySubrects;	      \
+									      \
+	    if (mono) {							      \
+		if (!validFg || (newFg != fg)) {			      \
+		    validFg = TRUE;					      \
+		    fg = newFg;						      \
+		    pVNC->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
+		    PUT_PIXEL##bpp(fg);					      \
+		}							      \
+	    } else {							      \
+		validFg = FALSE;					      \
+		pVNC->updateBuf[startUblen] |= rfbHextileSubrectsColoured;    \
+	    }								      \
+									      \
+	    if (!subrectEncode##bpp(cl->pScreen, clientPixelData, w, h, bg, fg, mono)) {   \
+		/* encoding was too large, use raw */			      \
+		validBg = FALSE;					      \
+		validFg = FALSE;					      \
+		pVNC->ublen = startUblen;				      \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextileRaw;		      \
+		(*cl->translateFn)(cl->pScreen, cl->translateLookupTable,     \
+				   &pVNC->rfbServerFormat, &cl->format, fbptr,\
+				   (char *)clientPixelData,		      \
+				   pVNC->paddedWidthInBytes, w, h, x, y);     \
+									      \
+		memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)clientPixelData,\
+		       w * h * (bpp/8));				      \
+									      \
+		pVNC->ublen += w * h * (bpp/8);				      \
+	    }								      \
+									      \
+	    cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \
+	}								      \
+    }									      \
+									      \
+    return TRUE;							      \
+}									      \
+									      \
+									      \
+static Bool								      \
+subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, int h,          \
+		   CARD##bpp bg, CARD##bpp fg, Bool mono)		      \
+{									      \
+    VNCSCREENPTR(pScreen);						      \
+    CARD##bpp clientdata;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    int nSubrectsUblen;							      \
+									      \
+    nSubrectsUblen = pVNC->ublen;					      \
+    pVNC->ublen++;							      \
+									      \
+    for (y=0; y<h; y++) {						      \
+	line = data+(y*w);						      \
+	for (x=0; x<w; x++) {						      \
+	    if (line[x] != bg) {					      \
+		clientdata = line[x];					      \
+		hy = y-1;						      \
+		hyflag = 1;						      \
+		for (j=y; j<h; j++) {					      \
+		    seg = data+(j*w);					      \
+		    if (seg[x] != clientdata) {break;}			      \
+		    i = x;						      \
+		    while ((seg[i] == clientdata) && (i < w)) i += 1;	      \
+		    i -= 1;						      \
+		    if (j == y) vx = hx = i;				      \
+		    if (i < vx) vx = i;					      \
+		    if ((hyflag > 0) && (i >= hx)) {			      \
+			hy += 1;					      \
+		    } else {						      \
+			hyflag = 0;					      \
+		    }							      \
+		}							      \
+		vy = j-1;						      \
+									      \
+		/* We now have two possible subrects: (x,y,hx,hy) and	      \
+		 * (x,y,vx,vy).  We'll choose the bigger of the two.	      \
+		 */							      \
+		hw = hx-x+1;						      \
+		hh = hy-y+1;						      \
+		vw = vx-x+1;						      \
+		vh = vy-y+1;						      \
+									      \
+		thex = x;						      \
+		they = y;						      \
+									      \
+		if ((hw*hh) > (vw*vh)) {				      \
+		    thew = hw;						      \
+		    theh = hh;						      \
+		} else {						      \
+		    thew = vw;						      \
+		    theh = vh;						      \
+		}							      \
+									      \
+		if (mono) {						      \
+		    newLen = pVNC->ublen - nSubrectsUblen + 2;		      \
+		} else {						      \
+		    newLen = pVNC->ublen - nSubrectsUblen + bpp/8 + 2;	      \
+		}							      \
+									      \
+		if (newLen > (w * h * (bpp/8)))				      \
+		    return FALSE;					      \
+									      \
+		numsubs += 1;						      \
+									      \
+		if (!mono) PUT_PIXEL##bpp(clientdata);			      \
+									      \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextilePackXY(thex,they); \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextilePackWH(thew,theh); \
+									      \
+		/*							      \
+		 * Now mark the subrect as done.			      \
+		 */							      \
+		for (j=they; j < (they+theh); j++) {			      \
+		    for (i=thex; i < (thex+thew); i++) {		      \
+			data[j*w+i] = bg;				      \
+		    }							      \
+		}							      \
+	    }								      \
+	}								      \
+    }									      \
+									      \
+    pVNC->updateBuf[nSubrectsUblen] = numsubs;				      \
+									      \
+    return TRUE;							      \
+}									      \
+									      \
+									      \
+/*									      \
+ * testColours() tests if there are one (solid), two (mono) or more	      \
+ * colours in a tile and gets a reasonable guess at the best background	      \
+ * pixel, and the foreground pixel for mono.				      \
+ */									      \
+									      \
+static void								      \
+testColours##bpp(data,size,mono,solid,bg,fg)				      \
+    CARD##bpp *data;							      \
+    int size;								      \
+    Bool *mono;								      \
+    Bool *solid;							      \
+    CARD##bpp *bg;							      \
+    CARD##bpp *fg;							      \
+{									      \
+    CARD##bpp colour1 = 0, colour2 = 0;					      \
+    int n1 = 0, n2 = 0;							      \
+    *mono = TRUE;							      \
+    *solid = TRUE;							      \
+									      \
+    for (; size > 0; size--, data++) {					      \
+									      \
+	if (n1 == 0)							      \
+	    colour1 = *data;						      \
+									      \
+	if (*data == colour1) {						      \
+	    n1++;							      \
+	    continue;							      \
+	}								      \
+									      \
+	if (n2 == 0) {							      \
+	    *solid = FALSE;						      \
+	    colour2 = *data;						      \
+	}								      \
+									      \
+	if (*data == colour2) {						      \
+	    n2++;							      \
+	    continue;							      \
+	}								      \
+									      \
+	*mono = FALSE;							      \
+	break;								      \
+    }									      \
+									      \
+    if (n1 > n2) {							      \
+	*bg = colour1;							      \
+	*fg = colour2;							      \
+    } else {								      \
+	*bg = colour2;							      \
+	*fg = colour1;							      \
+    }									      \
+}
+
+DEFINE_SEND_HEXTILES(8)
+DEFINE_SEND_HEXTILES(16)
+DEFINE_SEND_HEXTILES(32)
diff -u -rNp a/hw/vnc/httpd.c b/hw/vnc/httpd.c
--- a/hw/vnc/httpd.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/httpd.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,516 @@
+/*
+ * httpd.c - a simple HTTP server
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <netdb.h>
+
+#ifndef USE_LIBWRAP
+#define USE_LIBWRAP 0
+#endif
+#if USE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include "rfb.h"
+
+#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \
+    "<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \
+    "<BODY><H1>File Not Found</H1></BODY>\n"
+
+#define OK_STR "HTTP/1.0 200 OK\r\n\r\n"
+
+static void httpProcessInput(ScreenPtr pScreen);
+static Bool compareAndSkip(char **ptr, const char *str);
+static Bool parseParams(const char *request, char *result, int max_bytes);
+static Bool validateString(char *str);
+
+/*
+ * httpInitSockets sets up the TCP socket to listen for HTTP connections.
+ */
+
+Bool
+httpInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (!pVNC->httpDir)
+	return FALSE;
+
+    pVNC->buf_filled = 0;
+
+    if (pVNC->httpPort == 0) {
+	pVNC->httpPort = 5800 + atoi(display) + pScreen->myNum;
+    }
+
+    if ((pVNC->httpListenSock = ListenOnTCPPort(pScreen, pVNC->httpPort)) < 0) {
+	rfbLog("ListenOnTCPPort %d failed\n",pVNC->httpPort);
+	pVNC->httpPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for HTTP connections on TCP port %d\n", pVNC->httpPort);
+    rfbLog("  URL http://%s:%d\n",rfbThisHost,pVNC->httpPort);
+
+    AddEnabledDevice(pVNC->httpListenSock);
+
+    return TRUE;
+}
+
+
+/*
+ * httpCheckFds is called from ProcessInputEvents to check for input on the
+ * HTTP socket(s).  If there is input to process, httpProcessInput is called.
+ */
+
+void
+httpCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+
+    if (!pVNC->httpDir)
+	return;
+
+    FD_ZERO(&fds);
+    FD_SET(pVNC->httpListenSock, &fds);
+    if (pVNC->httpSock >= 0) {
+	FD_SET(pVNC->httpSock, &fds);
+    }
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(max(pVNC->httpSock,pVNC->httpListenSock) + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR) 
+		rfbLogPerror("httpCheckFds: select");
+	return;
+    }
+
+    if ((pVNC->httpSock >= 0) && FD_ISSET(pVNC->httpSock, &fds)) {
+	httpProcessInput(pScreen);
+    }
+
+    if (FD_ISSET(pVNC->httpListenSock, &fds)) {
+	int flags;
+
+	if (pVNC->httpSock >= 0) close(pVNC->httpSock);
+
+	if ((pVNC->httpSock = accept(pVNC->httpListenSock,
+			       (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("httpCheckFds: accept");
+	    return;
+	}
+
+#if USE_LIBWRAP
+	if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr),
+		       STRING_UNKNOWN)) {
+	    rfbLog("Rejected HTTP connection from client %s\n",
+		   inet_ntoa(addr.sin_addr));
+  	    close(pVNC->httpSock);
+  	    pVNC->httpSock = -1;
+  	    return;
+  	}
+#endif
+
+	flags = fcntl (pVNC->httpSock, F_GETFL);
+
+	if (flags == -1 ||
+	fcntl (pVNC->httpSock, F_SETFL, flags | O_NONBLOCK) == -1) {
+	    rfbLogPerror("httpCheckFds: fcntl");
+	    close (pVNC->httpSock);
+	    pVNC->httpSock = -1;
+	    return;
+	}
+
+	AddEnabledDevice(pVNC->httpSock);
+    }
+}
+
+
+static void
+httpCloseSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    close(pVNC->httpSock);
+    RemoveEnabledDevice(pVNC->httpSock);
+    pVNC->httpSock = -1;
+    pVNC->buf_filled = 0;
+}
+
+
+/*
+ * httpProcessInput is called when input is received on the HTTP socket.
+ */
+
+static void
+httpProcessInput(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+    char fullFname[512];
+    char params[1024];
+    char *ptr;
+    char *fname;
+    int maxFnameLen;
+    int fd;
+    Bool performSubstitutions = FALSE;
+    char str[256];
+    struct passwd *user = getpwuid(getuid());
+  
+    if (strlen(pVNC->httpDir) > 255) {
+	rfbLog("-httpd directory too long\n");
+  	httpCloseSock(pScreen);
+	return;
+    }
+    strcpy(fullFname, pVNC->httpDir);
+    fname = &fullFname[strlen(fullFname)];
+    maxFnameLen = 511 - strlen(fullFname);
+  
+    /* Read data from the HTTP client until we get a complete request. */
+    while (1) {
+	ssize_t got = read (pVNC->httpSock, pVNC->buf + pVNC->buf_filled,
+			    sizeof (pVNC->buf) - pVNC->buf_filled - 1);
+
+	if (got <= 0) {
+	    if (got == 0) {
+		rfbLog("httpd: premature connection close\n");
+	    } else {
+		if (errno == EAGAIN) {
+		    return;
+		}
+		rfbLogPerror("httpProcessInput: read");
+	    }
+	    httpCloseSock(pScreen);
+  	    return;
+	}
+  
+	pVNC->buf_filled += got;
+	pVNC->buf[pVNC->buf_filled] = '\0';
+  
+	/* Is it complete yet (is there a blank line)? */
+	if (strstr (pVNC->buf, "\r\r") || strstr (pVNC->buf, "\n\n") ||
+	    strstr (pVNC->buf, "\r\n\r\n") || strstr (pVNC->buf, "\n\r\n\r"))
+	    break;
+    }
+  
+    /* Process the request. */
+    if (strncmp(pVNC->buf, "GET ", 4)) {
+	rfbLog("httpd: no GET line\n");
+	httpCloseSock(pScreen);
+	return;
+    } else {
+	/* Only use the first line. */
+	pVNC->buf[strcspn(pVNC->buf, "\n\r")] = '\0';
+    }
+  
+    if (strlen(pVNC->buf) > maxFnameLen) {
+	rfbLog("httpd: GET line too long\n");
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (sscanf(pVNC->buf, "GET %s HTTP/1.0", fname) != 1) {
+	rfbLog("httpd: couldn't parse GET line\n");
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (fname[0] != '/') {
+	rfbLog("httpd: filename didn't begin with '/'\n");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (strchr(fname+1, '/') != NULL) {
+	rfbLog("httpd: asking for file in other directory\n");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    getpeername(pVNC->httpSock, (struct sockaddr *)&addr, &addrlen);
+    rfbLog("httpd: get '%s' for %s\n", fname+1,
+	   inet_ntoa(addr.sin_addr));
+
+    /* Extract parameters from the URL string if necessary */
+
+    params[0] = '\0';
+    ptr = strchr(fname, '?');
+    if (ptr != NULL) {
+	*ptr = '\0';
+	if (!parseParams(&ptr[1], params, 1024)) {
+	    params[0] = '\0';
+	    rfbLog("httpd: bad parameters in the URL\n");
+	}
+    }
+
+    /* If we were asked for '/', actually read the file index.vnc */
+
+    if (strcmp(fname, "/") == 0) {
+	strcpy(fname, "/index.vnc");
+	rfbLog("httpd: defaulting to '%s'\n", fname+1);
+    }
+
+    /* Substitutions are performed on files ending .vnc */
+
+    if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
+	performSubstitutions = TRUE;
+    }
+
+    /* Open the file */
+
+    if ((fd = open(fullFname, O_RDONLY)) < 0) {
+	rfbLogPerror("httpProcessInput: open");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+
+    WriteExact(pVNC->httpSock, OK_STR, strlen(OK_STR));
+
+    while (1) {
+	int n = read(fd, pVNC->buf, HTTP_BUF_SIZE-1);
+	if (n < 0) {
+	    rfbLogPerror("httpProcessInput: read");
+	    close(fd);
+	    httpCloseSock(pScreen);
+	    return;
+	}
+
+	if (n == 0)
+	    break;
+
+	if (performSubstitutions) {
+
+	    /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
+	       This won't quite work properly if the .vnc file is longer than
+	       HTTP_BUF_SIZE, but it's reasonable to assume that .vnc files will
+	       always be short. */
+
+	    char *ptr = pVNC->buf;
+	    char *dollar;
+	    pVNC->buf[n] = 0; /* make sure it's null-terminated */
+
+	    while ((dollar = strchr(ptr, '$'))) {
+		WriteExact(pVNC->httpSock, ptr, (dollar - ptr));
+
+		ptr = dollar;
+
+		if (compareAndSkip(&ptr, "$WIDTH")) {
+
+		    sprintf(str, "%d", pVNC->width);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$HEIGHT")) {
+
+		    sprintf(str, "%d", pVNC->height);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {
+
+		    sprintf(str, "%d", pVNC->width);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {
+
+		    sprintf(str, "%d", pVNC->height + 32);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$PORT")) {
+
+		    sprintf(str, "%d", pVNC->rfbPort);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$DESKTOP")) {
+
+		    WriteExact(pVNC->httpSock, desktopName, strlen(desktopName));
+
+		} else if (compareAndSkip(&ptr, "$DISPLAY")) {
+
+		    sprintf(str, "%s:%s", rfbThisHost, display);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$USER")) {
+
+		    if (user) {
+			WriteExact(pVNC->httpSock, user->pw_name,
+				   strlen(user->pw_name));
+		    } else {
+			WriteExact(pVNC->httpSock, "?", 1);
+		    }
+
+		} else if (compareAndSkip(&ptr, "$PARAMS")) {
+
+		    if (params[0] != '\0')
+			WriteExact(pVNC->httpSock, params, strlen(params));
+
+		} else {
+		    if (!compareAndSkip(&ptr, "$$"))
+			ptr++;
+
+		    if (WriteExact(pVNC->httpSock, "$", 1) < 0) {
+			close(fd);
+			httpCloseSock(pScreen);
+			return;
+		    }
+		}
+	    }
+	    if (WriteExact(pVNC->httpSock, ptr, (&pVNC->buf[n] - ptr)) < 0)
+		break;
+
+	} else {
+
+	    /* For files not ending .vnc, just write out the buffer */
+
+	    if (WriteExact(pVNC->httpSock, pVNC->buf, n) < 0)
+		break;
+	}
+    }
+
+    close(fd);
+    httpCloseSock(pScreen);
+}
+
+
+static Bool
+compareAndSkip(char **ptr, const char *str)
+{
+    if (strncmp(*ptr, str, strlen(str)) == 0) {
+	*ptr += strlen(str);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * Parse the request tail after the '?' character, and format a sequence
+ * of <param> tags for inclusion into an HTML page with embedded applet.
+ */
+
+static Bool
+parseParams(const char *request, char *result, int max_bytes)
+{
+    char param_request[128];
+    char param_formatted[196];
+    const char *tail;
+    char *delim_ptr;
+    char *value_str;
+    int cur_bytes, len;
+
+    result[0] = '\0';
+    cur_bytes = 0;
+
+    tail = request;
+    for (;;) {
+	/* Copy individual "name=value" string into a buffer */
+	delim_ptr = strchr((char *)tail, '&');
+	if (delim_ptr == NULL) {
+	    if (strlen(tail) >= sizeof(param_request)) {
+		return FALSE;
+	    }
+	    strcpy(param_request, tail);
+	} else {
+	    len = delim_ptr - tail;
+	    if (len >= sizeof(param_request)) {
+		return FALSE;
+	    }
+	    memcpy(param_request, tail, len);
+	    param_request[len] = '\0';
+	}
+
+	/* Split the request into parameter name and value */
+	value_str = strchr(&param_request[1], '=');
+	if (value_str == NULL) {
+	    return FALSE;
+	}
+	*value_str++ = '\0';
+	if (strlen(value_str) == 0) {
+	    return FALSE;
+	}
+
+	/* Validate both parameter name and value */
+	if (!validateString(param_request) || !validateString(value_str)) {
+	    return FALSE;
+	}
+
+	/* Prepare HTML-formatted representation of the name=value pair */
+	len = sprintf(param_formatted,
+		      "<PARAM NAME=\"%s\" VALUE=\"%s\">\n",
+		      param_request, value_str);
+	if (cur_bytes + len + 1 > max_bytes) {
+	    return FALSE;
+	}
+	strcat(result, param_formatted);
+	cur_bytes += len;
+
+	/* Go to the next parameter */
+	if (delim_ptr == NULL) {
+	    break;
+	}
+	tail = delim_ptr + 1;
+    }
+    return TRUE;
+}
+
+/*
+ * Check if the string consists only of alphanumeric characters, '+'
+ * signs, underscores, and dots. Replace all '+' signs with spaces.
+ */
+
+static Bool
+validateString(char *str)
+{
+    char *ptr;
+
+    for (ptr = str; *ptr != '\0'; ptr++) {
+	if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.') {
+	    if (*ptr == '+') {
+		*ptr = ' ';
+	    } else {
+		return FALSE;
+	    }
+	}
+    }
+    return TRUE;
+}
+
diff -u -rNp a/hw/vnc/init.c b/hw/vnc/init.c
--- a/hw/vnc/init.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/init.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1066 @@
+/*
+ * init.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1993  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+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 X CONSORTIUM 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 X Consortium 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 X Consortium.
+
+*/
+
+/* Use ``#define CORBA'' to enable CORBA control interface */
+
+/* XXX this definition should probably go elsewhere */
+#ifndef XVNCRELEASE
+#define XVNCRELEASE "X.org/xf4vnc custom version"
+#endif
+
+#include "rfb.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "X11/X.h"
+#define NEED_EVENTS
+#include "X11/Xproto.h"
+#include "X11/Xos.h"
+#include <X11/Xatom.h>
+#include "scrnintstr.h"
+#include "servermd.h"
+#include "fb.h"
+#include "mfb.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "dixstruct.h"
+#include <errno.h>
+#include <sys/param.h>
+#include "dix.h"
+#include "micmap.h"
+
+#ifdef CORBA
+#include <vncserverctrl.h>
+#endif
+
+#define RFB_DEFAULT_WIDTH  640
+#define RFB_DEFAULT_HEIGHT 480
+#define RFB_DEFAULT_DEPTH  8
+#define RFB_DEFAULT_WHITEPIXEL 0
+#define RFB_DEFAULT_BLACKPIXEL 1
+
+static unsigned long VNCGeneration = 0;
+rfbScreenInfo rfbScreen;
+int rfbGCIndex;
+extern char dispatchExceptionAtReset;
+
+extern void VncExtensionInit(void);
+extern Bool rfbDCInitialize(ScreenPtr, miPointerScreenFuncPtr);
+
+static Bool initOutputCalled = FALSE;
+static Bool noCursor = FALSE;
+char *desktopName = "x11";
+
+char rfbThisHost[256];
+
+Atom VNC_LAST_CLIENT_ID;
+Atom VNC_CONNECT;
+
+static HWEventQueueType alwaysCheckForInput[2] = { 0, 1 };
+static HWEventQueueType *mieqCheckForInput[2];
+
+static char primaryOrder[4] = "";
+static int redBits, greenBits, blueBits;
+
+static Bool rfbScreenInit(int index, ScreenPtr pScreen, int argc,
+			  char **argv);
+static int rfbKeybdProc(DeviceIntPtr pDevice, int onoff);
+static int rfbMouseProc(DeviceIntPtr pDevice, int onoff);
+static Bool CheckDisplayNumber(int n);
+
+static Bool rfbAlwaysTrue(void);
+static unsigned char *rfbAllocateFramebufferMemory(rfbScreenInfoPtr prfb);
+static Bool rfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y);
+static void rfbCrossScreen(ScreenPtr pScreen, Bool entering);
+
+static miPointerScreenFuncRec rfbPointerCursorFuncs = {
+    rfbCursorOffScreen,
+    rfbCrossScreen,
+    miPointerWarpCursor
+};
+
+
+int inetdSock = -1;
+static char inetdDisplayNumStr[10];
+
+/*
+ * ddxProcessArgument is our first entry point and will be called at the
+ * very start for each argument.  It is not called again on server reset.
+ */
+
+int
+ddxProcessArgument (argc, argv, i)
+    int argc;
+    char *argv[];
+    int i;
+{
+    ScreenPtr pScreen = screenInfo.screens[i];
+    VNCSCREENPTR(pScreen);
+    static Bool firstTime = TRUE;
+
+    if (firstTime)
+    {
+	pVNC->width  = RFB_DEFAULT_WIDTH;
+	pVNC->height = RFB_DEFAULT_HEIGHT;
+	pVNC->depth  = RFB_DEFAULT_DEPTH;
+	pVNC->blackPixel = RFB_DEFAULT_BLACKPIXEL;
+	pVNC->whitePixel = RFB_DEFAULT_WHITEPIXEL;
+	pVNC->pfbMemory = NULL;
+    	pVNC->httpPort = 0;
+    	pVNC->httpDir = NULL;
+        pVNC->rfbAuthPasswdFile = NULL;
+        pVNC->udpPort = 0;
+    	pVNC->rfbPort = 0;
+    	pVNC->rdpPort = 3389;
+	noCursor = FALSE;
+  	pVNC->loginAuthEnabled = FALSE;
+	pVNC->rfbAlwaysShared = FALSE;
+	pVNC->rfbNeverShared = FALSE;
+	pVNC->rfbDontDisconnect = FALSE;
+	pVNC->rfbViewOnly = FALSE;
+	pVNC->useGetImage = FALSE;
+
+	gethostname(rfbThisHost, 255);
+	pVNC->interface.s_addr = htonl (INADDR_ANY);
+	firstTime = FALSE;
+    }
+
+    if (strcmp (argv[i], "-geometry") == 0)	/* -geometry WxH */
+    {
+	if (i + 1 >= argc) UseMsg();
+	if (sscanf(argv[i+1],"%dx%d",
+		   &pVNC->width,&pVNC->height) != 2) {
+	    ErrorF("Invalid geometry %s\n", argv[i+1]);
+	    UseMsg();
+	}
+#ifdef CORBA
+	screenWidth= pVNC->width;
+	screenHeight= pVNC->height;
+#endif
+	return 2;
+    }
+
+    if (strcmp (argv[i], "-depth") == 0)	/* -depth D */
+    {
+	if (i + 1 >= argc) UseMsg();
+	pVNC->depth = atoi(argv[i+1]);
+#ifdef CORBA
+	screenDepth= pVNC->depth;
+#endif
+	return 2;
+    }
+
+    if (strcmp (argv[i], "-pixelformat") == 0) {
+	if (i + 1 >= argc) UseMsg();
+	if (sscanf(argv[i+1], "%3s", primaryOrder) < 1) {
+	    ErrorF("Invalid pixel format %s\n", argv[i+1]);
+	    UseMsg();
+	}
+
+	return 2;
+    }
+
+    if (strcmp (argv[i], "-blackpixel") == 0) {	/* -blackpixel n */
+	if (i + 1 >= argc) UseMsg();
+	pVNC->blackPixel = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp (argv[i], "-whitepixel") == 0) {	/* -whitepixel n */
+	if (i + 1 >= argc) UseMsg();
+	pVNC->whitePixel = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp (argv[i], "-usegetimage") == 0) {
+	pVNC->useGetImage = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-udpinputport") == 0) { /* -udpinputport port */
+	if (i + 1 >= argc) UseMsg();
+	pVNC->udpPort = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-rfbport") == 0) {	/* -rfbport port */
+	if (i + 1 >= argc) UseMsg();
+	pVNC->rfbPort = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-rfbwait") == 0) {	/* -rfbwait ms */
+	if (i + 1 >= argc) UseMsg();
+	rfbMaxClientWait = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-nocursor") == 0) {
+	noCursor = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-rfbauth") == 0) {	/* -rfbauth passwd-file */
+	if (i + 1 >= argc) UseMsg();
+	pVNC->rfbAuthPasswdFile = argv[i+1];
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-loginauth") == 0) {
+	if (geteuid() == 0) {
+	    /* Only when run as root! */
+	    pVNC->loginAuthEnabled = TRUE;
+	}
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-httpd") == 0) {
+	if (i + 1 >= argc) UseMsg();
+	pVNC->httpDir = argv[i+1];
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-httpport") == 0) {
+	if (i + 1 >= argc) UseMsg();
+	pVNC->httpPort = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-deferupdate") == 0) {	/* -deferupdate ms */
+	if (i + 1 >= argc) UseMsg();
+	rfbDeferUpdateTime = atoi(argv[i+1]);
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-economictranslate") == 0) {
+	rfbEconomicTranslate = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-lazytight") == 0) {
+	rfbTightDisableGradient = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-desktop") == 0) {	/* -desktop desktop-name */
+	if (i + 1 >= argc) UseMsg();
+	desktopName = argv[i+1];
+	return 2;
+    }
+
+#if 0 /* not deemed useful on standalone server - leave for completeness */
+    if (strcmp(argv[i], "-useraccept") == 0) {
+	pVNC->rfbUserAccept = TRUE;
+	return 1;
+    }
+#endif
+
+    if (strcmp(argv[i], "-alwaysshared") == 0) {
+	pVNC->rfbAlwaysShared = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-nevershared") == 0) {
+	pVNC->rfbNeverShared = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-dontdisconnect") == 0) {
+	pVNC->rfbDontDisconnect = TRUE;
+	return 1;
+    }
+
+    /* Run server in view-only mode - Ehud Karni SW */
+    if (strcmp(argv[i], "-viewonly") == 0) {
+	pVNC->rfbViewOnly = TRUE;
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-localhost") == 0) {
+	pVNC->interface.s_addr = htonl (INADDR_LOOPBACK);
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-interface") == 0) {	/* -interface ipaddr */
+	struct in_addr got;
+	unsigned long octet;
+	char *p, *end;
+	int q;
+	if (i + 1 >= argc) {
+	    UseMsg();
+	    return 2;
+	}
+	if (pVNC->interface.s_addr != htonl (INADDR_ANY)) {
+	    /* Already set (-localhost?). */
+	    return 2;
+	}
+	p = argv[i + 1];
+	for (q = 0; q < 4; q++) {
+	    octet = strtoul (p, &end, 10);
+	    if (p == end || octet > 255) {
+		UseMsg ();
+		return 2;
+	    }
+	    if ((q < 3 && *end != '.') ||
+	        (q == 3 && *end != '\0')) {
+		UseMsg ();
+		return 2;
+	    }
+	    got.s_addr = (got.s_addr << 8) | octet;
+	    p = end + 1;
+	}
+	pVNC->interface.s_addr = htonl (got.s_addr);
+	return 2;
+    }
+
+    if (strcmp(argv[i], "-inetd") == 0) {	/* -inetd */ 
+	int n;
+	for (n = 1; n < 100; n++) {
+	    if (CheckDisplayNumber(n))
+		break;
+	}
+
+	if (n >= 100)
+	    FatalError("-inetd: couldn't find free display number");
+
+	sprintf(inetdDisplayNumStr, "%d", n);
+	display = inetdDisplayNumStr;
+
+	/* fds 0, 1 and 2 (stdin, out and err) are all the same socket to the
+           RFB client.  OsInit() closes stdout and stdin, and we don't want
+           stderr to go to the RFB client, so make the client socket 3 and
+           close stderr.  OsInit() will redirect stderr logging to an
+           appropriate log file or /dev/null if that doesn't work. */
+
+	dup2(0,3);
+	inetdSock = 3;
+	close(2);
+
+	return 1;
+    }
+
+    if (strcmp(argv[i], "-version") == 0) {
+	ErrorF("Xvnc version %s\n", XVNCRELEASE);
+	exit(0);
+    }
+
+    if (inetdSock != -1 && argv[i][0] == ':') {
+	FatalError("can't specify both -inetd and :displaynumber");
+    }
+
+    return 0;
+}
+
+
+/*
+ * InitOutput is called every time the server resets.  It should call
+ * AddScreen for each screen (FIXME - but we only ever have one), 
+ * and in turn this will call rfbScreenInit.
+ */
+
+/* Common pixmap formats */
+
+static PixmapFormatRec formats[MAXFORMATS] = {
+	{ 1,	1,	BITMAP_SCANLINE_PAD },
+	{ 4,	8,	BITMAP_SCANLINE_PAD },
+	{ 8,	8,	BITMAP_SCANLINE_PAD },
+	{ 15,	16,	BITMAP_SCANLINE_PAD },
+	{ 16,	16,	BITMAP_SCANLINE_PAD },
+	{ 24,	32,	BITMAP_SCANLINE_PAD },
+#ifdef RENDER
+	{ 32,	32,	BITMAP_SCANLINE_PAD },
+#endif
+};
+#ifdef RENDER
+static int numFormats = 7;
+#else
+static int numFormats = 6;
+#endif
+
+void
+InitOutput(screenInfo, argc, argv)
+    ScreenInfo *screenInfo;
+    int argc;
+    char **argv;
+{
+    int i;
+    initOutputCalled = TRUE;
+
+    rfbLog("Xvnc version %s\n", XVNCRELEASE);
+    rfbLog("Copyright (C) 2001-2004 Alan Hourihane.\n");
+    rfbLog("Copyright (C) 2000-2004 Constantin Kaplinsky\n");
+    rfbLog("Copyright (C) 1999 AT&T Laboratories Cambridge\n");
+    rfbLog("All Rights Reserved.\n");
+    rfbLog("See http://www.tightvnc.com/ for information on TightVNC\n");
+    rfbLog("See http://xf4vnc.sf.net for xf4vnc-specific information\n");
+    rfbLog("Desktop name '%s' (%s:%s)\n",desktopName,rfbThisHost,display);
+    rfbLog("Protocol versions supported: %d.%d, %d.%d\n",
+	   rfbProtocolMajorVersion, rfbProtocolMinorVersion,
+	   rfbProtocolMajorVersion, rfbProtocolFallbackMinorVersion);
+
+    VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID",
+				  strlen("VNC_LAST_CLIENT_ID"), TRUE);
+    VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE);
+
+    /* initialize pixmap formats */
+
+    screenInfo->imageByteOrder = IMAGE_BYTE_ORDER;
+    screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
+    screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
+    screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER;
+    screenInfo->numPixmapFormats = numFormats;
+    for (i = 0; i < numFormats; i++)
+    	screenInfo->formats[i] = formats[i];
+
+    rfbGCIndex = AllocateGCPrivateIndex();
+    if (rfbGCIndex < 0) {
+	FatalError("InitOutput: AllocateGCPrivateIndex failed\n");
+    }
+
+    /* initialize screen */
+
+    if (AddScreen(rfbScreenInit, argc, argv) == -1) {
+	FatalError("Couldn't add screen");
+    }
+
+#ifdef CORBA
+    initialiseCORBA(argc, argv, desktopName);
+#endif
+}
+
+static void
+rfbWakeupHandler (
+    int 	i,	
+    pointer     blockData,
+    unsigned long err,
+    pointer     pReadmask
+){
+    ScreenPtr      pScreen = screenInfo.screens[i];
+    VNCSCREENPTR(pScreen);
+    int e = (int)err;
+
+    if (e < 0)
+	goto SKIPME;
+	
+    rfbRootPropertyChange(pScreen);
+
+#if XFREE86VNC
+    if (pScrn->vtSema) {
+    	rfbCheckFds(pScreen);
+    	httpCheckFds(pScreen);
+#if 0
+	rdpCheckFds(pScreen);
+#endif
+#ifdef CORBA
+    	corbaCheckFds();
+#endif
+    } else {
+    	rfbCheckFds(pScreen);
+#if 0
+	rdpCheckFds(pScreen);
+#endif
+    }
+#else
+    rfbCheckFds(pScreen);
+    httpCheckFds(pScreen);
+#if 0
+    rdpCheckFds(pScreen);
+#endif
+#ifdef CORBA
+    corbaCheckFds();
+#endif
+#endif
+
+SKIPME:
+
+    pScreen->WakeupHandler = pVNC->WakeupHandler;
+    (*pScreen->WakeupHandler) (i, blockData, err, pReadmask);
+    pScreen->WakeupHandler = rfbWakeupHandler;
+}
+
+static Bool
+rfbScreenInit(index, pScreen, argc, argv)
+    int index;
+    ScreenPtr pScreen;
+    int argc;
+    char ** argv;
+{
+    rfbScreenInfoPtr prfb = &rfbScreen;
+    int dpix = 75, dpiy = 75;
+    int ret;
+    unsigned char *pbits;
+    VisualPtr vis;
+#ifdef RENDER
+    PictureScreenPtr	ps;
+#endif
+
+    if (VNCGeneration != serverGeneration) {
+	VncExtensionInit();
+	VNCGeneration = serverGeneration;
+    }
+
+    if (monitorResolution != 0) {
+	dpix = monitorResolution;
+	dpiy = monitorResolution;
+    }
+
+    prfb->rfbAuthTries = 0;
+    prfb->rfbAuthTooManyTries = FALSE;
+    prfb->rfbUserAccept = FALSE;
+    prfb->udpSockConnected = FALSE;
+    prfb->timer = NULL;
+    prfb->httpListenSock = -1;
+    prfb->httpSock = -1;
+    prfb->rfbListenSock = -1;
+    prfb->rdpListenSock = -1;
+    prfb->paddedWidthInBytes = PixmapBytePad(prfb->width, prfb->depth);
+    prfb->bitsPerPixel = rfbBitsPerPixel(prfb->depth);
+    pbits = rfbAllocateFramebufferMemory(prfb);
+    if (!pbits) return FALSE;
+
+    miClearVisualTypes();
+
+    if (defaultColorVisualClass == -1)
+    	defaultColorVisualClass = TrueColor;
+
+    if (!miSetVisualTypes(prfb->depth, miGetDefaultVisualMask(prfb->depth), 8,
+						defaultColorVisualClass) )
+	return FALSE;
+
+    miSetPixmapDepths();
+
+    switch (prfb->bitsPerPixel)
+    {
+    case 1:
+	ret = mfbScreenInit(pScreen, pbits, prfb->width, prfb->height,
+			    dpix, dpiy, prfb->paddedWidthInBytes * 8);
+	break;
+    case 8:
+	ret = fbScreenInit(pScreen, pbits, prfb->width, prfb->height,
+			    dpix, dpiy, prfb->paddedWidthInBytes, 8);
+	break;
+    case 16:
+	ret = fbScreenInit(pScreen, pbits, prfb->width, prfb->height,
+			      dpix, dpiy, prfb->paddedWidthInBytes / 2, 16);
+	if (prfb->depth == 15) {
+  	    blueBits = 5; greenBits = 5; redBits = 5;
+	} else {
+	    blueBits = 5; greenBits = 6; redBits = 5;
+	}
+	break;
+    case 32:
+	ret = fbScreenInit(pScreen, pbits, prfb->width, prfb->height,
+			      dpix, dpiy, prfb->paddedWidthInBytes / 4, 32);
+	blueBits = 8; greenBits = 8; redBits = 8;
+	break;
+    default:
+	return FALSE;
+    }
+
+    if (!ret) return FALSE;
+
+    miInitializeBackingStore(pScreen);
+
+    if (prfb->bitsPerPixel > 8) {
+    	if (strcasecmp(primaryOrder, "bgr") == 0) {
+	    rfbLog("BGR format %d %d %d\n", blueBits, greenBits, redBits);
+            vis = pScreen->visuals + pScreen->numVisuals;
+            while (--vis >= pScreen->visuals) {
+	    	if ((vis->class | DynamicClass) == DirectColor) {
+		    vis->offsetRed = 0;
+		    vis->redMask = (1 << redBits) - 1;
+		    vis->offsetGreen = redBits;
+		    vis->greenMask = ((1 << greenBits) - 1) << vis->offsetGreen;
+		    vis->offsetBlue = redBits + greenBits;
+		    vis->blueMask = ((1 << blueBits) - 1) << vis->offsetBlue;
+	    	}
+	    }
+    	} else {
+	    rfbLog("RGB format %d %d %d\n", blueBits, greenBits, redBits);
+       	    vis = pScreen->visuals + pScreen->numVisuals;
+            while (--vis >= pScreen->visuals) {
+	    	if ((vis->class | DynamicClass) == DirectColor) {
+		    vis->offsetBlue = 0;
+		    vis->blueMask = (1 << blueBits) - 1;
+		    vis->offsetGreen = blueBits;
+		    vis->greenMask = ((1 << greenBits) - 1) << vis->offsetGreen;
+		    vis->offsetRed = blueBits + greenBits;
+		    vis->redMask = ((1 << redBits) - 1) << vis->offsetRed;
+	    	}
+	    }
+    	}
+    }
+
+    if (prfb->bitsPerPixel > 4)
+	fbPictureInit(pScreen, 0, 0);
+
+    if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec))) {
+	FatalError("rfbScreenInit: AllocateGCPrivate failed\n");
+    }
+
+    prfb->cursorIsDrawn = FALSE;
+    prfb->dontSendFramebufferUpdate = FALSE;
+
+    prfb->CloseScreen = pScreen->CloseScreen;
+    prfb->WakeupHandler = pScreen->WakeupHandler;
+    prfb->CreateGC = pScreen->CreateGC;
+    prfb->PaintWindowBackground = pScreen->PaintWindowBackground;
+    prfb->PaintWindowBorder = pScreen->PaintWindowBorder;
+    prfb->CopyWindow = pScreen->CopyWindow;
+    prfb->ClearToBackground = pScreen->ClearToBackground;
+    prfb->RestoreAreas = pScreen->RestoreAreas;
+#ifdef CHROMIUM
+    prfb->RealizeWindow = pScreen->RealizeWindow;
+    prfb->UnrealizeWindow = pScreen->UnrealizeWindow;
+    prfb->DestroyWindow = pScreen->DestroyWindow;
+    prfb->PositionWindow = pScreen->PositionWindow;
+    prfb->ResizeWindow = pScreen->ResizeWindow;
+    prfb->ClipNotify = pScreen->ClipNotify;
+#endif
+#ifdef RENDER
+    ps = GetPictureScreenIfSet(pScreen);
+    if (ps)
+    	prfb->Composite = ps->Composite;
+#endif
+    pScreen->CloseScreen = rfbCloseScreen;
+    pScreen->WakeupHandler = rfbWakeupHandler;
+    pScreen->CreateGC = rfbCreateGC;
+    pScreen->PaintWindowBackground = rfbPaintWindowBackground;
+    pScreen->PaintWindowBorder = rfbPaintWindowBorder;
+    pScreen->CopyWindow = rfbCopyWindow;
+    pScreen->ClearToBackground = rfbClearToBackground;
+    pScreen->RestoreAreas = rfbRestoreAreas;
+#ifdef CHROMIUM
+    pScreen->RealizeWindow = rfbRealizeWindow;
+    pScreen->UnrealizeWindow = rfbUnrealizeWindow;
+    pScreen->DestroyWindow = rfbDestroyWindow;
+    pScreen->PositionWindow = rfbPositionWindow;
+    pScreen->ResizeWindow = rfbResizeWindow;
+    pScreen->ClipNotify = rfbClipNotify;
+#endif
+#ifdef RENDER
+    if (ps)
+    	ps->Composite = rfbComposite;
+#endif
+
+    pScreen->InstallColormap = rfbInstallColormap;
+    pScreen->UninstallColormap = rfbUninstallColormap;
+    pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
+    pScreen->StoreColors = rfbStoreColors;
+
+    pScreen->SaveScreen = rfbAlwaysTrue;
+
+    rfbDCInitialize(pScreen, &rfbPointerCursorFuncs);
+
+    if (noCursor) {
+	pScreen->DisplayCursor = rfbAlwaysTrue;
+	prfb->cursorIsDrawn = TRUE;
+    }
+
+    pScreen->blackPixel = prfb->blackPixel;
+    pScreen->whitePixel = prfb->whitePixel;
+
+    prfb->rfbServerFormat.bitsPerPixel = prfb->bitsPerPixel;
+    prfb->rfbServerFormat.depth = prfb->depth;
+    prfb->rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest);
+
+    /* Find the root visual and set the server format */
+    for (vis = pScreen->visuals; vis->vid != pScreen->rootVisual; vis++)
+	;
+    prfb->rfbServerFormat.trueColour = (vis->class == TrueColor);
+
+    if ( (vis->class == TrueColor) || (vis->class == DirectColor) ) {
+	prfb->rfbServerFormat.redMax = vis->redMask >> vis->offsetRed;
+	prfb->rfbServerFormat.greenMax = vis->greenMask >> vis->offsetGreen;
+	prfb->rfbServerFormat.blueMax = vis->blueMask >> vis->offsetBlue;
+	prfb->rfbServerFormat.redShift = vis->offsetRed;
+	prfb->rfbServerFormat.greenShift = vis->offsetGreen;
+	prfb->rfbServerFormat.blueShift = vis->offsetBlue;
+    } else {
+	prfb->rfbServerFormat.redMax
+	    = prfb->rfbServerFormat.greenMax 
+	    = prfb->rfbServerFormat.blueMax = 0;
+	prfb->rfbServerFormat.redShift
+	    = prfb->rfbServerFormat.greenShift 
+	    = prfb->rfbServerFormat.blueShift = 0;
+    }
+
+    if (prfb->bitsPerPixel == 1)
+    {
+	ret = mfbCreateDefColormap(pScreen);
+    }
+    else
+    {
+	ret = fbCreateDefColormap(pScreen);
+    }
+
+    rfbInitSockets(pScreen);
+#if 0
+    rdpInitSockets(pScreen);
+#endif
+    if (inetdSock == -1)
+	httpInitSockets(pScreen);
+
+    return ret;
+
+} /* end rfbScreenInit */
+
+
+
+/*
+ * InitInput is also called every time the server resets.  It is called after
+ * InitOutput so we can assume that rfbInitSockets has already been called.
+ */
+
+void
+InitInput(argc, argv)
+    int argc;
+    char *argv[];
+{
+    DeviceIntPtr p, k;
+    k = AddInputDevice(rfbKeybdProc, TRUE);
+    p = AddInputDevice(rfbMouseProc, TRUE);
+    RegisterKeyboardDevice(k);
+    RegisterPointerDevice(p);
+    miRegisterPointerDevice(screenInfo.screens[0], p);
+    (void)mieqInit ((DevicePtr)k, (DevicePtr)p);
+#if 0
+    mieqCheckForInput[0] = checkForInput[0];
+    mieqCheckForInput[1] = checkForInput[1];
+    SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]);
+#endif
+}
+
+
+static int
+rfbKeybdProc(pDevice, onoff)
+    DeviceIntPtr pDevice;
+    int onoff;
+{
+    KeySymsRec		keySyms;
+    CARD8 		modMap[MAP_LENGTH];
+    DevicePtr pDev = (DevicePtr)pDevice;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT: 
+	KbdDeviceInit(pDevice, &keySyms, modMap);
+	InitKeyboardDeviceStruct(pDev, &keySyms, modMap,
+				 (BellProcPtr)rfbSendBell,
+				 (KbdCtrlProcPtr)NoopDDA);
+	    break;
+    case DEVICE_ON: 
+	pDev->on = TRUE;
+	KbdDeviceOn();
+	break;
+    case DEVICE_OFF: 
+	pDev->on = FALSE;
+	KbdDeviceOff();
+	break;
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    KbdDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static int
+rfbMouseProc(pDevice, onoff)
+    DeviceIntPtr pDevice;
+    int onoff;
+{
+    BYTE map[6];
+    DevicePtr pDev = (DevicePtr)pDevice;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT:
+	PtrDeviceInit();
+	map[1] = 1;
+	map[2] = 2;
+	map[3] = 3;
+	map[4] = 4;
+	map[5] = 5;
+	InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents,
+				PtrDeviceControl,
+				miPointerGetMotionBufferSize());
+	break;
+
+    case DEVICE_ON:
+	pDev->on = TRUE;
+	PtrDeviceOn(pDevice);
+        break;
+
+    case DEVICE_OFF:
+	pDev->on = FALSE;
+	PtrDeviceOff();
+	break;
+
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    PtrDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+
+Bool
+LegalModifier(key, pDev)
+    unsigned int key;
+    DevicePtr	pDev;
+{
+    return TRUE;
+}
+
+
+void
+ProcessInputEvents()
+{
+#if 0
+    if (*mieqCheckForInput[0] != *mieqCheckForInput[1]) {
+#endif
+	mieqProcessInputEvents();
+	miPointerUpdate();
+#if 0
+    }
+#endif
+}
+
+
+static Bool CheckDisplayNumber(int n)
+{
+    char fname[32];
+    int sock;
+    struct sockaddr_in addr;
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin_port = htons(6000+n);
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	close(sock);
+	return FALSE;
+    }
+    close(sock);
+
+    sprintf(fname, "/tmp/.X%d-lock", n);
+    if (access(fname, F_OK) == 0)
+	return FALSE;
+
+    sprintf(fname, "/tmp/.X11-unix/X%d", n);
+    if (access(fname, F_OK) == 0)
+	return FALSE;
+
+    return TRUE;
+}
+
+static Bool
+rfbAlwaysTrue(void)
+{
+    return TRUE;
+}
+
+
+static unsigned char *
+rfbAllocateFramebufferMemory(prfb)
+    rfbScreenInfoPtr prfb;
+{
+    if (prfb->pfbMemory) return prfb->pfbMemory; /* already done */
+
+    prfb->sizeInBytes = (prfb->paddedWidthInBytes * prfb->height);
+
+    prfb->pfbMemory = (unsigned char *)Xalloc(prfb->sizeInBytes);
+
+    return prfb->pfbMemory;
+}
+
+
+static Bool
+rfbCursorOffScreen (ppScreen, x, y)
+    ScreenPtr   *ppScreen;
+    int         *x, *y;
+{
+    return FALSE;
+}
+
+static void
+rfbCrossScreen (pScreen, entering)
+    ScreenPtr   pScreen;
+    Bool        entering;
+{
+}
+
+void
+ddxGiveUp()
+{
+    Xfree(rfbScreen.pfbMemory);
+    if (initOutputCalled) {
+	char unixSocketName[32];
+	sprintf(unixSocketName,"/tmp/.X11-unix/X%s",display);
+	unlink(unixSocketName);
+#ifdef CORBA
+	shutdownCORBA();
+#endif
+    }
+}
+
+void
+AbortDDX()
+{
+    ddxGiveUp();
+}
+
+void
+OsVendorInit()
+{
+}
+
+void
+OsVendorFatalError()
+{
+}
+
+#ifdef DDXTIME /* from ServerOSDefines */
+CARD32
+GetTimeInMillis()
+{
+    struct timeval  tp;
+
+    X_GETTIMEOFDAY(&tp);
+    return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+#endif
+
+void
+ddxUseMsg()
+{
+    ErrorF("-geometry WxH          set framebuffer width & height\n");
+    ErrorF("-depth D               set framebuffer depth\n");
+    ErrorF("-pixelformat format    set pixel format (BGRnnn or RGBnnn)\n");
+    ErrorF("-udpinputport port     UDP port for keyboard/pointer data\n");
+    ErrorF("-rfbport port          TCP port for RFB protocol\n");
+    ErrorF("-rfbwait time          max time in ms to wait for RFB client\n");
+    ErrorF("-nocursor              don't put up a cursor\n");
+    ErrorF("-rfbauth passwd-file   use authentication on RFB protocol\n");
+    ErrorF("-loginauth             use login-style Unix authentication\n");
+    ErrorF("-httpd dir             serve files via HTTP from here\n");
+    ErrorF("-httpport port         port for HTTP\n");
+    ErrorF("-deferupdate time      time in ms to defer updates "
+							     "(default 40)\n");
+    ErrorF("-economictranslate     less memory-hungry translation\n");
+    ErrorF("-lazytight             disable \"gradient\" filter in tight "
+								"encoding\n");
+    ErrorF("-desktop name          VNC desktop name (default x11)\n");
+    ErrorF("-alwaysshared          always treat new clients as shared\n");
+    ErrorF("-nevershared           never treat new clients as shared\n");
+    ErrorF("-dontdisconnect        don't disconnect existing clients when a "
+                                                             "new non-shared\n"
+	   "                       connection comes in (refuse new connection "
+								 "instead)\n");
+    ErrorF("-localhost             only allow connections from localhost\n"
+	   "			   to the vnc ports. Use -nolisten tcp to disable\n"
+	   "			   remote X clients as well.\n");
+    ErrorF("-viewonly              let clients only view the desktop\n");
+    ErrorF("-interface ipaddr      only bind to specified interface "
+								"address\n");
+    ErrorF("-inetd                 Xvnc is launched by inetd\n");
+    exit(1);
+}
+
+
+void ddxInitGlobals(void)
+{
+   /* dummy function called by InitGlobals in os/utils.c */
+}
+
+
+/*
+ * rfbLog prints a time-stamped message to the log file (stderr).
+ */
+void rfbLog(char *format, ...)
+{
+    va_list args;
+    char buf[256];
+    time_t clock;
+
+    va_start(args, format);
+
+    time(&clock);
+    strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock));
+    fprintf(stderr, buf);
+
+    vfprintf(stderr, format, args);
+    fflush(stderr);
+
+    va_end(args);
+}
+
+void rfbLogPerror(char *str)
+{
+    rfbLog("");
+    perror(str);
+}
diff -u -rNp a/hw/vnc/kbdptr.c b/hw/vnc/kbdptr.c
--- a/hw/vnc/kbdptr.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/kbdptr.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,425 @@
+/*
+ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include "rfb.h"
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#include "inputstr.h"
+#define XK_CYRILLIC
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include "mi.h"
+#include "mipointer.h"
+
+#if XFREE86VNC
+#ifdef XINPUT
+#include "xf86Xinput.h"
+#define Enqueue(ev) xf86eqEnqueue(ev)
+#else
+#define Enqueue(ev) mieqEnqueue(ev)
+#endif
+#else
+#define Enqueue(ev) mieqEnqueue(ev)
+#endif
+
+#define KEY_IS_PRESSED(keycode) \
+    (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
+
+static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper);
+
+DeviceIntPtr kbdDevice;
+
+#include "keyboard.h"
+
+/*
+ * Called when the rfbserver receives a rfbKeyEvent event from a client.
+ * Put an X keyboard event into the event queue.
+ */
+void
+KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl)
+{
+    xEvent ev, fake;
+    KeySymsPtr keySyms;
+    int i;
+    int keyCode = 0;
+    int freeIndex = -1;
+    unsigned long time;
+    Bool fakeShiftPress = FALSE;
+    Bool fakeShiftLRelease = FALSE;
+    Bool fakeShiftRRelease = FALSE;
+    Bool shiftMustBeReleased = FALSE;
+    Bool shiftMustBePressed = FALSE;
+
+    if (!kbdDevice) return;
+
+    keySyms = &kbdDevice->key->curKeySyms;
+
+#ifdef CORBA
+    if (cl) {
+	CARD32 clientId = cl->sock;
+	ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+			     32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+#endif
+
+    if (down) {
+	ev.u.u.type = KeyPress;
+    } else {
+	ev.u.u.type = KeyRelease;
+    }
+
+    /* NOTE: This is where it gets hairy for XFree86 servers.
+     * I think the best way to deal with this is invent a new protocol
+     * to send over the wire the remote keyboard type and correctly
+     * handle that as XINPUT extension device (we're part of the way
+     * there for that.
+     *
+     * Alan.
+     */
+#if !XFREE86VNC
+    /* First check if it's one of our predefined keys.  If so then we can make
+       some attempt at allowing an xmodmap inside a VNC desktop behave
+       something like you'd expect - e.g. if keys A & B are swapped over and
+       the VNC client sends an A, then map it to a B when generating the X
+       event.  We don't attempt to do this for keycodes which we make up on the
+       fly because it's too hard... */
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+	if (keySym == map[i]) {
+	    keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY;
+
+	    if (map[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) {
+
+		/* this keycode has more than one symbol associated with it,
+		   so shift state is important */
+
+		if ((i % GLYPHS_PER_KEY) == 0)
+		    shiftMustBeReleased = TRUE;
+		else
+		    shiftMustBePressed = TRUE;
+	    }
+	    break;
+	}
+    }
+#endif
+
+    if (!keyCode) {
+
+	/* not one of our predefined keys - see if it's in the current keyboard
+           mapping (i.e. we've already allocated an extra keycode for it) */
+
+	if (keySyms->mapWidth < 2) {
+	    ErrorF("KbdAddEvent: Sanity check failed - Keyboard mapping has "
+		   "less than 2 keysyms per keycode (KeySym 0x%x)\n", keySym);
+	    return;
+	}
+
+	for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) {
+	    if (keySym == keySyms->map[i]) {
+		keyCode = MIN_KEY_CODE + i / keySyms->mapWidth;
+
+		if (keySyms->map[(i / keySyms->mapWidth)
+					* keySyms->mapWidth + 1] != NoSymbol) {
+
+		    /* this keycode has more than one symbol associated with
+		       it, so shift state is important */
+
+		    if ((i % keySyms->mapWidth) == 0)
+			shiftMustBeReleased = TRUE;
+		    else
+			shiftMustBePressed = TRUE;
+		}
+		break;
+	    }
+	    if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol)
+		&& (i % keySyms->mapWidth) == 0)
+	    {
+		freeIndex = i;
+	    }
+	}
+    }
+
+    if (!keyCode) {
+	KeySym lower, upper;
+
+	/* we don't have an existing keycode - make one up on the fly and add
+	   it to the keyboard mapping.  Thanks to Vlad Harchev for pointing
+	   out problems with non-ascii capitalisation. */
+
+	if (freeIndex == -1) {
+	    ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n",
+		   keySym);
+	    return;
+	}
+
+	keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth;
+
+	XConvertCase(keySym, &lower, &upper);
+
+	if (lower == upper) {
+	    keySyms->map[freeIndex] = keySym;
+
+	} else {
+	    keySyms->map[freeIndex] = lower;
+	    keySyms->map[freeIndex+1] = upper;
+
+	    if (keySym == lower)
+		shiftMustBeReleased = TRUE;
+	    else
+		shiftMustBePressed = TRUE;
+	}
+
+	SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient);
+
+	ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n",
+	       keySym, keyCode);
+    }
+
+    time = GetTimeInMillis();
+
+    if (down) {
+	if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) {
+	    fakeShiftPress = TRUE;
+	    fake.u.u.type = KeyPress;
+	    fake.u.u.detail = SHIFT_L_KEY_CODE;
+	    fake.u.keyButtonPointer.time = time;
+	    Enqueue(&fake);
+	}
+	if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) {
+	    if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) {
+		fakeShiftLRelease = TRUE;
+		fake.u.u.type = KeyRelease;
+		fake.u.u.detail = SHIFT_L_KEY_CODE;
+		fake.u.keyButtonPointer.time = time;
+		Enqueue(&fake);
+	    }
+	    if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) {
+		fakeShiftRRelease = TRUE;
+		fake.u.u.type = KeyRelease;
+		fake.u.u.detail = SHIFT_R_KEY_CODE;
+		fake.u.keyButtonPointer.time = time;
+		Enqueue(&fake);
+	    }
+	}
+    }
+
+    ev.u.u.detail = keyCode;
+    ev.u.keyButtonPointer.time = time;
+    Enqueue(&ev);
+
+    if (fakeShiftPress) {
+	fake.u.u.type = KeyRelease;
+	fake.u.u.detail = SHIFT_L_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+    if (fakeShiftLRelease) {
+	fake.u.u.type = KeyPress;
+	fake.u.u.detail = SHIFT_L_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+    if (fakeShiftRRelease) {
+	fake.u.u.type = KeyPress;
+	fake.u.u.detail = SHIFT_R_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+}
+
+/*
+ * Called when the rfbserver receives a rfbPointerEvent event from a client.
+ * Put an X mouse event into the event queue.
+ */
+void
+PtrAddEvent(buttonMask, x, y, cl)
+    int buttonMask;
+    int x;
+    int y;
+    rfbClientPtr cl;
+{
+    xEvent ev;
+    int i;
+    unsigned long time;
+    static int oldButtonMask = 0;
+
+#ifdef CORBA
+    if (cl) {
+	CARD32 clientId = cl->sock;
+	ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+			     32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+#endif
+
+    time = GetTimeInMillis();
+
+    miPointerAbsoluteCursor(x, y, time);
+
+    for (i = 0; i < 5; i++) {
+	if ((buttonMask ^ oldButtonMask) & (1<<i)) {
+	    if (buttonMask & (1<<i)) {
+		ev.u.u.type = ButtonPress;
+		ev.u.u.detail = i + 1;
+		ev.u.keyButtonPointer.time = time;
+	    } else {
+		ev.u.u.type = ButtonRelease;
+		ev.u.u.detail = i + 1;
+		ev.u.keyButtonPointer.time = time;
+	    }
+ 	    Enqueue(&ev);
+	}
+    }
+
+    oldButtonMask = buttonMask;
+}
+
+void
+KbdReleaseAllKeys()
+{
+    int i, j;
+    xEvent ev;
+    unsigned long time = GetTimeInMillis();
+
+    if (!kbdDevice) 
+	return;
+
+    for (i = 0; i < DOWN_LENGTH; i++) {
+	if (kbdDevice->key->down[i] != 0) {
+	    for (j = 0; j < 8; j++) {
+		if (kbdDevice->key->down[i] & (1 << j)) {
+		    ev.u.u.type = KeyRelease;
+		    ev.u.u.detail = (i << 3) | j;
+		    ev.u.keyButtonPointer.time = time;
+		    Enqueue(&ev);
+		}
+	    }
+	}
+    }
+}
+
+
+/* copied from Xlib source */
+
+static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper)
+{
+    *lower = sym;
+    *upper = sym;
+    switch(sym >> 8) {
+    case 0: /* Latin 1 */
+	if ((sym >= XK_A) && (sym <= XK_Z))
+	    *lower += (XK_a - XK_A);
+	else if ((sym >= XK_a) && (sym <= XK_z))
+	    *upper -= (XK_a - XK_A);
+	else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
+	    *lower += (XK_agrave - XK_Agrave);
+	else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
+	    *upper -= (XK_agrave - XK_Agrave);
+	else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
+	    *lower += (XK_oslash - XK_Ooblique);
+	else if ((sym >= XK_oslash) && (sym <= XK_thorn))
+	    *upper -= (XK_oslash - XK_Ooblique);
+	break;
+    case 1: /* Latin 2 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym == XK_Aogonek)
+	    *lower = XK_aogonek;
+	else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+	    *lower += (XK_lstroke - XK_Lstroke);
+	else if (sym >= XK_Scaron && sym <= XK_Zacute)
+	    *lower += (XK_scaron - XK_Scaron);
+	else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+	    *lower += (XK_zcaron - XK_Zcaron);
+	else if (sym == XK_aogonek)
+	    *upper = XK_Aogonek;
+	else if (sym >= XK_lstroke && sym <= XK_sacute)
+	    *upper -= (XK_lstroke - XK_Lstroke);
+	else if (sym >= XK_scaron && sym <= XK_zacute)
+	    *upper -= (XK_scaron - XK_Scaron);
+	else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+	    *upper -= (XK_zcaron - XK_Zcaron);
+	else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+	    *lower += (XK_racute - XK_Racute);
+	else if (sym >= XK_racute && sym <= XK_tcedilla)
+	    *upper -= (XK_racute - XK_Racute);
+	break;
+    case 2: /* Latin 3 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+	    *lower += (XK_hstroke - XK_Hstroke);
+	else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+	    *lower += (XK_gbreve - XK_Gbreve);
+	else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+	    *upper -= (XK_hstroke - XK_Hstroke);
+	else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+	    *upper -= (XK_gbreve - XK_Gbreve);
+	else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+	    *lower += (XK_cabovedot - XK_Cabovedot);
+	else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+	    *upper -= (XK_cabovedot - XK_Cabovedot);
+	break;
+    case 3: /* Latin 4 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+	    *lower += (XK_rcedilla - XK_Rcedilla);
+	else if (sym >= XK_rcedilla && sym <= XK_tslash)
+	    *upper -= (XK_rcedilla - XK_Rcedilla);
+	else if (sym == XK_ENG)
+	    *lower = XK_eng;
+	else if (sym == XK_eng)
+	    *upper = XK_ENG;
+	else if (sym >= XK_Amacron && sym <= XK_Umacron)
+	    *lower += (XK_amacron - XK_Amacron);
+	else if (sym >= XK_amacron && sym <= XK_umacron)
+	    *upper -= (XK_amacron - XK_Amacron);
+	break;
+    case 6: /* Cyrillic */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+	    *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+	else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+	    *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+	else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+	    *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+	else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+	    *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+        break;
+    case 7: /* Greek */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+	    *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+	else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+		 sym != XK_Greek_iotaaccentdieresis &&
+		 sym != XK_Greek_upsilonaccentdieresis)
+	    *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+	else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+	    *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+	else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+		 sym != XK_Greek_finalsmallsigma)
+	    *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+        break;
+    }
+}
diff -u -rNp a/hw/vnc/keyboard.h b/hw/vnc/keyboard.h
--- a/hw/vnc/keyboard.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/keyboard.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,167 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#define MIN_KEY_CODE		8
+#define MAX_KEY_CODE		255
+#define NO_OF_KEYS		(MAX_KEY_CODE - MIN_KEY_CODE + 1)
+#define GLYPHS_PER_KEY		4
+
+#define CONTROL_L_KEY_CODE	(MIN_KEY_CODE + 29)
+#define CONTROL_R_KEY_CODE	(MIN_KEY_CODE + 101)
+#define SHIFT_L_KEY_CODE	(MIN_KEY_CODE + 42)
+#define SHIFT_R_KEY_CODE	(MIN_KEY_CODE + 54)
+#define META_L_KEY_CODE		(MIN_KEY_CODE + 107)
+#define META_R_KEY_CODE		(MIN_KEY_CODE + 108)
+#define ALT_L_KEY_CODE		(MIN_KEY_CODE + 56)
+#define ALT_R_KEY_CODE		(MIN_KEY_CODE + 105)
+
+static KeySym map[MAX_KEY_CODE * GLYPHS_PER_KEY] = {
+    /* 0x00 */  NoSymbol,       NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x01 */  XK_Escape,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x02 */  XK_1,           XK_exclam,	NoSymbol,	NoSymbol,
+    /* 0x03 */  XK_2,           XK_at,		NoSymbol,	NoSymbol,
+    /* 0x04 */  XK_3,           XK_numbersign,	NoSymbol,	NoSymbol,
+    /* 0x05 */  XK_4,           XK_dollar,	NoSymbol,	NoSymbol,
+    /* 0x06 */  XK_5,           XK_percent,	NoSymbol,	NoSymbol,
+    /* 0x07 */  XK_6,           XK_asciicircum,	NoSymbol,	NoSymbol,
+    /* 0x08 */  XK_7,           XK_ampersand,	NoSymbol,	NoSymbol,
+    /* 0x09 */  XK_8,           XK_asterisk,	NoSymbol,	NoSymbol,
+    /* 0x0a */  XK_9,           XK_parenleft,	NoSymbol,	NoSymbol,
+    /* 0x0b */  XK_0,           XK_parenright,	NoSymbol,	NoSymbol,
+    /* 0x0c */  XK_minus,       XK_underscore,	NoSymbol,	NoSymbol,
+    /* 0x0d */  XK_equal,       XK_plus,	NoSymbol,	NoSymbol,
+    /* 0x0e */  XK_BackSpace,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x0f */  XK_Tab,         XK_ISO_Left_Tab,NoSymbol,	NoSymbol,
+    /* 0x10 */  XK_q,           XK_Q,		NoSymbol,	NoSymbol,
+    /* 0x11 */  XK_w,           XK_W,		NoSymbol,	NoSymbol,
+    /* 0x12 */  XK_e,           XK_E,		NoSymbol,	NoSymbol,
+    /* 0x13 */  XK_r,           XK_R,		NoSymbol,	NoSymbol,
+    /* 0x14 */  XK_t,           XK_T,		NoSymbol,	NoSymbol,
+    /* 0x15 */  XK_y,           XK_Y,		NoSymbol,	NoSymbol,
+    /* 0x16 */  XK_u,           XK_U,		NoSymbol,	NoSymbol,
+    /* 0x17 */  XK_i,           XK_I,		NoSymbol,	NoSymbol,
+    /* 0x18 */  XK_o,           XK_O,		NoSymbol,	NoSymbol,
+    /* 0x19 */  XK_p,           XK_P,		NoSymbol,	NoSymbol,
+    /* 0x1a */  XK_bracketleft, XK_braceleft,	NoSymbol,	NoSymbol,
+    /* 0x1b */  XK_bracketright,XK_braceright,	NoSymbol,	NoSymbol,
+    /* 0x1c */  XK_Return,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x1d */  XK_Control_L,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x1e */  XK_a,           XK_A,		NoSymbol,	NoSymbol,
+    /* 0x1f */  XK_s,           XK_S,		NoSymbol,	NoSymbol,
+    /* 0x20 */  XK_d,           XK_D,		NoSymbol,	NoSymbol,
+    /* 0x21 */  XK_f,           XK_F,		NoSymbol,	NoSymbol,
+    /* 0x22 */  XK_g,           XK_G,		NoSymbol,	NoSymbol,
+    /* 0x23 */  XK_h,           XK_H,		NoSymbol,	NoSymbol,
+    /* 0x24 */  XK_j,           XK_J,		NoSymbol,	NoSymbol,
+    /* 0x25 */  XK_k,           XK_K,		NoSymbol,	NoSymbol,
+    /* 0x26 */  XK_l,           XK_L,		NoSymbol,	NoSymbol,
+    /* 0x27 */  XK_semicolon,   XK_colon,	NoSymbol,	NoSymbol,
+    /* 0x28 */  XK_quoteright,  XK_quotedbl,	NoSymbol,	NoSymbol,
+    /* 0x29 */  XK_quoteleft,	XK_asciitilde,	NoSymbol,	NoSymbol,
+    /* 0x2a */  XK_Shift_L,     NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x2b */  XK_backslash,   XK_bar,		NoSymbol,	NoSymbol,
+    /* 0x2c */  XK_z,           XK_Z,		NoSymbol,	NoSymbol,
+    /* 0x2d */  XK_x,           XK_X,		NoSymbol,	NoSymbol,
+    /* 0x2e */  XK_c,           XK_C,		NoSymbol,	NoSymbol,
+    /* 0x2f */  XK_v,           XK_V,		NoSymbol,	NoSymbol,
+    /* 0x30 */  XK_b,           XK_B,		NoSymbol,	NoSymbol,
+    /* 0x31 */  XK_n,           XK_N,		NoSymbol,	NoSymbol,
+    /* 0x32 */  XK_m,           XK_M,		NoSymbol,	NoSymbol,
+    /* 0x33 */  XK_comma,       XK_less,	NoSymbol,	NoSymbol,
+    /* 0x34 */  XK_period,      XK_greater,	NoSymbol,	NoSymbol,
+    /* 0x35 */  XK_slash,       XK_question,	NoSymbol,	NoSymbol,
+    /* 0x36 */  XK_Shift_R,     NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x37 */  XK_KP_Multiply, NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x38 */  XK_Alt_L,	XK_Meta_L,	NoSymbol,	NoSymbol,
+    /* 0x39 */  XK_space,       NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3a */  XK_Caps_Lock,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3b */  XK_F1,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3c */  XK_F2,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3d */  XK_F3,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3e */  XK_F4,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3f */  XK_F5,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x40 */  XK_F6,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x41 */  XK_F7,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x42 */  XK_F8,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x43 */  XK_F9,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x44 */  XK_F10,         NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x45 */  XK_Num_Lock,    NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x46 */  XK_Scroll_Lock,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x47 */  XK_KP_Home,	XK_KP_7,	NoSymbol,	NoSymbol,
+    /* 0x48 */  XK_KP_Up,	XK_KP_8,	NoSymbol,	NoSymbol,
+    /* 0x49 */  XK_KP_Prior,	XK_KP_9,	NoSymbol,	NoSymbol,
+    /* 0x4a */  XK_KP_Subtract, NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x4b */  XK_KP_Left,	XK_KP_4,	NoSymbol,	NoSymbol,
+    /* 0x4c */  XK_KP_Begin,	XK_KP_5,	NoSymbol,	NoSymbol,
+    /* 0x4d */  XK_KP_Right,	XK_KP_6,	NoSymbol,	NoSymbol,
+    /* 0x4e */  XK_KP_Add,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x4f */  XK_KP_End,	XK_KP_1,	NoSymbol,	NoSymbol,
+    /* 0x50 */  XK_KP_Down,	XK_KP_2,	NoSymbol,	NoSymbol,
+    /* 0x51 */  XK_KP_Next,	XK_KP_3,	NoSymbol,	NoSymbol,
+    /* 0x52 */  XK_KP_Insert,	XK_KP_0,	NoSymbol,	NoSymbol,
+    /* 0x53 */  XK_KP_Delete,	XK_KP_Decimal,	NoSymbol,	NoSymbol,
+    /* 0x54 */  XK_Sys_Req,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x55 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x56 */  XK_less,	XK_greater,	NoSymbol,	NoSymbol,
+    /* 0x57 */  XK_F11,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x58 */  XK_F12,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x59 */  XK_Home,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5a */  XK_Up,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5b */  XK_Prior,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5c */  XK_Left,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5d */  XK_Begin,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5e */  XK_Right,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5f */  XK_End,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x60 */  XK_Down,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x61 */  XK_Next,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x62 */  XK_Insert,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x63 */  XK_Delete,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x64 */  XK_KP_Enter,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x65 */  XK_Control_R,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x66 */  XK_Pause,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x67 */  XK_Print,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x68 */  XK_KP_Divide,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x69 */  XK_Alt_R,	XK_Meta_R,	NoSymbol,	NoSymbol,
+    /* 0x6a */  XK_Break,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6b */  XK_Meta_L,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6c */  XK_Meta_R,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6d */  XK_Menu,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6e */  XK_F13,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6f */  XK_F14,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x70 */  XK_F15,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x71 */  XK_F16,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x72 */  XK_F17,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x73 */  XK_backslash,	XK_underscore,	NoSymbol,	NoSymbol,
+    /* 0x74 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x75 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x76 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x77 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x78 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x79 */  XK_Henkan,	XK_Mode_switch,	NoSymbol,	NoSymbol,
+    /* 0x7a */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7b */  XK_Muhenkan,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7c */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7d */  XK_backslash,	XK_bar,		NoSymbol,	NoSymbol,
+    /* 0x7e */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7f */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+};
+
+#define N_PREDEFINED_KEYS (sizeof(map) / (sizeof(KeySym) * GLYPHS_PER_KEY))
diff -u -rNp a/hw/vnc/LICENCE.TXT b/hw/vnc/LICENCE.TXT
--- a/hw/vnc/LICENCE.TXT	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/LICENCE.TXT	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+	  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+	 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+    USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -u -rNp a/hw/vnc/loginauth.c b/hw/vnc/loginauth.c
--- a/hw/vnc/loginauth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/loginauth.c	2007-01-18 09:31:23.000000000 +0000
@@ -0,0 +1,140 @@
+/*
+ * loginauth.c - deal with login-style Unix authentication.
+ *
+ * This file implements the UnixLogin authentication protocol when setting up
+ * an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003 Constantin Kaplinsky.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef linux
+#include </usr/include/shadow.h> /* XXX xserver has a shadow.h file too */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "rfb.h"
+
+char *crypt(const char *key, const char *salt);
+
+void rfbLoginAuthProcessClientMessage(rfbClientPtr cl)
+{
+    int n1 = 0, n2 = 0;
+    CARD32 loginLen, passwdLen, authResult;
+    char *loginBuf, *passwdBuf;
+    struct passwd *ps;
+    char *encPasswd1, *encPasswd2;
+    Bool ok;
+
+    if ((n1 = ReadExact(cl->sock, (char *)&loginLen,
+			sizeof(loginLen))) <= 0 ||
+	(n2 = ReadExact(cl->sock, (char *)&passwdLen,
+			sizeof(passwdLen))) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginLen = Swap32IfLE(loginLen);
+    passwdLen = Swap32IfLE(passwdLen);
+    loginBuf = (char *)xalloc(loginLen + 1);
+    passwdBuf = (char *)xalloc(passwdLen + 1);
+
+    n1 = n2 = 0;
+    if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 ||
+	(n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginBuf[loginLen] = '\0';
+    passwdBuf[passwdLen] = '\0';
+
+    encPasswd1 = encPasswd2 = NULL;
+
+    ps = getpwnam(loginBuf);
+    if (ps == NULL) {
+	rfbLog("rfbLoginAuthProcessClientMessage: "
+	       "Cannot get password file entry for \"%s\"\n", loginBuf);
+    } else {
+	encPasswd1 = ps->pw_passwd;
+#ifdef linux
+	if (strlen(ps->pw_passwd) == 1) {
+	    struct spwd *sps;
+
+	    sps = getspnam(loginBuf);
+	    if (sps == NULL) {
+		rfbLog("rfbLoginAuthProcessClientMessage:"
+		       " getspnam() failed for user \"%s\"\n", loginBuf);
+	    } else {
+		encPasswd1 = sps->sp_pwdp;
+	    }
+	}
+#endif
+	encPasswd2 = crypt(passwdBuf, encPasswd1);
+	memset(passwdBuf, 0, strlen(passwdBuf));
+    }
+
+    ok = FALSE;
+    if (encPasswd1 != NULL && encPasswd2 != NULL) {
+	if (strcmp(encPasswd1, encPasswd2) == 0)
+	    ok = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult,
+		       sizeof(authResult)) < 0) {
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    cl->login = strdup(loginBuf);
+    rfbLog("Login-style authentication passed for user %s at %s\n",
+	   cl->login, cl->host);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) {
+	rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    cl->state = RFB_INITIALISATION;
+}
+
diff -u -rNp a/hw/vnc/loginauth.c.orig b/hw/vnc/loginauth.c.orig
--- a/hw/vnc/loginauth.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/loginauth.c.orig	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,138 @@
+/*
+ * loginauth.c - deal with login-style Unix authentication.
+ *
+ * This file implements the UnixLogin authentication protocol when setting up
+ * an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003 Constantin Kaplinsky.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef linux
+#include </usr/include/shadow.h> /* XXX xserver has a shadow.h file too */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "rfb.h"
+
+void rfbLoginAuthProcessClientMessage(rfbClientPtr cl)
+{
+    int n1 = 0, n2 = 0;
+    CARD32 loginLen, passwdLen, authResult;
+    char *loginBuf, *passwdBuf;
+    struct passwd *ps;
+    char *encPasswd1, *encPasswd2;
+    Bool ok;
+
+    if ((n1 = ReadExact(cl->sock, (char *)&loginLen,
+			sizeof(loginLen))) <= 0 ||
+	(n2 = ReadExact(cl->sock, (char *)&passwdLen,
+			sizeof(passwdLen))) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginLen = Swap32IfLE(loginLen);
+    passwdLen = Swap32IfLE(passwdLen);
+    loginBuf = (char *)xalloc(loginLen + 1);
+    passwdBuf = (char *)xalloc(passwdLen + 1);
+
+    n1 = n2 = 0;
+    if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 ||
+	(n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginBuf[loginLen] = '\0';
+    passwdBuf[passwdLen] = '\0';
+
+    encPasswd1 = encPasswd2 = NULL;
+
+    ps = getpwnam(loginBuf);
+    if (ps == NULL) {
+	rfbLog("rfbLoginAuthProcessClientMessage: "
+	       "Cannot get password file entry for \"%s\"\n", loginBuf);
+    } else {
+	encPasswd1 = ps->pw_passwd;
+#ifdef linux
+	if (strlen(ps->pw_passwd) == 1) {
+	    struct spwd *sps;
+
+	    sps = getspnam(loginBuf);
+	    if (sps == NULL) {
+		rfbLog("rfbLoginAuthProcessClientMessage:"
+		       " getspnam() failed for user \"%s\"\n", loginBuf);
+	    } else {
+		encPasswd1 = sps->sp_pwdp;
+	    }
+	}
+#endif
+	encPasswd2 = crypt(passwdBuf, encPasswd1);
+	memset(passwdBuf, 0, strlen(passwdBuf));
+    }
+
+    ok = FALSE;
+    if (encPasswd1 != NULL && encPasswd2 != NULL) {
+	if (strcmp(encPasswd1, encPasswd2) == 0)
+	    ok = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult,
+		       sizeof(authResult)) < 0) {
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    cl->login = strdup(loginBuf);
+    rfbLog("Login-style authentication passed for user %s at %s\n",
+	   cl->login, cl->host);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) {
+	rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    cl->state = RFB_INITIALISATION;
+}
+
diff -u -rNp a/hw/vnc/Makefile.am b/hw/vnc/Makefile.am
--- a/hw/vnc/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,54 @@
+# XXX This Makefile.am probably needs some work.
+
+bin_PROGRAMS = Xvnc
+
+Xvnc_SOURCES = \
+	$(top_srcdir)/fb/fbcmap.c \
+	$(top_srcdir)/mi/miinitext.c	\
+	auth.c \
+	cmap.c \
+	corre.c \
+	cursor.c \
+	cutpaste.c \
+	d3des.c \
+	dispcur.c \
+	dpmsstubs.c \
+	draw.c \
+	hextile.c \
+	httpd.c \
+	init.c \
+	kbdptr.c \
+	loginauth.c \
+	rfbkeyb.c \
+	rfbmouse.c \
+	rfbserver.c \
+	rre.c \
+	sprite.c \
+	sockets.c \
+	stats.c \
+	tight.c \
+	translate.c \
+	$(top_srcdir)/hw/dmx/vnc/vncauth.c \
+	vncext.c \
+	xistubs.c \
+	zlib.c
+
+
+JPEG_LIBS = -ljpeg
+CRYPT_LIBS = -lcrypt
+FB_LIBS = ../../fb/.libs/libfb.a
+
+AM_CFLAGS = $(DIX_CFLAGS) $(XVNC_CFLAGS) -I$(top_srcdir)/hw/dmx/vnc \
+            -I$(top_srcdir)/mfb
+
+Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
+Xvnc_LDADD = \
+             $(XORG_CORE_LIBS) \
+             $(XVNC_LIBS) \
+             $(JPEG_LIBS) \
+             $(CRYPT_LIBS) \
+             $(VNCMODULES_LIBS)
+
+
+relink:
+	rm -f Xvnc && $(MAKE) Xvnc
diff -u -rNp a/hw/vnc/rdp.c b/hw/vnc/rdp.c
--- a/hw/vnc/rdp.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rdp.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (C) 2004 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include "rfb.h"
+
+typedef struct rdpClientRec {
+	ScreenPtr pScreen;
+} rdpClientRec, *rdpClientPtr;
+
+typedef struct rdpInRec {
+	char version;
+	char pad;
+	short length; 
+	char hdrlen;
+	unsigned char pdu;
+} rdpInRec, *rdpInPtr;
+
+static void
+rdpCloseSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    close(pVNC->rdpListenSock);
+    RemoveEnabledDevice(pVNC->rdpListenSock);
+    pVNC->rdpListenSock = -1;
+}
+
+/*
+ * rdpNewClient is called when a new connection has been made by whatever
+ * means.
+ */
+
+static rdpClientPtr
+rdpNewClient(ScreenPtr pScreen, int sock)
+{
+    rdpInRec in;
+    rdpClientPtr cl;
+    BoxRec box;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
+    VNCSCREENPTR(pScreen);
+    int i;
+
+    cl = (rdpClientPtr)xalloc(sizeof(rdpClientRec));
+
+    cl->pScreen = pScreen;
+
+    in.version = 3;
+    in.pad = 0;
+    in.length = 0x600; /* big endian */
+    in.hdrlen = 0x00; 
+    in.pdu = 0xCC; 
+
+    if (WriteExact(sock, (char *)&in, sizeof(rdpInRec)) < 0) {
+	rfbLogPerror("rfbNewClient: write");
+	rdpCloseSock(pScreen);
+	return NULL;
+    }
+
+    return cl;
+}
+/*
+ * rdpCheckFds is called from ProcessInputEvents to check for input on the
+ * HTTP socket(s).  If there is input to process, rdpProcessInput is called.
+ */
+
+void
+rdpCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    int sock;
+    const int one =1;
+    SOCKLEN_T addrlen = sizeof(addr);
+
+    FD_ZERO(&fds);
+    FD_SET(pVNC->rdpListenSock, &fds);
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(pVNC->rdpListenSock + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR) 
+		rfbLogPerror("httpCheckFds: select");
+	return;
+    }
+
+    if (pVNC->rdpListenSock != -1 && FD_ISSET(pVNC->rdpListenSock, &fds)) {
+
+	if ((sock = accept(pVNC->rdpListenSock,
+			   (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("rdpCheckFds: accept");
+	    return;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("rdpCheckFds: fcntl");
+	    close(sock);
+	    return;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("rdpCheckFds: setsockopt");
+	    close(sock);
+	    return;
+	}
+
+	rfbLog("\n");
+
+	rfbLog("Got RDP connection from client %s\n", inet_ntoa(addr.sin_addr));
+
+	AddEnabledDevice(sock);
+
+	rdpNewClient(pScreen, sock);
+    }
+}
diff -u -rNp a/hw/vnc/README b/hw/vnc/README
--- a/hw/vnc/README	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/README	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,14 @@
+
+This is the directory containing the code specific to the TightVNC X server (Xvnc).
+Note that within this directory the name RFB is still used instead of VNC.
+
+NOTE:
+
+The is the new XFree86 v4 architecture VNC server code.
+
+Modified entirely by Alan Hourihane <alanh@fairlite.demon.co.uk>
+
+For information please visit http://xf4vnc.sourceforge.net
+
+Moved to X.org modular tree by Brian Paul.
+
diff -u -rNp a/hw/vnc/rfb.h b/hw/vnc/rfb.h
--- a/hw/vnc/rfb.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rfb.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,725 @@
+/*
+ * rfb.h - header file for RFB DDX implementation.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000-2004 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if HAVE_DIX_CONFIG_H
+#include "dix-config.h"
+#endif
+
+#include <zlib.h>
+#if 0 && XFREE86VNC /* not yet */
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86_ansic.h"
+#endif
+#include "scrnintstr.h"
+#include "colormapst.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "windowstr.h"
+#include "dixfontstr.h"
+#if 1 /* && !XFREE86VNC */
+/*#include "osdep.h"*/
+#endif
+#include <rfbproto.h>
+#include <vncauth.h>
+#define _VNC_SERVER
+#include <X11/extensions/vnc.h>
+#if 1/*def RENDER*/
+#include "picturestr.h"
+#endif
+
+#if defined(sun) || defined(hpux)
+#define SOCKLEN_T	int
+#else
+#define SOCKLEN_T	socklen_t
+#endif
+
+/* It's a good idea to keep these values a bit greater than required. */
+#define MAX_ENCODINGS 10
+#define MAX_SECURITY_TYPES 4
+#define MAX_TUNNELING_CAPS 16
+#define MAX_AUTH_CAPS 16
+
+/* 
+ * HTTP_BUF_SIZE for http transfers
+ */
+#define HTTP_BUF_SIZE 32768
+
+/*
+ * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the
+ * framebuffer.  So for a max screen width of say 2K with 32-bit pixels this
+ * means 8K minimum.
+ */
+#define UPDATE_BUF_SIZE 30000
+
+#if XFREE86VNC
+#include "xf86.h"
+#include "vnc.h"
+#define VNCSCREENPTR(ptr) \
+	vncScreenPtr pVNC = VNCPTR(ptr)
+#else
+#define VNCSCREENPTR(ptr) \
+/* Soon \
+	rfbScreenInfoPtr pVNC = rfbScreen[ptr->myNum] \
+*/ \
+	rfbScreenInfoPtr pVNC = &rfbScreen
+#endif
+
+/*
+ * Per-screen (framebuffer) structure.  There is only one of these, since we
+ * don't allow the X server to have multiple screens.
+ */
+
+typedef struct
+{
+    int			rfbPort;
+    int			rdpPort;
+    int			udpPort;
+    int			rfbListenSock;
+    int			rdpListenSock;
+    int			udpSock;
+    int			httpPort;
+    int			httpListenSock;
+    int			httpSock;
+    char *		httpDir;
+    char		buf[HTTP_BUF_SIZE];
+    Bool		udpSockConnected;
+    char *		rfbAuthPasswdFile;
+    size_t		buf_filled;
+    int			maxFd;
+    fd_set		allFds;
+    Bool		useGetImage;
+    Bool		noCursor;
+    Bool		rfbAlwaysShared;
+    Bool		rfbNeverShared;
+    Bool		rfbDontDisconnect;
+    Bool		rfbUserAccept;
+    Bool		rfbViewOnly;
+    ColormapPtr		savedColormap;
+    ColormapPtr 	rfbInstalledColormap;
+    rfbPixelFormat	rfbServerFormat;
+    Bool		rfbAuthTooManyTries;
+    int			rfbAuthTries;
+    Bool		loginAuthEnabled;
+    struct in_addr	interface;
+    OsTimerPtr 		timer;
+    char updateBuf[UPDATE_BUF_SIZE];
+    int ublen;
+    int width;
+    int paddedWidthInBytes;
+    int height;
+    int depth;
+    int bitsPerPixel;
+    int sizeInBytes;
+    unsigned char *pfbMemory;
+    Pixel blackPixel;
+    Pixel whitePixel;
+
+    /* The following two members are used to minimise the amount of unnecessary
+       drawing caused by cursor movement.  Whenever any drawing affects the
+       part of the screen where the cursor is, the cursor is removed first and
+       then the drawing is done (this is what the sprite routines test for).
+       Afterwards, however, we do not replace the cursor, even when the cursor
+       is logically being moved across the screen.  We only draw the cursor
+       again just as we are about to send the client a framebuffer update.
+
+       We need to be careful when removing and drawing the cursor because of
+       their relationship with the normal drawing routines.  The drawing
+       routines can invoke the cursor routines, but also the cursor routines
+       themselves end up invoking drawing routines.
+
+       Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by
+       doing a CopyArea from a pixmap to the screen, where the pixmap contains
+       the saved contents of the screen under the cursor.  Before doing this,
+       however, we set cursorIsDrawn to FALSE.  Then, when CopyArea is called,
+       it sees that cursorIsDrawn is FALSE and so doesn't feel the need to
+       (recursively!) remove the cursor before doing it.
+
+       Putting up the cursor (rfbSpriteRestoreCursor) involves a call to
+       PushPixels.  While this is happening, cursorIsDrawn must be FALSE so
+       that PushPixels doesn't think it has to remove the cursor first.
+       Obviously cursorIsDrawn is set to TRUE afterwards.
+
+       Another problem we face is that drawing routines sometimes cause a
+       framebuffer update to be sent to the RFB client.  When the RFB client is
+       already waiting for a framebuffer update and some drawing to the
+       framebuffer then happens, the drawing routine sees that the client is
+       ready, so it calls rfbSendFramebufferUpdate.  If the cursor is not drawn
+       at this stage, it must be put up, and so rfbSpriteRestoreCursor is
+       called.  However, if the original drawing routine was actually called
+       from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't
+       want this to happen.  So both the cursor routines set
+       dontSendFramebufferUpdate to TRUE, and all the drawing routines check
+       this before calling rfbSendFramebufferUpdate. */
+
+    Bool cursorIsDrawn;		    /* TRUE if the cursor is currently drawn */
+    Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the
+				       cursor */
+
+    /* wrapped screen functions */
+
+    CloseScreenProcPtr			CloseScreen;
+    CreateGCProcPtr			CreateGC;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    RestoreAreasProcPtr			RestoreAreas;
+    ScreenWakeupHandlerProcPtr 		WakeupHandler;
+#ifdef CHROMIUM
+    RealizeWindowProcPtr		RealizeWindow;
+    UnrealizeWindowProcPtr		UnrealizeWindow;
+    DestroyWindowProcPtr		DestroyWindow;
+    ResizeWindowProcPtr			ResizeWindow;
+    PositionWindowProcPtr		PositionWindow;
+    ClipNotifyProcPtr			ClipNotify;
+#endif
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+#endif
+
+} rfbScreenInfo, *rfbScreenInfoPtr;
+
+
+/*
+ * rfbTranslateFnType is the type of translation functions.
+ */
+
+struct rfbClientRec;
+typedef void (*rfbTranslateFnType)(ScreenPtr pScreen, 
+				   char *table, rfbPixelFormat *in,
+				   rfbPixelFormat *out,
+				   unsigned char *iptr, char *optr,
+				   int bytesBetweenInputLines,
+				   int width, int height,
+				   int x, int y);
+
+
+/*
+ * Per-client structure.
+ */
+
+typedef struct rfbClientRec {
+    int sock;
+    char *host;
+    char *login;
+
+    int protocol_minor_ver;	/* RFB protocol minor version in use. */
+    Bool protocol_tightvnc;	/* TightVNC protocol extensions enabled */
+
+    /* Possible client states: */
+
+    enum {
+	RFB_PROTOCOL_VERSION,	/* establishing protocol version */
+        RFB_SECURITY_TYPE,	/* negotiating security (RFB v.3.7) */
+	RFB_TUNNELING_TYPE,	/* establishing tunneling (RFB v.3.7t) */
+	RFB_AUTH_TYPE,		/* negotiating authentication (RFB v.3.7t) */
+	RFB_AUTHENTICATION,	/* authenticating (VNC authentication) */
+	RFB_INITIALISATION,	/* sending initialisation messages */
+	RFB_NORMAL		/* normal protocol messages */
+    } state;
+
+    Bool viewOnly;		/* Do not accept input from this client. */
+
+    Bool reverseConnection;
+
+    Bool readyForSetColourMapEntries;
+
+    Bool useCopyRect;
+    int preferredEncoding;
+    int correMaxWidth, correMaxHeight;
+
+    /* The list of security types sent to this client (protocol 3.7).
+       Note that the first entry is the number of list items following. */
+
+    CARD8 securityTypes[MAX_SECURITY_TYPES + 1];
+
+    /* Lists of capability codes sent to clients. We remember these
+       lists to restrict clients from choosing those tunneling and
+       authentication types that were not advertised. */
+
+    int nAuthCaps;
+    CARD32 authCaps[MAX_AUTH_CAPS];
+
+    /* This is not useful while we don't support tunneling:
+    int nTunnelingCaps;
+    CARD32 tunnelingCaps[MAX_TUNNELING_CAPS]; */
+
+    /* The following member is only used during VNC authentication */
+
+    CARD8 authChallenge[CHALLENGESIZE];
+
+    /* The following members represent the update needed to get the client's
+       framebuffer from its present state to the current state of our
+       framebuffer.
+
+       If the client does not accept CopyRect encoding then the update is
+       simply represented as the region of the screen which has been modified
+       (modifiedRegion).
+
+       If the client does accept CopyRect encoding, then the update consists of
+       two parts.  First we have a single copy from one region of the screen to
+       another (the destination of the copy is copyRegion), and second we have
+       the region of the screen which has been modified in some other way
+       (modifiedRegion).
+
+       Although the copy is of a single region, this region may have many
+       rectangles.  When sending an update, the copyRegion is always sent
+       before the modifiedRegion.  This is because the modifiedRegion may
+       overlap parts of the screen which are in the source of the copy.
+
+       In fact during normal processing, the modifiedRegion may even overlap
+       the destination copyRegion.  Just before an update is sent we remove
+       from the copyRegion anything in the modifiedRegion. */
+
+    RegionRec copyRegion;	/* the destination region of the copy */
+    int copyDX, copyDY;		/* the translation by which the copy happens */
+
+    RegionRec modifiedRegion;	/* the region of the screen modified in any
+				   other way */
+
+    /* As part of the FramebufferUpdateRequest, a client can express interest
+       in a subrectangle of the whole framebuffer.  This is stored in the
+       requestedRegion member.  In the normal case this is the whole
+       framebuffer if the client is ready, empty if it's not. */
+
+    RegionRec requestedRegion;
+
+    /* The following members represent the state of the "deferred update" timer
+       - when the framebuffer is modified and the client is ready, in most
+       cases it is more efficient to defer sending the update by a few
+       milliseconds so that several changes to the framebuffer can be combined
+       into a single update. */
+
+    Bool deferredUpdateScheduled;
+    OsTimerPtr deferredUpdateTimer;
+
+    /* translateFn points to the translation function which is used to copy
+       and translate a rectangle from the framebuffer to an output buffer. */
+
+    rfbTranslateFnType translateFn;
+
+    char *translateLookupTable;
+
+    rfbPixelFormat format;
+
+    /* statistics */
+
+    int rfbBytesSent[MAX_ENCODINGS];
+    int rfbRectanglesSent[MAX_ENCODINGS];
+    int rfbLastRectMarkersSent;
+    int rfbLastRectBytesSent;
+    int rfbCursorShapeBytesSent;
+    int rfbCursorShapeUpdatesSent;
+    int rfbCursorPosBytesSent;
+    int rfbCursorPosUpdatesSent;
+    int rfbFramebufferUpdateMessagesSent;
+    int rfbRawBytesEquivalent;
+    int rfbKeyEventsRcvd;
+    int rfbPointerEventsRcvd;
+
+    /* zlib encoding -- necessary compression state info per client */
+
+    struct z_stream_s compStream;
+    Bool compStreamInited;
+
+    CARD32 zlibCompressLevel;
+
+    /* tight encoding -- preserve zlib streams' state for each client */
+
+    z_stream zsStruct[4];
+    Bool zsActive[4];
+    int zsLevel[4];
+    int tightCompressLevel;
+    int tightQualityLevel;
+
+    Bool enableLastRectEncoding;   /* client supports LastRect encoding */
+    Bool enableCursorShapeUpdates; /* client supports cursor shape updates */
+    Bool enableCursorPosUpdates;   /* client supports PointerPos updates */
+#ifdef CHROMIUM
+    Bool enableChromiumEncoding;   /* client supports Chromium encoding */
+#endif
+    Bool useRichCursorEncoding;    /* rfbEncodingRichCursor is preferred */
+    Bool cursorWasChanged;         /* cursor shape update should be sent */
+    Bool cursorWasMoved;           /* cursor position update should be sent */
+
+    int cursorX, cursorY;          /* client's cursor position */
+
+    struct rfbClientRec *next;
+
+    ScreenPtr pScreen;
+    int userAccepted;
+
+#ifdef CHROMIUM
+    unsigned int chromium_port;
+    unsigned int chromium_msport;
+#endif
+} rfbClientRec, *rfbClientPtr;
+
+#ifdef CHROMIUM
+typedef struct CRWindowTable {
+	unsigned long CRwinId;
+	unsigned long XwinId;
+	BoxPtr clipRects;
+	int numRects;
+	struct CRWindowTable *next;
+} CRWindowTable, *CRWindowTablePtr;
+
+extern struct CRWindowTable *windowTable;
+#endif
+
+/*
+ * This macro is used to test whether there is a framebuffer update needing to
+ * be sent to the client.
+ */
+
+#define FB_UPDATE_PENDING(cl)                                           \
+    ((!(cl)->enableCursorShapeUpdates && !pVNC->cursorIsDrawn) ||   \
+     ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) ||      \
+     ((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) ||          \
+     REGION_NOTEMPTY(((cl)->pScreen),&(cl)->copyRegion) ||                    \
+     REGION_NOTEMPTY(((cl)->pScreen),&(cl)->modifiedRegion))
+
+/*
+ * This macro creates an empty region (ie. a region with no areas) if it is
+ * given a rectangle with a width or height of zero. It appears that 
+ * REGION_INTERSECT does not quite do the right thing with zero-width
+ * rectangles, but it should with completely empty regions.
+ */
+
+#define SAFE_REGION_INIT(pscreen, preg, rect, size)          \
+{                                                            \
+      if ( ( (rect) ) &&                                     \
+           ( ( (rect)->x2 == (rect)->x1 ) ||                 \
+	     ( (rect)->y2 == (rect)->y1 ) ) ) {              \
+	  REGION_NULL( (pscreen), (preg) ); 		     \
+      } else {                                               \
+	  REGION_INIT( (pscreen), (preg), (rect), (size) );  \
+      }                                                      \
+}
+
+/*
+ * An rfbGCRec is where we store the pointers to the original GC funcs and ops
+ * which we wrap (NULL means not wrapped).
+ */
+
+typedef struct {
+    GCFuncs *wrapFuncs;
+    GCOps *wrapOps;
+} rfbGCRec, *rfbGCPtr;
+
+
+
+/*
+ * Macros for endian swapping.
+ */
+
+#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
+
+#define Swap32(l) (((l) >> 24) | \
+		   (((l) & 0x00ff0000) >> 8)  | \
+		   (((l) & 0x0000ff00) << 8)  | \
+		   ((l) << 24))
+
+static const int rfbEndianTest = 1;
+
+#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s))
+
+#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l))
+
+
+/*
+ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.130).
+ * Normally, using macros is no good, but this macro saves us from
+ * writing constants twice -- it constructs signature names from codes.
+ * Note that "code_sym" argument should be a single symbol, not an expression.
+ */
+
+#define SetCapInfo(cap_ptr, code_sym, vendor)		\
+{							\
+    rfbCapabilityInfo *pcap;				\
+    pcap = (cap_ptr);					\
+    pcap->code = Swap32IfLE(code_sym);			\
+    memcpy(pcap->vendorSignature, (vendor),		\
+	   sz_rfbCapabilityInfoVendor);			\
+    memcpy(pcap->nameSignature, sig_##code_sym,		\
+	   sz_rfbCapabilityInfoName);			\
+}
+
+
+/* init.c */
+
+extern char *desktopName;
+extern char rfbThisHost[];
+extern Atom VNC_LAST_CLIENT_ID;
+
+extern rfbScreenInfo rfbScreen;
+extern int rfbGCIndex;
+
+extern int inetdSock;
+
+extern int rfbBitsPerPixel(int depth);
+extern void rfbLog(char *format, ...);
+extern void rfbLogPerror(char *str);
+
+
+/* sockets.c */
+
+extern int rfbMaxClientWait;
+
+extern Bool rfbInitSockets(ScreenPtr pScreen);
+extern void rfbDisconnectUDPSock(ScreenPtr pScreen);
+extern void rfbCloseSock(ScreenPtr pScreen, int sock);
+extern void rfbCheckFds(ScreenPtr pScreen);
+extern void rfbWaitForClient(int sock);
+extern int rfbConnect(ScreenPtr pScreen, char *host, int port);
+
+extern int ReadExact(int sock, char *buf, int len);
+extern int WriteExact(int sock, char *buf, int len);
+extern int ListenOnTCPPort(ScreenPtr pScreen, int port);
+extern int ListenOnUDPPort(ScreenPtr pScreen, int port);
+extern int ConnectToTcpAddr(char *host, int port);
+
+
+/* cmap.c */
+
+
+extern int rfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps);
+extern void rfbInstallColormap(ColormapPtr pmap);
+extern void rfbUninstallColormap(ColormapPtr pmap);
+extern void rfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs);
+
+
+/* draw.c */
+
+extern int rfbDeferUpdateTime;
+
+extern void
+rfbComposite(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pMask,
+    PicturePtr pDst,
+    INT16 xSrc,
+    INT16 ySrc,
+    INT16 xMask,
+    INT16 yMask,
+    INT16 xDst,
+    INT16 yDst,
+    CARD16 width,
+    CARD16 height
+);
+
+extern void rfbGlyphs(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pDst,
+    PictFormatPtr maskFormat,
+    INT16 xSrc,
+    INT16 ySrc,
+    int nlistInit,
+    GlyphListPtr listInit,
+    GlyphPtr *glyphsInit
+);
+extern Bool rfbCloseScreen(int,ScreenPtr);
+extern Bool rfbCreateGC(GCPtr);
+extern void rfbPaintWindowBackground(WindowPtr, RegionPtr, int what);
+extern void rfbPaintWindowBorder(WindowPtr, RegionPtr, int what);
+extern void rfbCopyWindow(WindowPtr, DDXPointRec, RegionPtr);
+#ifdef CHROMIUM
+extern Bool rfbRealizeWindow(WindowPtr); 
+extern Bool rfbUnrealizeWindow(WindowPtr); 
+extern Bool rfbDestroyWindow(WindowPtr);
+extern void rfbResizeWindow(WindowPtr, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib);
+extern Bool rfbPositionWindow(WindowPtr, int x, int y);
+extern void rfbClipNotify(WindowPtr, int x, int y);
+#endif
+extern void rfbClearToBackground(WindowPtr, int x, int y, int w,
+				 int h, Bool generateExposures);
+extern RegionPtr rfbRestoreAreas(WindowPtr, RegionPtr);
+
+
+/* cutpaste.c */
+
+extern void rfbSetXCutText(char *str, int len);
+extern void rfbGotXCutText(char *str, int len);
+
+
+/* kbdptr.c */
+
+extern Bool compatibleKbd;
+extern unsigned char ptrAcceleration;
+
+extern void PtrDeviceInit(void);
+extern void PtrDeviceOn(DeviceIntPtr pDev);
+extern void PtrDeviceOff(void);
+extern void PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl);
+extern void PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+
+extern void KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap);
+extern void KbdDeviceOn(void);
+extern void KbdDeviceOff(void);
+extern void KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl);
+extern void KbdReleaseAllKeys(void);
+
+
+/* rfbserver.c */
+
+
+extern rfbClientPtr rfbClientHead;
+extern rfbClientPtr pointerClient;
+
+extern void rfbNewClientConnection(ScreenPtr pScreen, int sock);
+extern rfbClientPtr rfbReverseConnection(ScreenPtr pScreen, char *host, int port);
+extern void rfbRootPropertyChange(ScreenPtr pScreen);
+extern void rfbClientConnectionGone(int sock);
+extern void rfbProcessClientMessage(ScreenPtr pScreen, int sock);
+extern void rfbClientConnFailed(rfbClientPtr cl, char *reason);
+extern void rfbNewUDPConnection(int sock);
+extern void rfbProcessUDPInput(ScreenPtr pScreen, int sock);
+extern Bool rfbSendFramebufferUpdate(ScreenPtr pScreen, rfbClientPtr cl);
+extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h);
+extern Bool rfbSendUpdateBuf(rfbClientPtr cl);
+extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour,
+				       int nColours);
+extern void rfbSendBell(void);
+extern void rfbSendServerCutText(char *str, int len);
+extern void rfbUserAllow(int sock, int accept);
+extern void rfbSetClip (WindowPtr pWin, BOOL enable);
+
+extern int GenerateVncConnectedEvent(int sock);
+extern int GenerateVncDisconnectedEvent(int sock);
+
+#ifdef CHROMIUM
+extern void rfbSendChromiumWindowShow(unsigned int winid, unsigned int show);
+extern void rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h);
+extern void rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects);
+#endif
+
+/* translate.c */
+
+extern Bool rfbEconomicTranslate;
+
+extern void rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+			     rfbPixelFormat *out,
+			     unsigned char *iptr, char *optr,
+			     int bytesBetweenInputLines,
+			     int width, int height,
+			     int x, int y);
+extern Bool rfbSetTranslateFunction(rfbClientPtr cl);
+extern void rfbSetClientColourMaps(int firstColour, int nColours);
+extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour,
+				  int nColours);
+
+
+/* httpd.c */
+
+extern Bool httpInitSockets(ScreenPtr pScreen);
+extern void httpCheckFds(ScreenPtr pScreen);
+
+
+/* vncext.c */
+
+#ifdef CHROMIUM
+extern void rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort, unsigned int mothershipPort);
+extern void rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid);
+int GenerateVncChromiumConnectedEvent(int sock);
+#endif
+
+
+/* auth.c */
+
+extern void rfbAuthNewClient(rfbClientPtr cl);
+extern void rfbProcessClientSecurityType(rfbClientPtr cl);
+extern void rfbProcessClientTunnelingType(rfbClientPtr cl);
+extern void rfbProcessClientAuthType(rfbClientPtr cl);
+extern void rfbVncAuthProcessResponse(rfbClientPtr cl);
+
+/* Functions to prevent too many successive authentication failures */
+extern Bool rfbAuthConsiderBlocking(rfbClientPtr cl);
+extern void rfbAuthUnblock(rfbClientPtr cl);
+extern Bool rfbAuthIsBlocked(rfbClientPtr cl);
+
+/* loginauth.c */
+
+extern void rfbLoginAuthProcessClientMessage(rfbClientPtr cl);
+  
+/* rre.c */
+
+extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* corre.c */
+
+extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* hextile.c */
+
+extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w,
+				       int h);
+
+
+/* zlib.c */
+
+/* Minimum zlib rectangle size in bytes.  Anything smaller will
+ * not compress well due to overhead.
+ */
+#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17)
+
+/* Set maximum zlib rectangle size in pixels.  Always allow at least
+ * two scan lines.
+ */
+#define ZLIB_MAX_RECT_SIZE (128*256)
+#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \
+			    ( min * 2 ) : ZLIB_MAX_RECT_SIZE )
+
+extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
+				    int h);
+
+
+/* tight.c */
+
+#define TIGHT_DEFAULT_COMPRESSION  6
+
+extern Bool rfbTightDisableGradient;
+
+extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h);
+extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* cursor.c */
+
+extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen);
+extern Bool rfbSendCursorPos(rfbClientPtr cl, ScreenPtr pScreen);
+
+
+/* stats.c */
+
+extern void rfbResetStats(rfbClientPtr cl);
+extern void rfbPrintStats(rfbClientPtr cl);
diff -u -rNp a/hw/vnc/rfbkeyb.c b/hw/vnc/rfbkeyb.c
--- a/hw/vnc/rfbkeyb.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rfbkeyb.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,412 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#if XFREE86VNC
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include <misc.h>
+#include <xf86.h>
+#define NEED_XF86_TYPES
+#if !defined(DGUX)
+#include <xf86_ansic.h>
+#include <xisb.h>
+#endif
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>		/* Needed for InitValuator/Proximity stuff */
+#include <X11/keysym.h>
+#include <mipointer.h>
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+#else
+#include <X11/keysym.h>
+#include <dix.h>
+#include <mipointer.h>
+#endif
+
+
+extern Bool noXkbExtension;
+extern void rfbSendBell(void);
+extern DeviceIntPtr kbdDevice;
+
+static const char *DEFAULTS[] = {
+    NULL
+};
+
+#include "keyboard.h"
+
+#undef XKB
+#ifdef XKB
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+#include <X11/extensions/XKBsrv.h>
+
+#if XFREE86VNC
+    /* 
+     * would like to use an XkbComponentNamesRec here but can't without
+     * pulling in a bunch of header files. :-(
+     */
+static    char *		xkbkeymap;
+static    char *		xkbkeycodes;
+static    char *		xkbtypes;
+static    char *		xkbcompat;
+static    char *		xkbsymbols;
+static    char *		xkbgeometry;
+static    Bool		xkbcomponents_specified;
+static    char *		xkbrules;
+static    char *		xkbmodel;
+static    char *		xkblayout;
+static    char *		xkbvariant;
+static    char *		xkboptions;
+#endif
+#endif
+
+void
+KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap)
+{
+    int i;
+
+    kbdDevice = pDevice;
+
+    for (i = 0; i < MAP_LENGTH; i++)
+	pModMap[i] = NoSymbol;
+
+    pModMap[CONTROL_L_KEY_CODE] = ControlMask;
+    pModMap[CONTROL_R_KEY_CODE] = ControlMask;
+    pModMap[SHIFT_L_KEY_CODE] = ShiftMask;
+    pModMap[SHIFT_R_KEY_CODE] = ShiftMask;
+    pModMap[META_L_KEY_CODE] = Mod1Mask;
+    pModMap[META_R_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_L_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_R_KEY_CODE] = Mod1Mask;
+
+    pKeySyms->minKeyCode = MIN_KEY_CODE;
+    pKeySyms->maxKeyCode = MAX_KEY_CODE;
+    pKeySyms->mapWidth = GLYPHS_PER_KEY;
+
+    pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym)
+				     * MAP_LENGTH * GLYPHS_PER_KEY);
+
+    if (!pKeySyms->map) {
+	ErrorF("xalloc failed\n");
+	exit(1);
+    }
+
+    for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++)
+	pKeySyms->map[i] = NoSymbol;
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+	pKeySyms->map[i] = map[i];
+    }
+}
+
+
+void
+KbdDeviceOn(void)
+{
+}
+
+
+void
+KbdDeviceOff(void)
+{
+}
+
+
+#if XFREE86VNC
+static int
+xf86rfbKeybControlProc(DeviceIntPtr device, int onoff)
+{
+    KeySymsRec		keySyms;
+    CARD8 		modMap[MAP_LENGTH];
+    DevicePtr pDev = (DevicePtr)device;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT: 
+	KbdDeviceInit(device, &keySyms, modMap);
+#ifdef XKB
+	if (noXkbExtension) {
+#endif
+	    InitKeyboardDeviceStruct(pDev, &keySyms, modMap,
+				 (BellProcPtr)rfbSendBell,
+				 (KbdCtrlProcPtr)NoopDDA);
+#ifdef XKB
+	} else {
+ 	    XkbComponentNamesRec names;
+	    if (XkbInitialMap) {
+	    	if ((xkbkeymap = strchr(XkbInitialMap, '/')) != NULL)
+		    xkbkeymap++;
+	    	else
+		    xkbkeymap = XkbInitialMap;
+	    }
+	    if (xkbkeymap) {
+	    	names.keymap = xkbkeymap;
+	    	names.keycodes = NULL;
+	    	names.types = NULL;
+	    	names.compat = NULL;
+	    	names.symbols = NULL;
+	    	names.geometry = NULL;
+	    } else {
+	    	names.keymap = NULL;
+	    	names.keycodes = xkbkeycodes;
+	    	names.types = xkbtypes;
+	    	names.compat = xkbcompat;
+	    	names.symbols = xkbsymbols;
+	    	names.geometry = xkbgeometry;
+	    }
+	if ((xkbkeymap || xkbcomponents_specified)
+	   && (xkbmodel == NULL || xkblayout == NULL)) {
+		xkbrules = NULL;
+	}
+#if 0
+	XkbSetRulesDflts(xkbrules, xkbmodel,
+			 xkblayout, xkbvariant,
+			 xkboptions);
+#endif
+	XkbInitKeyboardDeviceStruct(device, 
+				    &names,
+				    &keySyms, 
+				    modMap, 
+				    (BellProcPtr)rfbSendBell,
+				    (KbdCtrlProcPtr)NoopDDA);
+    }
+#endif
+	break;
+    case DEVICE_ON: 
+	pDev->on = TRUE;
+	KbdDeviceOn();
+	break;
+    case DEVICE_OFF: 
+	pDev->on = FALSE;
+	KbdDeviceOff();
+	break;
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    KbdDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static void
+xf86rfbKeybUninit(InputDriverPtr	drv,
+	       InputInfoPtr	pInfo,
+	       int		flags)
+{
+    xf86rfbKeybControlProc(pInfo->dev, DEVICE_OFF);
+}
+
+static InputInfoPtr
+xf86rfbKeybInit(InputDriverPtr	drv,
+	     IDevPtr		dev,
+	     int		flags)
+{
+    InputInfoPtr pInfo;
+    char *s;
+    Bool from;
+
+    if (!(pInfo = xf86AllocateInput(drv, 0)))
+	return NULL;
+
+    /* Initialise the InputInfoRec. */
+    pInfo->name = dev->identifier;
+    pInfo->type_name = "rfbKeyb";
+    pInfo->flags = XI86_KEYBOARD_CAPABLE;
+    pInfo->device_control = xf86rfbKeybControlProc;
+    pInfo->read_input = NULL;
+    pInfo->motion_history_proc = NULL;
+    pInfo->history_size = 0;
+    pInfo->control_proc = NULL;
+    pInfo->close_proc = NULL;
+    pInfo->switch_mode = NULL;
+    pInfo->conversion_proc = NULL;
+    pInfo->reverse_conversion_proc = NULL;
+    pInfo->fd = -1;
+    pInfo->dev = NULL;
+    pInfo->private_flags = 0;
+    pInfo->always_core_feedback = 0;
+    pInfo->conf_idev = dev;
+
+    /* Collect the options, and process the common options. */
+    xf86CollectInputOptions(pInfo, DEFAULTS, NULL);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    
+    /* Mark the device configured */
+    pInfo->flags |= XI86_CONFIGURED;
+
+#ifdef XKB
+  from = X_DEFAULT;
+  if (noXkbExtension)
+    from = X_CMDLINE;
+  else if (xf86FindOption(dev->commonOptions, "XkbDisable")) {
+    noXkbExtension =
+	xf86SetBoolOption(dev->commonOptions, "XkbDisable", FALSE);
+    from = X_CONFIG;
+  }
+  if (noXkbExtension)
+    xf86Msg(from, "XKB: disabled\n");
+
+#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL))
+
+  if (!noXkbExtension && !XkbInitialMap) {
+    if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeymap", NULL))) {
+      xkbkeymap = NULL_IF_EMPTY(s);
+      xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" "
+		"(overrides other XKB settings)\n", xkbkeymap);
+    } else {
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbCompat", NULL))) {
+	xkbcompat = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbTypes", NULL))) {
+	xkbtypes = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeycodes", NULL))) {
+	xkbkeycodes = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbGeometry", NULL))) {
+	xkbgeometry = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbSymbols", NULL))) {
+	xkbsymbols = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbRules", NULL))) {
+	xkbrules = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbModel", NULL))) {
+	xkbmodel = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbLayout", NULL))) {
+	xkblayout = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbVariant", NULL))) {
+	xkbvariant = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbOptions", NULL))) {
+	xkboptions = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s);
+      }
+    }
+  }
+#undef NULL_IF_EMPTY
+#endif
+
+    /* Return the configured device */
+    return (pInfo);
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec RFBKEYB = {
+    1,				/* driver version */
+    "rfbkeyb",			/* driver name */
+    NULL,			/* identify */
+    xf86rfbKeybInit,		/* pre-init */
+    xf86rfbKeybUninit,		/* un-init */
+    NULL,			/* module */
+    0				/* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+static void
+xf86rfbKeybUnplug(pointer	p)
+{
+}
+
+static pointer
+xf86rfbKeybPlug(pointer	module,
+	    pointer	options,
+	    int		*errmaj,
+	    int		*errmin)
+{
+    xf86AddInputDriver(&RFBKEYB, module, 0);
+
+    return module;
+}
+
+void
+vncInitKeyb(void)
+{
+    xf86AddInputDriver(&RFBKEYB, NULL, 0);
+}
+
+static XF86ModuleVersionInfo xf86rfbKeybVersionRec =
+{
+    "rfbkeyb",
+    "xf4vnc Project, see http://xf4vnc.sf.net",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XF86_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_XINPUT,
+    ABI_XINPUT_VERSION,
+    MOD_CLASS_XINPUT,
+    {0, 0, 0, 0}		/* signature, to be patched into the file by */
+				/* a tool */
+};
+
+XF86ModuleData rfbkeybModuleData = {&xf86rfbKeybVersionRec,
+				  xf86rfbKeybPlug,
+				  xf86rfbKeybUnplug};
+
+#endif /* XFree86LOADER */
+#endif
diff -u -rNp a/hw/vnc/rfbmouse.c b/hw/vnc/rfbmouse.c
--- a/hw/vnc/rfbmouse.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rfbmouse.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,244 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#if XFREE86VNC
+
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include <misc.h>
+#include <xf86.h>
+#define NEED_XF86_TYPES
+
+#if !defined(DGUX)
+#include <xf86_ansic.h>
+#include <xisb.h>
+#endif
+
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>		/* Needed for InitValuator/Proximity stuff */
+#include <X11/keysym.h>
+#include <mipointer.h>
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+
+static const char *DEFAULTS[] = {
+    NULL
+};
+#else
+#include <X11/keysym.h>
+#include <dix.h>
+#include <mipointer.h>
+#endif
+
+
+unsigned char ptrAcceleration = 50;
+
+void
+PtrDeviceOn(DeviceIntPtr pDev)
+{
+#if 0
+    ptrAcceleration = (unsigned char)pDev->ptrfeed->ctrl.num;
+#endif
+}
+
+void
+PtrDeviceInit(void)
+{
+}
+
+void
+PtrDeviceOff(void)
+{
+}
+
+
+void
+PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl)
+{
+#if 0
+    ptrAcceleration = (char)ctrl->num;
+
+    if (udpSockConnected) {
+	if (write(udpSock, &ptrAcceleration, 1) <= 0) {
+	    ErrorF("PtrDeviceControl: UDP input: write");
+	    rfbDisconnectUDPSock();
+	}
+    }
+#endif
+}
+
+#if XFREE86VNC
+static int
+xf86rfbMouseControlProc(DeviceIntPtr device, int onoff)
+{
+    BYTE map[6];
+    DevicePtr pDev = (DevicePtr)device;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT:
+	PtrDeviceInit();
+	map[1] = 1;
+	map[2] = 2;
+	map[3] = 3;
+	map[4] = 4;
+	map[5] = 5;
+	InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents,
+				PtrDeviceControl,
+				miPointerGetMotionBufferSize());
+	break;
+
+    case DEVICE_ON:
+	pDev->on = TRUE;
+	PtrDeviceOn(device);
+        break;
+
+    case DEVICE_OFF:
+	pDev->on = FALSE;
+	PtrDeviceOff();
+	break;
+
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    PtrDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static void
+xf86rfbMouseUninit(InputDriverPtr	drv,
+	       InputInfoPtr	pInfo,
+	       int		flags)
+{
+    xf86rfbMouseControlProc(pInfo->dev, DEVICE_OFF);
+}
+
+static InputInfoPtr
+xf86rfbMouseInit(InputDriverPtr	drv,
+	     IDevPtr		dev,
+	     int		flags)
+{
+    InputInfoPtr pInfo;
+
+    if (!(pInfo = xf86AllocateInput(drv, 0)))
+	return NULL;
+
+    /* Initialise the InputInfoRec. */
+    pInfo->name = dev->identifier;
+    pInfo->type_name = "rfbMouse";
+    pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+    pInfo->device_control = xf86rfbMouseControlProc;
+    pInfo->read_input = NULL;
+    pInfo->motion_history_proc = xf86GetMotionEvents;
+    pInfo->history_size = 0;
+    pInfo->control_proc = NULL;
+    pInfo->close_proc = NULL;
+    pInfo->switch_mode = NULL;
+    pInfo->conversion_proc = NULL;
+    pInfo->reverse_conversion_proc = NULL;
+    pInfo->fd = -1;
+    pInfo->dev = NULL;
+    pInfo->private_flags = 0;
+    pInfo->always_core_feedback = 0;
+    pInfo->conf_idev = dev;
+
+    /* Collect the options, and process the common options. */
+    xf86CollectInputOptions(pInfo, DEFAULTS, NULL);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    
+    /* Mark the device configured */
+    pInfo->flags |= XI86_CONFIGURED;
+
+    /* Return the configured device */
+    return (pInfo);
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec RFBMOUSE = {
+    1,				/* driver version */
+    "rfbmouse",			/* driver name */
+    NULL,			/* identify */
+    xf86rfbMouseInit,		/* pre-init */
+    xf86rfbMouseUninit,		/* un-init */
+    NULL,			/* module */
+    0				/* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+static void
+xf86rfbMouseUnplug(pointer	p)
+{
+}
+
+static pointer
+xf86rfbMousePlug(pointer	module,
+	    pointer	options,
+	    int		*errmaj,
+	    int		*errmin)
+{
+    xf86AddInputDriver(&RFBMOUSE, module, 0);
+
+    return module;
+}
+
+void
+vncInitMouse(void)
+{
+    xf86AddInputDriver(&RFBMOUSE, NULL, 0);
+}
+
+static XF86ModuleVersionInfo xf86rfbMouseVersionRec =
+{
+    "rfbmouse",
+    "xf4vnc Project, see http://xf4vnc.sf.net",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XF86_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_XINPUT,
+    ABI_XINPUT_VERSION,
+    MOD_CLASS_XINPUT,
+    {0, 0, 0, 0}		/* signature, to be patched into the file by */
+				/* a tool */
+};
+
+XF86ModuleData rfbmouseModuleData = {&xf86rfbMouseVersionRec,
+				  xf86rfbMousePlug,
+				  xf86rfbMouseUnplug};
+
+#endif /* XFree86LOADER */
+#endif
diff -u -rNp a/hw/vnc/rfbproto.h b/hw/vnc/rfbproto.h
--- a/hw/vnc/rfbproto.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rfbproto.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1347 @@
+/*
+ *  Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol, versions 3.3, 3.7 and 3.7t
+ * (protocol 3.7t is effectively 3.7 with TightVNC extensions enabled)
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first).  Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data.  The order of definitions in
+ * this file is as follows:
+ *
+ *  (1) Structures used in several types of message.
+ *  (2) Structures used in the initial handshaking.
+ *  (3) Message types.
+ *  (4) Encoding types.
+ *  (5) For each message type, the form of the data following the type byte.
+ *      Sometimes this is defined by a single structure but the more complex
+ *      messages have to be explained by comments.
+ */
+
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle.  This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+
+typedef struct _rfbRectangle {
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct _rfbPixelFormat {
+
+    CARD8 bitsPerPixel;		/* 8,16,32 only */
+
+    CARD8 depth;		/* 8 to 32 */
+
+    CARD8 bigEndian;		/* True if multi-byte pixels are interpreted
+				   as big endian, or if single-bit-per-pixel
+				   has most significant bit of the byte
+				   corresponding to first (leftmost) pixel. Of
+				   course this is meaningless for 8 bits/pix */
+
+    CARD8 trueColour;		/* If false then we need a "colour map" to
+				   convert pixels to RGB.  If true, xxxMax and
+				   xxxShift specify bits used for red, green
+				   and blue */
+
+    /* the following fields are only meaningful if trueColour is true */
+
+    CARD16 redMax;		/* maximum red value (= 2^n - 1 where n is the
+				   number of bits used for red). Note this
+				   value is always in big endian order. */
+
+    CARD16 greenMax;		/* similar for green */
+
+    CARD16 blueMax;		/* and blue */
+
+    CARD8 redShift;		/* number of shifts needed to get the red
+				   value in a pixel to the least significant
+				   bit. To find the red value from a given
+				   pixel, do the following:
+				   1) Swap pixel value according to bigEndian
+				      (e.g. if bigEndian is false and host byte
+				      order is big endian, then swap).
+				   2) Shift right by redShift.
+				   3) AND with redMax (in host byte order).
+				   4) You now have the red value between 0 and
+				      redMax. */
+
+    CARD8 greenShift;		/* similar for green */
+
+    CARD8 blueShift;		/* and blue */
+
+    CARD8 pad1;
+    CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to describe protocol options such as tunneling methods,
+ * authentication schemes and message types (protocol version 3.7t).
+ */
+
+typedef struct _rfbCapabilityInfo {
+
+    CARD32 code;		/* numeric identifier */
+    CARD8 vendorSignature[4];	/* vendor identification */
+    CARD8 nameSignature[8];	/* abbreviated option name */
+
+} rfbCapabilityInfo;
+
+#define sz_rfbCapabilityInfoVendor 4
+#define sz_rfbCapabilityInfoName 8
+#define sz_rfbCapabilityInfo 16
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define rfbStandardVendor "STDV"
+#define rfbTridiaVncVendor "TRDV"
+#define rfbTightVncVendor "TGHT"
+#define rfbTungstenGraphicsVendor "TGIV"
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports.  These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.7
+ * this is "RFB 003.007\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism.  Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent.  For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK.  This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 7
+#define rfbProtocolFallbackMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13];	/* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*
+ * Negotiation of the security type (protocol version 3.7)
+ *
+ * Once the protocol version has been decided, the server either sends a list
+ * of supported security types, or informs the client about an error (when the
+ * number of security types is 0).  Security type rfbSecTypeTight is used to
+ * enable TightVNC-specific protocol extensions.  The value rfbSecTypeVncAuth
+ * stands for classic VNC authentication.
+ *
+ * The client selects a particular security type from the list provided by the
+ * server.
+ */
+
+#define rfbSecTypeInvalid 0
+#define rfbSecTypeNone 1
+#define rfbSecTypeVncAuth 2
+#define rfbSecTypeTight 16
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Tunneling Capabilities (protocol version 3.7t)
+ *
+ * If the chosen security type is rfbSecTypeTight, the server sends a list of
+ * supported tunneling methods ("tunneling" refers to any additional layer of
+ * data transformation, such as encryption or external compression.)
+ *
+ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported tunneling methods in the order of preference.
+ *
+ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
+ * used, and the client should not send a response requesting a tunneling
+ * method.
+ */
+
+typedef struct _rfbTunnelingCapsMsg {
+    CARD32 nTunnelTypes;
+    /* followed by nTunnelTypes * rfbCapabilityInfo structures */
+} rfbTunnelingCapsMsg;
+
+#define sz_rfbTunnelingCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Tunneling Method Request (protocol version 3.7t)
+ *
+ * If the list of tunneling capabilities sent by the server was not empty, the
+ * client should reply with a 32-bit code specifying a particular tunneling
+ * method.  The following code should be used for no tunneling.
+ */
+
+#define rfbNoTunneling 0
+#define sig_rfbNoTunneling "NOTUNNEL"
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Authentication Capabilities (protocol version 3.7t)
+ *
+ * After setting up tunneling, the server sends a list of supported
+ * authentication schemes.
+ *
+ * nAuthTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported authentication schemes in the order of preference.
+ *
+ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is
+ * necessary, and the client should not send a response requesting an
+ * authentication scheme.
+ */
+
+typedef struct _rfbAuthenticationCapsMsg {
+    CARD32 nAuthTypes;
+    /* followed by nAuthTypes * rfbCapabilityInfo structures */
+} rfbAuthenticationCapsMsg;
+
+#define sz_rfbAuthenticationCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Authentication Scheme Request (protocol version 3.7t)
+ *
+ * If the list of authentication capabilities sent by the server was not empty,
+ * the client should reply with a 32-bit code specifying a particular
+ * authentication scheme.  The following codes are supported.
+ */
+
+#define rfbAuthNone 1
+#define rfbAuthVNC 2
+#define rfbAuthUnixLogin 129
+#define rfbAuthExternal 130
+
+#define sig_rfbAuthNone "NOAUTH__"
+#define sig_rfbAuthVNC "VNCAUTH_"
+#define sig_rfbAuthUnixLogin "ULGNAUTH"
+#define sig_rfbAuthExternal "XTRNAUTH"
+
+
+/*-----------------------------------------------------------------------------
+ * Standard VNC Authentication (all protocol versions)
+ *
+ * Standard authentication result codes are defined below.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct _rfbClientInitMsg {
+    CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct _rfbServerInitMsg {
+    CARD16 framebufferWidth;
+    CARD16 framebufferHeight;
+    rfbPixelFormat format;	/* the server's preferred pixel format */
+    CARD32 nameLength;
+    /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*-----------------------------------------------------------------------------
+ * Server Interaction Capabilities Message (protocol version 3.7t)
+ *
+ * In the protocol version 3.7t, the server informs the client what message
+ * types it supports in addition to ones defined in the protocol version 3.7.
+ * Also, the server sends the list of all supported encodings (note that it's
+ * not necessary to advertise the "raw" encoding sinse it MUST be supported in
+ * RFB 3.x protocols).
+ *
+ * This data immediately follows the server initialisation message.
+ */
+
+typedef struct _rfbInteractionCapsMsg {
+    CARD16 nServerMessageTypes;
+    CARD16 nClientMessageTypes;
+    CARD16 nEncodingTypes;
+    CARD16 pad;			/* reserved, must be 0 */
+    /* followed by nServerMessageTypes * rfbCapabilityInfo structures */
+    /* followed by nClientMessageTypes * rfbCapabilityInfo structures */
+} rfbInteractionCapsMsg;
+
+#define sz_rfbInteractionCapsMsg 8
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants.  Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest.  From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages.  The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+/* Chromium extensions, use higher values */
+#define rfbChromiumStart 50 
+#define rfbChromiumMoveResizeWindow 51
+#define rfbChromiumClipList 52
+#define rfbChromiumWindowShow 53
+
+#define rfbFileListData 130
+#define rfbFileDownloadData 131
+#define rfbFileUploadCancel 132
+#define rfbFileDownloadFailed 133
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListData "FTS_LSDT"
+#define sig_rfbFileDownloadData "FTS_DNDT"
+#define sig_rfbFileUploadCancel "FTS_UPCN"
+#define sig_rfbFileDownloadFailed "FTS_DNFL"
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1	/* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+/* Chromium extensions, use higher values */
+#define rfbChromiumStop 50
+#define rfbChromiumExpose 51
+
+#define rfbFileListRequest 130
+#define rfbFileDownloadRequest 131
+#define rfbFileUploadRequest 132
+#define rfbFileUploadData 133
+#define rfbFileDownloadCancel 134
+#define rfbFileUploadFailed 135
+#define rfbFileCreateDirRequest 136
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListRequest "FTC_LSRQ"
+#define sig_rfbFileDownloadRequest "FTC_DNRQ"
+#define sig_rfbFileUploadRequest "FTC_UPRQ"
+#define sig_rfbFileUploadData "FTC_UPDT"
+#define sig_rfbFileDownloadCancel "FTC_DNCN"
+#define sig_rfbFileUploadFailed "FTC_UPFL"
+#define sig_rfbFileCreateDirRequest "FTC_FCDR"
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw       0
+#define rfbEncodingCopyRect  1
+#define rfbEncodingRRE       2
+#define rfbEncodingCoRRE     4
+#define rfbEncodingHextile   5
+#define rfbEncodingZlib      6
+#define rfbEncodingTight     7
+#define rfbEncodingZlibHex   8
+
+/* signatures for basic encoding types */
+#define sig_rfbEncodingRaw       "RAW_____"
+#define sig_rfbEncodingCopyRect  "COPYRECT"
+#define sig_rfbEncodingRRE       "RRE_____"
+#define sig_rfbEncodingCoRRE     "CORRE___"
+#define sig_rfbEncodingHextile   "HEXTILE_"
+#define sig_rfbEncodingZlib      "ZLIB____"
+#define sig_rfbEncodingTight     "TIGHT___"
+#define sig_rfbEncodingZlibHex   "ZLIBHEX_"
+#define sig_rfbEncodingChromium  "CHROMIUM"
+
+/*
+ * Special encoding numbers:
+ *   0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
+ *   0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data;
+ *   0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions;
+ *   0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet;
+ *   0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor;
+ *   0xFFFFFFF0 .. 0xFFFFFFFF -- not allocated yet.
+ */
+
+#define rfbEncodingCompressLevel0  0xFFFFFF00
+#define rfbEncodingCompressLevel1  0xFFFFFF01
+#define rfbEncodingCompressLevel2  0xFFFFFF02
+#define rfbEncodingCompressLevel3  0xFFFFFF03
+#define rfbEncodingCompressLevel4  0xFFFFFF04
+#define rfbEncodingCompressLevel5  0xFFFFFF05
+#define rfbEncodingCompressLevel6  0xFFFFFF06
+#define rfbEncodingCompressLevel7  0xFFFFFF07
+#define rfbEncodingCompressLevel8  0xFFFFFF08
+#define rfbEncodingCompressLevel9  0xFFFFFF09
+
+#define rfbEncodingXCursor         0xFFFFFF10
+#define rfbEncodingRichCursor      0xFFFFFF11
+#define rfbEncodingPointerPos      0xFFFFFF18
+
+#define rfbEncodingLastRect        0xFFFFFF20
+#define rfbEncodingNewFBSize       0xFFFFFF21
+#define rfbEncodingChromium	   0xFFFFFF2F
+#define rfbEncodingChromium2	   0xFFFFFF30
+
+#define rfbEncodingQualityLevel0   0xFFFFFFE0
+#define rfbEncodingQualityLevel1   0xFFFFFFE1
+#define rfbEncodingQualityLevel2   0xFFFFFFE2
+#define rfbEncodingQualityLevel3   0xFFFFFFE3
+#define rfbEncodingQualityLevel4   0xFFFFFFE4
+#define rfbEncodingQualityLevel5   0xFFFFFFE5
+#define rfbEncodingQualityLevel6   0xFFFFFFE6
+#define rfbEncodingQualityLevel7   0xFFFFFFE7
+#define rfbEncodingQualityLevel8   0xFFFFFFE8
+#define rfbEncodingQualityLevel9   0xFFFFFFE9
+
+/* signatures for "fake" encoding types */
+#define sig_rfbEncodingCompressLevel0  "COMPRLVL"
+#define sig_rfbEncodingXCursor         "X11CURSR"
+#define sig_rfbEncodingRichCursor      "RCHCURSR"
+#define sig_rfbEncodingPointerPos      "POINTPOS"
+#define sig_rfbEncodingLastRect        "LASTRECT"
+#define sig_rfbEncodingNewFBSize       "NEWFBSIZ"
+#define sig_rfbEncodingQualityLevel0   "JPEGQLVL"
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves.  The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct _rfbFramebufferUpdateMsg {
+    CARD8 type;			/* always rfbFramebufferUpdate */
+    CARD8 pad;
+    CARD16 nRects;
+    /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data.  Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct _rfbFramebufferUpdateRectHeader {
+    rfbRectangle r;
+    CARD32 encoding;		/* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding.  Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding.  The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct _rfbCopyRect {
+    CARD16 srcX;
+    CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding.  We have an rfbRREHeader structure
+ * giving the number of subrectangles following.  Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct _rfbRREHeader {
+    CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding.  We have an rfbRREHeader structure giving
+ * the number of subrectangles following.  Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>].  This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct _rfbCoRRERectangle {
+    CARD8 x;
+    CARD8 y;
+    CARD8 w;
+    CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding.  The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order.  If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller.  Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller.  Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits.  If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile).  Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes.  The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ *    the background colour for this tile.  The first non-raw tile in a
+ *    rectangle must have this bit set.  If this bit isn't set then the
+ *    background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ *    the foreground colour to be used for all subrectangles in this tile.
+ *    If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ *    subrectangles following.  If not set, there are no subrectangles (i.e.
+ *    the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ *    value giving the colour of that subrectangle.  If not set, all
+ *    subrectangles are the same colour, the foreground colour;  if the
+ *    ForegroundSpecified bit wasn't set then the foreground is the same as
+ *    the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes.  The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw			(1 << 0)
+#define rfbHextileBackgroundSpecified	(1 << 1)
+#define rfbHextileForegroundSpecified	(1 << 2)
+#define rfbHextileAnySubrects		(1 << 3)
+#define rfbHextileSubrectsColoured	(1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZLIB - zlib compression Encoding.  We have an rfbZlibHeader structure
+ * giving the number of bytes to follow.  Finally the data follows in
+ * zlib compressed format.
+ */
+
+typedef struct _rfbZlibHeader {
+    CARD32 nBytes;
+} rfbZlibHeader;
+
+#define sz_rfbZlibHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Tight Encoding.
+ *
+ *-- The first byte of each Tight-encoded rectangle is a "compression control
+ *   byte". Its format is as follows (bit 0 is the least significant one):
+ *
+ *   bit 0:    if 1, then compression stream 0 should be reset;
+ *   bit 1:    if 1, then compression stream 1 should be reset;
+ *   bit 2:    if 1, then compression stream 2 should be reset;
+ *   bit 3:    if 1, then compression stream 3 should be reset;
+ *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
+ *             if 1001 (0x09), then the compression type is "jpeg",
+ *             if 0xxx, then the compression type is "basic",
+ *             values greater than 1001 are not valid.
+ *
+ * If the compression type is "basic", then bits 6..4 of the
+ * compression control byte (those xxx in 0xxx) specify the following:
+ *
+ *   bits 5-4:  decimal representation is the index of a particular zlib
+ *              stream which should be used for decompressing the data;
+ *   bit 6:     if 1, then a "filter id" byte is following this byte.
+ *
+ *-- The data that follows after the compression control byte described
+ * above depends on the compression type ("fill", "jpeg" or "basic").
+ *
+ *-- If the compression type is "fill", then the only pixel value follows, in
+ * client pixel format (see NOTE 1). This value applies to all pixels of the
+ * rectangle.
+ *
+ *-- If the compression type is "jpeg", the following data stream looks like
+ * this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     JPEG image.
+ *
+ * Data size is compactly represented in one, two or three bytes, according
+ * to the following scheme:
+ *
+ *  0xxxxxxx                    (for values 0..127)
+ *  1xxxxxxx 0yyyyyyy           (for values 128..16383)
+ *  1xxxxxxx 1yyyyyyy zzzzzzzz  (for values 16384..4194303)
+ *
+ * Here each character denotes one bit, xxxxxxx are the least significant 7
+ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
+ * most significant 8 bits (bits 14-21). For example, decimal value 10000
+ * should be represented as two bytes: binary 10010000 01001110, or
+ * hexadecimal 90 4E.
+ *
+ *-- If the compression type is "basic" and bit 6 of the compression control
+ * byte was set to 1, then the next (second) byte specifies "filter id" which
+ * tells the decoder what filter type was used by the encoder to pre-process
+ * pixel data before the compression. The "filter id" byte can be one of the
+ * following:
+ *
+ *   0:  no filter ("copy" filter);
+ *   1:  "palette" filter;
+ *   2:  "gradient" filter.
+ *
+ *-- If bit 6 of the compression control byte is set to 0 (no "filter id"
+ * byte), or if the filter id is 0, then raw pixel values in the client
+ * format (see NOTE 1) will be compressed. See below details on the
+ * compression.
+ *
+ *-- The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better. 
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ *   if (P[i,j] < 0) then P[i,j] := 0;
+ *   if (P[i,j] > MAX) then P[i,j] := MAX;
+ *   D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.
+ *
+ *-- The "palette" filter converts true-color pixel data to indexed colors
+ * and a palette which can consist of 2..256 colors. If the number of colors
+ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
+ * encode one pixel. 1-bit encoding is performed such way that the most
+ * significant bits correspond to the leftmost pixels, and each raw of pixels
+ * is aligned to the byte boundary. When "palette" filter is used, the
+ * palette is sent before the pixel data. The palette begins with an unsigned
+ * byte which value is the number of colors in the palette minus 1 (i.e. 1
+ * means 2 colors, 255 means 256 colors in the palette). Then follows the
+ * palette itself which consist of pixel values in client pixel format (see
+ * NOTE 1).
+ *
+ *-- The pixel data is compressed using the zlib library. But if the data
+ * size after applying the filter but before the compression is less then 12,
+ * then the data is sent as is, uncompressed. Four separate zlib streams
+ * (0..3) can be used and the decoder should read the actual stream id from
+ * the compression control byte (see NOTE 2).
+ *
+ * If the compression is not used, then the pixel data is sent as is,
+ * otherwise the data stream looks like this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     zlib-compressed data.
+ *
+ * Data size is compactly represented in one, two or three bytes, just like
+ * in the "jpeg" compression method (see above).
+ *
+ *-- NOTE 1. If the color depth is 24, and all three color components are
+ * 8-bit wide, then one pixel in Tight encoding is always represented by
+ * three bytes, where the first byte is red component, the second byte is
+ * green component, and the third byte is blue component of the pixel color
+ * value. This applies to colors in palettes as well.
+ *
+ *-- NOTE 2. The decoder must reset compression streams' states before
+ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
+ * byte are set to 1. Note that the decoder must reset zlib streams even if
+ * the compression type is "fill" or "jpeg".
+ *
+ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
+ * when bits-per-pixel value is either 16 or 32, not 8.
+ *
+ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
+ * pixels. If a rectangle is wider, it must be split into several rectangles
+ * and each one should be encoded separately.
+ *
+ */
+
+#define rfbTightExplicitFilter         0x04
+#define rfbTightFill                   0x08
+#define rfbTightJpeg                   0x09
+#define rfbTightMaxSubencoding         0x09
+
+/* Filters to improve compression efficiency */
+#define rfbTightFilterCopy             0x00
+#define rfbTightFilterPalette          0x01
+#define rfbTightFilterGradient         0x02
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZLIBHEX - zlib compressed Hextile Encoding.  Essentially, this is the
+ * hextile encoding with zlib compression on the tiles that can not be
+ * efficiently encoded with one of the other hextile subencodings.  The
+ * new zlib subencoding uses two bytes to specify the length of the
+ * compressed tile and then the compressed data follows.  As with the
+ * raw sub-encoding, the zlib subencoding invalidates the other
+ * values, if they are also set.
+ */
+
+#define rfbHextileZlibRaw		(1 << 5)
+#define rfbHextileZlibHex		(1 << 6)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * XCursor encoding. This is a special encoding used to transmit X-style
+ * cursor shapes from server to clients. Note that for this encoding,
+ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot
+ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB
+ * samples are sent after header in the rfbXCursorColors structure. They
+ * denote foreground and background colors of the cursor. If a client
+ * supports only black-and-white cursors, it should ignore these colors and
+ * assume that foreground is black and background is white. Next, two bitmaps
+ * (1 bits per pixel) follow: first one with actual data (value 0 denotes
+ * background color, value 1 denotes foreground color), second one with
+ * transparency data (bits with zero value mean that these pixels are
+ * transparent). Both bitmaps represent cursor data in a byte stream, from
+ * left to right, from top to bottom, and each row is byte-aligned. Most
+ * significant bits correspond to leftmost pixels. The number of bytes in
+ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor
+ * should be hidden (or default local cursor should be set by the client).
+ */
+
+typedef struct _rfbXCursorColors {
+    CARD8 foreRed;
+    CARD8 foreGreen;
+    CARD8 foreBlue;
+    CARD8 backRed;
+    CARD8 backGreen;
+    CARD8 backBlue;
+} rfbXCursorColors;
+
+#define sz_rfbXCursorColors 6
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RichCursor encoding. This is a special encoding used to transmit cursor
+ * shapes from server to clients. It is similar to the XCursor encoding but
+ * uses client pixel format instead of two RGB colors to represent cursor
+ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader
+ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h).
+ * After header, two pixmaps follow: first one with cursor image in current
+ * client pixel format (like in raw encoding), second with transparency data
+ * (1 bit per pixel, exactly the same format as used for transparency bitmap
+ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or
+ * default local cursor should be set by the client).
+ */
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries.  In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest.  So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct _rfbSetColourMapEntriesMsg {
+    CARD8 type;			/* always rfbSetColourMapEntries */
+    CARD8 redIndex;		/* used to be pad, but used for DirectColor */
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct _rfbBellMsg {
+    CARD8 type;			/* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct _rfbServerCutTextMsg {
+    CARD8 type;			/* always rfbServerCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ChromiumStart - a port number for the crserver
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumStart */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 crServerPort;
+    CARD32 mothershipPort;
+} rfbChromiumStartMsg;
+
+#define sz_rfbChromiumStartMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * ChromiumMoveResizeWindow - move a chromium window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumMoveResizeWindow */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 x;
+    CARD32 y;
+    CARD32 w;
+    CARD32 h;
+} rfbChromiumMoveResizeWindowMsg;
+
+#define sz_rfbChromiumMoveResizeWindowMsg 24
+
+/*-----------------------------------------------------------------------------
+ * ChromiumClipList - send clip list
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumClipList */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 length;
+} rfbChromiumClipListMsg;
+
+#define sz_rfbChromiumClipListMsg 12
+
+/*-----------------------------------------------------------------------------
+ * ChromiumWindowShow - map or unmap a window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumWindowShow */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 show;
+} rfbChromiumWindowShowMsg;
+
+#define sz_rfbChromiumWindowShowMsg 12
+
+/*-----------------------------------------------------------------------------
+ * FileListData
+ */
+
+typedef struct _rfbFileListDataMsg {
+    CARD8 type;
+    CARD8 flags;
+    CARD16 numFiles;
+    CARD16 dataSize;
+    CARD16 compressedSize;
+    /* Followed by SizeData[numFiles] */
+    /* Followed by Filenames[compressedSize] */
+} rfbFileListDataMsg;
+
+#define sz_rfbFileListDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadData
+ */
+
+typedef struct _rfbFileDownloadDataMsg {
+    CARD8 type;
+    CARD8 compressLevel;
+    CARD16 realSize;
+    CARD16 compressedSize;
+    /* Followed by File[copressedSize] */
+} rfbFileDownloadDataMsg;
+
+#define sz_rfbFileDownloadDataMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadCancel
+ */
+
+typedef struct _rfbFileUploadCancelMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileUploadCancelMsg;
+
+#define sz_rfbFileUploadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadFailed
+ */
+
+typedef struct _rfbFileDownloadFailedMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileDownloadFailedMsg;
+
+#define sz_rfbFileDownloadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union _rfbServerToClientMsg {
+    CARD8 type;
+    rfbFramebufferUpdateMsg fu;
+    rfbSetColourMapEntriesMsg scme;
+    rfbBellMsg b;
+    rfbServerCutTextMsg sct;
+    rfbFileListDataMsg fld;
+    rfbFileDownloadDataMsg fdd;
+    rfbFileUploadCancelMsg fuc;
+    rfbFileDownloadFailedMsg fdf;
+    rfbChromiumStartMsg scd;
+    rfbChromiumMoveResizeWindowMsg scm;
+    rfbChromiumClipListMsg sccl;
+    rfbChromiumWindowShowMsg scws;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct _rfbSetPixelFormatMsg {
+    CARD8 type;			/* always rfbSetPixelFormat */
+    CARD8 pad1;
+    CARD16 pad2;
+    rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ *    ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct _rfbFixColourMapEntriesMsg {
+    CARD8 type;			/* always rfbFixColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept.  Put them
+ * in order of preference, if we have any.  We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct _rfbSetEncodingsMsg {
+    CARD8 type;			/* always rfbSetEncodings */
+    CARD8 pad;
+    CARD16 nEncodings;
+    /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update.  If incremental
+ * is true then the client just wants the changes since the last update.  If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct _rfbFramebufferUpdateRequestMsg {
+    CARD8 type;			/* always rfbFramebufferUpdateRequest */
+    CARD8 incremental;
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value.  Other common keys are:
+ *
+ * BackSpace		0xff08
+ * Tab			0xff09
+ * Return or Enter	0xff0d
+ * Escape		0xff1b
+ * Insert		0xff63
+ * Delete		0xffff
+ * Home			0xff50
+ * End			0xff57
+ * Page Up		0xff55
+ * Page Down		0xff56
+ * Left			0xff51
+ * Up			0xff52
+ * Right		0xff53
+ * Down			0xff54
+ * F1			0xffbe
+ * F2			0xffbf
+ * ...			...
+ * F12			0xffc9
+ * Shift		0xffe1
+ * Control		0xffe3
+ * Meta			0xffe7
+ * Alt			0xffe9
+ */
+
+typedef struct _rfbKeyEventMsg {
+    CARD8 type;			/* always rfbKeyEvent */
+    CARD8 down;			/* true if down (press), false if up */
+    CARD16 pad;
+    CARD32 key;			/* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct _rfbPointerEventMsg {
+    CARD8 type;			/* always rfbPointerEvent */
+    CARD8 buttonMask;		/* bits 0-7 are buttons 1-8, 0=up, 1=down */
+    CARD16 x;
+    CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+#define rfbButton4Mask 8
+#define rfbButton5Mask 16
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct _rfbClientCutTextMsg {
+    CARD8 type;			/* always rfbClientCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileListRequest
+ */
+
+typedef struct _rfbFileListRequestMsg {
+    CARD8 type;
+    CARD8 flags;
+    CARD16 dirNameSize;
+    /* Followed by char Dirname[dirNameSize] */
+} rfbFileListRequestMsg;
+
+#define sz_rfbFileListRequestMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadRequest
+ */
+
+typedef struct _rfbFileDownloadRequestMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 fNameSize;
+    CARD32 position;
+    /* Followed by char Filename[fNameSize] */
+} rfbFileDownloadRequestMsg;
+
+#define sz_rfbFileDownloadRequestMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileUploadRequest
+ */
+
+typedef struct _rfbFileUploadRequestMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 fNameSize;
+    CARD32 position;
+    /* Followed by char Filename[fNameSize] */
+} rfbFileUploadRequestMsg;
+
+#define sz_rfbFileUploadRequestMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadData
+ */
+
+typedef struct _rfbFileUploadDataMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 realSize;
+    CARD16 compressedSize;
+    /* Followed by File[compressedSize]   */
+} rfbFileUploadDataMsg;
+
+#define sz_rfbFileUploadDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadCancel
+ */
+
+typedef struct _rfbFileDownloadCancelMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileDownloadCancelMsg;
+
+#define sz_rfbFileDownloadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileUploadFailed
+ */
+
+typedef struct _rfbFileUploadFailedMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileUploadFailedMsg;
+
+#define sz_rfbFileUploadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileCreateDirRequest
+ */
+
+typedef struct _rfbFileCreateDirRequestMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 dNameLen;
+    CARD32 dModTime;
+    /* Followed by dName[dNameLen] */
+} rfbFileCreateDirRequestMsg;
+ 
+#define sz_rfbFileCreateDirRequestMsg 8
+ 
+/*-----------------------------------------------------------------------------
+ * ChromiumStop - the client has stopped the GL app.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumStop */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 port;
+} rfbChromiumStopMsg;
+
+#define sz_rfbChromiumStopMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ChromiumExpose - redraw the window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumExpose */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+} rfbChromiumExposeMsg;
+
+#define sz_rfbChromiumExposeMsg 8
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union _rfbClientToServerMsg {
+    CARD8 type;
+    rfbSetPixelFormatMsg spf;
+    rfbFixColourMapEntriesMsg fcme;
+    rfbSetEncodingsMsg se;
+    rfbFramebufferUpdateRequestMsg fur;
+    rfbKeyEventMsg ke;
+    rfbPointerEventMsg pe;
+    rfbClientCutTextMsg cct;
+    rfbFileListRequestMsg flr;
+    rfbFileDownloadRequestMsg fdr;
+    rfbFileUploadRequestMsg fupr;
+    rfbFileUploadDataMsg fud;
+    rfbFileDownloadCancelMsg fdc;
+    rfbFileUploadFailedMsg fuf;
+    rfbFileCreateDirRequestMsg fcdr;
+    rfbChromiumStopMsg csd;
+    rfbChromiumExposeMsg cse;
+} rfbClientToServerMsg;
diff -u -rNp a/hw/vnc/rfbserver.c b/hw/vnc/rfbserver.c
--- a/hw/vnc/rfbserver.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rfbserver.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2273 @@
+/*
+ * rfbserver.c - deal with server-side of the RFB protocol.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000-2004 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* Use ``#define CORBA'' to enable CORBA control interface */
+
+#include "rfb.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <X11/Xatom.h>
+#include "windowstr.h"
+#include "input.h"
+#include "mipointer.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+#ifdef CHROMIUM
+#include "mivalidate.h"
+#endif
+#include "sprite.h"
+#include "propertyst.h"
+#include <mi.h>
+
+#ifdef CORBA
+#include <vncserverctrl.h>
+#endif
+
+#ifdef CHROMIUM
+struct CRWindowTable *windowTable = NULL;
+#endif
+
+extern Atom VNC_CONNECT;
+
+rfbClientPtr rfbClientHead = NULL;
+rfbClientPtr pointerClient = NULL;  /* Mutex for pointer events */
+
+static rfbClientPtr rfbNewClient(ScreenPtr pScreen, int sock);
+static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
+static void rfbProcessClientInitMessage(rfbClientPtr cl);
+static void rfbSendInteractionCaps(rfbClientPtr cl);
+static void rfbProcessClientNormalMessage(rfbClientPtr cl);
+static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy);
+static Bool rfbSendLastRectMarker(rfbClientPtr cl);
+
+static char *text = NULL;
+
+void
+rfbRootPropertyChange(ScreenPtr pScreen)
+{
+    PropertyPtr pProp;
+    WindowPtr pWin = WindowTable[pScreen->myNum];
+
+    pProp = wUserProps (pWin);
+
+    while (pProp) {
+        if ((pProp->propertyName == XA_CUT_BUFFER0) && 
+	    (pProp->type == XA_STRING) &&
+	    (pProp->format == 8))
+    	{
+	    /* Ensure we don't keep re-sending cut buffer */
+
+    	    if ( (text && pProp->data && strncmp(text, pProp->data, pProp->size)) || !text)
+	    	rfbGotXCutText(pProp->data, pProp->size);
+
+	    if (text) xfree(text);
+    	    text = xalloc(1 + pProp->size);
+    	    if (! text) return;
+    	    if (pProp->data) memcpy(text, pProp->data, pProp->size);
+    	    text[pProp->size] = '\0';
+
+	    return;
+    	}
+    	if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING)
+	    && (pProp->format == 8) && (pProp->size > 0))
+    	{
+	    int i;
+	    rfbClientPtr cl;
+	    int port = 5500;
+	    char *host = (char *)Xalloc(pProp->size+1);
+	    memcpy(host, pProp->data, pProp->size);
+	    host[pProp->size] = 0;
+	    for (i = 0; i < pProp->size; i++) {
+	    	if (host[i] == ':') {
+		    port = atoi(&host[i+1]);
+		    host[i] = 0;
+	    	}
+	    }
+
+	    cl = rfbReverseConnection(pScreen, host, port);
+
+#ifdef CORBA
+	    if (cl != NULL)
+	    	newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+
+	    ChangeWindowProperty(pWin,
+		 	     pProp->propertyName, pProp->type,
+			     pProp->format, PropModeReplace,
+			     0, NULL,
+			     FALSE
+			     );
+
+	    free(host);
+    	}
+	pProp = pProp->next;
+    }
+}
+
+int
+rfbBitsPerPixel(depth)
+    int depth;
+{
+    if (depth == 1) return 1;
+    else if (depth <= 8) return 8;
+    else if (depth <= 16) return 16;
+    else return 32;
+}
+
+void 
+rfbUserAllow(int sock, int accept)
+{
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (cl->sock == sock) {
+	    cl->userAccepted = accept;
+	}
+    }
+}
+
+/*
+ * rfbNewClientConnection is called from sockets.c when a new connection
+ * comes in.
+ */
+
+void
+rfbNewClientConnection(ScreenPtr pScreen, int sock)
+{
+    rfbClientPtr cl;
+
+    cl = rfbNewClient(pScreen, sock);
+
+    GenerateVncConnectedEvent(sock);
+
+#if XFREE86VNC
+    /* Someone is connected - disable VT switching */
+    xf86EnableVTSwitch(FALSE);
+#endif
+
+#ifdef CORBA
+    if (cl != NULL)
+	newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+}
+
+
+/*
+ * rfbReverseConnection is called by the CORBA stuff to make an outward
+ * connection to a "listening" RFB client.
+ */
+
+rfbClientPtr
+rfbReverseConnection(ScreenPtr pScreen, char *host, int port)
+{
+    int sock;
+    rfbClientPtr cl;
+
+    if ((sock = rfbConnect(pScreen, host, port)) < 0)
+	return (rfbClientPtr)NULL;
+
+    cl = rfbNewClient(pScreen, sock);
+
+    if (cl) {
+	cl->reverseConnection = TRUE;
+    }
+
+    return cl;
+}
+
+
+#ifdef CHROMIUM
+/*
+ * rfbSetClip --
+ * 	Generate expose event.
+ * 	This function is overkill and should be cleaned up, but it
+ * 	works for now.
+ */
+
+void
+rfbSetClip (WindowPtr pWin, BOOL enable)
+{
+    ScreenPtr   pScreen = pWin->drawable.pScreen;
+    WindowPtr	pChild;
+    Bool	WasViewable = (Bool)(pWin->viewable);
+    Bool	anyMarked = FALSE;
+    RegionPtr	pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+    Bool	dosave = FALSE;
+#endif
+    WindowPtr   pLayerWin;
+    BoxRec	box;
+
+    if (WasViewable)
+    {
+	for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+	{
+	    (void) (*pScreen->MarkOverlappedWindows)(pChild,
+						     pChild,
+						     &pLayerWin);
+	}
+	(*pScreen->MarkWindow) (pWin);
+	anyMarked = TRUE;
+	if (pWin->valdata)
+	{
+	    if (HasBorder (pWin))
+	    {
+		RegionPtr	borderVisible;
+
+		borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+		REGION_SUBTRACT(pScreen, borderVisible,
+				&pWin->borderClip, &pWin->winSize);
+		pWin->valdata->before.borderVisible = borderVisible;
+	    }
+	    pWin->valdata->before.resized = TRUE;
+	}
+    }
+    
+    /*
+     * Use REGION_BREAK to avoid optimizations in ValidateTree
+     * that assume the root borderClip can't change well, normally
+     * it doesn't...)
+     */
+    if (enable)
+    {
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = pScreen->width;
+	box.y2 = pScreen->height;
+	REGION_INIT (pScreen, &pWin->winSize, &box, 1);
+	REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
+	if (WasViewable)
+	    REGION_RESET(pScreen, &pWin->borderClip, &box);
+	pWin->drawable.width = pScreen->width;
+	pWin->drawable.height = pScreen->height;
+        REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    else
+    {
+	REGION_EMPTY(pScreen, &pWin->borderClip);
+	REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    
+    ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
+    
+    if (WasViewable)
+    {
+	if (pWin->backStorage)
+	{
+	    pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+	    REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+	}
+
+	if (pWin->firstChild)
+	{
+	    anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
+							   pWin->firstChild,
+							   (WindowPtr *)NULL);
+	}
+	else
+	{
+	    (*pScreen->MarkWindow) (pWin);
+	    anyMarked = TRUE;
+	}
+
+#ifdef DO_SAVE_UNDERS
+	if (DO_SAVE_UNDERS(pWin))
+	{
+	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
+	}
+#endif /* DO_SAVE_UNDERS */
+
+	if (anyMarked)
+	    (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
+    }
+
+    if (pWin->backStorage &&
+	((pWin->backingStore == Always) || WasViewable))
+    {
+	if (!WasViewable)
+	    pOldClip = &pWin->clipList; /* a convenient empty region */
+	bsExposed = (*pScreen->TranslateBackingStore)
+			     (pWin, 0, 0, pOldClip,
+			      pWin->drawable.x, pWin->drawable.y);
+	if (WasViewable)
+	    REGION_DESTROY(pScreen, pOldClip);
+	if (bsExposed)
+	{
+	    RegionPtr	valExposed = NullRegion;
+    
+	    if (pWin->valdata)
+		valExposed = &pWin->valdata->after.exposed;
+	    (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+	    if (valExposed)
+		REGION_EMPTY(pScreen, valExposed);
+	    REGION_DESTROY(pScreen, bsExposed);
+	}
+    }
+    if (WasViewable)
+    {
+	if (anyMarked)
+	    (*pScreen->HandleExposures)(pWin);
+#ifdef DO_SAVE_UNDERS
+	if (dosave)
+	    (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
+#endif /* DO_SAVE_UNDERS */
+	if (anyMarked && pScreen->PostValidateTree)
+	    (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
+    }
+    if (pWin->realized)
+	WindowsRestructured ();
+    FlushAllOutput ();
+}
+#endif /* CHROMIUM */
+
+/*
+ * rfbNewClient is called when a new connection has been made by whatever
+ * means.
+ */
+
+static rfbClientPtr
+rfbNewClient(ScreenPtr pScreen, int sock)
+{
+    rfbProtocolVersionMsg pv;
+    rfbClientPtr cl;
+    BoxRec box;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
+    VNCSCREENPTR(pScreen);
+    int i;
+
+    if (rfbClientHead == NULL) {
+	/* no other clients - make sure we don't think any keys are pressed */
+	KbdReleaseAllKeys();
+    } else {
+	rfbLog("  (other clients");
+	for (cl = rfbClientHead; cl; cl = cl->next) {
+	    rfbLog(" %s",cl->host);
+	}
+	rfbLog(")\n");
+    }
+
+    cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec));
+
+#ifdef CHROMIUM
+    cl->chromium_port = 0; /* no GL application on this port, yet */
+#endif
+    cl->userAccepted = 0; /* user hasn't even approached this yet .... */
+    cl->sock = sock;
+    getpeername(sock, (struct sockaddr *)&addr, &addrlen);
+    cl->host = strdup(inet_ntoa(addr.sin_addr));
+    cl->login = NULL;
+
+    /* Dispatch client input to rfbProcessClientProtocolVersion(). */
+    cl->state = RFB_PROTOCOL_VERSION;
+
+    cl->viewOnly = FALSE;
+    cl->reverseConnection = FALSE;
+    cl->readyForSetColourMapEntries = FALSE;
+    cl->useCopyRect = FALSE;
+    cl->preferredEncoding = rfbEncodingRaw;
+    cl->correMaxWidth = 48;
+    cl->correMaxHeight = 48;
+    cl->pScreen = pScreen;
+
+    REGION_NULL(pScreen,&cl->copyRegion);
+    cl->copyDX = 0;
+    cl->copyDY = 0;
+
+    box.x1 = box.y1 = 0;
+    box.x2 = pVNC->width;
+    box.y2 = pVNC->height;
+    REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
+
+    REGION_NULL(pScreen,&cl->requestedRegion);
+
+    cl->deferredUpdateScheduled = FALSE;
+    cl->deferredUpdateTimer = NULL;
+
+    cl->format = pVNC->rfbServerFormat;
+    cl->translateFn = rfbTranslateNone;
+    cl->translateLookupTable = NULL;
+
+    cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+    cl->tightQualityLevel = -1;
+    for (i = 0; i < 4; i++)
+        cl->zsActive[i] = FALSE;
+
+    cl->enableCursorShapeUpdates = FALSE;
+    cl->enableCursorPosUpdates = FALSE;
+    cl->enableLastRectEncoding = FALSE;
+#ifdef CHROMIUM
+    cl->enableChromiumEncoding = FALSE;
+#endif
+
+    cl->next = rfbClientHead;
+    rfbClientHead = cl;
+
+    rfbResetStats(cl);
+
+    cl->compStreamInited = FALSE;
+    cl->compStream.total_in = 0;
+    cl->compStream.total_out = 0;
+    cl->compStream.zalloc = Z_NULL;
+    cl->compStream.zfree = Z_NULL;
+    cl->compStream.opaque = Z_NULL;
+
+    cl->zlibCompressLevel = 5;
+
+    sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
+	    rfbProtocolMinorVersion);
+
+    if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) {
+	rfbLogPerror("rfbNewClient: write");
+	rfbCloseSock(pScreen, sock);
+	return NULL;
+    }
+
+    return cl;
+}
+
+
+/*
+ * rfbClientConnectionGone is called from sockets.c just after a connection
+ * has gone away.
+ */
+
+void
+rfbClientConnectionGone(sock)
+    int sock;
+{
+    rfbClientPtr cl, prev;
+    int i;
+#if XFREE86VNC
+    int allowvt = TRUE;
+#endif
+
+    for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) {
+	if (sock == cl->sock)
+	    break;
+    }
+
+    if (!cl) {
+	rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock);
+	return;
+    }
+
+    if (cl->login != NULL) {
+	rfbLog("Client %s (%s) gone\n", cl->login, cl->host);
+	free(cl->login);
+    } else {
+	rfbLog("Client %s gone\n", cl->host);
+    }
+    free(cl->host);
+
+    /* Release the compression state structures if any. */
+    if ( cl->compStreamInited == TRUE ) {
+	deflateEnd( &(cl->compStream) );
+    }
+
+    for (i = 0; i < 4; i++) {
+	if (cl->zsActive[i])
+	    deflateEnd(&cl->zsStruct[i]);
+    }
+
+    if (pointerClient == cl)
+	pointerClient = NULL;
+
+#ifdef CORBA
+    destroyConnection(cl);
+#endif
+
+    if (prev)
+	prev->next = cl->next;
+    else
+	rfbClientHead = cl->next;
+
+    REGION_UNINIT(cl->pScreen,&cl->copyRegion);
+    REGION_UNINIT(cl->pScreen,&cl->modifiedRegion);
+    TimerFree(cl->deferredUpdateTimer);
+
+    rfbPrintStats(cl);
+
+    if (cl->translateLookupTable) free(cl->translateLookupTable);
+
+    xfree(cl);
+
+    GenerateVncDisconnectedEvent(sock);
+
+#if XFREE86VNC
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	/* still someone connected */
+	allowvt = FALSE;
+    }
+
+    xf86EnableVTSwitch(allowvt);
+#endif
+}
+
+
+/*
+ * rfbProcessClientMessage is called when there is data to read from a client.
+ */
+
+void
+rfbProcessClientMessage(ScreenPtr pScreen, int sock)
+{
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (sock == cl->sock)
+	    break;
+    }
+
+    if (!cl) {
+	rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock);
+	rfbCloseSock(pScreen, sock);
+	return;
+    }
+
+#ifdef CORBA
+    if (isClosePending(cl)) {
+	rfbLog("Closing connection to client %s\n", cl->host);
+	rfbCloseSock(pScreen, sock);
+	return;
+    }
+#endif
+
+    switch (cl->state) {
+    case RFB_PROTOCOL_VERSION:
+	rfbProcessClientProtocolVersion(cl);
+	break;
+    case RFB_SECURITY_TYPE:	/* protocol 3.7 */
+	rfbProcessClientSecurityType(cl);
+	break;
+    case RFB_TUNNELING_TYPE:	/* protocol 3.7t */
+	rfbProcessClientTunnelingType(cl);
+	break;
+    case RFB_AUTH_TYPE:		/* protocol 3.7t */
+	rfbProcessClientAuthType(cl);
+	break;
+    case RFB_AUTHENTICATION:
+	rfbVncAuthProcessResponse(cl);
+	break;
+    case RFB_INITIALISATION:
+	rfbProcessClientInitMessage(cl);
+	break;
+    default:
+	rfbProcessClientNormalMessage(cl);
+    }
+}
+
+
+/*
+ * rfbProcessClientProtocolVersion is called when the client sends its
+ * protocol version.
+ */
+
+static void
+rfbProcessClientProtocolVersion(cl)
+    rfbClientPtr cl;
+{
+    rfbProtocolVersionMsg pv;
+    int n, major, minor;
+
+    if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientProtocolVersion: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientProtocolVersion: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    pv[sz_rfbProtocolVersionMsg] = 0;
+    if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
+	rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    rfbLog("Using protocol version %d.%d\n", major, minor);
+
+    if (major != rfbProtocolMajorVersion) {
+	rfbLog("RFB protocol version mismatch - server %d.%d, client %d.%d\n",
+		rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Always use one of the two standard versions of the RFB protocol. */
+    cl->protocol_minor_ver = minor;
+    if (minor > rfbProtocolMinorVersion) {
+	cl->protocol_minor_ver = rfbProtocolMinorVersion;
+    } else if (minor < rfbProtocolMinorVersion) {
+	cl->protocol_minor_ver = rfbProtocolFallbackMinorVersion;
+    }
+    if (minor != rfbProtocolMinorVersion &&
+	minor != rfbProtocolFallbackMinorVersion) {
+	rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n",
+	       major, minor, rfbProtocolMajorVersion, cl->protocol_minor_ver);
+    }
+ 
+    /* TightVNC protocol extensions are not enabled yet. */
+    cl->protocol_tightvnc = FALSE;
+
+    rfbAuthNewClient(cl);
+}
+
+/*
+ * rfbClientConnFailed is called when a client connection has failed
+ * before the authentication stage.
+ */
+
+void
+rfbClientConnFailed(cl, reason)
+    rfbClientPtr cl;
+    char *reason;
+{
+    int headerLen, reasonLen;
+    char buf[8];
+
+    headerLen = (cl->protocol_minor_ver >= 7) ? 1 : 4;
+    reasonLen = strlen(reason);
+    ((CARD32 *)buf)[0] = 0;
+    ((CARD32 *)buf)[1] = Swap32IfLE(reasonLen);
+
+    if ( WriteExact(cl->sock, buf, headerLen) < 0 ||
+	 WriteExact(cl->sock, buf + 4, 4) < 0 ||
+	 WriteExact(cl->sock, reason, reasonLen) < 0 ) {
+	rfbLogPerror("rfbClientConnFailed: write");
+    }
+
+    rfbCloseSock(cl->pScreen, cl->sock);
+}
+
+
+/*
+ * rfbProcessClientInitMessage is called when the client sends its
+ * initialisation message.
+ */
+
+static void
+rfbProcessClientInitMessage(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbClientInitMsg ci;
+    char buf[256];
+    rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
+    struct passwd *user;
+    int len, n;
+    rfbClientPtr otherCl, nextCl;
+
+    if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientInitMessage: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientInitMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    si->framebufferWidth = Swap16IfLE(pVNC->width);
+    si->framebufferHeight = Swap16IfLE(pVNC->height);
+    si->format = pVNC->rfbServerFormat;
+    si->format.redMax = Swap16IfLE(si->format.redMax);
+    si->format.greenMax = Swap16IfLE(si->format.greenMax);
+    si->format.blueMax = Swap16IfLE(si->format.blueMax);
+
+    user = getpwuid(getuid());
+
+    if (strlen(desktopName) > 128)	/* sanity check on desktop name len */
+	desktopName[128] = 0;
+
+    if (user) {
+	sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)",
+		user->pw_name, desktopName, rfbThisHost, display);
+    } else {
+	sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)",
+		desktopName, rfbThisHost, display);
+    }
+    len = strlen(buf + sz_rfbServerInitMsg);
+    si->nameLength = Swap32IfLE(len);
+
+    if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) {
+	rfbLogPerror("rfbProcessClientInitMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    if (cl->protocol_tightvnc)
+	rfbSendInteractionCaps(cl); /* protocol 3.7t */
+
+    /* Dispatch client input to rfbProcessClientNormalMessage(). */
+    cl->state = RFB_NORMAL;
+
+    if (!cl->reverseConnection &&
+	(pVNC->rfbNeverShared || (!pVNC->rfbAlwaysShared && !ci.shared))) {
+
+	if (pVNC->rfbDontDisconnect) {
+	    for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) {
+		if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+		    rfbLog("-dontdisconnect: Not shared & existing client\n");
+		    rfbLog("  refusing new client %s\n", cl->host);
+		    rfbCloseSock(cl->pScreen, cl->sock);
+		    return;
+		}
+	    }
+	} else {
+	    for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) {
+		nextCl = otherCl->next;
+		if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+		    rfbLog("Not shared - closing connection to client %s\n",
+			   otherCl->host);
+		    rfbCloseSock(otherCl->pScreen, otherCl->sock);
+		}
+	    }
+	}
+    }
+}
+
+
+/*
+ * rfbSendInteractionCaps is called after sending the server
+ * initialisation message, only if the protocol version is 3.130.
+ * In this function, we send the lists of supported protocol messages
+ * and encodings.
+ */
+
+/* Update these constants on changing capability lists below! */
+#define N_SMSG_CAPS  0
+#define N_CMSG_CAPS  0
+#define N_ENC_CAPS  12
+
+void
+rfbSendInteractionCaps(cl)
+    rfbClientPtr cl;
+{
+    rfbInteractionCapsMsg intr_caps;
+    rfbCapabilityInfo enc_list[N_ENC_CAPS];
+    int i;
+
+    /* Fill in the header structure sent prior to capability lists. */
+    intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
+    intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
+    intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
+    intr_caps.pad = 0;
+
+    /* Supported server->client message types. */
+    /* For future file transfer support:
+    i = 0;
+    SetCapInfo(&smsg_list[i++], rfbFileListData,           rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileDownloadData,       rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileUploadCancel,       rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed,     rfbTightVncVendor);
+    if (i != N_SMSG_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    */
+
+    /* Supported client->server message types. */
+    /* For future file transfer support:
+    i = 0;
+    SetCapInfo(&cmsg_list[i++], rfbFileListRequest,        rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest,    rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest,      rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadData,         rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel,     rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed,       rfbTightVncVendor);
+    if (i != N_CMSG_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    */
+
+    /* Encoding types. */
+    i = 0;
+    SetCapInfo(&enc_list[i++],  rfbEncodingCopyRect,       rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingRRE,            rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingCoRRE,          rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingHextile,        rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingZlib,           rfbTridiaVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingTight,          rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingCompressLevel0, rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingQualityLevel0,  rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingXCursor,        rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingRichCursor,     rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingPointerPos,     rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingLastRect,       rfbTightVncVendor);
+    if (i != N_ENC_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Send header and capability lists */
+    if (WriteExact(cl->sock, (char *)&intr_caps,
+		   sz_rfbInteractionCapsMsg) < 0 ||
+	WriteExact(cl->sock, (char *)&enc_list[0],
+		   sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
+	rfbLogPerror("rfbSendInteractionCaps: write");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientNormalMessage(). */
+    cl->state = RFB_NORMAL;
+}
+
+
+/*
+ * rfbProcessClientNormalMessage is called when the client has sent a normal
+ * protocol message.
+ */
+
+static void
+rfbProcessClientNormalMessage(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int n;
+    rfbClientToServerMsg msg;
+    char *str;
+
+    if (pVNC->rfbUserAccept) {
+	/* 
+	 * We've asked for another level of user authentication
+	 * If the user has not validated this connected, don't
+	 * process it.
+	 */
+	/*
+ 	 * NOTE: we do it here, so the vncviewer knows it's
+	 * connected, but waiting for the first screen update
+	 */
+	if (cl->userAccepted == VNC_USER_UNDEFINED) {
+	    usleep(10);
+	    return;
+	}
+	if (cl->userAccepted == VNC_USER_DISCONNECT) {
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+    }
+
+    if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) {
+	if (n != 0)
+	    rfbLogPerror("rfbProcessClientNormalMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    switch (msg.type) {
+
+    case rfbSetPixelFormat:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbSetPixelFormatMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
+	cl->format.depth = msg.spf.format.depth;
+	cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0);
+	cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0);
+	cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
+	cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
+	cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
+	cl->format.redShift = msg.spf.format.redShift;
+	cl->format.greenShift = msg.spf.format.greenShift;
+	cl->format.blueShift = msg.spf.format.blueShift;
+
+	cl->readyForSetColourMapEntries = TRUE;
+
+	rfbSetTranslateFunction(cl);
+	return;
+
+
+    case rfbFixColourMapEntries:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+	rfbLog("rfbProcessClientNormalMessage: %s",
+		"FixColourMapEntries unsupported\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+
+
+    case rfbSetEncodings:
+    {
+	int i;
+	CARD32 enc;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbSetEncodingsMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
+
+	cl->preferredEncoding = -1;
+	cl->useCopyRect = FALSE;
+	cl->enableCursorShapeUpdates = FALSE;
+	cl->enableCursorPosUpdates = FALSE;
+	cl->enableLastRectEncoding = FALSE;
+#ifdef CHROMIUM
+	cl->enableChromiumEncoding = FALSE;
+#endif
+	cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+	cl->tightQualityLevel = -1;
+
+	for (i = 0; i < msg.se.nEncodings; i++) {
+	    if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) {
+		if (n != 0)
+		    rfbLogPerror("rfbProcessClientNormalMessage: read");
+		rfbCloseSock(cl->pScreen, cl->sock);
+		return;
+	    }
+	    enc = Swap32IfLE(enc);
+
+	    switch (enc) {
+
+	    case rfbEncodingCopyRect:
+		cl->useCopyRect = TRUE;
+		rfbLog("Using copyrect encoding for client %s\n",
+			   cl->host);
+		break;
+	    case rfbEncodingRaw:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using raw encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingRRE:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using rre encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingCoRRE:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using CoRRE encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingHextile:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using hextile encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingZlib:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using zlib encoding for client %s\n",
+			   cl->host);
+		}
+              break;
+	    case rfbEncodingTight:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using tight encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingXCursor:
+		rfbLog("Enabling X-style cursor updates for client %s\n",
+		       cl->host);
+		cl->enableCursorShapeUpdates = TRUE;
+		cl->useRichCursorEncoding = FALSE;
+		cl->cursorWasChanged = TRUE;
+		break;
+	    case rfbEncodingRichCursor:
+		if (!cl->enableCursorShapeUpdates) {
+		    rfbLog("Enabling full-color cursor updates for client "
+			   "%s\n", cl->host);
+		    cl->enableCursorShapeUpdates = TRUE;
+		    cl->useRichCursorEncoding = TRUE;
+		    cl->cursorWasChanged = TRUE;
+		}
+		break;
+	    case rfbEncodingPointerPos:
+		if (!cl->enableCursorPosUpdates) {
+		    rfbLog("Enabling cursor position updates for client %s\n",
+			   cl->host);
+		    cl->enableCursorPosUpdates = TRUE;
+		    cl->cursorWasMoved = TRUE;
+		    cl->cursorX = -1;
+		    cl->cursorY = -1;
+		}
+	        break;
+	    case rfbEncodingLastRect:
+		if (!cl->enableLastRectEncoding) {
+		    rfbLog("Enabling LastRect protocol extension for client "
+			   "%s\n", cl->host);
+		    cl->enableLastRectEncoding = TRUE;
+		}
+		break;
+#ifdef CHROMIUM
+	    case rfbEncodingChromium:
+	    case rfbEncodingChromium2:
+		if (!cl->enableChromiumEncoding) {
+		    cl->enableChromiumEncoding = TRUE;
+		    /* This tells OpenGL apps/replicate SPUs that new viewer
+                     * has attached.
+                     */
+    		    GenerateVncChromiumConnectedEvent(cl->sock);
+                    if (enc == rfbEncodingChromium) {
+                        /* Generate exposures for all windows */
+                        WindowPtr pWin = WindowTable[cl->pScreen->myNum];
+                        rfbSetClip(pWin, 1);
+                    }
+                    else {
+                        /* don't generate exposures for Chromium2 because
+                         * that confused DMX.
+                         */
+                    }
+		}
+		break;
+#endif
+	    default:
+		if ( enc >= (CARD32)rfbEncodingCompressLevel0 &&
+		     enc <= (CARD32)rfbEncodingCompressLevel9 ) {
+		    cl->zlibCompressLevel = enc & 0x0F;
+		    cl->tightCompressLevel = enc & 0x0F;
+		    rfbLog("Using compression level %d for client %s\n",
+			   cl->tightCompressLevel, cl->host);
+		} else if ( enc >= (CARD32)rfbEncodingQualityLevel0 &&
+			    enc <= (CARD32)rfbEncodingQualityLevel9 ) {
+		    cl->tightQualityLevel = enc & 0x0F;
+		    rfbLog("Using image quality level %d for client %s\n",
+			   cl->tightQualityLevel, cl->host);
+		} else {
+		    rfbLog("rfbProcessClientNormalMessage: ignoring unknown "
+			   "encoding %d\n", (int)enc);
+		}
+	    }
+	}
+
+	if (cl->preferredEncoding == -1) {
+	    cl->preferredEncoding = rfbEncodingRaw;
+ 	    rfbLog("No encoding specified - using raw encoding for client %s\n",
+			   cl->host);
+	}
+
+	if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
+	    rfbLog("Disabling cursor position updates for client %s\n",
+		   cl->host);
+	    cl->enableCursorPosUpdates = FALSE;
+	}
+
+#if XFREE86VNC
+	/*
+	 * With XFree86 and the hardware cursor's we need to put up the
+	 * cursor again, and if we've detected a cursor shapeless client
+	 * we need to disable hardware cursors.
+	 */
+	if (!cl->enableCursorShapeUpdates)
+	    pVNC->SWCursor = (Bool *)TRUE;
+	else
+	    pVNC->SWCursor = (Bool *)FALSE;
+
+	{
+		int x, y;
+		miPointerPosition(&x, &y);
+		(*pVNC->spriteFuncs->SetCursor)(cl->pScreen, pVNC->pCurs, x, y);
+	}
+#endif
+
+	return;
+    }
+
+
+    case rfbFramebufferUpdateRequest:
+    {
+	RegionRec tmpRegion;
+	BoxRec box;
+
+#ifdef CORBA
+	addCapability(cl, DISPLAY_DEVICE);
+#endif
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	box.x1 = Swap16IfLE(msg.fur.x);
+	box.y1 = Swap16IfLE(msg.fur.y);
+	box.x2 = box.x1 + Swap16IfLE(msg.fur.w);
+	box.y2 = box.y1 + Swap16IfLE(msg.fur.h);
+	SAFE_REGION_INIT(cl->pScreen,&tmpRegion,&box,0);
+
+	REGION_UNION(cl->pScreen, &cl->requestedRegion, &cl->requestedRegion,
+		     &tmpRegion);
+
+	if (!cl->readyForSetColourMapEntries) {
+	    /* client hasn't sent a SetPixelFormat so is using server's */
+	    cl->readyForSetColourMapEntries = TRUE;
+	    if (!cl->format.trueColour) {
+		if (!rfbSetClientColourMap(cl, 0, 0)) {
+		    REGION_UNINIT(cl->pScreen,&tmpRegion);
+		    return;
+		}
+	    }
+	}
+
+	if (!msg.fur.incremental) {
+	    REGION_UNION(cl->pScreen,&cl->modifiedRegion,&cl->modifiedRegion,
+			 &tmpRegion);
+	    REGION_SUBTRACT(cl->pScreen,&cl->copyRegion,&cl->copyRegion,
+			    &tmpRegion);
+	}
+
+	if (FB_UPDATE_PENDING(cl)) {
+	    rfbSendFramebufferUpdate(cl->pScreen, cl);
+	}
+
+	REGION_UNINIT(cl->pScreen,&tmpRegion);
+	return;
+    }
+
+    case rfbKeyEvent:
+
+	cl->rfbKeyEventsRcvd++;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbKeyEventMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+#ifdef CORBA
+	addCapability(cl, KEYBOARD_DEVICE);
+
+	if (!isKeyboardEnabled(cl))
+	    return;
+#endif
+	if (!pVNC->rfbViewOnly && !cl->viewOnly) {
+	    KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl);
+	}
+	return;
+
+
+    case rfbPointerEvent:
+
+	cl->rfbPointerEventsRcvd++;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbPointerEventMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+#ifdef CORBA
+	addCapability(cl, POINTER_DEVICE);
+
+	if (!isPointerEnabled(cl))
+	    return;
+#endif
+
+	if (pointerClient && (pointerClient != cl))
+	    return;
+
+	if (msg.pe.buttonMask == 0)
+	    pointerClient = NULL;
+	else
+	    pointerClient = cl;
+
+	if (!pVNC->rfbViewOnly && !cl->viewOnly) {
+	    cl->cursorX = (int)Swap16IfLE(msg.pe.x);
+            cl->cursorY = (int)Swap16IfLE(msg.pe.y);
+	    PtrAddEvent(msg.pe.buttonMask, cl->cursorX, cl->cursorY, cl);
+	}
+	return;
+
+
+    case rfbClientCutText:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbClientCutTextMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	msg.cct.length = Swap32IfLE(msg.cct.length);
+
+	str = (char *)xalloc(msg.cct.length);
+
+	if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    xfree(str);
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* NOTE: We do not accept cut text from a view-only client */
+	if (!cl->viewOnly)
+	    rfbSetXCutText(str, msg.cct.length);
+
+	xfree(str);
+	return;
+
+#ifdef CHROMIUM
+    case rfbChromiumStop:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbChromiumStopMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* would we use msg.csd.port ??? */
+
+	cl->chromium_port = 0;
+
+	/* tear down window information */
+    	{
+	    CRWindowTable *wt, *nextWt = NULL;
+
+   	    for (wt = windowTable; wt; wt = nextWt) {
+   	 	nextWt = wt->next;
+		xfree(wt);
+	    }
+
+	    windowTable = NULL;
+	}
+
+	return;
+
+    case rfbChromiumExpose:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbChromiumExposeMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* find the window and re-expose it */
+    	{
+	    CRWindowTable *wt, *nextWt = NULL;
+
+   	    for (wt = windowTable; wt; wt = nextWt) {
+   	 	nextWt = wt->next;
+		if (wt->CRwinId == msg.cse.winid) {
+			WindowPtr pWin;
+	    		pWin = LookupIDByType(wt->XwinId, RT_WINDOW);
+			if (pWin) {
+				miSendExposures(pWin, &pWin->clipList,
+						pWin->drawable.x,
+						pWin->drawable.y);
+				FlushAllOutput();
+			}
+		}
+	    }
+	}
+
+	return;
+#endif
+
+    default:
+
+	rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
+		msg.type);
+	rfbLog(" ... closing connection\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+}
+
+
+
+/*
+ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
+ * the RFB client.
+ */
+
+Bool
+rfbSendFramebufferUpdate(pScreen, cl)
+    ScreenPtr pScreen;
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(pScreen);
+    int i;
+    int nUpdateRegionRects;
+    rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)pVNC->updateBuf;
+    RegionRec updateRegion, updateCopyRegion;
+    int dx, dy;
+    Bool sendCursorShape = FALSE;
+    Bool sendCursorPos = FALSE;
+
+    /*
+     * If this client understands cursor shape updates, cursor should be
+     * removed from the framebuffer. Otherwise, make sure it's put up.
+     */
+
+#if !XFREE86VNC
+    if (cl->enableCursorShapeUpdates) {
+	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor(pScreen);
+	if (!pVNC->cursorIsDrawn && cl->cursorWasChanged)
+	    sendCursorShape = TRUE;
+    } else {
+	if (!pVNC->cursorIsDrawn)
+	    rfbSpriteRestoreCursor(pScreen);
+    }
+#else
+    if (cl->enableCursorShapeUpdates)
+	if (cl->cursorWasChanged) 
+	    sendCursorShape = TRUE;
+#endif
+
+    /*
+     * Do we plan to send cursor position update?
+     */
+
+    if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
+	sendCursorPos = TRUE;
+
+    /*
+     * The modifiedRegion may overlap the destination copyRegion.  We remove
+     * any overlapping bits from the copyRegion (since they'd only be
+     * overwritten anyway).
+     */
+
+    REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
+		    &cl->modifiedRegion);
+
+    /*
+     * The client is interested in the region requestedRegion.  The region
+     * which should be updated now is the intersection of requestedRegion
+     * and the union of modifiedRegion and copyRegion.  If it's empty then
+     * no update is needed.
+     */
+
+    REGION_NULL(pScreen,&updateRegion);
+    REGION_UNION(pScreen, &updateRegion, &cl->copyRegion,
+		 &cl->modifiedRegion);
+    REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion,
+		     &updateRegion);
+
+    if ( !REGION_NOTEMPTY(pScreen,&updateRegion) &&
+	 !sendCursorShape && !sendCursorPos ) {
+	REGION_UNINIT(pScreen,&updateRegion);
+	return TRUE;
+    }
+
+    /*
+     * We assume that the client doesn't have any pixel data outside the
+     * requestedRegion.  In other words, both the source and destination of a
+     * copy must lie within requestedRegion.  So the region we can send as a
+     * copy is the intersection of the copyRegion with both the requestedRegion
+     * and the requestedRegion translated by the amount of the copy.  We set
+     * updateCopyRegion to this.
+     */
+
+    REGION_NULL(pScreen,&updateCopyRegion);
+    REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion,
+		     &cl->requestedRegion);
+    REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY);
+    REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion,
+		     &cl->requestedRegion);
+    dx = cl->copyDX;
+    dy = cl->copyDY;
+
+    /*
+     * Next we remove updateCopyRegion from updateRegion so that updateRegion
+     * is the part of this update which is sent as ordinary pixel data (i.e not
+     * a copy).
+     */
+
+    REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion);
+
+    /*
+     * Finally we leave modifiedRegion to be the remainder (if any) of parts of
+     * the screen which are modified but outside the requestedRegion.  We also
+     * empty both the requestedRegion and the copyRegion - note that we never
+     * carry over a copyRegion for a future update.
+     */
+
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		 &cl->copyRegion);
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &updateRegion);
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &updateCopyRegion);
+
+    REGION_EMPTY(pScreen, &cl->requestedRegion);
+    REGION_EMPTY(pScreen, &cl->copyRegion);
+    cl->copyDX = 0;
+    cl->copyDY = 0;
+
+    /*
+     * Now send the update.
+     */
+
+    cl->rfbFramebufferUpdateMessagesSent++;
+
+    if (cl->preferredEncoding == rfbEncodingCoRRE) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1)
+				     * ((h-1) / cl->correMaxHeight + 1));
+	}
+    } else if (cl->preferredEncoding == rfbEncodingZlib) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
+	}
+    } else if (cl->preferredEncoding == rfbEncodingTight) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    int n = rfbNumCodedRectsTight(cl, x, y, w, h);
+	    if (n == 0) {
+		nUpdateRegionRects = 0xFFFF;
+		break;
+	    }
+	    nUpdateRegionRects += n;
+	}
+    } else {
+	nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion);
+    }
+
+    fu->type = rfbFramebufferUpdate;
+    if (nUpdateRegionRects != 0xFFFF) {
+	fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) +
+				nUpdateRegionRects +
+				!!sendCursorShape + !!sendCursorPos);
+    } else {
+	fu->nRects = 0xFFFF;
+    }
+    pVNC->ublen = sz_rfbFramebufferUpdateMsg;
+
+    if (sendCursorShape) {
+	cl->cursorWasChanged = FALSE;
+	if (!rfbSendCursorShape(cl, pScreen))
+	    return FALSE;
+    }
+
+    if (sendCursorPos) {
+	cl->cursorWasMoved = FALSE;
+	if (!rfbSendCursorPos(cl, pScreen))
+ 	    return FALSE;
+    }
+
+    if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) {
+	if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) {
+	    REGION_UNINIT(pScreen,&updateRegion);
+	    REGION_UNINIT(pScreen,&updateCopyRegion);
+	    return FALSE;
+	}
+    }
+
+    REGION_UNINIT(pScreen,&updateCopyRegion);
+
+    for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	int x = REGION_RECTS(&updateRegion)[i].x1;
+	int y = REGION_RECTS(&updateRegion)[i].y1;
+	int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+
+	cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
+				      + w * (cl->format.bitsPerPixel / 8) * h);
+
+	switch (cl->preferredEncoding) {
+	case rfbEncodingRaw:
+	    if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingRRE:
+	    if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingCoRRE:
+	    if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingHextile:
+	    if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingZlib:
+	    if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingTight:
+	    if (!rfbSendRectEncodingTight(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	}
+    }
+
+    REGION_UNINIT(pScreen,&updateRegion);
+
+    if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl))
+	return FALSE;
+
+    if (!rfbSendUpdateBuf(cl))
+	return FALSE;
+
+    return TRUE;
+}
+
+
+
+/*
+ * Send the copy region as a string of CopyRect encoded rectangles.
+ * The only slightly tricky thing is that we should send the messages in
+ * the correct order so that an earlier CopyRect will not corrupt the source
+ * of a later one.
+ */
+
+static Bool
+rfbSendCopyRegion(cl, reg, dx, dy)
+    rfbClientPtr cl;
+    RegionPtr reg;
+    int dx, dy;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand;
+    int x, y, w, h;
+    rfbFramebufferUpdateRectHeader rect;
+    rfbCopyRect cr;
+
+    nrects = REGION_NUM_RECTS(reg);
+
+    if (dx <= 0) {
+	x_inc = 1;
+    } else {
+	x_inc = -1;
+    }
+
+    if (dy <= 0) {
+	thisRect = 0;
+	y_inc = 1;
+    } else {
+	thisRect = nrects - 1;
+	y_inc = -1;
+    }
+
+    while (nrects > 0) {
+
+	firstInNextBand = thisRect;
+	nrectsInBand = 0;
+
+	while ((nrects > 0) &&
+	       (REGION_RECTS(reg)[firstInNextBand].y1
+		== REGION_RECTS(reg)[thisRect].y1))
+	{
+	    firstInNextBand += y_inc;
+	    nrects--;
+	    nrectsInBand++;
+	}
+
+	if (x_inc != y_inc) {
+	    thisRect = firstInNextBand - y_inc;
+	}
+
+	while (nrectsInBand > 0) {
+	    if ((pVNC->ublen + sz_rfbFramebufferUpdateRectHeader
+		 + sz_rfbCopyRect) > UPDATE_BUF_SIZE)
+	    {
+		if (!rfbSendUpdateBuf(cl))
+		    return FALSE;
+	    }
+
+	    x = REGION_RECTS(reg)[thisRect].x1;
+	    y = REGION_RECTS(reg)[thisRect].y1;
+	    w = REGION_RECTS(reg)[thisRect].x2 - x;
+	    h = REGION_RECTS(reg)[thisRect].y2 - y;
+
+	    rect.r.x = Swap16IfLE(x);
+	    rect.r.y = Swap16IfLE(y);
+	    rect.r.w = Swap16IfLE(w);
+	    rect.r.h = Swap16IfLE(h);
+	    rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
+
+	    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+		   sz_rfbFramebufferUpdateRectHeader);
+	    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+	    cr.srcX = Swap16IfLE(x - dx);
+	    cr.srcY = Swap16IfLE(y - dy);
+
+	    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&cr, sz_rfbCopyRect);
+	    pVNC->ublen += sz_rfbCopyRect;
+
+	    cl->rfbRectanglesSent[rfbEncodingCopyRect]++;
+	    cl->rfbBytesSent[rfbEncodingCopyRect]
+		+= sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
+
+	    thisRect += x_inc;
+	    nrectsInBand--;
+	}
+
+	thisRect = firstInNextBand;
+    }
+
+    return TRUE;
+}
+
+
+/*
+ * Send a given rectangle in raw encoding (rfbEncodingRaw).
+ */
+
+Bool
+rfbSendRectEncodingRaw(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    int nlines;
+    int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
+    unsigned char *fbptr = NULL;
+    int newy = 0;
+
+    if (pVNC->useGetImage) {
+	newy = y;
+    } else {
+    	fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+    }
+
+    /* Flush the buffer to guarantee correct alignment for translateFn(). */
+    if (pVNC->ublen > 0) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingRaw);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingRaw]++;
+    cl->rfbBytesSent[rfbEncodingRaw]
+	+= sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
+
+    nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine;
+
+    while (TRUE) {
+	if (nlines > h)
+	    nlines = h;
+
+    	if (pVNC->useGetImage) {
+    	    (*cl->pScreen->GetImage)((DrawablePtr)WindowTable[cl->pScreen->myNum], x, newy, w, nlines, ZPixmap, ~0, &pVNC->updateBuf[pVNC->ublen]);
+	    newy += nlines;
+    	} else {
+	    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+			   &cl->format, fbptr, &pVNC->updateBuf[pVNC->ublen],
+			   pVNC->paddedWidthInBytes, w, nlines, x, y);
+    	}
+
+	pVNC->ublen += nlines * bytesPerLine;
+	h -= nlines;
+
+	if (h == 0)	/* rect fitted in buffer, do next one */
+	    return TRUE;
+
+	/* buffer full - flush partial rect and do another nlines */
+
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+
+	if (!pVNC->useGetImage)
+	    fbptr += (pVNC->paddedWidthInBytes * nlines);
+
+	nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine;
+	if (nlines == 0) {
+	    rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d "
+		   "bytes per line\n", bytesPerLine);
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return FALSE;
+	}
+    }
+}
+
+
+/*
+ * Send an empty rectangle with encoding field set to value of
+ * rfbEncodingLastRect to notify client that this is the last
+ * rectangle in framebuffer update ("LastRect" extension of RFB
+ * protocol).
+ */
+
+static Bool
+rfbSendLastRectMarker(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.encoding = Swap32IfLE(rfbEncodingLastRect);
+    rect.r.x = 0;
+    rect.r.y = 0;
+    rect.r.w = 0;
+    rect.r.h = 0;
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbLastRectMarkersSent++;
+    cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+
+    return TRUE;
+}
+
+
+/*
+ * Send the contents of pVNC->updateBuf.  Returns 1 if successful, -1 if
+ * not (errno should be set).
+ */
+
+Bool
+rfbSendUpdateBuf(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+
+    /*
+    int i;
+    for (i = 0; i < pVNC->ublen; i++) {
+	rfbLog("%02x ",((unsigned char *)pVNC->updateBuf)[i]);
+    }
+    rfbLog("\n");
+    */
+
+    if (pVNC->ublen > 0 && WriteExact(cl->sock, pVNC->updateBuf, pVNC->ublen) < 0) {
+	rfbLogPerror("rfbSendUpdateBuf: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    pVNC->ublen = 0;
+    return TRUE;
+}
+
+
+
+/*
+ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
+ * client, using values from the currently installed colormap.
+ */
+
+Bool
+rfbSendSetColourMapEntries(cl, firstColour, nColours)
+    rfbClientPtr cl;
+    int firstColour;
+    int nColours;
+{
+#if !XFREE86VNC
+    VNCSCREENPTR(cl->pScreen);
+#endif
+    char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+    rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+    CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+    EntryPtr pent;
+    EntryPtr redEntry, greenEntry, blueEntry;
+    unsigned short redPart, greenPart, bluePart;
+    int i, len;
+
+    scme->type = rfbSetColourMapEntries;
+    scme->nColours = Swap16IfLE(nColours);
+
+    len = sz_rfbSetColourMapEntriesMsg;
+
+    /* PseudoColor */
+#if XFREE86VNC
+    if (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor) {
+#else
+    if (pVNC->rfbInstalledColormap->class == PseudoColor) {
+#endif
+      scme->firstColour = Swap16IfLE(firstColour);
+#if XFREE86VNC
+      pent = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[firstColour];
+#else
+      pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[firstColour];
+#endif
+      for (i = 0; i < nColours; i++) {
+  	  if (pent->fShared) {
+	      rgb[i*3] = Swap16IfLE(pent->co.shco.red->color);
+	      rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color);
+	      rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color);
+	  } else {
+	      rgb[i*3] = Swap16IfLE(pent->co.local.red);
+	      rgb[i*3+1] = Swap16IfLE(pent->co.local.green);
+	      rgb[i*3+2] = Swap16IfLE(pent->co.local.blue);
+	  }
+	  pent++;
+      }
+    }
+
+    else {
+
+      /* Break the DirectColor pixel into its r/g/b components */
+#if XFREE86VNC
+      redPart   = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->redMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetRed;
+      greenPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->greenMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetGreen;
+      bluePart  = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->blueMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetBlue;
+#else
+      redPart   = (firstColour & pVNC->rfbInstalledColormap->pVisual->redMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetRed;
+      greenPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->greenMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetGreen;
+      bluePart  = (firstColour & pVNC->rfbInstalledColormap->pVisual->blueMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetBlue;
+#endif
+
+      /*
+       * The firstColour field is only 16 bits. To support 24-bit pixels we
+       * sneak the red component in the 8-bit padding field which we renamed
+       * to redIndex. Green and blue are in firstColour (MSB, LSB respectively).
+       */
+      scme->redIndex    = Swap16IfLE(redPart);
+      scme->firstColour = Swap16IfLE((greenPart << 8) | bluePart);
+
+#if XFREE86VNC
+      redEntry   = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[redPart];
+      greenEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->green[greenPart];
+      blueEntry  = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->blue[bluePart];
+#else
+      redEntry   = (EntryPtr)&pVNC->rfbInstalledColormap->red[redPart];
+      greenEntry = (EntryPtr)&pVNC->rfbInstalledColormap->green[greenPart];
+      blueEntry  = (EntryPtr)&pVNC->rfbInstalledColormap->blue[bluePart];
+#endif
+      for (i = 0; i < nColours; i++) {
+	  if (redEntry->fShared)
+	      rgb[i*3] = Swap16IfLE(redEntry->co.shco.red->color);
+	  else
+	      rgb[i*3] = Swap16IfLE(redEntry->co.local.red);
+
+	  if (greenEntry->fShared)
+	      rgb[i*3+1] = Swap16IfLE(greenEntry->co.shco.green->color);
+	  else
+	      rgb[i*3+1] = Swap16IfLE(greenEntry->co.local.green);
+
+	  if (blueEntry->fShared)
+	      rgb[i*3+2] = Swap16IfLE(blueEntry->co.shco.blue->color);
+	  else
+	      rgb[i*3+2] = Swap16IfLE(blueEntry->co.local.blue);
+
+	  redEntry++;
+	  greenEntry++;
+	  blueEntry++;
+      }
+    }
+
+    len += nColours * 3 * 2;
+
+    if (WriteExact(cl->sock, buf, len) < 0) {
+	rfbLogPerror("rfbSendSetColourMapEntries: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+ * rfbSendBell sends a Bell message to all the clients.
+ */
+
+void
+rfbSendBell()
+{
+    rfbClientPtr cl, nextCl;
+    rfbBellMsg b;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	b.type = rfbBell;
+	if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) {
+	    rfbLogPerror("rfbSendBell: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	}
+    }
+}
+
+#ifdef CHROMIUM
+#ifdef sun
+extern int inet_aton(const char *cp, struct in_addr *inp);
+#endif
+
+void
+rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort,
+                     unsigned int mothershipPort)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumStartMsg scd;
+    struct in_addr ip;
+    unsigned int vncipaddress;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	inet_aton(cl->host, &ip);
+	memcpy(&vncipaddress, &ip, sizeof(unsigned int));
+	if (ipaddress == vncipaddress /***&& !cl->chromium_port***/) {
+	    cl->chromium_port = crServerPort;
+	    cl->chromium_msport = mothershipPort;
+    	    scd.type = rfbChromiumStart;
+    	    scd.crServerPort = crServerPort;
+    	    scd.mothershipPort = mothershipPort;
+    	    if (WriteExact(cl->sock, (char *)&scd,
+		       sz_rfbChromiumStartMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumStart: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+    	    }
+	    /* We only start one client at at time, so break now! */
+	    break;
+	}
+    }
+}
+
+
+/**
+ * Begin monitoring the given X windowid.
+ * When we detect size/position/visibiliy changes we'll send a 
+ * rfbChromiumMoveResizeWindow, rfbChromiumClipList, or rfbChromiumWindowShow
+ * message to the VNC viewer, passing the corresponding Chromium window id.
+ */
+void
+rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long xwindowid)
+{
+    CRWindowTable *newRec, *wt, *nextWt = NULL;
+
+    if (xwindowid && !cr_windowid) {
+        /* stop monitoring the X window, remove from list */
+        CRWindowTable *prev = NULL;
+        for (wt = windowTable; wt; wt = nextWt) {
+            nextWt = wt->next;
+            if (wt->XwinId == xwindowid) {
+                /* remove */
+                if (prev)
+                    prev->next = wt->next;
+                else
+                windowTable = wt->next;
+                xfree(wt);
+            }
+            else {
+                prev = wt;
+            }
+        }
+        return;
+    }
+
+    /* See if we're already managing this window */
+    for (wt = windowTable; wt; wt = nextWt) {
+        nextWt = wt->next;
+        /* and if so, update it's window ID */
+        if (wt->CRwinId == cr_windowid) {
+            wt->XwinId = xwindowid;
+            return;
+        }
+    }
+
+    /* o.k, new window so create new slot information */
+    newRec = (CRWindowTable *)xalloc(sizeof(CRWindowTable));
+    if (!newRec) {
+        rfbLog("Out of memory allocating CRWindowTable.\n");
+        return;
+    }
+    
+    newRec->next = NULL;
+    newRec->CRwinId = cr_windowid;
+    newRec->XwinId = xwindowid;
+    newRec->clipRects = NULL;
+    newRec->numRects = 0;
+
+    if (!windowTable) {
+        windowTable = newRec;
+    }
+    else {
+        for (wt = windowTable; wt; wt = nextWt) {
+            nextWt = wt->next;
+            if (!wt->next) /* found the next slot */
+                wt->next = newRec;
+        }
+    }
+}
+
+
+void
+rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumMoveResizeWindowMsg scm;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    scm.type = rfbChromiumMoveResizeWindow;
+	    scm.winid = winid;
+	    scm.x = x;
+	    scm.y = y;
+	    scm.w = w;
+	    scm.h = h;
+    	    if (WriteExact(cl->sock, (char *)&scm,
+		       sz_rfbChromiumMoveResizeWindowMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumMoveResizeWindow: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	}
+    }
+}
+
+void
+rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumClipListMsg sccl;
+    int len = sizeof(BoxRec) * numClipRects;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    sccl.type = rfbChromiumClipList;
+	    sccl.winid = winid;
+	    sccl.length = Swap32IfLE(len);
+    	    if (WriteExact(cl->sock, (char *)&sccl,
+		       sz_rfbChromiumClipListMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumClipList: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	    if (WriteExact(cl->sock, (char *)pClipRects, len) < 0) {
+	   	rfbLogPerror("rfbSendChromiumClipList: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+	    }
+	}
+    }
+}
+
+void
+rfbSendChromiumWindowShow(unsigned int winid, unsigned int show)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumWindowShowMsg scws;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    scws.type = rfbChromiumWindowShow;
+	    scws.winid = winid;
+	    scws.show = show;
+    	    if (WriteExact(cl->sock, (char *)&scws,
+		       sz_rfbChromiumWindowShowMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumWindowShow: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	}
+    }
+}
+#endif /* CHROMIUM */
+
+/*
+ * rfbSendServerCutText sends a ServerCutText message to all the clients.
+ */
+
+void
+rfbSendServerCutText(char *str, int len)
+{
+    rfbClientPtr cl, nextCl = NULL;
+    rfbServerCutTextMsg sct;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	if (cl->state != RFB_NORMAL) continue;
+	nextCl = cl->next;
+	sct.type = rfbServerCutText;
+	sct.length = Swap32IfLE(len);
+	if (WriteExact(cl->sock, (char *)&sct,
+		       sz_rfbServerCutTextMsg) < 0) {
+	    rfbLogPerror("rfbSendServerCutText: write\n");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    continue;
+	}
+	if (WriteExact(cl->sock, str, len) < 0) {
+	    rfbLogPerror("rfbSendServerCutText: write\n");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	}
+    }
+}
+
+
+
+
+/*****************************************************************************
+ *
+ * UDP can be used for keyboard and pointer events when the underlying
+ * network is highly reliable.  This is really here to support ORL's
+ * videotile, whose TCP implementation doesn't like sending lots of small
+ * packets (such as 100s of pen readings per second!).
+ */
+
+void
+rfbNewUDPConnection(sock)
+    int sock;
+{
+    if (write(sock, &ptrAcceleration, 1) < 0) {
+	rfbLogPerror("rfbNewUDPConnection: write");
+    }
+}
+
+/*
+ * Because UDP is a message based service, we can't read the first byte and
+ * then the rest of the packet separately like we do with TCP.  We will always
+ * get a whole packet delivered in one go, so we ask read() for the maximum
+ * number of bytes we can possibly get.
+ */
+
+void
+rfbProcessUDPInput(ScreenPtr pScreen, int sock)
+{
+    VNCSCREENPTR(pScreen);
+    int n;
+    rfbClientToServerMsg msg;
+
+    if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) {
+	if (n < 0) {
+	    rfbLogPerror("rfbProcessUDPInput: read");
+	}
+	rfbDisconnectUDPSock(pScreen);
+	return;
+    }
+
+    switch (msg.type) {
+
+    case rfbKeyEvent:
+	if (n != sz_rfbKeyEventMsg) {
+	    rfbLog("rfbProcessUDPInput: key event incorrect length\n");
+	    rfbDisconnectUDPSock(pScreen);
+	    return;
+	}
+	if (!pVNC->rfbViewOnly) {
+	    KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), 0);
+	}
+	break;
+
+    case rfbPointerEvent:
+	if (n != sz_rfbPointerEventMsg) {
+	    rfbLog("rfbProcessUDPInput: ptr event incorrect length\n");
+	    rfbDisconnectUDPSock(pScreen);
+	    return;
+	}
+	if (!pVNC->rfbViewOnly) {
+	    PtrAddEvent(msg.pe.buttonMask,
+			Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), 0);
+	}
+	break;
+
+    default:
+	rfbLog("rfbProcessUDPInput: unknown message type %d\n",
+	       msg.type);
+	rfbDisconnectUDPSock(pScreen);
+    }
+}
diff -u -rNp a/hw/vnc/rre.c b/hw/vnc/rre.c
--- a/hw/vnc/rre.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/rre.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,323 @@
+/*
+ * rre.c
+ *
+ * Routines to implement Rise-and-Run-length Encoding (RRE).  This
+ * code is based on krw's original javatel rfbserver.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version.  If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(CARD8 *data, int w, int h);
+static int subrectEncode16(CARD16 *data, int w, int h);
+static int subrectEncode32(CARD32 *data, int w, int h);
+static CARD32 getBgColour(char *data, int size, int bpp);
+
+
+/*
+ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
+ */
+
+Bool
+rfbSendRectEncodingRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbRREHeader hdr;
+    int nSubrects;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize = (pVNC->width * pVNC->height
+		      * (cl->format.bitsPerPixel / 8));
+
+    if (rreBeforeBufSize < maxRawSize) {
+	rreBeforeBufSize = maxRawSize;
+	if (rreBeforeBuf == NULL)
+	    rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
+	else
+	    rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+    }
+
+    if (rreAfterBufSize < maxRawSize) {
+	rreAfterBufSize = maxRawSize;
+	if (rreAfterBuf == NULL)
+	    rreAfterBuf = (char *)xalloc(rreAfterBufSize);
+	else
+	    rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+    }
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, rreBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
+	break;
+    case 16:
+	nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
+	break;
+    case 32:
+	nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
+	break;
+    default:
+	rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+	exit(1);
+    }
+	
+    if (nSubrects < 0) {
+
+	/* RRE encoding was too large, use raw */
+
+	return rfbSendRectEncodingRaw(cl, x, y, w, h);
+    }
+
+    cl->rfbRectanglesSent[rfbEncodingRRE]++;
+    cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader
+					 + sz_rfbRREHeader + rreAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingRRE);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nSubrects = Swap32IfLE(nSubrects);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader);
+    pVNC->ublen += sz_rfbRREHeader;
+
+    for (i = 0; i < rreAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > rreAfterBufLen) {
+	    bytesToCopy = rreAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background 
+ * colour overwritten by single-coloured rectangles.  It returns the number 
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive 
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp)					      \
+static int								      \
+subrectEncode##bpp(data,w,h)						      \
+    CARD##bpp *data;							      \
+    int w;								      \
+    int h;								      \
+{									      \
+    CARD##bpp cl;							      \
+    rfbRectangle subrect;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp);		      \
+									      \
+    *((CARD##bpp*)rreAfterBuf) = bg;					      \
+									      \
+    rreAfterBufLen = (bpp/8);						      \
+									      \
+    for (y=0; y<h; y++) {						      \
+      line = data+(y*w);						      \
+      for (x=0; x<w; x++) {						      \
+        if (line[x] != bg) {						      \
+          cl = line[x];							      \
+          hy = y-1;							      \
+          hyflag = 1;							      \
+          for (j=y; j<h; j++) {						      \
+            seg = data+(j*w);						      \
+            if (seg[x] != cl) {break;}					      \
+            i = x;							      \
+            while ((seg[i] == cl) && (i < w)) i += 1;			      \
+            i -= 1;							      \
+            if (j == y) vx = hx = i;					      \
+            if (i < vx) vx = i;						      \
+            if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      \
+          }								      \
+          vy = j-1;							      \
+									      \
+          /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  \
+           *  We'll choose the bigger of the two.			      \
+           */								      \
+          hw = hx-x+1;							      \
+          hh = hy-y+1;							      \
+          vw = vx-x+1;							      \
+          vh = vy-y+1;							      \
+									      \
+          thex = x;							      \
+          they = y;							      \
+									      \
+          if ((hw*hh) > (vw*vh)) {					      \
+            thew = hw;							      \
+            theh = hh;							      \
+          } else {							      \
+            thew = vw;							      \
+            theh = vh;							      \
+          }								      \
+									      \
+          subrect.x = Swap16IfLE(thex);					      \
+          subrect.y = Swap16IfLE(they);					      \
+          subrect.w = Swap16IfLE(thew);					      \
+          subrect.h = Swap16IfLE(theh);					      \
+									      \
+	  newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle;		      \
+          if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize))     \
+	    return -1;							      \
+									      \
+	  numsubs += 1;							      \
+	  *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl;		      \
+	  rreAfterBufLen += (bpp/8);					      \
+	  memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle);      \
+	  rreAfterBufLen += sz_rfbRectangle;				      \
+									      \
+          /*								      \
+           * Now mark the subrect as done.				      \
+           */								      \
+          for (j=they; j < (they+theh); j++) {				      \
+            for (i=thex; i < (thex+thew); i++) {			      \
+              data[j*w+i] = bg;						      \
+            }								      \
+          }								      \
+        }								      \
+      }									      \
+    }									      \
+									      \
+    return numsubs;							      \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static CARD32
+getBgColour(data,size,bpp)
+    char *data;
+    int size;
+    int bpp;
+{
+    
+#define NUMCLRS 256
+  
+  static int counts[NUMCLRS];
+  int i,j,k;
+
+  int maxcount = 0;
+  CARD8 maxclr = 0;
+
+  if (bpp != 8) {
+    if (bpp == 16) {
+      return ((CARD16 *)data)[0];
+    } else if (bpp == 32) {
+      return ((CARD32 *)data)[0];
+    } else {
+      rfbLog("getBgColour: bpp %d?\n",bpp);
+      exit(1);
+    }
+  }
+
+  for (i=0; i<NUMCLRS; i++) {
+    counts[i] = 0;
+  }
+
+  for (j=0; j<size; j++) {
+    k = (int)(((CARD8 *)data)[j]);
+    if (k >= NUMCLRS) {
+      rfbLog("getBgColour: unusual colour = %d\n", k);
+      exit(1);
+    }
+    counts[k] += 1;
+    if (counts[k] > maxcount) {
+      maxcount = counts[k];
+      maxclr = ((CARD8 *)data)[j];
+    }
+  }
+  
+  return maxclr;
+}
diff -u -rNp a/hw/vnc/sockets.c b/hw/vnc/sockets.c
--- a/hw/vnc/sockets.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/sockets.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,654 @@
+/*
+ * sockets.c - deal with TCP & UDP sockets.
+ *
+ * This code should be independent of any changes in the RFB protocol.  It just
+ * deals with the X server scheduling stuff, calling rfbNewClientConnection and
+ * rfbProcessClientMessage to actually deal with the protocol.  If a socket
+ * needs to be closed for any reason then rfbCloseSock should be called, and
+ * this in turn will call rfbClientConnectionGone.  To make an active
+ * connection out, call rfbConnect - note that this does _not_ call
+ * rfbNewClientConnection.
+ *
+ * This file is divided into two types of function.  Those beginning with
+ * "rfb" are specific to sockets using the RFB protocol.  Those without the
+ * "rfb" prefix are more general socket routines (which are used by the http
+ * code).
+ *
+ * Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN
+ * not EWOULDBLOCK.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if HAVE_DIX_CONFIG_H
+#include "dix-config.h"
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "windowstr.h"
+
+#ifndef USE_LIBWRAP
+#define USE_LIBWRAP 0
+#endif
+#if USE_LIBWRAP
+#include <syslog.h>
+#include <tcpd.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif
+
+#include "rfb.h"
+
+int rfbMaxClientWait = 20000;	/* time (ms) after which we decide client has
+				   gone away - needed to stop us hanging */
+
+static struct sockaddr_in udpRemoteAddr;
+
+/*
+ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB
+ * connections.  It does nothing if called again.
+ */
+
+Bool
+rfbInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (inetdSock != -1) {
+	const int one = 1;
+
+	if (fcntl(inetdSock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("fcntl");
+	    return FALSE;
+	}
+
+	if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("setsockopt");
+	    return FALSE;
+	}
+
+    	AddEnabledDevice(inetdSock);
+    	FD_ZERO(&pVNC->allFds);
+    	FD_SET(inetdSock, &pVNC->allFds);
+    	pVNC->maxFd = inetdSock;
+	return TRUE;
+    }
+
+    if (pVNC->rfbPort == 0) {
+	pVNC->rfbPort = 5900 + atoi(display) + pScreen->myNum;
+    }
+
+    if ((pVNC->rfbListenSock = ListenOnTCPPort(pScreen, pVNC->rfbPort)) < 0) {
+	rfbLogPerror("ListenOnTCPPort");
+	pVNC->rfbPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for VNC connections on TCP port %d\n", pVNC->rfbPort);
+
+    AddEnabledDevice(pVNC->rfbListenSock);
+
+    FD_ZERO(&pVNC->allFds);
+    FD_SET(pVNC->rfbListenSock, &pVNC->allFds);
+    pVNC->maxFd = pVNC->rfbListenSock;
+
+    if (pVNC->udpPort != 0) {
+	rfbLog("rfbInitSockets: listening for input on UDP port %d\n",pVNC->udpPort);
+
+	if ((pVNC->udpSock = ListenOnUDPPort(pScreen, pVNC->udpPort)) < 0) {
+	    rfbLogPerror("ListenOnUDPPort");
+	    return FALSE;
+	}
+	AddEnabledDevice(pVNC->udpSock);
+	FD_SET(pVNC->udpSock, &pVNC->allFds);
+	pVNC->maxFd = max(pVNC->udpSock,pVNC->maxFd);
+    }
+   
+    return TRUE;
+}
+
+
+/*
+ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB
+ * socket(s).  If there is input to process, the appropriate function in the
+ * RFB server code will be called (rfbNewClientConnection,
+ * rfbProcessClientMessage, etc).
+ */
+
+void
+rfbCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+#if XFREE86VNC
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+#endif
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+    char buf[6];
+    const int one = 1;
+    int sock;
+    static Bool inetdInitDone = FALSE;
+
+    if (!inetdInitDone && inetdSock != -1) {
+	rfbNewClientConnection(pScreen, inetdSock); 
+	inetdInitDone = TRUE;
+    }
+
+    memcpy((char *)&fds, (char *)&pVNC->allFds, sizeof(fd_set));
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(pVNC->maxFd + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR)
+		rfbLogPerror("rfbCheckFds: select");
+	return;
+    }
+
+    if (pVNC->rfbListenSock != -1 && FD_ISSET(pVNC->rfbListenSock, &fds)) {
+
+	if ((sock = accept(pVNC->rfbListenSock,
+			   (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("rfbCheckFds: accept");
+	    return;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("rfbCheckFds: fcntl");
+	    close(sock);
+	    return;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("rfbCheckFds: setsockopt");
+	    close(sock);
+	    return;
+	}
+
+	rfbLog("\n");
+
+#if USE_LIBWRAP
+        if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr),
+                       STRING_UNKNOWN)) {
+          rfbLog("Rejected connection from client %s\n",
+                 inet_ntoa(addr.sin_addr));
+          close(sock);
+          return;
+        }
+#endif
+
+	rfbLog("Got VNC connection from client %s\n", inet_ntoa(addr.sin_addr));
+
+	AddEnabledDevice(sock);
+	FD_SET(sock, &pVNC->allFds);
+	pVNC->maxFd = max(sock,pVNC->maxFd);
+
+	rfbNewClientConnection(pScreen, sock);
+
+	FD_CLR(pVNC->rfbListenSock, &fds);
+	if (--nfds == 0)
+	    return;
+    }
+
+    if ((pVNC->udpSock != -1) && FD_ISSET(pVNC->udpSock, &fds)) {
+
+	if (recvfrom(pVNC->udpSock, buf, 1, MSG_PEEK,
+		     (struct sockaddr *)&addr, &addrlen) < 0) {
+
+	    rfbLogPerror("rfbCheckFds: UDP: recvfrom");
+	    rfbDisconnectUDPSock(pScreen);
+
+	} else {
+
+	    if (!pVNC->udpSockConnected ||
+		(memcmp(&addr, &udpRemoteAddr, addrlen) != 0))
+	    {
+		/* new remote end */
+		rfbLog("rfbCheckFds: UDP: got connection\n");
+
+		memcpy(&udpRemoteAddr, &addr, addrlen);
+		pVNC->udpSockConnected = TRUE;
+
+		if (connect(pVNC->udpSock,
+			    (struct sockaddr *)&addr, addrlen) < 0) {
+		    rfbLogPerror("rfbCheckFds: UDP: connect");
+		    rfbDisconnectUDPSock(pScreen);
+		    return;
+		}
+
+		rfbNewUDPConnection(pVNC->udpSock);
+	    }
+
+	    rfbProcessUDPInput(pScreen, pVNC->udpSock);
+	}
+
+	FD_CLR(pVNC->udpSock, &fds);
+	if (--nfds == 0)
+	    return;
+    }
+
+    for (sock = 0; sock <= pVNC->maxFd; sock++) {
+	if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &pVNC->allFds)) {
+#if XFREE86VNC
+	    if (!pScrn->vtSema)
+		rfbCloseSock(pScreen, sock);
+	    else
+#endif
+	    	rfbProcessClientMessage(pScreen, sock);
+	}
+    }
+}
+
+
+void
+rfbDisconnectUDPSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    pVNC->udpSockConnected = FALSE;
+}
+
+
+void
+rfbCloseSock(ScreenPtr pScreen, int sock)
+{
+    VNCSCREENPTR(pScreen);
+    close(sock);
+    RemoveEnabledDevice(sock);
+    FD_CLR(sock, &pVNC->allFds);
+    rfbClientConnectionGone(sock);
+    if (sock == inetdSock)
+	GiveUp(0);
+}
+
+#if 0
+/*
+ * rfbWaitForClient can be called to wait for the RFB client to send us a
+ * message.  When one is received it is processed by calling
+ * rfbProcessClientMessage().
+ */
+
+void
+rfbWaitForClient(sock)
+    int sock;
+{
+    int n;
+    fd_set fds;
+    struct timeval tv;
+
+    FD_ZERO(&fds);
+    FD_SET(sock, &fds);
+    tv.tv_sec = rfbMaxClientWait / 1000;
+    tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
+    n = select(sock+1, &fds, NULL, NULL, &tv);
+    if (n < 0) {
+	rfbLogPerror("rfbWaitForClient: select");
+	exit(1);
+    }
+    if (n == 0) {
+	rfbCloseSock(sock);
+	return;
+    }
+
+    rfbProcessClientMessage(sock);
+}
+#endif
+
+/*
+ * rfbConnect is called to make a connection out to a given TCP address.
+ */
+
+int
+rfbConnect(ScreenPtr pScreen, char *host, int port)
+{
+    VNCSCREENPTR(pScreen);
+    int sock;
+    int one = 1;
+
+    rfbLog("\n");
+    rfbLog("Making connection to client on host %s port %d\n",
+	   host,port);
+
+    if ((sock = ConnectToTcpAddr(host, port)) < 0) {
+	rfbLogPerror("connection failed");
+	return -1;
+    }
+
+    if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	rfbLogPerror("fcntl failed");
+	close(sock);
+	return -1;
+    }
+
+    if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		   (char *)&one, sizeof(one)) < 0) {
+	rfbLogPerror("setsockopt failed");
+	close(sock);
+	return -1;
+    }
+
+    AddEnabledDevice(sock);
+    FD_SET(sock, &pVNC->allFds);
+    pVNC->maxFd = max(sock,pVNC->maxFd);
+
+    return sock;
+}
+
+
+
+
+/*
+ * ReadExact reads an exact number of bytes on a TCP socket.  Returns 1 if
+ * those bytes have been read, 0 if the other end has closed, or -1 if an error
+ * occurred (errno is set to ETIMEDOUT if it timed out).
+ */
+
+int
+ReadExact(sock, buf, len)
+    int sock;
+    char *buf;
+    int len;
+{
+    int n;
+    fd_set fds;
+    int tries = 5;
+    struct timeval tv;
+
+    while (len > 0) {
+	n = read(sock, buf, len);
+
+	if (n > 0) {
+
+	    buf += n;
+	    len -= n;
+
+	} else if (n == 0) {
+
+	    return 0;
+
+	} else {
+	    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+		return n;
+	    }
+
+	    do {
+	   	FD_ZERO(&fds);
+	    	FD_SET(sock, &fds);
+	    	tv.tv_sec = rfbMaxClientWait / 1000;
+	    	tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
+	    	n = select(sock+1, &fds, NULL, NULL, &tv);
+		tries--;
+		
+	    /* We really need to retry if we get EINTR, so spin */
+	    /* If after 5 attempts we're still broke, abort.... */
+
+	    } while ((n < 0 && errno == EINTR) && tries > 0);
+
+	    if (n < 0) {
+		rfbLogPerror("ReadExact: select");
+		return n;
+	    }
+	    if (n == 0) {
+		errno = ETIMEDOUT;
+		return -1;
+	    }
+	}
+    }
+    return 1;
+}
+
+
+
+/*
+ * WriteExact writes an exact number of bytes on a TCP socket.  Returns 1 if
+ * those bytes have been written, or -1 if an error occurred (errno is set to
+ * ETIMEDOUT if it timed out).
+ */
+
+int
+WriteExact(sock, buf, len)
+    int sock;
+    char *buf;
+    int len;
+{
+    int n;
+    fd_set fds;
+    struct timeval tv;
+    int totalTimeWaited = 0;
+
+    while (len > 0) {
+	n = write(sock, buf, len);
+
+	if (n > 0) {
+
+	    buf += n;
+	    len -= n;
+
+	} else if (n == 0) {
+
+	    rfbLog("WriteExact: write returned 0?\n");
+	    return -1;
+
+	} else {
+	    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+		return n;
+	    }
+
+#if 0
+	    /* Retry every 5 seconds until we exceed rfbMaxClientWait.  We
+	       need to do this because select doesn't necessarily return
+	       immediately when the other end has gone away */
+
+	    FD_ZERO(&fds);
+	    FD_SET(sock, &fds);
+	    tv.tv_sec = 5;
+	    tv.tv_usec = 0;
+#else
+	    /* We're in the WakeupHandler now, so don't wait */
+
+	    FD_ZERO(&fds);
+	    FD_SET(sock, &fds);
+	    tv.tv_sec = 0;
+	    tv.tv_usec = 0;
+#endif
+	    n = select(sock+1, NULL, &fds, NULL, &tv);
+#if 0
+	    if (n < 0) {
+		rfbLogPerror("WriteExact: select");
+		return n;
+	    }
+	    if (n == 0) {
+		totalTimeWaited += 5000;
+		if (totalTimeWaited >= rfbMaxClientWait) {
+		    errno = ETIMEDOUT;
+		    return -1;
+		}
+	    } else {
+		totalTimeWaited = 0;
+	    }
+#endif
+	}
+    }
+    return 1;
+}
+
+
+int
+ListenOnTCPPort(ScreenPtr pScreen, int port)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    int sock;
+    int one = 1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = pVNC->interface.s_addr;
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one)) < 0) {
+	close(sock);
+	return -1;
+    }
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	close(sock);
+	return -1;
+    }
+    if (listen(sock, 5) < 0) {
+	close(sock);
+	return -1;
+    }
+
+    return sock;
+}
+
+
+int
+ConnectToTcpAddr(host, port)
+    char *host;
+    int port;
+{
+    struct hostent *hp;
+    int sock, n;
+    struct sockaddr_in addr;
+    int tries = 5;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    if ((addr.sin_addr.s_addr = inet_addr(host)) == -1)
+    {
+	if (!(hp = gethostbyname(host))) {
+	    errno = EINVAL;
+	    return -1;
+	}
+	addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
+    }
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	return -1;
+    }
+
+    do {
+    	sock = socket(AF_INET, SOCK_STREAM, 0);
+	tries--;
+
+	/* We really need to retry if we get EINTR, so spin */
+	/* If after 5 attempts we're still broke, abort.... */
+
+    } while ((sock < 0 && errno == EINTR) && tries > 0);
+
+    if (sock < 0) {
+	return -1;
+    }
+
+    tries = 5;
+
+    do {
+    	n = connect(sock, (struct sockaddr *)&addr, (sizeof(addr)));
+	tries--;
+
+	/* We really need to retry if we get EINTR, so spin */
+	/* If after 5 attempts we're still broke, abort.... */
+
+    } while ((n < 0 && errno == EINTR) && tries > 0);
+
+    if (n < 0) {
+	close(sock);
+	return -1;
+    }
+
+    return sock;
+}
+
+
+int
+ListenOnUDPPort(ScreenPtr pScreen, int port)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    int sock;
+    int one = 1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = pVNC->interface.s_addr;
+
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one)) < 0) {
+	return -1;
+    }
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	return -1;
+    }
+
+    return sock;
+}
+
+#if 0
+/*
+ * rdpInitSockets sets up the TCP for RDP
+ * connections.  It does nothing if called again.
+ */
+
+Bool
+rdpInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if ((pVNC->rdpListenSock = ListenOnTCPPort(pScreen, pVNC->rdpPort)) < 0) {
+	rfbLogPerror("ListenOnTCPPort");
+	pVNC->rdpPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for RDP connections on TCP port %d\n", pVNC->rdpPort);
+
+    AddEnabledDevice(pVNC->rdpListenSock);
+
+    return TRUE;
+}
+#endif
diff -u -rNp a/hw/vnc/sprite.c b/hw/vnc/sprite.c
--- a/hw/vnc/sprite.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/sprite.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2491 @@
+/*
+ * sprite.c
+ *
+ * software sprite routines - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* $XConsortium: misprite.c,v 5.47 94/04/17 20:27:53 dpw Exp $ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#include "rfb.h"
+# include   <X11/X.h>
+# include   <X11/Xproto.h>
+# include   <X11/fonts/font.h>
+# include   <X11/fonts/fontstruct.h>
+# include   "misc.h"
+# include   "pixmapstr.h"
+# include   "input.h"
+# include   "mi.h"
+# include   "cursorstr.h"
+# include   "scrnintstr.h"
+# include   "colormapst.h"
+# include   "windowstr.h"
+# include   "gcstruct.h"
+# include   "mipointer.h"
+# include   "spritest.h"
+# include   "dixfontstr.h"
+#ifdef RENDER
+# include   "mipict.h"
+#endif
+
+/*
+ * screen wrappers
+ */
+
+static int  rfbSpriteScreenIndex;
+static unsigned long rfbSpriteGeneration = 0;
+
+static Bool	    rfbSpriteCloseScreen(int i, ScreenPtr pScreen);
+static void	    rfbSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
+				     int w, int h, unsigned int format,
+				     unsigned long planemask, char *pdstLine);
+static void	    rfbSpriteGetSpans(DrawablePtr pDrawable, int wMax,
+				     DDXPointPtr ppt, int *pwidth, int nspans,
+			     char *pdstStart);
+static void	    rfbSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
+					   int width, int height);
+static Bool	    rfbSpriteCreateGC(GCPtr pGC);
+static void	    rfbSpriteBlockHandler(int i, pointer blockData,
+					 pointer pTimeout,
+					 pointer pReadMask);
+static void	    rfbSpriteInstallColormap(ColormapPtr pMap);
+static void	    rfbSpriteStoreColors(ColormapPtr pMap, int ndef,
+					xColorItem *pdef);
+
+static void	    rfbSpritePaintWindowBackground(WindowPtr pWin,
+						  RegionPtr pRegion, int what);
+static void	    rfbSpritePaintWindowBorder(WindowPtr pWin,
+					      RegionPtr pRegion, int what);
+static void	    rfbSpriteCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
+				       RegionPtr pRegion);
+static void	    rfbSpriteClearToBackground(WindowPtr pWin, int x, int y,
+					      int w, int h,
+					      Bool generateExposures);
+
+#ifdef RENDER
+static void	    rfbSpriteComposite(CARD8	op,
+				      PicturePtr pSrc,
+				      PicturePtr pMask,
+				      PicturePtr pDst,
+				      INT16	xSrc,
+				      INT16	ySrc,
+				      INT16	xMask,
+				      INT16	yMask,
+				      INT16	xDst,
+				      INT16	yDst,
+				      CARD16	width,
+				      CARD16	height);
+
+static void	    rfbSpriteGlyphs(CARD8	op,
+				   PicturePtr	pSrc,
+				   PicturePtr	pDst,
+				   PictFormatPtr maskFormat,
+				   INT16	xSrc,
+				   INT16	ySrc,
+				   int		nlist,
+				   GlyphListPtr	list,
+				   GlyphPtr	*glyphs);
+#endif
+
+static void	    rfbSpriteSaveDoomedAreas(WindowPtr pWin,
+					    RegionPtr pObscured, int dx,
+					    int dy);
+static RegionPtr    rfbSpriteRestoreAreas(WindowPtr pWin, RegionPtr pRgnExposed);
+static void	    rfbSpriteComputeSaved(ScreenPtr pScreen);
+
+#define SCREEN_PROLOGUE(pScreen, field)\
+  ((pScreen)->field = \
+   ((rfbSpriteScreenPtr) (pScreen)->devPrivates[rfbSpriteScreenIndex].ptr)->field) 
+
+#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
+    ((pScreen)->field = wrapper)
+
+/*
+ * GC func wrappers
+ */
+
+static int  rfbSpriteGCIndex;
+
+static void rfbSpriteValidateGC(GCPtr pGC, unsigned long stateChanges,
+			       DrawablePtr pDrawable);
+static void rfbSpriteCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
+static void rfbSpriteDestroyGC(GCPtr pGC);
+static void rfbSpriteChangeGC(GCPtr pGC, unsigned long mask);
+static void rfbSpriteChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
+static void rfbSpriteDestroyClip(GCPtr pGC);
+static void rfbSpriteCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
+
+static GCFuncs	rfbSpriteGCFuncs = {
+    rfbSpriteValidateGC,
+    rfbSpriteChangeGC,
+    rfbSpriteCopyGC,
+    rfbSpriteDestroyGC,
+    rfbSpriteChangeClip,
+    rfbSpriteDestroyClip,
+    rfbSpriteCopyClip,
+};
+
+#define GC_FUNC_PROLOGUE(pGC)					\
+    rfbSpriteGCPtr   pGCPriv =					\
+	(rfbSpriteGCPtr) (pGC)->devPrivates[rfbSpriteGCIndex].ptr;\
+    (pGC)->funcs = pGCPriv->wrapFuncs;				\
+    if (pGCPriv->wrapOps)					\
+	(pGC)->ops = pGCPriv->wrapOps;
+
+#define GC_FUNC_EPILOGUE(pGC)					\
+    pGCPriv->wrapFuncs = (pGC)->funcs;				\
+    (pGC)->funcs = &rfbSpriteGCFuncs;				\
+    if (pGCPriv->wrapOps)					\
+    {								\
+	pGCPriv->wrapOps = (pGC)->ops;				\
+	(pGC)->ops = &rfbSpriteGCOps;				\
+    }
+
+/*
+ * GC op wrappers
+ */
+
+static void	    rfbSpriteFillSpans(DrawablePtr pDrawable, GCPtr pGC,
+				      int nInit, DDXPointPtr pptInit,
+				      int *pwidthInit, int fSorted);
+static void	    rfbSpriteSetSpans(DrawablePtr pDrawable, GCPtr pGC,
+				     char *psrc, DDXPointPtr ppt, int *pwidth,
+				     int nspans, int fSorted);
+static void	    rfbSpritePutImage(DrawablePtr pDrawable, GCPtr pGC,
+				     int depth, int x, int y, int w, int h,
+				     int leftPad, int format, char *pBits);
+static RegionPtr    rfbSpriteCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
+				     GCPtr pGC, int srcx, int srcy, int w,
+				     int h, int dstx, int dsty);
+static RegionPtr    rfbSpriteCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
+				     GCPtr pGC, int srcx, int srcy, int w,
+				     int h, int dstx, int dsty,
+				     unsigned long plane);
+static void	    rfbSpritePolyPoint(DrawablePtr pDrawable, GCPtr pGC,
+				      int mode, int npt, xPoint *pptInit);
+static void	    rfbSpritePolylines(DrawablePtr pDrawable, GCPtr pGC,
+				      int mode, int npt, DDXPointPtr pptInit);
+static void	    rfbSpritePolySegment(DrawablePtr pDrawable, GCPtr pGC,
+					int nseg, xSegment *pSegs);
+static void	    rfbSpritePolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
+					  int nrects, xRectangle *pRects);
+static void	    rfbSpritePolyArc(DrawablePtr pDrawable, GCPtr pGC,
+				    int narcs, xArc *parcs);
+static void	    rfbSpriteFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
+					int shape, int mode, int count,
+					DDXPointPtr pPts);
+static void	    rfbSpritePolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
+					 int nrectFill, xRectangle *prectInit);
+static void	    rfbSpritePolyFillArc(DrawablePtr pDrawable, GCPtr pGC,
+					int narcs, xArc *parcs);
+static int	    rfbSpritePolyText8(DrawablePtr pDrawable, GCPtr pGC,
+				      int x, int y, int count, char *chars);
+static int	    rfbSpritePolyText16(DrawablePtr pDrawable, GCPtr pGC,
+				       int x, int y, int count,
+				       unsigned short *chars);
+static void	    rfbSpriteImageText8(DrawablePtr pDrawable, GCPtr pGC,
+				       int x, int y, int count, char *chars);
+static void	    rfbSpriteImageText16(DrawablePtr pDrawable, GCPtr pGC,
+					int x, int y, int count,
+					unsigned short *chars);
+static void	    rfbSpriteImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+					  int x, int y, unsigned int nglyph,
+					  CharInfoPtr *ppci,
+					  pointer pglyphBase);
+static void	    rfbSpritePolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
+					 int x, int y, unsigned int nglyph,
+					 CharInfoPtr *ppci,
+					 pointer pglyphBase);
+static void	    rfbSpritePushPixels(GCPtr pGC, PixmapPtr pBitMap,
+				       DrawablePtr pDst, int w, int h,
+				       int x, int y);
+#ifdef NEED_LINEHELPER
+static void	    rfbSpriteLineHelper();
+#endif
+
+static GCOps rfbSpriteGCOps = {
+    rfbSpriteFillSpans,	    rfbSpriteSetSpans,	    rfbSpritePutImage,	
+    rfbSpriteCopyArea,	    rfbSpriteCopyPlane,	    rfbSpritePolyPoint,
+    rfbSpritePolylines,	    rfbSpritePolySegment,   rfbSpritePolyRectangle,
+    rfbSpritePolyArc,	    rfbSpriteFillPolygon,   rfbSpritePolyFillRect,
+    rfbSpritePolyFillArc,   rfbSpritePolyText8,	    rfbSpritePolyText16,
+    rfbSpriteImageText8,    rfbSpriteImageText16,   rfbSpriteImageGlyphBlt,
+    rfbSpritePolyGlyphBlt,  rfbSpritePushPixels
+#ifdef NEED_LINEHELPER
+    , rfbSpriteLineHelper
+#endif
+};
+
+/*
+ * testing only -- remove cursor for every draw.  Eventually,
+ * each draw operation will perform a bounding box check against
+ * the saved cursor area
+ */
+
+#define GC_SETUP_CHEAP(pDrawable)				    \
+    rfbSpriteScreenPtr	pScreenPriv = (rfbSpriteScreenPtr)	    \
+	(pDrawable)->pScreen->devPrivates[rfbSpriteScreenIndex].ptr; \
+
+#define GC_SETUP(pDrawable, pGC)				    \
+    GC_SETUP_CHEAP(pDrawable)					    \
+    rfbSpriteGCPtr	pGCPrivate = (rfbSpriteGCPtr)		    \
+	(pGC)->devPrivates[rfbSpriteGCIndex].ptr;		    \
+    GCFuncs *oldFuncs = pGC->funcs;
+
+#define GC_SETUP_AND_CHECK(pDrawable, pGC)			    \
+    GC_SETUP(pDrawable, pGC);					    \
+    if (GC_CHECK((WindowPtr)pDrawable))				    \
+	rfbSpriteRemoveCursor (pDrawable->pScreen);
+    
+#define GC_CHECK(pWin)						    \
+    (pVNC->cursorIsDrawn &&					    \
+        (pScreenPriv->pCacheWin == pWin ?			    \
+	    pScreenPriv->isInCacheWin : (			    \
+	    (pScreenPriv->pCacheWin = (pWin)) ,			    \
+	    (pScreenPriv->isInCacheWin =			    \
+		(pWin)->drawable.x < pScreenPriv->saved.x2 &&	    \
+		pScreenPriv->saved.x1 < (pWin)->drawable.x +	    \
+				    (int) (pWin)->drawable.width && \
+		(pWin)->drawable.y < pScreenPriv->saved.y2 &&	    \
+		pScreenPriv->saved.y1 < (pWin)->drawable.y +	    \
+				    (int) (pWin)->drawable.height &&\
+		RECT_IN_REGION((pWin)->drawable.pScreen, &(pWin)->borderClip, \
+			&pScreenPriv->saved) != rgnOUT))))
+
+#define GC_OP_PROLOGUE(pGC) { \
+    (pGC)->funcs = pGCPrivate->wrapFuncs; \
+    (pGC)->ops = pGCPrivate->wrapOps; \
+    }
+
+#define GC_OP_EPILOGUE(pGC) { \
+    pGCPrivate->wrapOps = (pGC)->ops; \
+    (pGC)->funcs = oldFuncs; \
+    (pGC)->ops = &rfbSpriteGCOps; \
+    }
+
+/*
+ * pointer-sprite method table
+ */
+
+static Bool rfbSpriteRealizeCursor (),	rfbSpriteUnrealizeCursor ();
+static void rfbSpriteSetCursor (),	rfbSpriteMoveCursor ();
+
+miPointerSpriteFuncRec rfbSpritePointerFuncs = {
+    rfbSpriteRealizeCursor,
+    rfbSpriteUnrealizeCursor,
+    rfbSpriteSetCursor,
+    rfbSpriteMoveCursor,
+};
+
+/*
+ * other misc functions
+ */
+
+static Bool rfbDisplayCursor (ScreenPtr pScreen, CursorPtr pCursor);
+
+
+/*
+ * rfbSpriteInitialize -- called from device-dependent screen
+ * initialization proc after all of the function pointers have
+ * been stored in the screen structure.
+ */
+
+Bool
+rfbSpriteInitialize (pScreen, cursorFuncs, screenFuncs)
+    ScreenPtr		    pScreen;
+    rfbSpriteCursorFuncPtr   cursorFuncs;
+    miPointerScreenFuncPtr  screenFuncs;
+{
+    rfbSpriteScreenPtr	pPriv;
+    VisualPtr		pVisual;
+#ifdef RENDER
+    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
+#endif
+    
+    if (rfbSpriteGeneration != serverGeneration)
+    {
+	rfbSpriteScreenIndex = AllocateScreenPrivateIndex ();
+	if (rfbSpriteScreenIndex < 0)
+	    return FALSE;
+	rfbSpriteGeneration = serverGeneration;
+	rfbSpriteGCIndex = AllocateGCPrivateIndex ();
+    }
+    if (!AllocateGCPrivate(pScreen, rfbSpriteGCIndex, sizeof(rfbSpriteGCRec)))
+	return FALSE;
+    pPriv = (rfbSpriteScreenPtr) xalloc (sizeof (rfbSpriteScreenRec));
+    if (!pPriv)
+	return FALSE;
+    if (!miPointerInitialize (pScreen, &rfbSpritePointerFuncs, screenFuncs,TRUE))
+    {
+	xfree ((pointer) pPriv);
+	return FALSE;
+    }
+    for (pVisual = pScreen->visuals;
+	 pVisual->vid != pScreen->rootVisual;
+	 pVisual++)
+	;
+    pPriv->pVisual = pVisual;
+    pPriv->CloseScreen = pScreen->CloseScreen;
+    pPriv->GetImage = pScreen->GetImage;
+    pPriv->GetSpans = pScreen->GetSpans;
+    pPriv->SourceValidate = pScreen->SourceValidate;
+    pPriv->CreateGC = pScreen->CreateGC;
+#if 0
+    pPriv->BlockHandler = pScreen->BlockHandler;
+#endif
+    pPriv->InstallColormap = pScreen->InstallColormap;
+    pPriv->StoreColors = pScreen->StoreColors;
+    pPriv->DisplayCursor = pScreen->DisplayCursor;
+
+    pPriv->PaintWindowBackground = pScreen->PaintWindowBackground;
+    pPriv->PaintWindowBorder = pScreen->PaintWindowBorder;
+    pPriv->CopyWindow = pScreen->CopyWindow;
+    pPriv->ClearToBackground = pScreen->ClearToBackground;
+
+    pPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas;
+    pPriv->RestoreAreas = pScreen->RestoreAreas;
+#ifdef RENDER
+    if (ps)
+    {
+	pPriv->Composite = ps->Composite;
+	pPriv->Glyphs = ps->Glyphs;
+    }
+#endif
+
+    pPriv->pCursor = NULL;
+    pPriv->x = 0;
+    pPriv->y = 0;
+    pPriv->shouldBeUp = FALSE;
+    pPriv->pCacheWin = NullWindow;
+    pPriv->isInCacheWin = FALSE;
+    pPriv->checkPixels = TRUE;
+    pPriv->pInstalledMap = NULL;
+    pPriv->pColormap = NULL;
+    pPriv->funcs = cursorFuncs;
+    pPriv->colors[SOURCE_COLOR].red = 0;
+    pPriv->colors[SOURCE_COLOR].green = 0;
+    pPriv->colors[SOURCE_COLOR].blue = 0;
+    pPriv->colors[MASK_COLOR].red = 0;
+    pPriv->colors[MASK_COLOR].green = 0;
+    pPriv->colors[MASK_COLOR].blue = 0;
+    pScreen->devPrivates[rfbSpriteScreenIndex].ptr = (pointer) pPriv;
+    pScreen->CloseScreen = rfbSpriteCloseScreen;
+    pScreen->GetImage = rfbSpriteGetImage;
+    pScreen->GetSpans = rfbSpriteGetSpans;
+    pScreen->SourceValidate = rfbSpriteSourceValidate;
+    pScreen->CreateGC = rfbSpriteCreateGC;
+#if 0
+    pScreen->BlockHandler = rfbSpriteBlockHandler;
+#endif
+    pScreen->InstallColormap = rfbSpriteInstallColormap;
+    pScreen->StoreColors = rfbSpriteStoreColors;
+
+    pScreen->PaintWindowBackground = rfbSpritePaintWindowBackground;
+    pScreen->PaintWindowBorder = rfbSpritePaintWindowBorder;
+    pScreen->CopyWindow = rfbSpriteCopyWindow;
+    pScreen->ClearToBackground = rfbSpriteClearToBackground;
+
+    pScreen->SaveDoomedAreas = rfbSpriteSaveDoomedAreas;
+    pScreen->RestoreAreas = rfbSpriteRestoreAreas;
+
+    pScreen->DisplayCursor = rfbDisplayCursor;
+#ifdef RENDER
+    if (ps)
+    {
+	ps->Composite = rfbSpriteComposite;
+	ps->Glyphs = rfbSpriteGlyphs;
+    }
+#endif
+
+    return TRUE;
+}
+
+/*
+ * Screen wrappers
+ */
+
+/*
+ * CloseScreen wrapper -- unwrap everything, free the private data
+ * and call the wrapped function
+ */
+
+static Bool
+rfbSpriteCloseScreen (i, pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+#ifdef RENDER
+    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
+#endif
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    pScreen->CloseScreen = pScreenPriv->CloseScreen;
+    pScreen->GetImage = pScreenPriv->GetImage;
+    pScreen->GetSpans = pScreenPriv->GetSpans;
+    pScreen->SourceValidate = pScreenPriv->SourceValidate;
+    pScreen->CreateGC = pScreenPriv->CreateGC;
+#if 0
+    pScreen->BlockHandler = pScreenPriv->BlockHandler;
+#endif
+    pScreen->InstallColormap = pScreenPriv->InstallColormap;
+    pScreen->StoreColors = pScreenPriv->StoreColors;
+
+    pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground;
+    pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder;
+    pScreen->CopyWindow = pScreenPriv->CopyWindow;
+    pScreen->ClearToBackground = pScreenPriv->ClearToBackground;
+
+    pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas;
+    pScreen->RestoreAreas = pScreenPriv->RestoreAreas;
+#ifdef RENDER
+    if (ps)
+    {
+	ps->Composite = pScreenPriv->Composite;
+	ps->Glyphs = pScreenPriv->Glyphs;
+    }
+#endif
+
+    xfree ((pointer) pScreenPriv);
+
+    return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+static void
+rfbSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine)
+    DrawablePtr	    pDrawable;
+    int		    sx, sy, w, h;
+    unsigned int    format;
+    unsigned long   planemask;
+    char	    *pdstLine;
+{
+    ScreenPtr	    pScreen = pDrawable->pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, GetImage);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    if (pDrawable->type == DRAWABLE_WINDOW &&
+        pVNC->cursorIsDrawn &&
+	ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h))
+    {
+	rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
+			  format, planemask, pdstLine);
+
+    SCREEN_EPILOGUE (pScreen, GetImage, rfbSpriteGetImage);
+}
+
+static void
+rfbSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart)
+    DrawablePtr	pDrawable;
+    int		wMax;
+    DDXPointPtr	ppt;
+    int		*pwidth;
+    int		nspans;
+    char	*pdstStart;
+{
+    ScreenPtr		    pScreen = pDrawable->pScreen;
+    rfbSpriteScreenPtr	    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, GetSpans);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn)
+    {
+	register DDXPointPtr    pts;
+	register int    	*widths;
+	register int    	nPts;
+	register int    	xorg,
+				yorg;
+
+	xorg = pDrawable->x;
+	yorg = pDrawable->y;
+
+	for (pts = ppt, widths = pwidth, nPts = nspans;
+	     nPts--;
+	     pts++, widths++)
+ 	{
+	    if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg,
+			     pts->x+xorg,*widths))
+	    {
+		rfbSpriteRemoveCursor (pScreen);
+		break;
+	    }
+	}
+    }
+
+    (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+
+    SCREEN_EPILOGUE (pScreen, GetSpans, rfbSpriteGetSpans);
+}
+
+static void
+rfbSpriteSourceValidate (pDrawable, x, y, width, height)
+    DrawablePtr	pDrawable;
+    int		x, y, width, height;
+{
+    ScreenPtr		    pScreen = pDrawable->pScreen;
+    rfbSpriteScreenPtr	    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, SourceValidate);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn &&
+	ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y,
+		    x, y, width, height))
+    {
+	rfbSpriteRemoveCursor (pScreen);
+    }
+
+    if (pScreen->SourceValidate)
+	(*pScreen->SourceValidate) (pDrawable, x, y, width, height);
+
+    SCREEN_EPILOGUE (pScreen, SourceValidate, rfbSpriteSourceValidate);
+}
+
+static Bool
+rfbSpriteCreateGC (pGC)
+    GCPtr   pGC;
+{
+    ScreenPtr	    pScreen = pGC->pScreen;
+    Bool	    ret;
+    rfbSpriteGCPtr   pPriv;
+
+    SCREEN_PROLOGUE (pScreen, CreateGC);
+    
+    pPriv = (rfbSpriteGCPtr)pGC->devPrivates[rfbSpriteGCIndex].ptr;
+
+    ret = (*pScreen->CreateGC) (pGC);
+
+    pPriv->wrapOps = NULL;
+    pPriv->wrapFuncs = pGC->funcs;
+    pGC->funcs = &rfbSpriteGCFuncs;
+
+    SCREEN_EPILOGUE (pScreen, CreateGC, rfbSpriteCreateGC);
+
+    return ret;
+}
+
+static void
+rfbSpriteBlockHandler (i, blockData, pTimeout, pReadmask)
+    int	i;
+    pointer	blockData;
+    pointer	pTimeout;
+    pointer	pReadmask;
+{
+    ScreenPtr		pScreen = screenInfo.screens[i];
+    rfbSpriteScreenPtr	pPriv;
+    VNCSCREENPTR(pScreen);
+
+    pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    SCREEN_PROLOGUE(pScreen, BlockHandler);
+    
+    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+
+    SCREEN_EPILOGUE(pScreen, BlockHandler, rfbSpriteBlockHandler);
+
+    if (!pVNC->cursorIsDrawn && pPriv->shouldBeUp)
+	rfbSpriteRestoreCursor (pScreen);
+}
+
+static void
+rfbSpriteInstallColormap (pMap)
+    ColormapPtr	pMap;
+{
+    ScreenPtr		pScreen = pMap->pScreen;
+    rfbSpriteScreenPtr	pPriv;
+    VNCSCREENPTR(pScreen);
+
+    pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    SCREEN_PROLOGUE(pScreen, InstallColormap);
+    
+    (*pScreen->InstallColormap) (pMap);
+
+    SCREEN_EPILOGUE(pScreen, InstallColormap, rfbSpriteInstallColormap);
+
+    pPriv->pInstalledMap = pMap;
+    if (pPriv->pColormap != pMap)
+    {
+    	pPriv->checkPixels = TRUE;
+	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+}
+
+static void
+rfbSpriteStoreColors (pMap, ndef, pdef)
+    ColormapPtr	pMap;
+    int		ndef;
+    xColorItem	*pdef;
+{
+    ScreenPtr		pScreen = pMap->pScreen;
+    rfbSpriteScreenPtr	pPriv;
+    int			i;
+    int			updated;
+    VisualPtr		pVisual;
+    VNCSCREENPTR(pScreen);
+
+    pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    SCREEN_PROLOGUE(pScreen, StoreColors);
+    
+    (*pScreen->StoreColors) (pMap, ndef, pdef);
+
+    SCREEN_EPILOGUE(pScreen, StoreColors, rfbSpriteStoreColors);
+
+    if (pPriv->pColormap == pMap)
+    {
+	updated = 0;
+	pVisual = pMap->pVisual;
+	if (pVisual->class == DirectColor)
+	{
+	    /* Direct color - match on any of the subfields */
+
+#define MaskMatch(a,b,mask) ((a) & ((pVisual->mask) == (b)) & (pVisual->mask))
+
+#define UpdateDAC(plane,dac,mask) {\
+    if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\
+	pPriv->colors[plane].dac = pdef[i].dac; \
+	updated = 1; \
+    } \
+}
+
+#define CheckDirect(plane) \
+	    UpdateDAC(plane,red,redMask) \
+	    UpdateDAC(plane,green,greenMask) \
+	    UpdateDAC(plane,blue,blueMask)
+
+	    for (i = 0; i < ndef; i++)
+	    {
+		CheckDirect (SOURCE_COLOR)
+		CheckDirect (MASK_COLOR)
+	    }
+	}
+	else
+	{
+	    /* PseudoColor/GrayScale - match on exact pixel */
+	    for (i = 0; i < ndef; i++)
+	    {
+	    	if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel)
+	    	{
+		    pPriv->colors[SOURCE_COLOR] = pdef[i];
+		    if (++updated == 2)
+		    	break;
+	    	}
+	    	if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel)
+	    	{
+		    pPriv->colors[MASK_COLOR] = pdef[i];
+		    if (++updated == 2)
+		    	break;
+	    	}
+	    }
+	}
+    	if (updated)
+    	{
+	    pPriv->checkPixels = TRUE;
+	    if (pVNC->cursorIsDrawn)
+	    	rfbSpriteRemoveCursor (pScreen);
+    	}
+    }
+}
+
+static void
+rfbSpriteFindColors (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr	pScreenPriv = (rfbSpriteScreenPtr)
+			    pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    CursorPtr		pCursor;
+    xColorItem		*sourceColor, *maskColor;
+
+    pCursor = pScreenPriv->pCursor;
+    sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
+    maskColor = &pScreenPriv->colors[MASK_COLOR];
+    if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
+	!(pCursor->foreRed == sourceColor->red &&
+	  pCursor->foreGreen == sourceColor->green &&
+          pCursor->foreBlue == sourceColor->blue &&
+	  pCursor->backRed == maskColor->red &&
+	  pCursor->backGreen == maskColor->green &&
+	  pCursor->backBlue == maskColor->blue))
+    {
+	pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
+	sourceColor->red = pCursor->foreRed;
+	sourceColor->green = pCursor->foreGreen;
+	sourceColor->blue = pCursor->foreBlue;
+	FakeAllocColor (pScreenPriv->pColormap, sourceColor);
+	maskColor->red = pCursor->backRed;
+	maskColor->green = pCursor->backGreen;
+	maskColor->blue = pCursor->backBlue;
+	FakeAllocColor (pScreenPriv->pColormap, maskColor);
+	/* "free" the pixels right away, don't let this confuse you */
+	FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
+	FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
+    }
+    pScreenPriv->checkPixels = FALSE;
+}
+
+/*
+ * BackingStore wrappers
+ */
+
+static void
+rfbSpriteSaveDoomedAreas (pWin, pObscured, dx, dy)
+    WindowPtr	pWin;
+    RegionPtr	pObscured;
+    int		dx, dy;
+{
+    ScreenPtr		pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr   pScreenPriv;
+    BoxRec		cursorBox;
+    VNCSCREENPTR(pScreen);
+    
+    SCREEN_PROLOGUE (pScreen, SaveDoomedAreas);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	cursorBox = pScreenPriv->saved;
+
+	if (dx || dy)
+ 	{
+	    cursorBox.x1 += dx;
+	    cursorBox.y1 += dy;
+	    cursorBox.x2 += dx;
+	    cursorBox.y2 += dy;
+	}
+	if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy);
+
+    SCREEN_EPILOGUE (pScreen, SaveDoomedAreas, rfbSpriteSaveDoomedAreas);
+}
+
+static RegionPtr
+rfbSpriteRestoreAreas (pWin, prgnExposed)
+    WindowPtr	pWin;
+    RegionPtr	prgnExposed;
+{
+    ScreenPtr		pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr   pScreenPriv;
+    RegionPtr		result;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, RestoreAreas);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	if (RECT_IN_REGION( pScreen, prgnExposed, &pScreenPriv->saved) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    result = (*pScreen->RestoreAreas) (pWin, prgnExposed);
+
+    SCREEN_EPILOGUE (pScreen, RestoreAreas, rfbSpriteRestoreAreas);
+
+    return result;
+}
+
+/*
+ * Window wrappers
+ */
+
+static void
+rfbSpritePaintWindowBackground (pWin, pRegion, what)
+    WindowPtr	pWin;
+    RegionPtr	pRegion;
+    int		what;
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, PaintWindowBackground);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	/*
+	 * If the cursor is on the same screen as the window, check the
+	 * region to paint for the cursor and remove it as necessary
+	 */
+	if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
+
+    SCREEN_EPILOGUE (pScreen, PaintWindowBackground, rfbSpritePaintWindowBackground);
+}
+
+static void
+rfbSpritePaintWindowBorder (pWin, pRegion, what)
+    WindowPtr	pWin;
+    RegionPtr	pRegion;
+    int		what;
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, PaintWindowBorder);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	/*
+	 * If the cursor is on the same screen as the window, check the
+	 * region to paint for the cursor and remove it as necessary
+	 */
+	if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
+
+    SCREEN_EPILOGUE (pScreen, PaintWindowBorder, rfbSpritePaintWindowBorder);
+}
+
+static void
+rfbSpriteCopyWindow (pWin, ptOldOrg, pRegion)
+    WindowPtr	pWin;
+    DDXPointRec	ptOldOrg;
+    RegionPtr	pRegion;
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr    pScreenPriv;
+    BoxRec	    cursorBox;
+    int		    dx, dy;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, CopyWindow);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pVNC->cursorIsDrawn)
+    {
+	/*
+	 * check both the source and the destination areas.  The given
+	 * region is source relative, so offset the cursor box by
+	 * the delta position
+	 */
+	cursorBox = pScreenPriv->saved;
+	dx = pWin->drawable.x - ptOldOrg.x;
+	dy = pWin->drawable.y - ptOldOrg.y;
+	cursorBox.x1 -= dx;
+	cursorBox.x2 -= dx;
+	cursorBox.y1 -= dy;
+	cursorBox.y2 -= dy;
+	if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT ||
+	    RECT_IN_REGION( pScreen, pRegion, &cursorBox) != rgnOUT)
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+
+    (*pScreen->CopyWindow) (pWin, ptOldOrg, pRegion);
+
+    SCREEN_EPILOGUE (pScreen, CopyWindow, rfbSpriteCopyWindow);
+}
+
+static void
+rfbSpriteClearToBackground (pWin, x, y, w, h, generateExposures)
+    WindowPtr pWin;
+    short x,y;
+    unsigned short w,h;
+    Bool generateExposures;
+{
+    ScreenPtr		pScreen = pWin->drawable.pScreen;
+    rfbSpriteScreenPtr	pScreenPriv;
+    int			realw, realh;
+    VNCSCREENPTR(pScreen);
+
+    SCREEN_PROLOGUE (pScreen, ClearToBackground);
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (GC_CHECK(pWin))
+    {
+	if (!(realw = w))
+	    realw = (int) pWin->drawable.width - x;
+	if (!(realh = h))
+	    realh = (int) pWin->drawable.height - y;
+	if (ORG_OVERLAP(&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y,
+			x, y, realw, realh))
+	{
+	    rfbSpriteRemoveCursor (pScreen);
+	}
+    }
+
+    (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+    SCREEN_EPILOGUE (pScreen, ClearToBackground, rfbSpriteClearToBackground);
+}
+
+/*
+ * GC Func wrappers
+ */
+
+static void
+rfbSpriteValidateGC (pGC, changes, pDrawable)
+    GCPtr	pGC;
+    unsigned long	changes;
+    DrawablePtr	pDrawable;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+    
+    pGCPriv->wrapOps = NULL;
+    if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDrawable)->viewable)
+    {
+	WindowPtr   pWin;
+	RegionPtr   pRegion;
+
+	pWin = (WindowPtr) pDrawable;
+	pRegion = &pWin->clipList;
+	if (pGC->subWindowMode == IncludeInferiors)
+	    pRegion = &pWin->borderClip;
+	if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion))
+	    pGCPriv->wrapOps = pGC->ops;
+    }
+
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteChangeGC (pGC, mask)
+    GCPtr	    pGC;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->ChangeGC) (pGC, mask);
+    
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteCopyGC (pGCSrc, mask, pGCDst)
+    GCPtr	    pGCSrc, pGCDst;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE (pGCDst);
+
+    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+    
+    GC_FUNC_EPILOGUE (pGCDst);
+}
+
+static void
+rfbSpriteDestroyGC (pGC)
+    GCPtr   pGC;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->DestroyGC) (pGC);
+    
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteChangeClip (pGC, type, pvalue, nrects)
+    GCPtr   pGC;
+    int		type;
+    pointer	pvalue;
+    int		nrects;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteCopyClip(pgcDst, pgcSrc)
+    GCPtr pgcDst, pgcSrc;
+{
+    GC_FUNC_PROLOGUE (pgcDst);
+
+    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+
+    GC_FUNC_EPILOGUE (pgcDst);
+}
+
+static void
+rfbSpriteDestroyClip(pGC)
+    GCPtr	pGC;
+{
+    GC_FUNC_PROLOGUE (pGC);
+
+    (* pGC->funcs->DestroyClip)(pGC);
+
+    GC_FUNC_EPILOGUE (pGC);
+}
+
+/*
+ * GC Op wrappers
+ */
+
+static void
+rfbSpriteFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nInit;			/* number of spans to fill */
+    DDXPointPtr pptInit;		/* pointer to list of start points */
+    int		*pwidthInit;		/* pointer to list of n widths */
+    int 	fSorted;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register DDXPointPtr    pts;
+	register int    	*widths;
+	register int    	nPts;
+
+	for (pts = pptInit, widths = pwidthInit, nPts = nInit;
+	     nPts--;
+	     pts++, widths++)
+ 	{
+	     if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths))
+	     {
+		 rfbSpriteRemoveCursor (pDrawable->pScreen);
+		 break;
+	     }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted)
+    DrawablePtr		pDrawable;
+    GCPtr		pGC;
+    char		*psrc;
+    register DDXPointPtr ppt;
+    int			*pwidth;
+    int			nspans;
+    int			fSorted;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register DDXPointPtr    pts;
+	register int    	*widths;
+	register int    	nPts;
+
+	for (pts = ppt, widths = pwidth, nPts = nspans;
+	     nPts--;
+	     pts++, widths++)
+ 	{
+	     if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths))
+	     {
+		 rfbSpriteRemoveCursor(pDrawable->pScreen);
+		 break;
+	     }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int		  depth;
+    int	    	  x;
+    int	    	  y;
+    int	    	  w;
+    int	    	  h;
+    int	    	  format;
+    char    	  *pBits;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	if (ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,
+			x,y,w,h))
+ 	{
+	    rfbSpriteRemoveCursor (pDrawable->pScreen);
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static RegionPtr
+rfbSpriteCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    GCPtr   	  pGC;
+    int	    	  srcx;
+    int	    	  srcy;
+    int	    	  w;
+    int	    	  h;
+    int	    	  dstx;
+    int	    	  dsty;
+{
+    RegionPtr rgn;
+    ScreenPtr 		pScreen = pGC->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDst, pGC);
+
+    /* check destination/source overlap. */
+    if (GC_CHECK((WindowPtr) pDst) &&
+	 (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) ||
+	  ((pDst == pSrc) &&
+	   ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h))))
+    {
+	rfbSpriteRemoveCursor (pDst->pScreen);
+    }
+ 
+    GC_OP_PROLOGUE (pGC);
+
+    rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				 dstx, dsty);
+
+    GC_OP_EPILOGUE (pGC);
+
+    return rgn;
+}
+
+static RegionPtr
+rfbSpriteCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    register GCPtr pGC;
+    int     	  srcx,
+		  srcy;
+    int     	  w,
+		  h;
+    int     	  dstx,
+		  dsty;
+    unsigned long  plane;
+{
+    RegionPtr rgn;
+    ScreenPtr 		pScreen = pGC->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDst, pGC);
+
+    /*
+     * check destination/source for overlap.
+     */
+    if (GC_CHECK((WindowPtr) pDst) &&
+	(ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) ||
+	 ((pDst == pSrc) &&
+	  ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h))))
+    {
+	rfbSpriteRemoveCursor (pDst->pScreen);
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx, dsty, plane);
+
+    GC_OP_EPILOGUE (pGC);
+
+    return rgn;
+}
+
+static void
+rfbSpritePolyPoint (pDrawable, pGC, mode, npt, pptInit)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		mode;		/* Origin or Previous */
+    int		npt;
+    xPoint 	*pptInit;
+{
+    xPoint	t;
+    int		n;
+    BoxRec	cursor;
+    register xPoint *pts;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    if (npt && GC_CHECK((WindowPtr) pDrawable))
+    {
+	cursor.x1 = pScreenPriv->saved.x1 - pDrawable->x;
+	cursor.y1 = pScreenPriv->saved.y1 - pDrawable->y;
+	cursor.x2 = pScreenPriv->saved.x2 - pDrawable->x;
+	cursor.y2 = pScreenPriv->saved.y2 - pDrawable->y;
+
+	if (mode == CoordModePrevious)
+	{
+	    t.x = 0;
+	    t.y = 0;
+	    for (pts = pptInit, n = npt; n--; pts++)
+	    {
+		t.x += pts->x;
+		t.y += pts->y;
+		if (cursor.x1 <= t.x && t.x <= cursor.x2 &&
+		    cursor.y1 <= t.y && t.y <= cursor.y2)
+		{
+		    rfbSpriteRemoveCursor (pDrawable->pScreen);
+		    break;
+		}
+	    }
+	}
+	else
+	{
+	    for (pts = pptInit, n = npt; n--; pts++)
+	    {
+		if (cursor.x1 <= pts->x && pts->x <= cursor.x2 &&
+		    cursor.y1 <= pts->y && pts->y <= cursor.y2)
+		{
+		    rfbSpriteRemoveCursor (pDrawable->pScreen);
+		    break;
+		}
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolylines (pDrawable, pGC, mode, npt, pptInit)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int	    	  mode;
+    int	    	  npt;
+    DDXPointPtr	  pptInit;
+{
+    BoxPtr  cursor;
+    register DDXPointPtr pts;
+    int	    n;
+    int	    x, y, x1, y1, x2, y2;
+    int	    lw;
+    int	    extra;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    if (npt && GC_CHECK((WindowPtr) pDrawable))
+    {
+	cursor = &pScreenPriv->saved;
+	lw = pGC->lineWidth;
+	x = pptInit->x + pDrawable->x;
+	y = pptInit->y + pDrawable->y;
+
+	if (npt == 1)
+	{
+	    extra = lw >> 1;
+	    if (LINE_OVERLAP(cursor, x, y, x, y, extra))
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+	}
+	else
+	{
+	    extra = lw >> 1;
+	    /*
+	     * mitered joins can project quite a way from
+	     * the line end; the 11 degree miter limit limits
+	     * this extension to 10.43 * lw / 2, rounded up
+	     * and converted to int yields 6 * lw
+	     */
+	    if (pGC->joinStyle == JoinMiter)
+		extra = 6 * lw;
+	    else if (pGC->capStyle == CapProjecting)
+		extra = lw;
+	    for (pts = pptInit + 1, n = npt - 1; n--; pts++)
+	    {
+		x1 = x;
+		y1 = y;
+		if (mode == CoordModeOrigin)
+		{
+		    x2 = pDrawable->x + pts->x;
+		    y2 = pDrawable->y + pts->y;
+		}
+		else
+		{
+		    x2 = x + pts->x;
+		    y2 = y + pts->y;
+		}
+		x = x2;
+		y = y2;
+		LINE_SORT(x1, y1, x2, y2);
+		if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra))
+		{
+		    rfbSpriteRemoveCursor (pDrawable->pScreen);
+		    break;
+		}
+	    }
+	}
+    }
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, pptInit);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolySegment(pDrawable, pGC, nseg, pSegs)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int		nseg;
+    xSegment	*pSegs;
+{
+    int	    n;
+    register xSegment *segs;
+    BoxPtr  cursor;
+    int	    x1, y1, x2, y2;
+    int	    extra;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (nseg && GC_CHECK((WindowPtr) pDrawable))
+    {
+	cursor = &pScreenPriv->saved;
+	extra = pGC->lineWidth >> 1;
+	if (pGC->capStyle == CapProjecting)
+	    extra = pGC->lineWidth;
+	for (segs = pSegs, n = nseg; n--; segs++)
+	{
+	    x1 = segs->x1 + pDrawable->x;
+	    y1 = segs->y1 + pDrawable->y;
+	    x2 = segs->x2 + pDrawable->x;
+	    y2 = segs->y2 + pDrawable->y;
+	    LINE_SORT(x1, y1, x2, y2);
+	    if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, pSegs);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyRectangle(pDrawable, pGC, nrects, pRects)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*pRects;
+{
+    register xRectangle *rects;
+    BoxPtr  cursor;
+    int	    lw;
+    int	    n;
+    int     x1, y1, x2, y2;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    
+    GC_SETUP (pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	lw = pGC->lineWidth >> 1;
+	cursor = &pScreenPriv->saved;
+	for (rects = pRects, n = nrects; n--; rects++)
+	{
+	    x1 = rects->x + pDrawable->x;
+	    y1 = rects->y + pDrawable->y;
+	    x2 = x1 + (int)rects->width;
+	    y2 = y1 + (int)rects->height;
+	    if (LINE_OVERLAP(cursor, x1, y1, x2, y1, lw) ||
+		LINE_OVERLAP(cursor, x2, y1, x2, y2, lw) ||
+		LINE_OVERLAP(cursor, x1, y2, x2, y2, lw) ||
+		LINE_OVERLAP(cursor, x1, y1, x1, y2, lw))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, pRects);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyArc(pDrawable, pGC, narcs, parcs)
+    DrawablePtr	pDrawable;
+    register GCPtr	pGC;
+    int		narcs;
+    xArc	*parcs;
+{
+    BoxPtr  cursor;
+    int	    lw;
+    int	    n;
+    register xArc *arcs;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    
+    GC_SETUP (pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	lw = pGC->lineWidth >> 1;
+	cursor = &pScreenPriv->saved;
+	for (arcs = parcs, n = narcs; n--; arcs++)
+	{
+	    if (ORG_OVERLAP (cursor, pDrawable->x, pDrawable->y,
+			     arcs->x - lw, arcs->y - lw,
+			     (int) arcs->width + pGC->lineWidth,
+ 			     (int) arcs->height + pGC->lineWidth))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, parcs);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteFillPolygon(pDrawable, pGC, shape, mode, count, pPts)
+    register DrawablePtr pDrawable;
+    register GCPtr	pGC;
+    int			shape, mode;
+    int			count;
+    DDXPointPtr		pPts;
+{
+    int x, y, minx, miny, maxx, maxy;
+    register DDXPointPtr pts;
+    int n;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    if (count && GC_CHECK((WindowPtr) pDrawable))
+    {
+	x = pDrawable->x;
+	y = pDrawable->y;
+	pts = pPts;
+	minx = maxx = pts->x;
+	miny = maxy = pts->y;
+	pts++;
+	n = count - 1;
+
+	if (mode == CoordModeOrigin)
+	{
+	    for (; n--; pts++)
+	    {
+		if (pts->x < minx)
+		    minx = pts->x;
+		else if (pts->x > maxx)
+		    maxx = pts->x;
+		if (pts->y < miny)
+		    miny = pts->y;
+		else if (pts->y > maxy)
+		    maxy = pts->y;
+	    }
+	    minx += x;
+	    miny += y;
+	    maxx += x;
+	    maxy += y;
+	}
+	else
+	{
+	    x += minx;
+	    y += miny;
+	    minx = maxx = x;
+	    miny = maxy = y;
+	    for (; n--; pts++)
+	    {
+		x += pts->x;
+		y += pts->y;
+		if (x < minx)
+		    minx = x;
+		else if (x > maxx)
+		    maxx = x;
+		if (y < miny)
+		    miny = y;
+		else if (y > maxy)
+		    maxy = y;
+	    }
+	}
+	if (BOX_OVERLAP(&pScreenPriv->saved,minx,miny,maxx,maxy))
+	    rfbSpriteRemoveCursor (pDrawable->pScreen);
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pPts);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyFillRect(pDrawable, pGC, nrectFill, prectInit)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nrectFill; 	/* number of rectangles to fill */
+    xRectangle	*prectInit;  	/* Pointer to first rectangle to fill */
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register int	    nRect;
+	register xRectangle *pRect;
+	register int	    xorg, yorg;
+
+	xorg = pDrawable->x;
+	yorg = pDrawable->y;
+
+	for (nRect = nrectFill, pRect = prectInit; nRect--; pRect++) {
+	    if (ORGRECT_OVERLAP(&pScreenPriv->saved,xorg,yorg,pRect)){
+		rfbSpriteRemoveCursor(pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrectFill, prectInit);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyFillArc(pDrawable, pGC, narcs, parcs)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		narcs;
+    xArc	*parcs;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+    {
+	register int	n;
+	BoxPtr		cursor;
+	register xArc *arcs;
+
+	cursor = &pScreenPriv->saved;
+
+	for (arcs = parcs, n = narcs; n--; arcs++)
+	{
+	    if (ORG_OVERLAP(cursor, pDrawable->x, pDrawable->y,
+			    arcs->x, arcs->y,
+ 			    (int) arcs->width, (int) arcs->height))
+	    {
+		rfbSpriteRemoveCursor (pDrawable->pScreen);
+		break;
+	    }
+	}
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, parcs);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+/*
+ * general Poly/Image text function.  Extract glyph information,
+ * compute bounding box and remove cursor if it is overlapped.
+ */
+
+static Bool
+rfbSpriteTextOverlap (pDraw, font, x, y, n, charinfo, imageblt, w, cursorBox)
+    DrawablePtr   pDraw;
+    FontPtr	  font;
+    int		  x, y;
+    unsigned int  n;
+    CharInfoPtr   *charinfo;
+    Bool	  imageblt;
+    unsigned int  w;
+    BoxPtr	  cursorBox;
+{
+    ExtentInfoRec extents;
+
+    x += pDraw->x;
+    y += pDraw->y;
+
+    if (FONTMINBOUNDS(font,characterWidth) >= 0)
+    {
+	/* compute an approximate (but covering) bounding box */
+	if (!imageblt || (charinfo[0]->metrics.leftSideBearing < 0))
+	    extents.overallLeft = charinfo[0]->metrics.leftSideBearing;
+	else
+	    extents.overallLeft = 0;
+	if (w)
+	    extents.overallRight = w - charinfo[n-1]->metrics.characterWidth;
+	else
+	    extents.overallRight = FONTMAXBOUNDS(font,characterWidth)
+				    * (n - 1);
+	if (imageblt && (charinfo[n-1]->metrics.characterWidth >
+			 charinfo[n-1]->metrics.rightSideBearing))
+	    extents.overallRight += charinfo[n-1]->metrics.characterWidth;
+	else
+	    extents.overallRight += charinfo[n-1]->metrics.rightSideBearing;
+	if (imageblt && FONTASCENT(font) > FONTMAXBOUNDS(font,ascent))
+	    extents.overallAscent = FONTASCENT(font);
+	else
+	    extents.overallAscent = FONTMAXBOUNDS(font, ascent);
+	if (imageblt && FONTDESCENT(font) > FONTMAXBOUNDS(font,descent))
+	    extents.overallDescent = FONTDESCENT(font);
+	else
+	    extents.overallDescent = FONTMAXBOUNDS(font,descent);
+	if (!BOX_OVERLAP(cursorBox,
+			 x + extents.overallLeft,
+			 y - extents.overallAscent,
+			 x + extents.overallRight,
+			 y + extents.overallDescent))
+	    return FALSE;
+	else if (imageblt && w)
+	    return TRUE;
+	/* if it does overlap, fall through and compute exactly, because
+	 * taking down the cursor is expensive enough to make this worth it
+	 */
+    }
+    QueryGlyphExtents(font, charinfo, n, &extents);
+    if (imageblt)
+    {
+	if (extents.overallWidth > extents.overallRight)
+	    extents.overallRight = extents.overallWidth;
+	if (extents.overallWidth < extents.overallLeft)
+	    extents.overallLeft = extents.overallWidth;
+	if (extents.overallLeft > 0)
+	    extents.overallLeft = 0;
+	if (extents.fontAscent > extents.overallAscent)
+	    extents.overallAscent = extents.fontAscent;
+	if (extents.fontDescent > extents.overallDescent)
+	    extents.overallDescent = extents.fontDescent;
+    }
+    return (BOX_OVERLAP(cursorBox,
+			x + extents.overallLeft,
+			y - extents.overallAscent,
+			x + extents.overallRight,
+			y + extents.overallDescent));
+}
+
+/*
+ * values for textType:
+ */
+#define TT_POLY8   0
+#define TT_IMAGE8  1
+#define TT_POLY16  2
+#define TT_IMAGE16 3
+
+static int 
+rfbSpriteText (pDraw, pGC, x, y, count, chars, fontEncoding, textType, cursorBox)
+    DrawablePtr	    pDraw;
+    GCPtr	    pGC;
+    int		    x,
+		    y;
+    unsigned long    count;
+    char	    *chars;
+    FontEncoding    fontEncoding;
+    Bool	    textType;
+    BoxPtr	    cursorBox;
+{
+    CharInfoPtr *charinfo;
+    register CharInfoPtr *info;
+    unsigned long i;
+    unsigned int  n;
+    int		  w;
+    void   	  (*drawFunc)() = NULL;
+
+    Bool imageblt;
+
+    imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16);
+
+    charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr));
+    if (!charinfo)
+	return x;
+
+    GetGlyphs(pGC->font, count, (unsigned char *)chars,
+	      fontEncoding, &i, charinfo);
+    n = (unsigned int)i;
+    w = 0;
+    if (!imageblt)
+	for (info = charinfo; i--; info++)
+	    w += (*info)->metrics.characterWidth;
+
+    if (n != 0) {
+	if (rfbSpriteTextOverlap(pDraw, pGC->font, x, y, n, charinfo, imageblt, w, cursorBox))
+	    rfbSpriteRemoveCursor(pDraw->pScreen);
+
+#ifdef AVOID_GLYPHBLT
+	/*
+	 * On displays like Apollos, which do not optimize the GlyphBlt functions because they
+	 * convert fonts to their internal form in RealizeFont and optimize text directly, we
+	 * want to invoke the text functions here, not the GlyphBlt functions.
+	 */
+	switch (textType)
+	{
+	case TT_POLY8:
+	    drawFunc = (void (*)())pGC->ops->PolyText8;
+	    break;
+	case TT_IMAGE8:
+	    drawFunc = pGC->ops->ImageText8;
+	    break;
+	case TT_POLY16:
+	    drawFunc = (void (*)())pGC->ops->PolyText16;
+	    break;
+	case TT_IMAGE16:
+	    drawFunc = pGC->ops->ImageText16;
+	    break;
+	}
+	(*drawFunc) (pDraw, pGC, x, y, (int) count, chars);
+#else /* don't AVOID_GLYPHBLT */
+	/*
+	 * On the other hand, if the device does use GlyphBlt ultimately to do text, we
+	 * don't want to slow it down by invoking the text functions and having them call
+	 * GetGlyphs all over again, so we go directly to the GlyphBlt functions here.
+	 */
+	drawFunc = imageblt ? pGC->ops->ImageGlyphBlt : pGC->ops->PolyGlyphBlt;
+	(*drawFunc) (pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font));
+#endif /* AVOID_GLYPHBLT */
+    }
+    DEALLOCATE_LOCAL(charinfo);
+    return x + w;
+}
+
+static int
+rfbSpritePolyText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int 	count;
+    char	*chars;
+{
+    int	ret;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, chars,
+			    Linear8Bit, TT_POLY8, &pScreenPriv->saved);
+    else
+	ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+    return ret;
+}
+
+static int
+rfbSpritePolyText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    int	ret;
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count,
+			    (char *)chars,
+			    FONTLASTROW(pGC->font) == 0 ?
+			    Linear16Bit : TwoD16Bit, TT_POLY16, &pScreenPriv->saved);
+    else
+	ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+    return ret;
+}
+
+static void
+rfbSpriteImageText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    char	*chars;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	(void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count,
+			     chars, Linear8Bit, TT_IMAGE8, &pScreenPriv->saved);
+    else
+	(*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteImageText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable))
+	(void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count,
+			     (char *)chars,
+			    FONTLASTROW(pGC->font) == 0 ?
+			    Linear16Bit : TwoD16Bit, TT_IMAGE16, &pScreenPriv->saved);
+    else
+	(*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpriteImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer 	pglyphBase;	/* start of array of glyphs */
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP(pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable) &&
+	rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, TRUE, 0, &pScreenPriv->saved))
+    {
+	rfbSpriteRemoveCursor(pDrawable->pScreen);
+    }
+    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer	pglyphBase;	/* start of array of glyphs */
+{
+    ScreenPtr 		pScreen = pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+
+    GC_SETUP (pDrawable, pGC);
+
+    GC_OP_PROLOGUE (pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable) &&
+	rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, FALSE, 0, &pScreenPriv->saved))
+    {
+	rfbSpriteRemoveCursor(pDrawable->pScreen);
+    }
+    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+static void
+rfbSpritePushPixels(pGC, pBitMap, pDrawable, w, h, x, y)
+    GCPtr	pGC;
+    PixmapPtr	pBitMap;
+    DrawablePtr pDrawable;
+    int		w, h, x, y;
+{
+    VNCSCREENPTR(pScreen);
+    GC_SETUP(pDrawable, pGC);
+
+    if (GC_CHECK((WindowPtr) pDrawable) &&
+	ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,x,y,w,h))
+    {
+	rfbSpriteRemoveCursor (pDrawable->pScreen);
+    }
+
+    GC_OP_PROLOGUE (pGC);
+
+    (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+    GC_OP_EPILOGUE (pGC);
+}
+
+#ifdef NEED_LINEHELPER
+/*
+ * I don't expect this routine will ever be called, as the GC
+ * will have been unwrapped for the line drawing
+ */
+
+static void
+rfbSpriteLineHelper()
+{
+    FatalError("rfbSpriteLineHelper called\n");
+}
+#endif
+
+#ifdef RENDER
+
+# define mod(a,b)	((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
+
+static void
+rfbSpritePictureOverlap (PicturePtr  pPict,
+			INT16	    x,
+			INT16	    y,
+			CARD16	    w,
+			CARD16	    h)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (pPict->pDrawable->type == DRAWABLE_WINDOW)
+    {
+	WindowPtr		pWin = (WindowPtr) (pPict->pDrawable);
+	rfbSpriteScreenPtr	pScreenPriv = (rfbSpriteScreenPtr)
+	    pPict->pDrawable->pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+	if (GC_CHECK(pWin))
+	{
+	    if (pPict->repeat)
+	    {
+		x = mod(x,pWin->drawable.width);
+		y = mod(y,pWin->drawable.height);
+	    }
+	    if (ORG_OVERLAP (&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y,
+			     x, y, w, h))
+		rfbSpriteRemoveCursor (pWin->drawable.pScreen);
+	}
+    }
+}
+
+#define PICTURE_PROLOGUE(ps, pScreenPriv, field) \
+    ps->field = pScreenPriv->field
+
+#define PICTURE_EPILOGUE(ps, field, wrap) \
+    ps->field = wrap
+
+static void
+rfbSpriteComposite(CARD8	op,
+		  PicturePtr pSrc,
+		  PicturePtr pMask,
+		  PicturePtr pDst,
+		  INT16	xSrc,
+		  INT16	ySrc,
+		  INT16	xMask,
+		  INT16	yMask,
+		  INT16	xDst,
+		  INT16	yDst,
+		  CARD16	width,
+		  CARD16	height)
+{
+    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
+    PictureScreenPtr	ps = GetPictureScreen(pScreen);
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    PICTURE_PROLOGUE(ps, pScreenPriv, Composite);
+    rfbSpritePictureOverlap (pSrc, xSrc, ySrc, width, height);
+    if (pMask)
+	rfbSpritePictureOverlap (pMask, xMask, yMask, width, height);
+    rfbSpritePictureOverlap (pDst, xDst, yDst, width, height);
+
+    (*ps->Composite) (op,
+		       pSrc,
+		       pMask,
+		       pDst,
+		       xSrc,
+		       ySrc,
+		       xMask,
+		       yMask,
+		       xDst,
+		       yDst,
+		       width,
+		       height);
+    
+    PICTURE_EPILOGUE(ps, Composite, rfbSpriteComposite);
+}
+
+static void
+rfbSpriteGlyphs(CARD8		op,
+	       PicturePtr	pSrc,
+	       PicturePtr	pDst,
+	       PictFormatPtr	maskFormat,
+	       INT16		xSrc,
+	       INT16		ySrc,
+	       int		nlist,
+	       GlyphListPtr	list,
+	       GlyphPtr		*glyphs)
+{
+    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    PictureScreenPtr	ps = GetPictureScreen(pScreen);
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    PICTURE_PROLOGUE(ps, pScreenPriv, Glyphs);
+    if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
+    {
+	WindowPtr   pSrcWin = (WindowPtr) (pSrc->pDrawable);
+
+	if (GC_CHECK(pSrcWin))
+	    rfbSpriteRemoveCursor (pScreen);
+    }
+    if (pDst->pDrawable->type == DRAWABLE_WINDOW)
+    {
+	WindowPtr   pDstWin = (WindowPtr) (pDst->pDrawable);
+
+	if (GC_CHECK(pDstWin))
+	{
+	    BoxRec  extents;
+
+	    miGlyphExtents (nlist, list, glyphs, &extents);
+	    if (BOX_OVERLAP(&pScreenPriv->saved,
+			    extents.x1 + pDstWin->drawable.x,
+			    extents.y1 + pDstWin->drawable.y,
+			    extents.x2 + pDstWin->drawable.x,
+			    extents.y2 + pDstWin->drawable.y))
+	    {
+		rfbSpriteRemoveCursor (pScreen);
+	    }
+	}
+    }
+    
+    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+    
+    PICTURE_EPILOGUE (ps, Glyphs, rfbSpriteGlyphs);
+}
+#endif
+
+/*
+ * miPointer interface routines
+ */
+
+#define SPRITE_PAD 8
+
+static Bool
+rfbSpriteRealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (pCursor == pScreenPriv->pCursor)
+	pScreenPriv->checkPixels = TRUE;
+    return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor);
+}
+
+static Bool
+rfbSpriteUnrealizeCursor (pScreen, pCursor)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor);
+}
+
+static void
+rfbSpriteSetCursor (pScreen, pCursor, x, y)
+    ScreenPtr	pScreen;
+    CursorPtr	pCursor;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+    rfbClientPtr cl, nextCl;
+    VNCSCREENPTR(pScreen);
+
+    pScreenPriv
+	= (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    if (!pCursor)
+    {
+    	pScreenPriv->shouldBeUp = FALSE;
+    	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor (pScreen);
+	pScreenPriv->pCursor = 0;
+	return;
+    }
+    pScreenPriv->shouldBeUp = TRUE;
+    if (pScreenPriv->x == x &&
+	pScreenPriv->y == y &&
+	pScreenPriv->pCursor == pCursor &&
+	!pScreenPriv->checkPixels)
+    {
+	return;
+    }
+    pScreenPriv->x = x;
+    pScreenPriv->y = y;
+    pScreenPriv->pCacheWin = NullWindow;
+    if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor)
+    {
+	pScreenPriv->pCursor = pCursor;
+	rfbSpriteFindColors (pScreen);
+    }
+    if (pVNC->cursorIsDrawn) {
+	int	sx, sy;
+	/*
+	 * check to see if the old saved region
+	 * encloses the new sprite, in which case we use
+	 * the flicker-free MoveCursor primitive.
+	 */
+	sx = pScreenPriv->x - (int)pCursor->bits->xhot;
+	sy = pScreenPriv->y - (int)pCursor->bits->yhot;
+	if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 &&
+	    sx < pScreenPriv->saved.x2 &&
+	    sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 &&
+	    sy < pScreenPriv->saved.y2 &&
+	    (int) pCursor->bits->width + (2 * SPRITE_PAD) ==
+		pScreenPriv->saved.x2 - pScreenPriv->saved.x1 &&
+	    (int) pCursor->bits->height + (2 * SPRITE_PAD) ==
+		pScreenPriv->saved.y2 - pScreenPriv->saved.y1
+	    )
+	{
+	    pVNC->cursorIsDrawn = FALSE;
+	    if (!(sx >= pScreenPriv->saved.x1 &&
+	      	  sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 &&
+	      	  sy >= pScreenPriv->saved.y1 &&
+	      	  sy + (int)pCursor->bits->height < pScreenPriv->saved.y2))
+	    {
+		int oldx1, oldy1, dx, dy;
+
+		oldx1 = pScreenPriv->saved.x1;
+		oldy1 = pScreenPriv->saved.y1;
+		dx = oldx1 - (sx - SPRITE_PAD);
+		dy = oldy1 - (sy - SPRITE_PAD);
+		pScreenPriv->saved.x1 -= dx;
+		pScreenPriv->saved.y1 -= dy;
+		pScreenPriv->saved.x2 -= dx;
+		pScreenPriv->saved.y2 -= dy;
+		(void) (*pScreenPriv->funcs->ChangeSave) (pScreen,
+				pScreenPriv->saved.x1,
+ 				pScreenPriv->saved.y1,
+				pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+				pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
+				dx, dy);
+	    }
+	    (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor,
+				  pScreenPriv->saved.x1,
+ 				  pScreenPriv->saved.y1,
+				  pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+				  pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
+				  sx - pScreenPriv->saved.x1,
+				  sy - pScreenPriv->saved.y1,
+				  pScreenPriv->colors[SOURCE_COLOR].pixel,
+				  pScreenPriv->colors[MASK_COLOR].pixel);
+	    pVNC->cursorIsDrawn = TRUE;
+	}
+	else
+	{
+	    rfbSpriteRemoveCursor (pScreen);
+	}
+    }
+#if 0
+    if (!pVNC->cursorIsDrawn && pScreenPriv->pCursor)
+	rfbSpriteRestoreCursor (pScreen);
+#endif
+    if (pVNC->cursorIsDrawn)
+	rfbSpriteRemoveCursor (pScreen);
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (cl->enableCursorPosUpdates) {
+	    if (x == cl->cursorX && y == cl->cursorY) {
+		cl->cursorWasMoved = FALSE;
+		continue;
+	    }
+	    cl->cursorWasMoved = TRUE;
+	}
+	if (REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) {
+	    /* cursorIsDrawn is guaranteed to be FALSE here, so we definitely
+	       want to send a screen update to the client, even if that's only
+	       putting up the cursor */
+	    rfbSendFramebufferUpdate(pScreen, cl);
+	}
+    }
+}
+
+static void
+rfbSpriteMoveCursor (pScreen, x, y)
+    ScreenPtr	pScreen;
+    int		x, y;
+{
+    rfbSpriteScreenPtr	pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    rfbSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y);
+}
+
+/*
+ * undraw/draw cursor
+ */
+
+void
+rfbSpriteRemoveCursor (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+    VNCSCREENPTR(pScreen);
+
+    if (!pVNC->cursorIsDrawn)
+	return;
+
+    pScreenPriv
+	= (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    pVNC->dontSendFramebufferUpdate = TRUE;
+    pVNC->cursorIsDrawn = FALSE;
+    pScreenPriv->pCacheWin = NullWindow;
+    if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen,
+					 pScreenPriv->saved.x1,
+					 pScreenPriv->saved.y1,
+					 pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+					 pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
+    {
+	pVNC->cursorIsDrawn = TRUE;
+    }
+    pVNC->dontSendFramebufferUpdate = FALSE;
+}
+
+
+void
+rfbSpriteRestoreCursor (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+    int			x, y;
+    CursorPtr		pCursor;
+    VNCSCREENPTR(pScreen);
+
+    pScreenPriv
+	= (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    pCursor = pScreenPriv->pCursor;
+
+    if (pVNC->cursorIsDrawn || !pCursor)
+	return;
+
+    pVNC->dontSendFramebufferUpdate = TRUE;
+
+    rfbSpriteComputeSaved (pScreen);
+
+    x = pScreenPriv->x - (int)pCursor->bits->xhot;
+    y = pScreenPriv->y - (int)pCursor->bits->yhot;
+    if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen,
+				      pScreenPriv->saved.x1,
+				      pScreenPriv->saved.y1,
+				      pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
+				      pScreenPriv->saved.y2 - pScreenPriv->saved.y1))
+    {
+	if (pScreenPriv->checkPixels)
+	    rfbSpriteFindColors (pScreen);
+	if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y,
+				  pScreenPriv->colors[SOURCE_COLOR].pixel,
+				  pScreenPriv->colors[MASK_COLOR].pixel))
+	    pVNC->cursorIsDrawn = TRUE;
+    }
+
+    pVNC->dontSendFramebufferUpdate = FALSE;
+}
+
+/*
+ * compute the desired area of the screen to save
+ */
+
+static void
+rfbSpriteComputeSaved (pScreen)
+    ScreenPtr	pScreen;
+{
+    rfbSpriteScreenPtr   pScreenPriv;
+    int		    x, y, w, h;
+    int		    wpad, hpad;
+    CursorPtr	    pCursor;
+
+    pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    pCursor = pScreenPriv->pCursor;
+    x = pScreenPriv->x - (int)pCursor->bits->xhot;
+    y = pScreenPriv->y - (int)pCursor->bits->yhot;
+    w = pCursor->bits->width;
+    h = pCursor->bits->height;
+    wpad = SPRITE_PAD;
+    hpad = SPRITE_PAD;
+    pScreenPriv->saved.x1 = x - wpad;
+    pScreenPriv->saved.y1 = y - hpad;
+    pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2;
+    pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2;
+}
+
+
+/*
+ * this function is called when the cursor shape is being changed
+ */
+
+static Bool
+rfbDisplayCursor(pScreen, pCursor)
+    ScreenPtr pScreen;
+    CursorPtr pCursor;
+{
+    rfbClientPtr cl;
+    rfbSpriteScreenPtr pPriv;
+
+    for (cl = rfbClientHead; cl ; cl = cl->next) {
+	if (cl->enableCursorShapeUpdates)
+	    cl->cursorWasChanged = TRUE;
+    }
+
+    pPriv = (rfbSpriteScreenPtr)pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+    return (*pPriv->DisplayCursor)(pScreen, pCursor);
+}
+
+
+/*
+ * obtain current cursor pointer
+ */
+
+CursorPtr
+rfbSpriteGetCursorPtr (pScreen)
+    ScreenPtr pScreen;
+{
+    rfbSpriteScreenPtr pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr)
+	pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    return pScreenPriv->pCursor;
+}
+
+/*
+ * obtain current cursor position
+ */
+
+void
+rfbSpriteGetCursorPos (pScreen, px, py)
+    ScreenPtr pScreen;
+    int *px, *py;
+{
+    rfbSpriteScreenPtr pScreenPriv;
+
+    pScreenPriv = (rfbSpriteScreenPtr)
+	pScreen->devPrivates[rfbSpriteScreenIndex].ptr;
+
+    *px = pScreenPriv->x;
+    *py = pScreenPriv->y;
+}
+
diff -u -rNp a/hw/vnc/sprite.h b/hw/vnc/sprite.h
--- a/hw/vnc/sprite.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/sprite.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,141 @@
+/*
+ * sprite.h
+ *
+ * software-sprite/sprite drawing - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+typedef struct {
+    Bool	(*RealizeCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/
+);
+    Bool	(*UnrealizeCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/
+);
+    Bool	(*PutUpCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/,
+		int /*x*/,
+		int /*y*/,
+		unsigned long /*source*/,
+		unsigned long /*mask*/
+);
+    Bool	(*SaveUnderCursor)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/
+);
+    Bool	(*RestoreUnderCursor)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/
+);
+    Bool	(*MoveCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/,
+		int /*dx*/,
+		int /*dy*/,
+		unsigned long /*source*/,
+		unsigned long /*mask*/
+);
+    Bool	(*ChangeSave)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/,
+		int /*dx*/,
+		int /*dy*/
+);
+
+} rfbSpriteCursorFuncRec, *rfbSpriteCursorFuncPtr;
+
+extern Bool rfbSpriteInitialize(
+#if NeedFunctionPrototypes
+    ScreenPtr /*pScreen*/,
+    rfbSpriteCursorFuncPtr /*cursorFuncs*/,
+    miPointerScreenFuncPtr /*screenFuncs*/
+#endif
+);
+
+extern void rfbSpriteRestoreCursor(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern void rfbSpriteRemoveCursor(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern CursorPtr rfbSpriteGetCursorPtr(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern void rfbSpriteGetCursorPos(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/,
+    int *       /*px*/,
+    int *       /*py*/
+#endif
+);
diff -u -rNp a/hw/vnc/spritest.h b/hw/vnc/spritest.h
--- a/hw/vnc/spritest.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/spritest.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,138 @@
+/*
+ * spritest.h
+ *
+ * sprite structures - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+# include   "sprite.h"
+
+#ifdef RENDER
+# include   "picturestr.h"
+#endif
+
+/*
+ * per screen information
+ */
+
+typedef struct {
+    CloseScreenProcPtr			CloseScreen;
+    GetImageProcPtr			GetImage;
+    GetSpansProcPtr			GetSpans;
+    SourceValidateProcPtr		SourceValidate;
+    CreateGCProcPtr			CreateGC;
+    ScreenBlockHandlerProcPtr		BlockHandler;
+    InstallColormapProcPtr		InstallColormap;
+    StoreColorsProcPtr			StoreColors;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    SaveDoomedAreasProcPtr		SaveDoomedAreas;
+    RestoreAreasProcPtr			RestoreAreas;
+    DisplayCursorProcPtr		DisplayCursor;
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+    GlyphsProcPtr			Glyphs;
+#endif
+
+    CursorPtr	    pCursor;
+    int		    x;
+    int		    y;
+    Bool	    shouldBeUp;
+    BoxRec	    saved;
+    WindowPtr	    pCacheWin;
+    Bool	    isInCacheWin;
+    Bool	    checkPixels;
+    xColorItem	    colors[2];
+    ColormapPtr	    pInstalledMap;
+    ColormapPtr	    pColormap;
+    VisualPtr	    pVisual;
+    rfbSpriteCursorFuncPtr    funcs;
+} rfbSpriteScreenRec, *rfbSpriteScreenPtr;
+
+#define SOURCE_COLOR	0
+#define MASK_COLOR	1
+
+typedef struct {
+    GCFuncs		*wrapFuncs;
+    GCOps		*wrapOps;
+} rfbSpriteGCRec, *rfbSpriteGCPtr;
+
+/*
+ * Overlap BoxPtr and Box elements
+ */
+#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
+ 	(((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
+	 ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
+
+/*
+ * Overlap BoxPtr, origins, and rectangle
+ */
+#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
+    BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
+
+/*
+ * Overlap BoxPtr, origins and RectPtr
+ */
+#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
+    ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
+		(int)((pRect)->width), (int)((pRect)->height))
+/*
+ * Overlap BoxPtr and horizontal span
+ */
+#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
+
+#define LINE_SORT(x1,y1,x2,y2) \
+{ int _t; \
+  if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
+  if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
+
+#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
+    BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
diff -u -rNp a/hw/vnc/stats.c b/hw/vnc/stats.c
--- a/hw/vnc/stats.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/stats.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * stats.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "rfb.h"
+
+static char* encNames[] = {
+    "raw", "copyRect", "RRE", "[encoding 3]", "CoRRE", "hextile",
+    "zlib", "tight", "[encoding 8]", "[encoding 9]"
+};
+
+
+void
+rfbResetStats(rfbClientPtr cl)
+{
+    int i;
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	cl->rfbBytesSent[i] = 0;
+	cl->rfbRectanglesSent[i] = 0;
+    }
+    cl->rfbLastRectMarkersSent = 0;
+    cl->rfbLastRectBytesSent = 0;
+    cl->rfbCursorShapeBytesSent = 0;
+    cl->rfbCursorShapeUpdatesSent = 0;
+    cl->rfbCursorPosBytesSent = 0;
+    cl->rfbCursorPosUpdatesSent = 0;
+    cl->rfbFramebufferUpdateMessagesSent = 0;
+    cl->rfbRawBytesEquivalent = 0;
+    cl->rfbKeyEventsRcvd = 0;
+    cl->rfbPointerEventsRcvd = 0;
+}
+
+void
+rfbPrintStats(rfbClientPtr cl)
+{
+    int i;
+    int totalRectanglesSent = 0;
+    int totalBytesSent = 0;
+
+    rfbLog("Statistics:\n");
+
+    if ((cl->rfbKeyEventsRcvd != 0) || (cl->rfbPointerEventsRcvd != 0))
+	rfbLog("  key events received %d, pointer events %d\n",
+		cl->rfbKeyEventsRcvd, cl->rfbPointerEventsRcvd);
+
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	totalRectanglesSent += cl->rfbRectanglesSent[i];
+	totalBytesSent += cl->rfbBytesSent[i];
+    }
+    totalRectanglesSent += (cl->rfbCursorShapeUpdatesSent +
+			    cl->rfbCursorPosUpdatesSent +
+			    cl->rfbLastRectMarkersSent);
+    totalBytesSent += (cl->rfbCursorShapeBytesSent +
+		       cl->rfbCursorPosBytesSent +
+		       cl->rfbLastRectBytesSent);
+
+    rfbLog("  framebuffer updates %d, rectangles %d, bytes %d\n",
+	    cl->rfbFramebufferUpdateMessagesSent, totalRectanglesSent,
+	    totalBytesSent);
+
+    if (cl->rfbLastRectMarkersSent != 0)
+	rfbLog("    LastRect markers %d, bytes %d\n",
+		cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent);
+
+    if (cl->rfbCursorShapeUpdatesSent != 0)
+	rfbLog("    cursor shape updates %d, bytes %d\n",
+		cl->rfbCursorShapeUpdatesSent, cl->rfbCursorShapeBytesSent);
+
+    if (cl->rfbCursorPosUpdatesSent != 0)
+	rfbLog("    cursor position updates %d, bytes %d\n",
+	       cl->rfbCursorPosUpdatesSent, cl->rfbCursorPosBytesSent);
+
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	if (cl->rfbRectanglesSent[i] != 0)
+	    rfbLog("    %s rectangles %d, bytes %d\n",
+		   encNames[i], cl->rfbRectanglesSent[i], cl->rfbBytesSent[i]);
+    }
+
+    if ((totalBytesSent - cl->rfbBytesSent[rfbEncodingCopyRect]) != 0) {
+	rfbLog("  raw bytes equivalent %d, compression ratio %f\n",
+		cl->rfbRawBytesEquivalent,
+		(double)cl->rfbRawBytesEquivalent
+		/ (double)(totalBytesSent -
+			   cl->rfbBytesSent[rfbEncodingCopyRect] -
+			   cl->rfbCursorShapeBytesSent -
+			   cl->rfbCursorPosBytesSent -
+			   cl->rfbLastRectBytesSent));
+    }
+}
diff -u -rNp a/hw/vnc/tableinitcmtemplate.c b/hw/vnc/tableinitcmtemplate.c
--- a/hw/vnc/tableinitcmtemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/tableinitcmtemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,89 @@
+/*
+ * tableinitcmtemplate.c - template for initialising lookup tables for
+ * translation from a colour map to true colour.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines a function which allocates an
+ * appropriately sized lookup table and initialises it.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT2E(CARD,OUT)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitColourMapSingleTableOUT \
+				CONCAT2E(rfbInitColourMapSingleTable,OUT)
+
+static void
+rfbInitColourMapSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				rfbPixelFormat *out)
+{
+    VNCSCREENPTR(pScreen);
+    int i, r, g, b;
+    OUT_T *t;
+    EntryPtr pent;
+    int nEntries = 1 << in->bitsPerPixel;
+
+    if (*table) free(*table);
+    *table = (char *)malloc(nEntries * sizeof(OUT_T));
+    t = (OUT_T *)*table;
+
+#if XFREE86VNC
+    pent = (EntryPtr)&miInstalledMaps[pScreen->myNum]->red[0];
+#else
+    pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[0];
+#endif
+
+    for (i = 0; i < nEntries; i++) {
+	if (pent->fShared) {
+	    r = pent->co.shco.red->color;
+	    g = pent->co.shco.green->color;
+	    b = pent->co.shco.blue->color;
+	} else {
+	    r = pent->co.local.red;
+	    g = pent->co.local.green;
+	    b = pent->co.local.blue;
+	}
+	t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) |
+		(((g * out->greenMax + 32767) / 65535) << out->greenShift) |
+		(((b * out->blueMax + 32767) / 65535) << out->blueShift));
+#if (OUT != 8)
+	if (out->bigEndian != in->bigEndian) {
+	    t[i] = SwapOUT(t[i]);
+	}
+#endif
+	pent++;
+    }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitColourMapSingleTableOUT
diff -u -rNp a/hw/vnc/tableinittctemplate.c b/hw/vnc/tableinittctemplate.c
--- a/hw/vnc/tableinittctemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/tableinittctemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ * tableinittctemplate.c - template for initialising lookup tables for
+ * truecolour to truecolour translation.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines two functions for initialising
+ * lookup tables.  One is for truecolour translation using a single lookup
+ * table, the other is for truecolour translation using three separate
+ * lookup tables for the red, green and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT2E(CARD,OUT)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitTrueColourSingleTableOUT \
+				CONCAT2E(rfbInitTrueColourSingleTable,OUT)
+#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT)
+#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT)
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+		       int swap);
+
+
+/*
+ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
+ * translation.
+ */
+
+static void
+rfbInitTrueColourSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				 rfbPixelFormat *out)
+{
+    int i;
+    int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
+    OUT_T *t;
+    int nEntries = 1 << in->bitsPerPixel;
+
+    if (*table) free(*table);
+    *table = (char *)malloc(nEntries * sizeof(OUT_T));
+    t = (OUT_T *)*table;
+
+    for (i = 0; i < nEntries; i++) {
+	inRed   = (i >> in->redShift)   & in->redMax;
+	inGreen = (i >> in->greenShift) & in->greenMax;
+	inBlue  = (i >> in->blueShift)  & in->blueMax;
+
+	outRed   = (inRed   * out->redMax   + in->redMax / 2)   / in->redMax;
+	outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
+	outBlue  = (inBlue  * out->blueMax  + in->blueMax / 2)  / in->blueMax;
+
+	t[i] = ((outRed   << out->redShift)   |
+		(outGreen << out->greenShift) |
+		(outBlue  << out->blueShift));
+#if (OUT != 8)
+	if (out->bigEndian != in->bigEndian) {
+	    t[i] = SwapOUT(t[i]);
+	}
+#endif
+    }
+}
+
+
+/*
+ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the
+ * red, green and blue values.
+ */
+
+static void
+rfbInitTrueColourRGBTablesOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+			       rfbPixelFormat *out)
+{
+    OUT_T *redTable;
+    OUT_T *greenTable;
+    OUT_T *blueTable;
+
+    if (*table) free(*table);
+    *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
+			    * sizeof(OUT_T));
+    redTable = (OUT_T *)*table;
+    greenTable = redTable + in->redMax + 1;
+    blueTable = greenTable + in->greenMax + 1;
+
+    rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax,
+			   out->redShift, (out->bigEndian != in->bigEndian));
+    rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax,
+			   out->greenShift, (out->bigEndian != in->bigEndian));
+    rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax,
+			   out->blueShift, (out->bigEndian != in->bigEndian));
+}
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+		       int swap)
+{
+    int i;
+    int nEntries = inMax + 1;
+
+    for (i = 0; i < nEntries; i++) {
+	table[i] = ((i * outMax + inMax / 2) / inMax) << outShift;
+#if (OUT != 8)
+	if (swap) {
+	    table[i] = SwapOUT(table[i]);
+	}
+#endif
+    }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitTrueColourSingleTableOUT
+#undef rfbInitTrueColourRGBTablesOUT
+#undef rfbInitOneRGBTableOUT
diff -u -rNp a/hw/vnc/tabletranstemplate.c b/hw/vnc/tabletranstemplate.c
--- a/hw/vnc/tabletranstemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/tabletranstemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,119 @@
+/*
+ * tabletranstemplate.c - template for translation using lookup tables.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with different definitions of the macros IN and OUT.
+ *
+ * For each pair of values IN and OUT, this file defines two functions for
+ * translating a given rectangle of pixel data.  One uses a single lookup
+ * table, and the other uses three separate lookup tables for the red, green
+ * and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(IN) || !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define IN_T CONCAT2E(CARD,IN)
+#define OUT_T CONCAT2E(CARD,OUT)
+#define rfbTranslateWithSingleTableINtoOUT \
+				CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT)
+#define rfbTranslateWithRGBTablesINtoOUT \
+				CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT)
+
+/*
+ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTableINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+				    rfbPixelFormat *out,
+				    unsigned char *iptr, char *optr,
+				    int bytesBetweenInputLines,
+				    int width, int height,
+				    int x, int y)
+{
+    IN_T *ip = (IN_T *)iptr;
+    OUT_T *op = (OUT_T *)optr;
+    int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+    OUT_T *opLineEnd;
+    OUT_T *t = (OUT_T *)table;
+
+    while (height > 0) {
+	opLineEnd = op + width;
+
+	while (op < opLineEnd) {
+	    *(op++) = t[*(ip++)];
+	}
+
+	ip += ipextra;
+	height--;
+    }
+}
+
+
+/*
+ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTablesINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+				  rfbPixelFormat *out,
+				  unsigned char *iptr, char *optr,
+				  int bytesBetweenInputLines,
+				  int width, int height,
+				  int x, int y)
+{
+    IN_T *ip = (IN_T *)iptr;
+    OUT_T *op = (OUT_T *)optr;
+    int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+    OUT_T *opLineEnd;
+    OUT_T *redTable = (OUT_T *)table;
+    OUT_T *greenTable = redTable + in->redMax + 1;
+    OUT_T *blueTable = greenTable + in->greenMax + 1;
+
+    while (height > 0) {
+	opLineEnd = op + width;
+
+	while (op < opLineEnd) {
+	    *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] |
+		       greenTable[(*ip >> in->greenShift) & in->greenMax] |
+		       blueTable[(*ip >> in->blueShift) & in->blueMax]);
+	    ip++;
+	}
+	ip += ipextra;
+	height--;
+    }
+}
+
+#undef IN_T
+#undef OUT_T
+#undef rfbTranslateWithSingleTableINtoOUT
+#undef rfbTranslateWithRGBTablesINtoOUT
diff -u -rNp a/hw/vnc/tight.c b/hw/vnc/tight.c
--- a/hw/vnc/tight.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/tight.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1824 @@
+/*
+ * tight.c
+ *
+ * Routines to implement Tight Encoding
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+#include <jpeglib.h>
+
+
+/* Note: The following constant should not be changed. */
+#define TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define MIN_SPLIT_RECT_SIZE     4096
+#define MIN_SOLID_SUBRECT_SIZE  2048
+#define MAX_SPLIT_TILE_SIZE       16
+
+/* May be set to TRUE with "-lazytight" Xvnc option. */
+Bool rfbTightDisableGradient = FALSE;
+
+/* This variable is set on every rfbSendRectEncodingTight() call. */
+static Bool usePixelFormat24;
+
+
+/* Compression level stuff. The following array contains various
+   encoder parameters for each of 10 compression levels (0..9).
+   Last three parameters correspond to JPEG quality levels (0..9). */
+
+typedef struct TIGHT_CONF_s {
+    int maxRectSize, maxRectWidth;
+    int monoMinRectSize, gradientMinRectSize;
+    int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel;
+    int gradientThreshold, gradientThreshold24;
+    int idxMaxColorsDivisor;
+    int jpegQuality, jpegThreshold, jpegThreshold24;
+} TIGHT_CONF;
+
+static TIGHT_CONF tightConf[10] = {
+    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
+    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
+    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
+    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
+    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
+    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
+    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
+    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
+    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
+    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
+};
+
+/* Stuff dealing with palettes. */
+
+typedef struct COLOR_LIST_s {
+    struct COLOR_LIST_s *next;
+    int idx;
+    CARD32 rgb;
+} COLOR_LIST;
+
+typedef struct PALETTE_ENTRY_s {
+    COLOR_LIST *listNode;
+    int numPixels;
+} PALETTE_ENTRY;
+
+typedef struct PALETTE_s {
+    PALETTE_ENTRY entry[256];
+    COLOR_LIST *hash[256];
+    COLOR_LIST list[256];
+} PALETTE;
+
+static int paletteNumColors, paletteMaxColors;
+static CARD32 monoBackground, monoForeground;
+static PALETTE palette;
+
+/* Pointers to dynamically-allocated buffers. */
+
+static int tightBeforeBufSize = 0;
+static char *tightBeforeBuf = NULL;
+
+static int tightAfterBufSize = 0;
+static char *tightAfterBuf = NULL;
+
+static int *prevRowBuf = NULL;
+
+
+/* Prototypes for static functions. */
+
+static void FindBestSolidArea (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 colorValue, int *w_ptr, int *h_ptr);
+static void ExtendSolidArea   (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 colorValue,
+                               int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
+static Bool CheckSolidTile    (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile8   (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile16  (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile32  (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+
+static Bool SendRectSimple    (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendSubrect       (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendTightHeader   (rfbClientPtr cl, int x, int y, int w, int h);
+
+static Bool SendSolidRect     (rfbClientPtr cl);
+static Bool SendMonoRect      (rfbClientPtr cl, int w, int h);
+static Bool SendIndexedRect   (rfbClientPtr cl, int w, int h);
+static Bool SendFullColorRect (rfbClientPtr cl, int w, int h);
+static Bool SendGradientRect  (rfbClientPtr cl, int w, int h);
+
+static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen,
+                         int zlibLevel, int zlibStrategy);
+static Bool SendCompressedData(rfbClientPtr cl, int compressedLen);
+
+static void FillPalette8(int count);
+static void FillPalette16(int count);
+static void FillPalette32(int count);
+
+static void PaletteReset(void);
+static int PaletteInsert(CARD32 rgb, int numPixels, int bpp);
+
+static void Pack24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int count);
+
+static void EncodeIndexedRect16(CARD8 *buf, int count);
+static void EncodeIndexedRect32(CARD8 *buf, int count);
+
+static void EncodeMonoRect8(CARD8 *buf, int w, int h);
+static void EncodeMonoRect16(CARD8 *buf, int w, int h);
+static void EncodeMonoRect32(CARD8 *buf, int w, int h);
+
+static void FilterGradient24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient16(ScreenPtr pScreen, CARD16 *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient32(ScreenPtr pScreen, CARD32 *buf, rfbPixelFormat *fmt, int w, int h);
+
+static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+
+static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
+                         int quality);
+static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+
+static void JpegInitDestination(j_compress_ptr cinfo);
+static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo);
+static void JpegTermDestination(j_compress_ptr cinfo);
+static void JpegSetDstManager(j_compress_ptr cinfo);
+
+
+/*
+ * Tight encoding implementation.
+ */
+
+int
+rfbNumCodedRectsTight(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    int maxRectSize, maxRectWidth;
+    int subrectMaxWidth, subrectMaxHeight;
+
+    /* No matter how many rectangles we will send if LastRect markers
+       are used to terminate rectangle stream. */
+    if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
+      return 0;
+
+    maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+    maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+    if (w > maxRectWidth || w * h > maxRectSize) {
+        subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        subrectMaxHeight = maxRectSize / subrectMaxWidth;
+        return (((w - 1) / maxRectWidth + 1) *
+                ((h - 1) / subrectMaxHeight + 1));
+    } else {
+        return 1;
+    }
+}
+
+Bool
+rfbSendRectEncodingTight(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int nMaxRows;
+    CARD32 colorValue;
+    int dx, dy, dw, dh;
+    int x_best, y_best, w_best, h_best;
+    unsigned char *fbptr;
+
+    if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
+         cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
+        usePixelFormat24 = TRUE;
+    } else {
+        usePixelFormat24 = FALSE;
+    }
+
+    if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
+        return SendRectSimple(cl, x, y, w, h);
+
+    /* Make sure we can write at least one pixel into tightBeforeBuf. */
+
+    if (tightBeforeBufSize < 4) {
+        tightBeforeBufSize = 4;
+        if (tightBeforeBuf == NULL)
+            tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+        else
+            tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+                                              tightBeforeBufSize);
+    }
+
+    /* Calculate maximum number of rows in one non-solid rectangle. */
+
+    {
+        int maxRectSize, maxRectWidth, nMaxWidth;
+
+        maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+        maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+        nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        nMaxRows = maxRectSize / nMaxWidth;
+    }
+
+    /* Try to find large solid-color areas and send them separately. */
+
+    for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+        /* If a rectangle becomes too large, send its upper part now. */
+
+        if (dy - y >= nMaxRows) {
+            if (!SendRectSimple(cl, x, y, w, nMaxRows))
+                return 0;
+            y += nMaxRows;
+            h -= nMaxRows;
+        }
+
+        dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+            MAX_SPLIT_TILE_SIZE : (y + h - dy);
+
+        for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
+
+            dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
+                MAX_SPLIT_TILE_SIZE : (x + w - dx);
+
+            if (CheckSolidTile(cl->pScreen, dx, dy, dw, dh, &colorValue, FALSE)) {
+
+                /* Get dimensions of solid-color area. */
+
+                FindBestSolidArea(cl->pScreen, dx, dy, w - (dx - x), h - (dy - y),
+				  colorValue, &w_best, &h_best);
+
+                /* Make sure a solid rectangle is large enough
+                   (or the whole rectangle is of the same color). */
+
+                if ( w_best * h_best != w * h &&
+                     w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
+                    continue;
+
+                /* Try to extend solid rectangle to maximum size. */
+
+                x_best = dx; y_best = dy;
+                ExtendSolidArea(cl->pScreen, x, y, w, h, colorValue,
+                                &x_best, &y_best, &w_best, &h_best);
+
+                /* Send rectangles at top and left to solid-color area. */
+
+                if ( y_best != y &&
+                     !SendRectSimple(cl, x, y, w, y_best-y) )
+                    return FALSE;
+                if ( x_best != x &&
+                     !rfbSendRectEncodingTight(cl, x, y_best,
+                                               x_best-x, h_best) )
+                    return FALSE;
+
+                /* Send solid-color rectangle. */
+
+                if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
+                    return FALSE;
+
+                fbptr = (pVNC->pfbMemory +
+                         (pVNC->paddedWidthInBytes * y_best) +
+                         (x_best * (pVNC->bitsPerPixel / 8)));
+
+                (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+				   &pVNC->rfbServerFormat,
+                                   &cl->format, fbptr, tightBeforeBuf,
+                                   pVNC->paddedWidthInBytes, 1, 1, 
+				   x_best, y_best);
+
+                if (!SendSolidRect(cl))
+                    return FALSE;
+
+                /* Send remaining rectangles (at right and bottom). */
+
+                if ( x_best + w_best != x + w &&
+                     !rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
+                                               w-(x_best-x)-w_best, h_best) )
+                    return FALSE;
+                if ( y_best + h_best != y + h &&
+                     !rfbSendRectEncodingTight(cl, x, y_best+h_best,
+                                               w, h-(y_best-y)-h_best) )
+                    return FALSE;
+
+                /* Return after all recursive calls are done. */
+
+                return TRUE;
+            }
+
+        }
+
+    }
+
+    /* No suitable solid-color rectangles found. */
+
+    return SendRectSimple(cl, x, y, w, h);
+}
+
+static void
+FindBestSolidArea(pScreen, x, y, w, h, colorValue, w_ptr, h_ptr)
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 colorValue;
+    int *w_ptr, *h_ptr;
+{
+    int dx, dy, dw, dh;
+    int w_prev;
+    int w_best = 0, h_best = 0;
+
+    w_prev = w;
+
+    for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+        dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+            MAX_SPLIT_TILE_SIZE : (y + h - dy);
+        dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
+            MAX_SPLIT_TILE_SIZE : w_prev;
+
+        if (!CheckSolidTile(pScreen, x, dy, dw, dh, &colorValue, TRUE))
+            break;
+
+        for (dx = x + dw; dx < x + w_prev;) {
+            dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
+                MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
+            if (!CheckSolidTile(pScreen, dx, dy, dw, dh, &colorValue, TRUE))
+                break;
+	    dx += dw;
+        }
+
+        w_prev = dx - x;
+        if (w_prev * (dy + dh - y) > w_best * h_best) {
+            w_best = w_prev;
+            h_best = dy + dh - y;
+        }
+    }
+
+    *w_ptr = w_best;
+    *h_ptr = h_best;
+}
+
+static void
+ExtendSolidArea(pScreen, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr)
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 colorValue;
+    int *x_ptr, *y_ptr, *w_ptr, *h_ptr;
+{
+    int cx, cy;
+
+    /* Try to extend the area upwards. */
+    for ( cy = *y_ptr - 1;
+          cy >= y && CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+          cy-- );
+    *h_ptr += *y_ptr - (cy + 1);
+    *y_ptr = cy + 1;
+
+    /* ... downwards. */
+    for ( cy = *y_ptr + *h_ptr;
+          cy < y + h &&
+              CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+          cy++ );
+    *h_ptr += cy - (*y_ptr + *h_ptr);
+
+    /* ... to the left. */
+    for ( cx = *x_ptr - 1;
+          cx >= x && CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+          cx-- );
+    *w_ptr += *x_ptr - (cx + 1);
+    *x_ptr = cx + 1;
+
+    /* ... to the right. */
+    for ( cx = *x_ptr + *w_ptr;
+          cx < x + w &&
+              CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+          cx++ );
+    *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successfull, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+static Bool
+CheckSolidTile(pScreen, x, y, w, h, colorPtr, needSameColor) 
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 *colorPtr;
+    Bool needSameColor;
+{
+    VNCSCREENPTR(pScreen);
+    switch(pVNC->rfbServerFormat.bitsPerPixel) {
+    case 32:
+        return CheckSolidTile32(pScreen, x, y, w, h, colorPtr, needSameColor);
+    case 16:
+        return CheckSolidTile16(pScreen, x, y, w, h, colorPtr, needSameColor);
+    default:
+        return CheckSolidTile8(pScreen, x, y, w, h, colorPtr, needSameColor);
+    }
+}
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                      \
+                                                                              \
+static Bool                                                                   \
+CheckSolidTile##bpp(pScreen, x, y, w, h, colorPtr, needSameColor)             \
+    ScreenPtr pScreen;							      \
+    int x, y;                                                                 \
+    CARD32 *colorPtr;                                                         \
+    Bool needSameColor;                                                       \
+{                                                                             \
+    VNCSCREENPTR(pScreen);						      \
+    CARD##bpp *fbptr;                                                         \
+    CARD##bpp colorValue;                                                     \
+    int dx, dy;                                                               \
+                                                                              \
+    fbptr = (CARD##bpp *)                                                     \
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * (bpp/8)]; \
+                                                                              \
+    colorValue = *fbptr;                                                      \
+    if (needSameColor && (CARD32)colorValue != *colorPtr)                     \
+        return FALSE;                                                         \
+                                                                              \
+    for (dy = 0; dy < h; dy++) {                                              \
+        for (dx = 0; dx < w; dx++) {                                          \
+            if (colorValue != fbptr[dx])                                      \
+                return FALSE;                                                 \
+        }                                                                     \
+        fbptr = (CARD##bpp *)((CARD8 *)fbptr + pVNC->paddedWidthInBytes);     \
+    }                                                                         \
+                                                                              \
+    *colorPtr = (CARD32)colorValue;                                           \
+    return TRUE;                                                              \
+}
+
+DEFINE_CHECK_SOLID_FUNCTION(8)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(32)
+
+static Bool
+SendRectSimple(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    int maxBeforeSize, maxAfterSize;
+    int maxRectSize, maxRectWidth;
+    int subrectMaxWidth, subrectMaxHeight;
+    int dx, dy;
+    int rw, rh;
+
+    maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+    maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+    maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
+    maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
+
+    if (tightBeforeBufSize < maxBeforeSize) {
+        tightBeforeBufSize = maxBeforeSize;
+        if (tightBeforeBuf == NULL)
+            tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+        else
+            tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+                                              tightBeforeBufSize);
+    }
+
+    if (tightAfterBufSize < maxAfterSize) {
+        tightAfterBufSize = maxAfterSize;
+        if (tightAfterBuf == NULL)
+            tightAfterBuf = (char *)xalloc(tightAfterBufSize);
+        else
+            tightAfterBuf = (char *)xrealloc(tightAfterBuf,
+                                             tightAfterBufSize);
+    }
+
+    if (w > maxRectWidth || w * h > maxRectSize) {
+        subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        subrectMaxHeight = maxRectSize / subrectMaxWidth;
+
+        for (dy = 0; dy < h; dy += subrectMaxHeight) {
+            for (dx = 0; dx < w; dx += maxRectWidth) {
+                rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
+                rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+                if (!SendSubrect(cl, x+dx, y+dy, rw, rh))
+                    return FALSE;
+            }
+        }
+    } else {
+        if (!SendSubrect(cl, x, y, w, h))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+SendSubrect(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    unsigned char *fbptr;
+    Bool success = FALSE;
+
+    /* Send pending data if there is more than 128 bytes. */
+    if (pVNC->ublen > 128) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    if (!SendTightHeader(cl, x, y, w, h))
+        return FALSE;
+
+    fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+             + (x * (pVNC->bitsPerPixel / 8)));
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+                       &cl->format, fbptr, tightBeforeBuf,
+                       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    paletteMaxColors = w * h / tightConf[cl->tightCompressLevel].idxMaxColorsDivisor;
+    if ( paletteMaxColors < 2 &&
+         w * h >= tightConf[cl->tightCompressLevel].monoMinRectSize ) {
+        paletteMaxColors = 2;
+    }
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+        FillPalette8(w * h);
+        break;
+    case 16:
+        FillPalette16(w * h);
+        break;
+    default:
+        FillPalette32(w * h);
+    }
+
+    switch (paletteNumColors) {
+    case 0:
+        /* Truecolor image */
+        if (DetectSmoothImage(cl, &cl->format, w, h)) {
+            if (cl->tightQualityLevel != -1) {
+                success = SendJpegRect(cl, x, y, w, h,
+                                  tightConf[cl->tightQualityLevel].jpegQuality);
+            } else {
+                success = SendGradientRect(cl, w, h);
+            }
+        } else {
+            success = SendFullColorRect(cl, w, h);
+        }
+        break;
+    case 1:
+        /* Solid rectangle */
+        success = SendSolidRect(cl);
+        break;
+    case 2:
+        /* Two-color rectangle */
+        success = SendMonoRect(cl, w, h);
+        break;
+    default:
+        /* Up to 256 different colors */
+        if ( paletteNumColors > 96 &&
+             cl->tightQualityLevel != -1 && cl->tightQualityLevel <= 3 &&
+             DetectSmoothImage(cl, &cl->format, w, h) ) {
+            success = SendJpegRect(cl, x, y, w, h,
+                                  tightConf[cl->tightQualityLevel].jpegQuality);
+        } else {
+            success = SendIndexedRect(cl, w, h);
+        }
+    }
+    return success;
+}
+
+static Bool
+SendTightHeader(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingTight);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+           sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingTight]++;
+    cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
+
+    return TRUE;
+}
+
+/*
+ * Subencoding implementations.
+ */
+
+static Bool
+SendSolidRect(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int len;
+
+    if (usePixelFormat24) {
+        Pack24(cl->pScreen, tightBeforeBuf, &cl->format, 1);
+        len = 3;
+    } else
+        len = cl->format.bitsPerPixel / 8;
+
+    if (pVNC->ublen + 1 + len > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightFill << 4);
+    memcpy (&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, len);
+    pVNC->ublen += len;
+
+    cl->rfbBytesSent[rfbEncodingTight] += len + 1;
+
+    return TRUE;
+}
+
+static Bool
+SendMonoRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 1;
+    int paletteLen, dataLen;
+
+    if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+          2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    /* Prepare tight encoding header. */
+    dataLen = (w + 7) / 8;
+    dataLen *= h;
+
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette;
+    pVNC->updateBuf[pVNC->ublen++] = 1;
+
+    /* Prepare palette, convert image. */
+    switch (cl->format.bitsPerPixel) {
+
+    case 32:
+        EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h);
+
+        ((CARD32 *)tightAfterBuf)[0] = monoBackground;
+        ((CARD32 *)tightAfterBuf)[1] = monoForeground;
+        if (usePixelFormat24) {
+            Pack24(cl->pScreen, tightAfterBuf, &cl->format, 2);
+            paletteLen = 6;
+        } else
+            paletteLen = 8;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteLen);
+        pVNC->ublen += paletteLen;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen;
+        break;
+
+    case 16:
+        EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h);
+
+        ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground;
+        ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, 4);
+        pVNC->ublen += 4;
+        cl->rfbBytesSent[rfbEncodingTight] += 7;
+        break;
+
+    default:
+        EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h);
+
+        pVNC->updateBuf[pVNC->ublen++] = (char)monoBackground;
+        pVNC->updateBuf[pVNC->ublen++] = (char)monoForeground;
+        cl->rfbBytesSent[rfbEncodingTight] += 5;
+    }
+
+    return CompressData(cl, streamId, dataLen,
+                        tightConf[cl->tightCompressLevel].monoZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendIndexedRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 2;
+    int i, entryLen;
+
+    if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+          paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    /* Prepare tight encoding header. */
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette;
+    pVNC->updateBuf[pVNC->ublen++] = (char)(paletteNumColors - 1);
+
+    /* Prepare palette, convert image. */
+    switch (cl->format.bitsPerPixel) {
+
+    case 32:
+        EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h);
+
+        for (i = 0; i < paletteNumColors; i++) {
+            ((CARD32 *)tightAfterBuf)[i] =
+                palette.entry[i].listNode->rgb;
+        }
+        if (usePixelFormat24) {
+            Pack24(cl->pScreen, tightAfterBuf, &cl->format, paletteNumColors);
+            entryLen = 3;
+        } else
+            entryLen = 4;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * entryLen);
+        pVNC->ublen += paletteNumColors * entryLen;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
+        break;
+
+    case 16:
+        EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h);
+
+        for (i = 0; i < paletteNumColors; i++) {
+            ((CARD16 *)tightAfterBuf)[i] =
+                (CARD16)palette.entry[i].listNode->rgb;
+        }
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * 2);
+        pVNC->ublen += paletteNumColors * 2;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
+        break;
+
+    default:
+        return FALSE;           /* Should never happen. */
+    }
+
+    return CompressData(cl, streamId, w * h,
+                        tightConf[cl->tightCompressLevel].idxZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendFullColorRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 0;
+    int len;
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = 0x00;  /* stream id = 0, no flushing, no filter */
+    cl->rfbBytesSent[rfbEncodingTight]++;
+
+    if (usePixelFormat24) {
+        Pack24(cl->pScreen, tightBeforeBuf, &cl->format, w * h);
+        len = 3;
+    } else
+        len = cl->format.bitsPerPixel / 8;
+
+    return CompressData(cl, streamId, w * h * len,
+                        tightConf[cl->tightCompressLevel].rawZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendGradientRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 3;
+    int len;
+
+    if (cl->format.bitsPerPixel == 8)
+        return SendFullColorRect(cl, w, h);
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    if (prevRowBuf == NULL)
+        prevRowBuf = (int *)xalloc(2048 * 3 * sizeof(int));
+
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterGradient;
+    cl->rfbBytesSent[rfbEncodingTight] += 2;
+
+    if (usePixelFormat24) {
+        FilterGradient24(cl->pScreen, tightBeforeBuf, &cl->format, w, h);
+        len = 3;
+    } else if (cl->format.bitsPerPixel == 32) {
+        FilterGradient32(cl->pScreen, (CARD32 *)tightBeforeBuf, &cl->format, w, h);
+        len = 4;
+    } else {
+        FilterGradient16(cl->pScreen, (CARD16 *)tightBeforeBuf, &cl->format, w, h);
+        len = 2;
+    }
+
+    return CompressData(cl, streamId, w * h * len,
+                        tightConf[cl->tightCompressLevel].gradientZlibLevel,
+                        Z_FILTERED);
+}
+
+static Bool
+CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy)
+    rfbClientPtr cl;
+    int streamId, dataLen, zlibLevel, zlibStrategy;
+{
+    VNCSCREENPTR(cl->pScreen);
+    z_streamp pz;
+    int err;
+
+    if (dataLen < TIGHT_MIN_TO_COMPRESS) {
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, dataLen);
+        pVNC->ublen += dataLen;
+        cl->rfbBytesSent[rfbEncodingTight] += dataLen;
+        return TRUE;
+    }
+
+    pz = &cl->zsStruct[streamId];
+
+    /* Initialize compression stream if needed. */
+    if (!cl->zsActive[streamId]) {
+        pz->zalloc = Z_NULL;
+        pz->zfree = Z_NULL;
+        pz->opaque = Z_NULL;
+
+        err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
+                            MAX_MEM_LEVEL, zlibStrategy);
+        if (err != Z_OK)
+            return FALSE;
+
+        cl->zsActive[streamId] = TRUE;
+        cl->zsLevel[streamId] = zlibLevel;
+    }
+
+    /* Prepare buffer pointers. */
+    pz->next_in = (Bytef *)tightBeforeBuf;
+    pz->avail_in = dataLen;
+    pz->next_out = (Bytef *)tightAfterBuf;
+    pz->avail_out = tightAfterBufSize;
+
+    /* Change compression parameters if needed. */
+    if (zlibLevel != cl->zsLevel[streamId]) {
+        if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
+            return FALSE;
+        }
+        cl->zsLevel[streamId] = zlibLevel;
+    }
+
+    /* Actual compression. */
+    if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK ||
+         pz->avail_in != 0 || pz->avail_out == 0 ) {
+        return FALSE;
+    }
+
+    return SendCompressedData(cl, tightAfterBufSize - pz->avail_out);
+}
+
+static Bool SendCompressedData(cl, compressedLen)
+    rfbClientPtr cl;
+    int compressedLen;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int i, portionLen;
+
+    pVNC->updateBuf[pVNC->ublen++] = compressedLen & 0x7F;
+    cl->rfbBytesSent[rfbEncodingTight]++;
+    if (compressedLen > 0x7F) {
+        pVNC->updateBuf[pVNC->ublen-1] |= 0x80;
+        pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 7 & 0x7F;
+        cl->rfbBytesSent[rfbEncodingTight]++;
+        if (compressedLen > 0x3FFF) {
+            pVNC->updateBuf[pVNC->ublen-1] |= 0x80;
+            pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 14 & 0xFF;
+            cl->rfbBytesSent[rfbEncodingTight]++;
+        }
+    }
+
+    portionLen = UPDATE_BUF_SIZE;
+    for (i = 0; i < compressedLen; i += portionLen) {
+        if (i + portionLen > compressedLen) {
+            portionLen = compressedLen - i;
+        }
+        if (pVNC->ublen + portionLen > UPDATE_BUF_SIZE) {
+            if (!rfbSendUpdateBuf(cl))
+                return FALSE;
+        }
+        memcpy(&pVNC->updateBuf[pVNC->ublen], &tightAfterBuf[i], portionLen);
+        pVNC->ublen += portionLen;
+    }
+    cl->rfbBytesSent[rfbEncodingTight] += compressedLen;
+    return TRUE;
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+
+static void
+FillPalette8(count)
+    int count;
+{
+    CARD8 *data = (CARD8 *)tightBeforeBuf;
+    CARD8 c0, c1;
+    int i, n0, n1;
+
+    paletteNumColors = 0;
+
+    c0 = data[0];
+    for (i = 1; i < count && data[i] == c0; i++);
+    if (i == count) {
+        paletteNumColors = 1;
+        return;                 /* Solid rectangle */
+    }
+
+    if (paletteMaxColors < 2)
+        return;
+
+    n0 = i;
+    c1 = data[i];
+    n1 = 0;
+    for (i++; i < count; i++) {
+        if (data[i] == c0) {
+            n0++;
+        } else if (data[i] == c1) {
+            n1++;
+        } else
+            break;
+    }
+    if (i == count) {
+        if (n0 > n1) {
+            monoBackground = (CARD32)c0;
+            monoForeground = (CARD32)c1;
+        } else {
+            monoBackground = (CARD32)c1;
+            monoForeground = (CARD32)c0;
+        }
+        paletteNumColors = 2;   /* Two colors */
+    }
+}
+
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
+                                                                        \
+static void                                                             \
+FillPalette##bpp(count)                                                 \
+    int count;                                                          \
+{                                                                       \
+    CARD##bpp *data = (CARD##bpp *)tightBeforeBuf;                      \
+    CARD##bpp c0, c1, ci = 0;                                           \
+    int i, n0, n1, ni;                                                  \
+                                                                        \
+    c0 = data[0];                                                       \
+    for (i = 1; i < count && data[i] == c0; i++);                       \
+    if (i >= count) {                                                   \
+        paletteNumColors = 1;   /* Solid rectangle */                   \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    if (paletteMaxColors < 2) {                                         \
+        paletteNumColors = 0;   /* Full-color encoding preferred */     \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    n0 = i;                                                             \
+    c1 = data[i];                                                       \
+    n1 = 0;                                                             \
+    for (i++; i < count; i++) {                                         \
+        ci = data[i];                                                   \
+        if (ci == c0) {                                                 \
+            n0++;                                                       \
+        } else if (ci == c1) {                                          \
+            n1++;                                                       \
+        } else                                                          \
+            break;                                                      \
+    }                                                                   \
+    if (i >= count) {                                                   \
+        if (n0 > n1) {                                                  \
+            monoBackground = (CARD32)c0;                                \
+            monoForeground = (CARD32)c1;                                \
+        } else {                                                        \
+            monoBackground = (CARD32)c1;                                \
+            monoForeground = (CARD32)c0;                                \
+        }                                                               \
+        paletteNumColors = 2;   /* Two colors */                        \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    PaletteReset();                                                     \
+    PaletteInsert (c0, (CARD32)n0, bpp);                                \
+    PaletteInsert (c1, (CARD32)n1, bpp);                                \
+                                                                        \
+    ni = 1;                                                             \
+    for (i++; i < count; i++) {                                         \
+        if (data[i] == ci) {                                            \
+            ni++;                                                       \
+        } else {                                                        \
+            if (!PaletteInsert (ci, (CARD32)ni, bpp))                   \
+                return;                                                 \
+            ci = data[i];                                               \
+            ni = 1;                                                     \
+        }                                                               \
+    }                                                                   \
+    PaletteInsert (ci, (CARD32)ni, bpp);                                \
+}
+
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+
+/*
+ * Functions to operate with palette structures.
+ */
+
+#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF))
+#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF))
+
+static void
+PaletteReset(void)
+{
+    paletteNumColors = 0;
+    memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
+}
+
+static int
+PaletteInsert(CARD32 rgb, int numPixels, int bpp)
+{
+    COLOR_LIST *pnode;
+    COLOR_LIST *prev_pnode = NULL;
+    int hash_key, idx, new_idx, count;
+
+    hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+    pnode = palette.hash[hash_key];
+
+    while (pnode != NULL) {
+        if (pnode->rgb == rgb) {
+            /* Such palette entry already exists. */
+            new_idx = idx = pnode->idx;
+            count = palette.entry[idx].numPixels + numPixels;
+            if (new_idx && palette.entry[new_idx-1].numPixels < count) {
+                do {
+                    palette.entry[new_idx] = palette.entry[new_idx-1];
+                    palette.entry[new_idx].listNode->idx = new_idx;
+                    new_idx--;
+                }
+                while (new_idx && palette.entry[new_idx-1].numPixels < count);
+                palette.entry[new_idx].listNode = pnode;
+                pnode->idx = new_idx;
+            }
+            palette.entry[new_idx].numPixels = count;
+            return paletteNumColors;
+        }
+        prev_pnode = pnode;
+        pnode = pnode->next;
+    }
+
+    /* Check if palette is full. */
+    if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
+        paletteNumColors = 0;
+        return 0;
+    }
+
+    /* Move palette entries with lesser pixel counts. */
+    for ( idx = paletteNumColors;
+          idx > 0 && palette.entry[idx-1].numPixels < numPixels;
+          idx-- ) {
+        palette.entry[idx] = palette.entry[idx-1];
+        palette.entry[idx].listNode->idx = idx;
+    }
+
+    /* Add new palette entry into the freed slot. */
+    pnode = &palette.list[paletteNumColors];
+    if (prev_pnode != NULL) {
+        prev_pnode->next = pnode;
+    } else {
+        palette.hash[hash_key] = pnode;
+    }
+    pnode->next = NULL;
+    pnode->idx = idx;
+    pnode->rgb = rgb;
+    palette.entry[idx].listNode = pnode;
+    palette.entry[idx].numPixels = numPixels;
+
+    return (++paletteNumColors);
+}
+
+
+/*
+ * Converting 32-bit color samples into 24-bit colors.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void Pack24(pScreen, buf, fmt, count)
+    ScreenPtr pScreen;
+    char *buf;
+    rfbPixelFormat *fmt;
+    int count;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *buf32;
+    CARD32 pix;
+    int r_shift, g_shift, b_shift;
+
+    buf32 = (CARD32 *)buf;
+
+    if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+        r_shift = fmt->redShift;
+        g_shift = fmt->greenShift;
+        b_shift = fmt->blueShift;
+    } else {
+        r_shift = 24 - fmt->redShift;
+        g_shift = 24 - fmt->greenShift;
+        b_shift = 24 - fmt->blueShift;
+    }
+
+    while (count--) {
+        pix = *buf32++;
+        *buf++ = (char)(pix >> r_shift);
+        *buf++ = (char)(pix >> g_shift);
+        *buf++ = (char)(pix >> b_shift);
+    }
+}
+
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
+                                                                        \
+static void                                                             \
+EncodeIndexedRect##bpp(buf, count)                                      \
+    CARD8 *buf;                                                         \
+    int count;                                                          \
+{                                                                       \
+    COLOR_LIST *pnode;                                                  \
+    CARD##bpp *src;                                                     \
+    CARD##bpp rgb;                                                      \
+    int rep = 0;                                                        \
+                                                                        \
+    src = (CARD##bpp *) buf;                                            \
+                                                                        \
+    while (count--) {                                                   \
+        rgb = *src++;                                                   \
+        while (count && *src == rgb) {                                  \
+            rep++, src++, count--;                                      \
+        }                                                               \
+        pnode = palette.hash[HASH_FUNC##bpp(rgb)];                      \
+        while (pnode != NULL) {                                         \
+            if ((CARD##bpp)pnode->rgb == rgb) {                         \
+                *buf++ = (CARD8)pnode->idx;                             \
+                while (rep) {                                           \
+                    *buf++ = (CARD8)pnode->idx;                         \
+                    rep--;                                              \
+                }                                                       \
+                break;                                                  \
+            }                                                           \
+            pnode = pnode->next;                                        \
+        }                                                               \
+    }                                                                   \
+}
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
+                                                                        \
+static void                                                             \
+EncodeMonoRect##bpp(buf, w, h)                                          \
+    CARD8 *buf;                                                         \
+    int w, h;                                                           \
+{                                                                       \
+    CARD##bpp *ptr;                                                     \
+    CARD##bpp bg;                                                       \
+    unsigned int value, mask;                                           \
+    int aligned_width;                                                  \
+    int x, y, bg_bits;                                                  \
+                                                                        \
+    ptr = (CARD##bpp *) buf;                                            \
+    bg = (CARD##bpp) monoBackground;                                    \
+    aligned_width = w - w % 8;                                          \
+                                                                        \
+    for (y = 0; y < h; y++) {                                           \
+        for (x = 0; x < aligned_width; x += 8) {                        \
+            for (bg_bits = 0; bg_bits < 8; bg_bits++) {                 \
+                if (*ptr++ != bg)                                       \
+                    break;                                              \
+            }                                                           \
+            if (bg_bits == 8) {                                         \
+                *buf++ = 0;                                             \
+                continue;                                               \
+            }                                                           \
+            mask = 0x80 >> bg_bits;                                     \
+            value = mask;                                               \
+            for (bg_bits++; bg_bits < 8; bg_bits++) {                   \
+                mask >>= 1;                                             \
+                if (*ptr++ != bg) {                                     \
+                    value |= mask;                                      \
+                }                                                       \
+            }                                                           \
+            *buf++ = (CARD8)value;                                      \
+        }                                                               \
+                                                                        \
+        mask = 0x80;                                                    \
+        value = 0;                                                      \
+        if (x >= w)                                                     \
+            continue;                                                   \
+                                                                        \
+        for (; x < w; x++) {                                            \
+            if (*ptr++ != bg) {                                         \
+                value |= mask;                                          \
+            }                                                           \
+            mask >>= 1;                                                 \
+        }                                                               \
+        *buf++ = (CARD8)value;                                          \
+    }                                                                   \
+}
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+
+/*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+FilterGradient24(pScreen, buf, fmt, w, h)
+    ScreenPtr pScreen;
+    char *buf;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *buf32;
+    CARD32 pix32;
+    int *prevRowPtr;
+    int shiftBits[3];
+    int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];
+    int prediction;
+    int x, y, c;
+
+    buf32 = (CARD32 *)buf;
+    memset (prevRowBuf, 0, w * 3 * sizeof(int));
+
+    if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+        shiftBits[0] = fmt->redShift;
+        shiftBits[1] = fmt->greenShift;
+        shiftBits[2] = fmt->blueShift;
+    } else {
+        shiftBits[0] = 24 - fmt->redShift;
+        shiftBits[1] = 24 - fmt->greenShift;
+        shiftBits[2] = 24 - fmt->blueShift;
+    }
+
+    for (y = 0; y < h; y++) {
+        for (c = 0; c < 3; c++) {
+            pixUpper[c] = 0;
+            pixHere[c] = 0;
+        }
+        prevRowPtr = prevRowBuf;
+        for (x = 0; x < w; x++) {
+            pix32 = *buf32++;
+            for (c = 0; c < 3; c++) {
+                pixUpperLeft[c] = pixUpper[c];
+                pixLeft[c] = pixHere[c];
+                pixUpper[c] = *prevRowPtr;
+                pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF);
+                *prevRowPtr++ = pixHere[c];
+
+                prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c];
+                if (prediction < 0) {
+                    prediction = 0;
+                } else if (prediction > 0xFF) {
+                    prediction = 0xFF;
+                }
+                *buf++ = (char)(pixHere[c] - prediction);
+            }
+        }
+    }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                             \
+                                                                         \
+static void                                                              \
+FilterGradient##bpp(pScreen, buf, fmt, w, h)                             \
+    ScreenPtr pScreen;							 \
+    CARD##bpp *buf;                                                      \
+    rfbPixelFormat *fmt;                                                 \
+    int w, h;                                                            \
+{                                                                        \
+    VNCSCREENPTR(pScreen);						 \
+    CARD##bpp pix, diff;                                                 \
+    Bool endianMismatch;                                                 \
+    int *prevRowPtr;                                                     \
+    int maxColor[3], shiftBits[3];                                       \
+    int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];            \
+    int prediction;                                                      \
+    int x, y, c;                                                         \
+                                                                         \
+    memset (prevRowBuf, 0, w * 3 * sizeof(int));                         \
+                                                                         \
+    endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian);    \
+                                                                         \
+    maxColor[0] = fmt->redMax;                                           \
+    maxColor[1] = fmt->greenMax;                                         \
+    maxColor[2] = fmt->blueMax;                                          \
+    shiftBits[0] = fmt->redShift;                                        \
+    shiftBits[1] = fmt->greenShift;                                      \
+    shiftBits[2] = fmt->blueShift;                                       \
+                                                                         \
+    for (y = 0; y < h; y++) {                                            \
+        for (c = 0; c < 3; c++) {                                        \
+            pixUpper[c] = 0;                                             \
+            pixHere[c] = 0;                                              \
+        }                                                                \
+        prevRowPtr = prevRowBuf;                                         \
+        for (x = 0; x < w; x++) {                                        \
+            pix = *buf;                                                  \
+            if (endianMismatch) {                                        \
+                pix = Swap##bpp(pix);                                    \
+            }                                                            \
+            diff = 0;                                                    \
+            for (c = 0; c < 3; c++) {                                    \
+                pixUpperLeft[c] = pixUpper[c];                           \
+                pixLeft[c] = pixHere[c];                                 \
+                pixUpper[c] = *prevRowPtr;                               \
+                pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]);   \
+                *prevRowPtr++ = pixHere[c];                              \
+                                                                         \
+                prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \
+                if (prediction < 0) {                                    \
+                    prediction = 0;                                      \
+                } else if (prediction > maxColor[c]) {                   \
+                    prediction = maxColor[c];                            \
+                }                                                        \
+                diff |= ((pixHere[c] - prediction) & maxColor[c])        \
+                    << shiftBits[c];                                     \
+            }                                                            \
+            if (endianMismatch) {                                        \
+                diff = Swap##bpp(diff);                                  \
+            }                                                            \
+            *buf++ = diff;                                               \
+        }                                                                \
+    }                                                                    \
+}
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+
+/*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+#define JPEG_MIN_RECT_SIZE  4096
+
+#define DETECT_SUBROW_WIDTH    7
+#define DETECT_MIN_WIDTH       8
+#define DETECT_MIN_HEIGHT      8
+
+static int
+DetectSmoothImage (cl, fmt, w, h)
+    rfbClientPtr cl;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    unsigned long avgError;
+
+    if ( pVNC->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 ||
+         w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) {
+        return 0;
+    }
+
+    if (cl->tightQualityLevel != -1) {
+        if (w * h < JPEG_MIN_RECT_SIZE) {
+            return 0;
+        }
+    } else {
+        if ( rfbTightDisableGradient ||
+             w * h < tightConf[cl->tightCompressLevel].gradientMinRectSize ) {
+            return 0;
+        }
+    }
+
+    if (fmt->bitsPerPixel == 32) {
+        if (usePixelFormat24) {
+            avgError = DetectSmoothImage24(cl, fmt, w, h);
+            if (cl->tightQualityLevel != -1) {
+                return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold24);
+            }
+            return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold24);
+        } else {
+            avgError = DetectSmoothImage32(cl, fmt, w, h);
+        }
+    } else {
+        avgError = DetectSmoothImage16(cl, fmt, w, h);
+    }
+    if (cl->tightQualityLevel != -1) {
+        return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold);
+    }
+    return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold);
+}
+
+static unsigned long
+DetectSmoothImage24 (cl, fmt, w, h)
+    rfbClientPtr cl;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    int off;
+    int x, y, d, dx, c;
+    int diffStat[256];
+    int pixelCount = 0;
+    int pix, left[3];
+    unsigned long avgError;
+
+    /* If client is big-endian, color samples begin from the second
+       byte (offset 1) of a 32-bit pixel value. */
+    off = (fmt->bigEndian != 0);
+
+    memset(diffStat, 0, 256*sizeof(int));
+
+    y = 0, x = 0;
+    while (y < h && x < w) {
+        for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {
+            for (c = 0; c < 3; c++) {
+                left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+            }
+            for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {
+                for (c = 0; c < 3; c++) {
+                    pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+                    diffStat[abs(pix - left[c])]++;
+                    left[c] = pix;
+                }
+                pixelCount++;
+            }
+        }
+        if (w > h) {
+            x += h;
+            y = 0;
+        } else {
+            x = 0;
+            y += w;
+        }
+    }
+
+    if (diffStat[0] * 33 / pixelCount >= 95)
+        return 0;
+
+    avgError = 0;
+    for (c = 1; c < 8; c++) {
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+        if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)
+            return 0;
+    }
+    for (; c < 256; c++) {
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+    }
+    avgError /= (pixelCount * 3 - diffStat[0]);
+
+    return avgError;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp)                                          \
+                                                                             \
+static unsigned long                                                         \
+DetectSmoothImage##bpp (cl, fmt, w, h)                                       \
+    rfbClientPtr cl;							     \
+    rfbPixelFormat *fmt;                                                     \
+    int w, h;                                                                \
+{                                                                            \
+    VNCSCREENPTR(cl->pScreen);						     \
+    Bool endianMismatch;                                                     \
+    CARD##bpp pix;                                                           \
+    int maxColor[3], shiftBits[3];                                           \
+    int x, y, d, dx, c;                                                      \
+    int diffStat[256];                                                       \
+    int pixelCount = 0;                                                      \
+    int sample, sum, left[3];                                                \
+    unsigned long avgError;                                                  \
+                                                                             \
+    endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian);        \
+                                                                             \
+    maxColor[0] = fmt->redMax;                                               \
+    maxColor[1] = fmt->greenMax;                                             \
+    maxColor[2] = fmt->blueMax;                                              \
+    shiftBits[0] = fmt->redShift;                                            \
+    shiftBits[1] = fmt->greenShift;                                          \
+    shiftBits[2] = fmt->blueShift;                                           \
+                                                                             \
+    memset(diffStat, 0, 256*sizeof(int));                                    \
+                                                                             \
+    y = 0, x = 0;                                                            \
+    while (y < h && x < w) {                                                 \
+        for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {     \
+            pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d];                \
+            if (endianMismatch) {                                            \
+                pix = Swap##bpp(pix);                                        \
+            }                                                                \
+            for (c = 0; c < 3; c++) {                                        \
+                left[c] = (int)(pix >> shiftBits[c] & maxColor[c]);          \
+            }                                                                \
+            for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {                  \
+                pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d+dx];         \
+                if (endianMismatch) {                                        \
+                    pix = Swap##bpp(pix);                                    \
+                }                                                            \
+                sum = 0;                                                     \
+                for (c = 0; c < 3; c++) {                                    \
+                    sample = (int)(pix >> shiftBits[c] & maxColor[c]);       \
+                    sum += abs(sample - left[c]);                            \
+                    left[c] = sample;                                        \
+                }                                                            \
+                if (sum > 255)                                               \
+                    sum = 255;                                               \
+                diffStat[sum]++;                                             \
+                pixelCount++;                                                \
+            }                                                                \
+        }                                                                    \
+        if (w > h) {                                                         \
+            x += h;                                                          \
+            y = 0;                                                           \
+        } else {                                                             \
+            x = 0;                                                           \
+            y += w;                                                          \
+        }                                                                    \
+    }                                                                        \
+                                                                             \
+    if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90)                \
+        return 0;                                                            \
+                                                                             \
+    avgError = 0;                                                            \
+    for (c = 1; c < 8; c++) {                                                \
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);     \
+        if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)             \
+            return 0;                                                        \
+    }                                                                        \
+    for (; c < 256; c++) {                                                   \
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);     \
+    }                                                                        \
+    avgError /= (pixelCount - diffStat[0]);                                  \
+                                                                             \
+    return avgError;                                                         \
+}
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+
+/*
+ * JPEG compression stuff.
+ */
+
+static struct jpeg_destination_mgr jpegDstManager;
+static Bool jpegError;
+static int jpegDstDataLen;
+
+static Bool
+SendJpegRect(cl, x, y, w, h, quality)
+    rfbClientPtr cl;
+    int x, y, w, h;
+    int quality;
+{
+    VNCSCREENPTR(cl->pScreen);
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    CARD8 *srcBuf;
+    JSAMPROW rowPointer[1];
+    int dy;
+
+    if (pVNC->rfbServerFormat.bitsPerPixel == 8)
+        return SendFullColorRect(cl, w, h);
+
+    srcBuf = (CARD8 *)xalloc(w * 3);
+    if (srcBuf == NULL) {
+        return SendFullColorRect(cl, w, h);
+    }
+    rowPointer[0] = srcBuf;
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+
+    cinfo.image_width = w;
+    cinfo.image_height = h;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, TRUE);
+
+    JpegSetDstManager (&cinfo);
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    for (dy = 0; dy < h; dy++) {
+        PrepareRowForJpeg(cl->pScreen, srcBuf, x, y + dy, w);
+        jpeg_write_scanlines(&cinfo, rowPointer, 1);
+        if (jpegError)
+            break;
+    }
+
+    if (!jpegError)
+        jpeg_finish_compress(&cinfo);
+
+    jpeg_destroy_compress(&cinfo);
+    xfree((char *)srcBuf);
+
+    if (jpegError)
+        return SendFullColorRect(cl, w, h);
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightJpeg << 4);
+    cl->rfbBytesSent[rfbEncodingTight]++;
+
+    return SendCompressedData(cl, jpegDstDataLen);
+}
+
+static void
+PrepareRowForJpeg(pScreen, dst, x, y, count)
+    ScreenPtr pScreen;
+    CARD8 *dst;
+    int x, y, count;
+{
+    VNCSCREENPTR(pScreen);
+    if (pVNC->rfbServerFormat.bitsPerPixel == 32) {
+        if ( pVNC->rfbServerFormat.redMax == 0xFF &&
+             pVNC->rfbServerFormat.greenMax == 0xFF &&
+             pVNC->rfbServerFormat.blueMax == 0xFF ) {
+            PrepareRowForJpeg24(pScreen, dst, x, y, count);
+        } else {
+            PrepareRowForJpeg32(pScreen, dst, x, y, count);
+        }
+    } else {
+        /* 16 bpp assumed. */
+        PrepareRowForJpeg16(pScreen, dst, x, y, count);
+    }
+}
+
+static void
+PrepareRowForJpeg24(pScreen, dst, x, y, count)
+    ScreenPtr pScreen;
+    CARD8 *dst;
+    int x, y, count;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *fbptr;
+    CARD32 pix;
+
+    fbptr = (CARD32 *)
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * 4];
+
+    while (count--) {
+        pix = *fbptr++;
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift);
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift);
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift);
+    }
+}
+
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                                   \
+                                                                            \
+static void                                                                 \
+PrepareRowForJpeg##bpp(pScreen, dst, x, y, count)                           \
+    ScreenPtr pScreen;							    \
+    CARD8 *dst;                                                             \
+    int x, y, count;                                                        \
+{                                                                           \
+    VNCSCREENPTR(pScreen);						    \
+    CARD##bpp *fbptr;                                                       \
+    CARD##bpp pix;                                                          \
+    int inRed, inGreen, inBlue;                                             \
+                                                                            \
+    fbptr = (CARD##bpp *)                                                   \
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes +                        \
+                             x * (bpp / 8)];                                \
+                                                                            \
+    while (count--) {                                                       \
+        pix = *fbptr++;                                                     \
+                                                                            \
+        inRed = (int)                                                       \
+            (pix >> pVNC->rfbServerFormat.redShift   & pVNC->rfbServerFormat.redMax);   \
+        inGreen = (int)                                                     \
+            (pix >> pVNC->rfbServerFormat.greenShift & pVNC->rfbServerFormat.greenMax); \
+        inBlue  = (int)                                                     \
+            (pix >> pVNC->rfbServerFormat.blueShift  & pVNC->rfbServerFormat.blueMax);  \
+                                                                            \
+	*dst++ = (CARD8)((inRed   * 255 + pVNC->rfbServerFormat.redMax / 2) /     \
+                         pVNC->rfbServerFormat.redMax);                           \
+	*dst++ = (CARD8)((inGreen * 255 + pVNC->rfbServerFormat.greenMax / 2) /   \
+                         pVNC->rfbServerFormat.greenMax);                         \
+	*dst++ = (CARD8)((inBlue  * 255 + pVNC->rfbServerFormat.blueMax / 2) /    \
+                         pVNC->rfbServerFormat.blueMax);                          \
+    }                                                                       \
+}
+
+DEFINE_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+static void
+JpegInitDestination(j_compress_ptr cinfo)
+{
+    jpegError = FALSE;
+    jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+    jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+}
+
+static boolean
+JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+    jpegError = TRUE;
+    jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+    jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+
+    return TRUE;
+}
+
+static void
+JpegTermDestination(j_compress_ptr cinfo)
+{
+    jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer;
+}
+
+static void
+JpegSetDstManager(j_compress_ptr cinfo)
+{
+    jpegDstManager.init_destination = JpegInitDestination;
+    jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+    jpegDstManager.term_destination = JpegTermDestination;
+    cinfo->dest = &jpegDstManager;
+}
+
diff -u -rNp a/hw/vnc/translate.c b/hw/vnc/translate.c
--- a/hw/vnc/translate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/translate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,496 @@
+/*
+ * translate.c - translate between different pixel formats
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+
+static void PrintPixelFormat(rfbPixelFormat *pf);
+static Bool rfbSetClientColourMapBGR233();
+
+Bool rfbEconomicTranslate = FALSE;
+
+/*
+ * Some standard pixel formats.
+ */
+
+static const rfbPixelFormat BGR233Format = {
+    8, 8, 0, 1, 7, 7, 3, 0, 3, 6
+};
+
+
+/*
+ * Macro to compare pixel formats.
+ */
+
+#define PF_EQ(x,y)							\
+	((x.bitsPerPixel == y.bitsPerPixel) &&				\
+	 (x.depth == y.depth) &&					\
+	 ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) &&	\
+	 (x.trueColour == y.trueColour) &&				\
+	 (!x.trueColour || ((x.redMax == y.redMax) &&			\
+			    (x.greenMax == y.greenMax) &&		\
+			    (x.blueMax == y.blueMax) &&			\
+			    (x.redShift == y.redShift) &&		\
+			    (x.greenShift == y.greenShift) &&		\
+			    (x.blueShift == y.blueShift))))
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+
+#define OUT 8
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 16
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 32
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+typedef void (*rfbInitTableFnType)(ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				   rfbPixelFormat *out);
+
+rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = {
+    rfbInitTrueColourSingleTable8,
+    rfbInitTrueColourSingleTable16,
+    rfbInitTrueColourSingleTable32
+};
+
+rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = {
+    rfbInitColourMapSingleTable8,
+    rfbInitColourMapSingleTable16,
+    rfbInitColourMapSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = {
+    rfbInitTrueColourRGBTables8,
+    rfbInitTrueColourRGBTables16,
+    rfbInitTrueColourRGBTables32
+};
+
+rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = {
+    { rfbTranslateWithSingleTable8to8,
+      rfbTranslateWithSingleTable8to16,
+      rfbTranslateWithSingleTable8to32 },
+    { rfbTranslateWithSingleTable16to8,
+      rfbTranslateWithSingleTable16to16,
+      rfbTranslateWithSingleTable16to32 },
+    { rfbTranslateWithSingleTable32to8,
+      rfbTranslateWithSingleTable32to16,
+      rfbTranslateWithSingleTable32to32 }
+};
+
+rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = {
+    { rfbTranslateWithRGBTables8to8,
+      rfbTranslateWithRGBTables8to16,
+      rfbTranslateWithRGBTables8to32 },
+    { rfbTranslateWithRGBTables16to8,
+      rfbTranslateWithRGBTables16to16,
+      rfbTranslateWithRGBTables16to32 },
+    { rfbTranslateWithRGBTables32to8,
+      rfbTranslateWithRGBTables32to16,
+      rfbTranslateWithRGBTables32to32 }
+};
+
+
+
+/*
+ * rfbTranslateNone is used when no translation is required.
+ */
+
+void
+rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, rfbPixelFormat *out,
+		 unsigned char *iptr, char *optr, int bytesBetweenInputLines,
+		 int width, int height, int x, int y)
+{
+    VNCSCREENPTR(pScreen);
+    int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
+
+    if (pVNC->useGetImage) {
+    	DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum];
+
+    	/* catch all for other TranslateNone cases - hextile, corre, rre, etc.*/
+    	(*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, optr);
+    } else {
+    	while (height > 0) {
+	    memcpy(optr, iptr, bytesPerOutputLine);
+	    iptr += bytesBetweenInputLines;
+	    optr += bytesPerOutputLine;
+	    height--;
+     	}
+    }
+}
+
+
+/*
+ * rfbSetTranslateFunction sets the translation function.
+ */
+
+Bool
+rfbSetTranslateFunction(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbLog("Pixel format for client %s:\n",cl->host);
+    PrintPixelFormat(&cl->format);
+
+    /*
+     * Check that bits per pixel values are valid
+     */
+
+    if ((pVNC->rfbServerFormat.bitsPerPixel != 8) &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 16) &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 32))
+    {
+	rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
+		"rfbSetTranslateFunction");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if ((cl->format.bitsPerPixel != 8) &&
+	(cl->format.bitsPerPixel != 16) &&
+	(cl->format.bitsPerPixel != 32))
+    {
+	rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
+		"rfbSetTranslateFunction");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if (!pVNC->rfbServerFormat.trueColour &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 8) &&
+#if XFREE86VNC
+	(miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) {
+#else
+	(pVNC->rfbInstalledColormap->class == PseudoColor)) {
+#endif
+	rfbLog("rfbSetTranslateFunction: server has colour map "
+		"but %d-bit - can only cope with 8-bit colour maps\n",
+		pVNC->rfbServerFormat.bitsPerPixel);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if (!cl->format.trueColour &&
+	(cl->format.bitsPerPixel != 8) &&
+#if XFREE86VNC
+	(miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) {
+#else
+	(pVNC->rfbInstalledColormap->class == PseudoColor) ) {
+#endif
+	rfbLog("rfbSetTranslateFunction: client has colour map "
+		"but %d-bit - can only cope with 8-bit colour maps\n",
+		cl->format.bitsPerPixel);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    /*
+     * bpp is valid, now work out how to translate
+     */
+
+    if (!cl->format.trueColour) {
+
+	/* ? -> colour map */
+
+	if (!pVNC->rfbServerFormat.trueColour) {
+
+	    /* colour map -> colour map */
+
+#if XFREE86VNC
+	    if (miInstalledMaps[cl->pScreen->myNum]->class == DirectColor) {
+#else
+	    if (pVNC->rfbInstalledColormap->class == DirectColor) {
+#endif
+	      rfbLog("rfbSetTranslateFunction: client is %d-bit DirectColor,"
+ 		     " client has colour map\n",cl->format.bitsPerPixel);
+
+	      cl->translateFn = rfbTranslateWithRGBTablesFns
+			          [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+  	      (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16])
+		   (cl->pScreen, &cl->translateLookupTable,
+		   &pVNC->rfbServerFormat, &cl->format);
+
+	      return rfbSetClientColourMap(cl, 0, 0);
+
+	    /* PseudoColor colormap */
+
+	    } else {
+	      rfbLog("rfbSetTranslateFunction: both 8-bit colour map: "
+		     "no translation needed\n");
+	      cl->translateFn = rfbTranslateNone;
+	      return rfbSetClientColourMap(cl, 0, 0);
+	    }
+	}
+
+	/*
+	 * truecolour -> colour map
+	 *
+	 * Set client's colour map to BGR233, then effectively it's
+	 * truecolour as well
+	 */
+
+	if (!rfbSetClientColourMapBGR233(cl))
+	    return FALSE;
+
+	cl->format = BGR233Format;
+    }
+
+    /* ? -> truecolour */
+
+    if (!pVNC->rfbServerFormat.trueColour) {
+
+	/* colour map -> truecolour */
+
+	rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour,"
+		" server has colour map\n",cl->format.bitsPerPixel);
+
+	cl->translateFn = rfbTranslateWithSingleTableFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	return rfbSetClientColourMap(cl, 0, 0);
+    }
+
+    /* truecolour -> truecolour */
+
+    if (PF_EQ(cl->format,pVNC->rfbServerFormat)) {
+
+	/* client & server the same */
+
+	rfbLog("  no translation needed\n");
+	cl->translateFn = rfbTranslateNone;
+	return TRUE;
+    }
+
+    if ((pVNC->rfbServerFormat.bitsPerPixel < 16) ||
+	(!rfbEconomicTranslate && (pVNC->rfbServerFormat.bitsPerPixel == 16))) {
+
+	/* we can use a single lookup table for <= 16 bpp */
+
+	cl->translateFn = rfbTranslateWithSingleTableFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	(*rfbInitTrueColourSingleTableFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+
+    } else {
+
+	/* otherwise we use three separate tables for red, green and blue */
+
+	cl->translateFn = rfbTranslateWithRGBTablesFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	(*rfbInitTrueColourRGBTablesFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
+ * just like an 8-bit BGR233 true colour client.
+ */
+
+static Bool
+rfbSetClientColourMapBGR233(cl)
+    rfbClientPtr cl;
+{
+    char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+    rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+    CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+    int i, len;
+    int r, g, b;
+
+    if (cl->format.bitsPerPixel != 8) {
+	rfbLog("%s: client not 8 bits per pixel\n",
+		"rfbSetClientColourMapBGR233");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    scme->type = rfbSetColourMapEntries;
+
+    scme->firstColour = Swap16IfLE(0);
+    scme->nColours = Swap16IfLE(256);
+
+    len = sz_rfbSetColourMapEntriesMsg;
+
+    i = 0;
+
+    for (b = 0; b < 4; b++) {
+	for (g = 0; g < 8; g++) {
+	    for (r = 0; r < 8; r++) {
+		rgb[i++] = Swap16IfLE(r * 65535 / 7);
+		rgb[i++] = Swap16IfLE(g * 65535 / 7);
+		rgb[i++] = Swap16IfLE(b * 65535 / 3);
+	    }
+	}
+    }
+
+    len += 256 * 3 * 2;
+
+    if (WriteExact(cl->sock, buf, len) < 0) {
+	rfbLogPerror("rfbSetClientColourMapBGR233: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+ * rfbSetClientColourMap is called to set the client's colour map.  If the
+ * client is a true colour client, we simply update our own translation table
+ * and mark the whole screen as having been modified.
+ */
+
+Bool
+rfbSetClientColourMap(cl, firstColour, nColours)
+    rfbClientPtr cl;
+    int firstColour;
+    int nColours;
+{
+    VNCSCREENPTR(cl->pScreen);
+    BoxRec box;
+
+    if (nColours == 0) {
+#if XFREE86VNC
+	nColours = miInstalledMaps[cl->pScreen->myNum]->pVisual->ColormapEntries;
+#else
+	nColours = pVNC->rfbInstalledColormap->pVisual->ColormapEntries;
+#endif
+    }
+
+    if (pVNC->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
+	return TRUE;
+    }
+
+    if (cl->format.trueColour) {
+	(*rfbInitColourMapSingleTableFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+
+	REGION_UNINIT(cl->pScreen,&cl->modifiedRegion);
+	box.x1 = box.y1 = 0;
+	box.x2 = pVNC->width;
+	box.y2 = pVNC->height;
+	REGION_INIT(cl->pScreen,&cl->modifiedRegion,&box,0);
+
+	return TRUE;
+    }
+
+    return rfbSendSetColourMapEntries(cl, firstColour, nColours);
+}
+
+
+/*
+ * rfbSetClientColourMaps sets the colour map for each RFB client.
+ */
+
+void
+rfbSetClientColourMaps(firstColour, nColours)
+    int firstColour;
+    int nColours;
+{
+    rfbClientPtr cl, nextCl;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	rfbSetClientColourMap(cl, firstColour, nColours);
+    }
+}
+
+
+static void
+PrintPixelFormat(pf)
+    rfbPixelFormat *pf;
+{
+    if (pf->bitsPerPixel == 1) {
+	rfbLog("  1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
+	       (pf->bigEndian ? "most" : "least"));
+    } else {
+	rfbLog("  %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
+	       ((pf->bitsPerPixel == 8) ? ""
+		: (pf->bigEndian ? ", big endian" : ", little endian")));
+	if (pf->trueColour) {
+	    rfbLog("  true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
+		   pf->redMax, pf->greenMax, pf->blueMax,
+		   pf->redShift, pf->greenShift, pf->blueShift);
+	} else {
+	    rfbLog("  uses a colour map (not true colour).\n");
+	}
+    }
+}
diff -u -rNp a/hw/vnc/vncauth.h b/hw/vnc/vncauth.h
--- a/hw/vnc/vncauth.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/vncauth.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,33 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* 
+ * vncauth.h - describes the functions provided by the vncauth library.
+ */
+
+#define MAXPWLEN 8
+#define CHALLENGESIZE 16
+
+extern int vncEncryptAndStorePasswd(char *passwd, char *fname);
+extern char *vncDecryptPasswdFromFile(char *fname);
+extern void vncRandomBytes(unsigned char *bytes);
+extern void vncEncryptBytes(unsigned char *bytes, char *passwd);
+extern int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname);
+extern int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly);
+
diff -u -rNp a/hw/vnc/vncext.c b/hw/vnc/vncext.c
--- a/hw/vnc/vncext.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/vncext.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,794 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include "rfb.h"
+
+#include "extnsionst.h"
+#define _VNC_SERVER
+#include <X11/extensions/vncstr.h>
+#ifdef XFree86LOADER
+#include "xf86Module.h"
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int VncSelectNotify(ClientPtr client, BOOL onoff);
+void VncExtensionInit(void);
+
+static int VncErrorBase;  /* first vnc error number */
+static int VncEventBase;  /* first vnc event number */
+
+#define USE_ORIG_RES_CODE 0
+
+#if USE_ORIG_RES_CODE
+unsigned long VncResourceGeneration = 0;
+
+static RESTYPE VncNotifyList;
+
+static XID faked;
+
+typedef struct _VncNotifyListRec {
+    struct _VncNotifyListRec *next;
+    ClientPtr client;
+} VncNotifyListRec, *VncNotifyListPtr;
+#endif
+
+
+/**
+ * Each X client that uses libVnc to talk to this extension will get
+ * recorded by one of these records.
+ */
+typedef struct _VncClientRec {
+    ClientPtr client;
+    struct _VncClientRec *next;
+    XID fakeID;
+    RESTYPE res;
+} VncClientRec, *VncClientRecPtr;
+
+static VncClientRecPtr ClientsList = NULL;
+
+
+/**
+ * Remove client record from list
+ */
+static void
+VncRemoveClientRecord(ClientPtr client)
+{
+   /* XXX need 'deleteresource' flag? */
+    VncClientRecPtr p = ClientsList, prev = NULL;
+    rfbLog("%s client %p\n", __func__, (void *) client);
+    while (p) {
+        if (p->client == client) {
+            /* remove this one */
+            if (prev)
+                prev->next = p->next;
+            else
+                ClientsList = p->next;
+            xfree(p);
+            return;
+        }
+        prev = p;
+        p = p->next;
+    }
+}
+
+
+/**
+ * This callback will be called by X's resource manager to delete the
+ * given resource.  We create one resource for each client.  When X
+ * deletes the resource, we know the client is going away.
+ */
+static int
+VncDestroyClientResourceCallback(pointer pn, XID id)
+{
+    VncClientRecPtr rec = (VncClientRecPtr) pn;
+    VncRemoveClientRecord(rec->client);
+    return Success;
+}
+
+
+/**
+ * Add a client record to the list of clients (unless already in list).
+ * We'll create a new, unique resource for this client.  This is used
+ * to detect when an X client goes away.
+ */
+static void
+VncSaveClientRecord(ClientPtr client)
+{
+    VncClientRecPtr rec = ClientsList;
+
+    rfbLog("%s saving client %p\n", __func__, (void *) client);
+
+    /* look if already in list */
+    while (rec) {
+        if (rec->client == client) {
+            return; /* already in list */
+        }
+        rec = rec->next;
+    }
+
+    /* allocate new client record */
+    rec = (VncClientRecPtr) xalloc(sizeof(VncClientRec));
+    if (rec) {
+        rec->client = client;
+        rec->fakeID = FakeClientID(client->index);
+        rec->res = CreateNewResourceType(VncDestroyClientResourceCallback);
+        if (!AddResource(rec->fakeID, rec->res, rec)) {
+            xfree(rec);
+        }
+
+        /* insert at head of list */
+        rec->next = ClientsList;
+        ClientsList = rec;
+    }
+}
+
+
+
+static int
+ProcVncQueryVersion(ClientPtr client)
+{
+    xVncQueryVersionReply 	rep;
+
+    REQUEST_SIZE_MATCH(xVncQueryVersionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.majorVersion  	= VNC_MAJOR_VERSION;
+    rep.minorVersion  	= VNC_MINOR_VERSION;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.majorVersion, n);
+	swaps(&rep.minorVersion, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncQueryVersionReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncQueryVersion */
+
+static int
+ProcVncConnection(ClientPtr client)
+{
+    REQUEST(xVncConnectionReq);
+    xVncConnectionReply 	rep;
+
+    rfbUserAllow( stuff->sock, stuff->accept );
+
+    REQUEST_SIZE_MATCH(xVncConnectionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.sock  		= 0;
+    rep.accept  	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.sock, n);
+	swaps(&rep.accept, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncConnectionReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncConnection */
+
+static int
+ProcVncSelectNotify(ClientPtr client)
+{
+    REQUEST(xVncSelectNotifyReq);
+    xVncSelectNotifyReply 	rep;
+
+    VncSelectNotify(client, stuff->onoff);
+
+    REQUEST_SIZE_MATCH(xVncSelectNotifyReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncSelectNotifyReply),
+			(char *)&rep);
+    return (client->noClientException);
+
+}
+
+static int
+ProcVncListConnections(ClientPtr client)
+{
+    xVncListConnectionsReply 	rep;
+    rfbClientPtr cl;
+    int count = 0;
+    struct in_addr ipaddress;
+    xVncConnectionListInfo Info;
+
+    /* count connections */
+    for (cl = rfbClientHead; cl; cl = cl->next)
+#ifdef CHROMIUM
+    /* 
+     * Fix this, as it should be generic, but we're only using it
+     * for Chromium at the moment, so we only list the connections
+     * that have a valid chromium encoding. We should be able to list
+     * any type requested. FIXME! XXXX
+     * See furthur down this function too!!!
+     */
+	    if (cl->enableChromiumEncoding)
+#endif
+	    	count++;
+
+    REQUEST_SIZE_MATCH(xVncListConnectionsReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.count		= count;
+    rep.length 		= count * sizeof(xVncConnectionListInfo) >> 2;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    	swaps(&rep.count, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncListConnectionsReply),
+			(char *)&rep);
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+#ifdef CHROMIUM
+        /* 
+         * Fix this, as it should be generic, but we're only using it
+         * for Chromium at the moment, so we only list the connections
+         * that have a valid chromium encoding. We should be able to list
+         * any type requested. FIXME! XXXX
+         */
+	if (!cl->enableChromiumEncoding)
+	    continue;
+#endif
+	inet_aton(cl->host, &ipaddress);
+	memcpy(&Info, &ipaddress, sizeof(struct in_addr));
+	WriteToClient(client, SIZEOF(xVncConnectionListInfo), (char*)&Info);
+    }
+
+    return (client->noClientException);
+} /* ProcVncListConnections */
+
+#ifdef CHROMIUM
+static int
+ProcVncChromiumStart(ClientPtr client)
+{
+    REQUEST(xVncChromiumStartReq);
+    xVncChromiumStartReply 	rep;
+
+    rfbSendChromiumStart(stuff->ipaddress, stuff->crServerPort, stuff->mothershipPort);
+
+    REQUEST_SIZE_MATCH(xVncChromiumStartReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncChromiumStartReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncChromiumStart */
+
+static int
+ProcVncChromiumMonitor(ClientPtr client)
+{
+    REQUEST(xVncChromiumMonitorReq);
+    xVncChromiumMonitorReply 	rep;
+
+    rfbChromiumMonitorWindowID(stuff->cr_windowid, stuff->windowid);
+
+    REQUEST_SIZE_MATCH(xVncChromiumMonitorReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncChromiumMonitorReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncChromiumMonitor */
+#endif /* CHROMIUM */
+
+static int
+ProcVncDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_VncQueryVersion:
+	    return ProcVncQueryVersion(client);
+	case X_VncSelectNotify:
+	    return ProcVncSelectNotify(client);
+	case X_VncConnection:
+	    return ProcVncConnection(client);
+	case X_VncListConnections:
+	    return ProcVncListConnections(client);
+#ifdef CHROMIUM
+	case X_VncChromiumStart:
+	    return ProcVncChromiumStart(client);
+	case X_VncChromiumMonitor:
+	    return ProcVncChromiumMonitor(client);
+#endif
+	default:
+	    return BadRequest;
+    }
+} /* ProcVncDispatch */
+
+static int
+SProcVncQueryVersion(ClientPtr client)
+{
+    REQUEST(xVncQueryVersionReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncQueryVersionReq);
+    swaps(&stuff->majorVersion, n);
+    swaps(&stuff->minorVersion,n);
+    return ProcVncQueryVersion(client);
+} /* SProcVncQueryVersion */
+
+static int
+SProcVncSelectNotify(ClientPtr client)
+{
+    REQUEST(xVncSelectNotifyReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncSelectNotifyReq);
+    return ProcVncSelectNotify(client);
+} /* SProcVncSelectNotify */
+
+static int
+SProcVncListConnections(ClientPtr client)
+{
+    REQUEST(xVncListConnectionsReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncListConnectionsReq);
+    return ProcVncListConnections(client);
+} /* SProcVncListConnections */
+
+#ifdef CHROMIUM
+static int
+SProcVncChromiumStart(ClientPtr client)
+{
+    REQUEST(xVncChromiumStartReq);
+    register char 	n;
+
+    swaps(&stuff->ipaddress, n);
+    swaps(&stuff->crServerPort, n);
+    swaps(&stuff->mothershipPort, n);
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncChromiumStartReq);
+    return ProcVncChromiumStart(client);
+} /* SProcVncChromiumStart */
+
+static int
+SProcVncChromiumMonitor(ClientPtr client)
+{
+    REQUEST(xVncChromiumMonitorReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    swaps(&stuff->windowid, n);
+    swaps(&stuff->cr_windowid, n);
+    REQUEST_SIZE_MATCH(xVncChromiumMonitorReq);
+    return ProcVncChromiumMonitor(client);
+} /* SProcVncChromiumMonitor */
+#endif /* CHROMIUM */
+
+static int
+SProcVncConnection(ClientPtr client)
+{
+    REQUEST(xVncConnectionReq);
+    register char 	n;
+
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncConnectionReq);
+    swaps(&stuff->sock, n);
+    swaps(&stuff->accept,n);
+    return ProcVncConnection(client);
+} /* SProcVncConnection */
+
+static int
+SProcVncDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_VncQueryVersion:
+	    return SProcVncQueryVersion(client);
+	case X_VncSelectNotify:
+	    return SProcVncSelectNotify(client);
+	case X_VncConnection:
+	    return SProcVncConnection(client);
+	case X_VncListConnections:
+	    return SProcVncListConnections(client);
+#ifdef CHROMIUM
+	case X_VncChromiumStart:
+	    return SProcVncChromiumStart(client);
+	case X_VncChromiumMonitor:
+	    return SProcVncChromiumMonitor(client);
+#endif
+	default:
+	    return BadRequest;
+    }
+} /* SProcVncDispatch */
+
+static void 
+SwapVncConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+
+#ifdef CHROMIUM
+static void 
+SwapVncChromiumConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+#endif
+
+static void 
+SwapVncDisconnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+
+int
+GenerateVncConnectedEvent(int sock)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+#else
+    VncClientRecPtr pn = ClientsList;
+#endif
+
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncConnectedEvent conn;
+    	  SOCKLEN_T peer_len;
+    	  struct sockaddr_in peer;
+
+    	  conn.type = VncEventBase + XVncConnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+
+    	  peer_len = sizeof(peer);
+    	  if (getpeername(sock, (struct sockaddr *) &peer, &peer_len) == -1)
+		conn.ipaddress = 0;
+   	  else
+		conn.ipaddress = (CARD32)peer.sin_addr.s_addr;
+
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+
+
+
+#ifdef CHROMIUM
+int
+GenerateVncChromiumConnectedEvent(int sock)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr pn;
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+#else
+    VncClientRecPtr pn = ClientsList;
+#endif
+    rfbLog("Enter GenerateVncChromiumConnectedEvent\n");
+    while (pn)
+    {
+	if (pn->client) 
+	{
+    	  xVncConnectedEvent conn;
+    	  SOCKLEN_T peer_len;
+    	  struct sockaddr_in peer;
+
+          rfbLog("Sending XVncChromiumConnected to client %p\n",
+                 (void *) pn->client);
+
+    	  conn.type = VncEventBase + XVncChromiumConnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+
+    	  peer_len = sizeof(peer);
+    	  if (getpeername(sock, (struct sockaddr *)&peer, &peer_len) == -1)
+		conn.ipaddress = 0;
+   	  else
+		conn.ipaddress = (CARD32)peer.sin_addr.s_addr;
+
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+    return 1;
+}
+#endif /* CHROMIUM */
+
+
+int
+GenerateVncDisconnectedEvent(int sock)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+#else
+    VncClientRecPtr pn = ClientsList;
+#endif
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncDisconnectedEvent conn;
+    	  conn.type = VncEventBase + XVncDisconnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+
+static void
+VncResetProc(ExtensionEntry *extEntry)
+{
+} /* VncResetProc */
+
+
+
+/**
+ * When the app calls libVnc's XVncSelectNotify() we wind up here.
+ * Either add or remove 'client' from the VncNotifyList depending on 'onoff'.
+ */
+int
+VncSelectNotify(ClientPtr client, BOOL onoff)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr head, newRec, tmp, freeRec = NULL;
+
+    rfbLog("%s client %p onoff=%d\n", __func__, (void *) client, (int) onoff);
+    if (!faked)
+	faked = FakeClientID(client->index);
+#else
+    /* ignore onoff param */
+    VncSaveClientRecord(client);
+#endif
+
+#if USE_ORIG_RES_CODE
+    /* Get the first VncNotifyListPtr */
+    head = (VncNotifyListPtr) LookupIDByType(faked, VncNotifyList);
+
+    /* search list for this client */
+    tmp = head;
+    while (tmp) {
+        if (tmp->client == client) {
+            /* found client! */
+            if (!onoff)
+                tmp->client = NULL;
+            return Success;
+        }
+        if (!tmp->client)
+            freeRec = tmp;  /* save ptr to free record */
+        tmp = tmp->next;
+    }
+
+    /* if we get here, we didn't find client in the list */
+
+    if (!onoff) {
+        /* if turning off non-existing client, just return */
+        return Success;
+    }
+
+    /* OK, add new client to list now */
+
+    if (freeRec) {
+        /* re-using a free spot */
+        freeRec->client = client;
+        return Success;
+    }
+
+    /* need to allocate new node */
+    if (!(newRec = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec))))
+        return BadAlloc;
+    /* insert at head, just as AddResource() does!!! */
+    newRec->next = head;
+    newRec->client = client;
+    if (!AddResource(faked, VncNotifyList, newRec)) {
+        xfree(newRec);
+        return BadAlloc;
+    }
+#endif
+    return Success;
+}
+
+
+#if USE_ORIG_RES_CODE
+static int
+VncDestroyNotifyList(pointer pn, XID id)
+{
+    VncNotifyListPtr cpn = (VncNotifyListPtr) pn;
+    rfbLog("%s client %p\n", __func__, (void *) cpn->client);
+    cpn->client = NULL;
+    return Success;
+}
+#endif
+
+static Bool
+CreateResourceTypes(void)
+{
+#if USE_ORIG_RES_CODE
+    if (VncResourceGeneration == serverGeneration)
+        return TRUE;
+
+    VncResourceGeneration = serverGeneration;
+
+    if (!(VncNotifyList = CreateNewResourceType(VncDestroyNotifyList))) {
+        ErrorF("CreateResourceTypes: failed to allocate vnc notify list resource.\n");
+        return FALSE;
+    }
+#endif
+    return TRUE;
+}
+
+
+
+#if XFREE86VNC
+static unsigned long vncCreateScreenResourcesIndex;
+static unsigned long vncExtGeneration = 0;
+extern Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart);
+
+/* copied from miscrinit.c */
+typedef struct
+{
+    pointer pbits; /* pointer to framebuffer */
+    int width;    /* delta to add to a framebuffer addr to move one row down */
+} miScreenInitParmsRec, *miScreenInitParmsPtr;
+
+
+static Bool
+vncCreateScreenResources(ScreenPtr pScreen)
+{
+    int ret = TRUE;
+    CreateScreenResourcesProcPtr CreateScreenResources =
+        (CreateScreenResourcesProcPtr)
+        pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr;
+    miScreenInitParmsPtr pScrInitParms;
+
+    pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate;
+
+    if ( pScreen->CreateScreenResources != vncCreateScreenResources ) {
+        /* Can't find hook we are hung on */
+	xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */,
+                   "vncCreateScreenResources %p called when not in "
+                   "pScreen->CreateScreenResources %p n",
+		   (void *) vncCreateScreenResources,
+                   (void *) pScreen->CreateScreenResources );
+    }
+
+    /* Now do our stuff */
+    VNCInit(pScreen, pScrInitParms->pbits);
+
+    /* Unhook this function ... */
+    pScreen->CreateScreenResources = CreateScreenResources;
+    pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr = NULL;
+
+    /* ... and call the previous CreateScreenResources fuction, if any */
+    if (pScreen->CreateScreenResources) {
+        ret = (*pScreen->CreateScreenResources)(pScreen);
+    }
+
+#ifdef DEBUG
+    ErrorF("vncCreateScreenResources() returns %d\n", ret);
+#endif
+    return ret;
+}
+#endif
+
+
+
+void
+VncExtensionInit(void)
+{
+    ExtensionEntry	*extEntry;
+
+#if XFREE86VNC
+    if (vncExtGeneration != serverGeneration) {
+	unsigned int i;
+
+	vncExtGeneration = serverGeneration;
+
+    	if ( ((vncCreateScreenResourcesIndex = AllocateScreenPrivateIndex()) < 0) ||
+	     ((vncScreenPrivateIndex = AllocateScreenPrivateIndex()) < 0) ||
+	     ((rfbGCIndex = AllocateGCPrivateIndex()) < 0) )
+		return;
+
+    	for (i = 0 ; i < screenInfo.numScreens; i++) 
+	{
+      	    screenInfo.screens[i]->devPrivates[vncCreateScreenResourcesIndex].ptr
+	 		= (void*)(xf86Screens[i]->pScreen->CreateScreenResources);
+      	    xf86Screens[i]->pScreen->CreateScreenResources = vncCreateScreenResources;
+    	}
+
+	gethostname(rfbThisHost, 255);
+    }
+#endif
+
+    if (!CreateResourceTypes())
+	    return;
+
+    extEntry = AddExtension(VNC_EXTENSION_NAME,
+			    XVncNumberEvents, XVncNumberErrors,
+			    ProcVncDispatch, SProcVncDispatch,
+                            VncResetProc, StandardMinorOpcode);
+
+    VncErrorBase = extEntry->errorBase;
+    VncEventBase = extEntry->eventBase;
+
+    EventSwapVector[VncEventBase + XVncConnected] =
+	(EventSwapPtr)SwapVncConnectedEvent;
+    EventSwapVector[VncEventBase + XVncDisconnected] =
+	(EventSwapPtr)SwapVncDisconnectedEvent;
+#ifdef CHROMIUM
+    EventSwapVector[VncEventBase + XVncChromiumConnected] =
+	(EventSwapPtr)SwapVncChromiumConnectedEvent;
+#endif
+} /* VncExtensionInit */
diff -u -rNp a/hw/vnc/xistubs.c b/hw/vnc/xistubs.c
--- a/hw/vnc/xistubs.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/xistubs.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,319 @@
+/* $Xorg: stubs.c,v 1.4 2001/02/09 02:04:35 xorgcvs Exp $ */
+
+/************************************************************
+
+Copyright 1989, 1998  The Open Group
+
+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
+OPEN GROUP 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 Open Group 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 Open Group.
+
+Copyright 1989 by Hewlett-Packard Company, Palo Alto, California.
+
+			All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Hewlett-Packard not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+********************************************************/
+/* $XFree86: xc/programs/Xserver/Xi/stubs.c,v 3.3 2001/01/17 22:13:26 dawes Exp $ */
+
+/*
+ * stubs.c -- stub routines for the X server side of the XINPUT
+ * extension.  This file is mainly to be used only as documentation.
+ * There is not much code here, and you can't get a working XINPUT
+ * server just using this.
+ * The Xvfb server uses this file so it will compile with the same
+ * object files as the real X server for a platform that has XINPUT.
+ * Xnest could do the same thing.
+ */
+
+#define	 NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include "inputstr.h"
+#include "XIstubs.h"
+
+/***********************************************************************
+ *
+ * Caller:	ProcXChangeKeyboardDevice
+ *
+ * This procedure does the implementation-dependent portion of the work
+ * needed to change the keyboard device.
+ *
+ * The X keyboard device has a FocusRec.  If the device that has been 
+ * made into the new X keyboard did not have a FocusRec, 
+ * ProcXChangeKeyboardDevice will allocate one for it.
+ *
+ * If you do not want clients to be able to focus the old X keyboard
+ * device, call DeleteFocusClassDeviceStruct to free the FocusRec.
+ *
+ * If you support input devices with keys that you do not want to be 
+ * used as the X keyboard, you need to check for them here and return 
+ * a BadDevice error.
+ *
+ * The default implementation is to do nothing (assume you do want
+ * clients to be able to focus the old X keyboard).  The commented-out
+ * sample code shows what you might do if you don't want the default.
+ *
+ */
+
+int
+ChangeKeyboardDevice (old_dev, new_dev)
+    DeviceIntPtr	old_dev;
+    DeviceIntPtr	new_dev;
+    {
+    /***********************************************************************
+     DeleteFocusClassDeviceStruct(old_dev);	 * defined in xchgptr.c *
+    **********************************************************************/
+    return BadMatch;
+    }
+
+
+/***********************************************************************
+ *
+ * Caller:	ProcXChangePointerDevice
+ *
+ * This procedure does the implementation-dependent portion of the work
+ * needed to change the pointer device.
+ *
+ * The X pointer device does not have a FocusRec.  If the device that
+ * has been made into the new X pointer had a FocusRec, 
+ * ProcXChangePointerDevice will free it.
+ *
+ * If you want clients to be able to focus the old pointer device that
+ * has now become accessible through the input extension, you need to 
+ * add a FocusRec to it here.
+ *
+ * The XChangePointerDevice protocol request also allows the client
+ * to choose which axes of the new pointer device are used to move 
+ * the X cursor in the X- and Y- directions.  If the axes are different
+ * than the default ones, you need to keep track of that here.
+ *
+ * If you support input devices with valuators that you do not want to be 
+ * used as the X pointer, you need to check for them here and return a 
+ * BadDevice error.
+ *
+ * The default implementation is to do nothing (assume you don't want
+ * clients to be able to focus the old X pointer).  The commented-out
+ * sample code shows what you might do if you don't want the default.
+ *
+ */
+
+int
+#if NeedFunctionPrototypes
+ChangePointerDevice (
+    DeviceIntPtr	old_dev,
+    DeviceIntPtr	new_dev,
+    unsigned char	x,
+    unsigned char	y)
+#else
+ChangePointerDevice (old_dev, new_dev, x, y)
+    DeviceIntPtr	old_dev, new_dev;
+    unsigned char	x, y;
+#endif
+    {
+    /***********************************************************************
+    InitFocusClassDeviceStruct(old_dev);	* allow focusing old ptr*
+
+    x_axis = x;					* keep track of new x-axis*
+    y_axis = y;					* keep track of new y-axis*
+    if (x_axis != 0 || y_axis != 1)
+	axes_changed = TRUE;			* remember axes have changed*
+    else
+	axes_changed = FALSE;
+    *************************************************************************/
+    return BadMatch;
+    }
+
+/***********************************************************************
+ *
+ * Caller:	ProcXCloseDevice
+ *
+ * Take care of implementation-dependent details of closing a device.
+ * Some implementations may actually close the device, others may just
+ * remove this clients interest in that device.
+ *
+ * The default implementation is to do nothing (assume all input devices
+ * are initialized during X server initialization and kept open).
+ *
+ */
+
+void
+CloseInputDevice (d, client)
+    DeviceIntPtr d;
+    ClientPtr client;
+    {
+    }
+
+/***********************************************************************
+ *
+ * Caller:	ProcXListInputDevices
+ *
+ * This is the implementation-dependent routine to initialize an input 
+ * device to the point that information about it can be listed.
+ * Some implementations open all input devices when the server is first
+ * initialized, and never close them.  Other implementations open only
+ * the X pointer and keyboard devices during server initialization,
+ * and only open other input devices when some client makes an
+ * XOpenDevice request.  If some other process has the device open, the
+ * server may not be able to get information about the device to list it.
+ *
+ * This procedure should be used by implementations that do not initialize
+ * all input devices at server startup.  It should do device-dependent
+ * initialization for any devices not previously initialized, and call
+ * AddInputDevice for each of those devices so that a DeviceIntRec will be 
+ * created for them.
+ *
+ * The default implementation is to do nothing (assume all input devices
+ * are initialized during X server initialization and kept open).
+ * The commented-out sample code shows what you might do if you don't want 
+ * the default.
+ *
+ */
+
+void
+AddOtherInputDevices ()
+    {
+    /**********************************************************************
+     for each uninitialized device, do something like: 
+
+    DeviceIntPtr dev;
+    DeviceProc deviceProc;
+    pointer private;
+
+    dev = (DeviceIntPtr) AddInputDevice(deviceProc, TRUE);
+    dev->public.devicePrivate = private;
+    RegisterOtherDevice(dev);
+    dev->inited = ((*dev->deviceProc)(dev, DEVICE_INIT) == Success);
+    ************************************************************************/
+
+    }
+
+/***********************************************************************
+ *
+ * Caller:	ProcXOpenDevice
+ *
+ * This is the implementation-dependent routine to open an input device.
+ * Some implementations open all input devices when the server is first
+ * initialized, and never close them.  Other implementations open only
+ * the X pointer and keyboard devices during server initialization,
+ * and only open other input devices when some client makes an
+ * XOpenDevice request.  This entry point is for the latter type of 
+ * implementation.
+ *
+ * If the physical device is not already open, do it here.  In this case,
+ * you need to keep track of the fact that one or more clients has the
+ * device open, and physically close it when the last client that has
+ * it open does an XCloseDevice.
+ *
+ * The default implementation is to do nothing (assume all input devices
+ * are opened during X server initialization and kept open).
+ *
+ */
+
+void
+OpenInputDevice (dev, client, status)
+    DeviceIntPtr dev;
+    ClientPtr client;
+    int *status;
+    {
+    }
+
+/****************************************************************************
+ *
+ * Caller:	ProcXSetDeviceMode
+ *
+ * Change the mode of an extension device.
+ * This function is used to change the mode of a device from reporting
+ * relative motion to reporting absolute positional information, and
+ * vice versa.
+ * The default implementation below is that no such devices are supported.
+ *
+ */
+
+int
+SetDeviceMode (client, dev, mode)
+    register	ClientPtr	client;
+    DeviceIntPtr dev;
+    int		mode;
+    {
+    return BadMatch;
+    }
+
+/****************************************************************************
+ *
+ * Caller:	ProcXSetDeviceValuators
+ *
+ * Set the value of valuators on an extension input device.
+ * This function is used to set the initial value of valuators on
+ * those input devices that are capable of reporting either relative
+ * motion or an absolute position, and allow an initial position to be set.
+ * The default implementation below is that no such devices are supported.
+ *
+ */
+
+int
+SetDeviceValuators (client, dev, valuators, first_valuator, num_valuators)
+    register	ClientPtr	client;
+    DeviceIntPtr dev;
+    int		*valuators;
+    int		first_valuator;
+    int		num_valuators;
+    {
+    return BadMatch;
+    }
+
+/****************************************************************************
+ *
+ * Caller:	ProcXChangeDeviceControl
+ *
+ * Change the specified device controls on an extension input device.
+ *
+ */
+
+int
+ChangeDeviceControl (client, dev, control)
+    register	ClientPtr	client;
+    DeviceIntPtr dev;
+    xDeviceCtl	*control;
+    {
+    switch (control->control)
+	{
+	case DEVICE_RESOLUTION:
+	    return (BadMatch);
+	default:
+	    return (BadMatch);
+	}
+    }
diff -u -rNp a/hw/vnc/zlib.c b/hw/vnc/zlib.c
--- a/hw/vnc/zlib.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/vnc/zlib.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,309 @@
+/*
+ * zlib.c
+ *
+ * Routines to implement zlib based encoding (deflate).
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ * For the latest source code, please check:
+ *
+ * http://www.developVNC.org/
+ *
+ * or send email to feedback@developvnc.org.
+ */
+
+#include <stdio.h>
+#include "rfb.h"
+
+/*
+ * zlibBeforeBuf contains pixel data in the client's format.
+ * zlibAfterBuf contains the zlib (deflated) encoding version.
+ * If the zlib compressed/encoded version is
+ * larger than the raw data or if it exceeds zlibAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int zlibBeforeBufSize = 0;
+static char *zlibBeforeBuf = NULL;
+
+static int zlibAfterBufSize = 0;
+static char *zlibAfterBuf = NULL;
+static int zlibAfterBufLen;
+
+/*
+ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
+ *                              rectangle encoding.
+ */
+
+Bool
+rfbSendOneRectEncodingZlib(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbZlibHeader hdr;
+    int deflateResult;
+    int previousOut;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+    	   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize;
+    int maxCompSize;
+
+    maxRawSize = (pVNC->width * pVNC->height
+                  * (cl->format.bitsPerPixel / 8));
+
+    if (zlibBeforeBufSize < maxRawSize) {
+	zlibBeforeBufSize = maxRawSize;
+	if (zlibBeforeBuf == NULL)
+	    zlibBeforeBuf = (char *)xalloc(zlibBeforeBufSize);
+	else
+	    zlibBeforeBuf = (char *)xrealloc(zlibBeforeBuf, zlibBeforeBufSize);
+    }
+
+    /* zlib compression is not useful for very small data sets.
+     * So, we just send these raw without any compression.
+     */
+    if (( w * h * (pVNC->bitsPerPixel / 8)) <
+          VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
+
+        int result;
+
+        /* The translation function (used also by the in raw encoding)
+         * requires 4/2/1 byte alignment in the output buffer (which is
+         * pVNC->updateBuf for the raw encoding) based on the bitsPerPixel of
+         * the viewer/client.  This prevents SIGBUS errors on some
+         * architectures like SPARC, PARISC...
+         */
+        if (( cl->format.bitsPerPixel > 8 ) &&
+            ( pVNC->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
+            if (!rfbSendUpdateBuf(cl))
+                return FALSE;
+        }
+
+        result = rfbSendRectEncodingRaw(cl, x, y, w, h);
+
+        return result;
+
+    }
+
+    /*
+     * zlib requires output buffer to be slightly larger than the input
+     * buffer, in the worst case.
+     */
+    maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
+
+    if (zlibAfterBufSize < maxCompSize) {
+	zlibAfterBufSize = maxCompSize;
+	if (zlibAfterBuf == NULL)
+	    zlibAfterBuf = (char *)xalloc(zlibAfterBufSize);
+	else
+	    zlibAfterBuf = (char *)xrealloc(zlibAfterBuf, zlibAfterBufSize);
+    }
+
+    /* 
+     * Convert pixel data to client format.
+     */
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, zlibBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    cl->compStream.next_in = ( Bytef * )zlibBeforeBuf;
+    cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
+    cl->compStream.next_out = ( Bytef * )zlibAfterBuf;
+    cl->compStream.avail_out = maxCompSize;
+    cl->compStream.data_type = Z_BINARY;
+
+    /* Initialize the deflation state. */
+    if ( cl->compStreamInited == FALSE ) {
+
+        cl->compStream.total_in = 0;
+        cl->compStream.total_out = 0;
+        cl->compStream.zalloc = Z_NULL;
+        cl->compStream.zfree = Z_NULL;
+        cl->compStream.opaque = Z_NULL;
+
+        deflateInit2( &(cl->compStream),
+                        cl->zlibCompressLevel,
+                        Z_DEFLATED,
+                        MAX_WBITS,
+                        MAX_MEM_LEVEL,
+                        Z_DEFAULT_STRATEGY );
+        /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
+        /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
+        cl->compStreamInited = TRUE;
+
+    }
+
+    previousOut = cl->compStream.total_out;
+
+    /* Perform the compression here. */
+    deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
+
+    /* Find the total size of the resulting compressed data. */
+    zlibAfterBufLen = cl->compStream.total_out - previousOut;
+
+    if ( deflateResult != Z_OK ) {
+        rfbLog("zlib deflation error: %s\n", cl->compStream.msg);
+        return FALSE;
+    }
+
+    /* Note that it is not possible to switch zlib parameters based on
+     * the results of the compression pass.  The reason is
+     * that we rely on the compressor and decompressor states being
+     * in sync.  Compressing and then discarding the results would
+     * cause lose of synchronization.
+     */
+
+    /* Update statics */
+    cl->rfbRectanglesSent[rfbEncodingZlib]++;
+    cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
+					 + sz_rfbZlibHeader + zlibAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingZlib);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbZlibHeader);
+    pVNC->ublen += sz_rfbZlibHeader;
+
+    for (i = 0; i < zlibAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > zlibAfterBufLen) {
+	    bytesToCopy = zlibAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &zlibAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+
+}
+
+
+/*
+ * rfbSendRectEncodingZlib - send a given rectangle using one or more
+ *                           Zlib encoding rectangles.
+ */
+
+Bool
+rfbSendRectEncodingZlib(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int  maxLines;
+    int  linesRemaining;
+    rfbRectangle partialRect;
+
+    partialRect.x = x;
+    partialRect.y = y;
+    partialRect.w = w;
+    partialRect.h = h;
+
+    /* Determine maximum pixel/scan lines allowed per rectangle. */
+    maxLines = ( ZLIB_MAX_SIZE(w) / w );
+
+    /* Initialize number of scan lines left to do. */
+    linesRemaining = h;
+
+    /* Loop until all work is done. */
+    while ( linesRemaining > 0 ) {
+
+        int linesToComp;
+
+        if ( maxLines < linesRemaining )
+            linesToComp = maxLines;
+        else
+            linesToComp = linesRemaining;
+
+        partialRect.h = linesToComp;
+
+        /* Encode (compress) and send the next rectangle. */
+        if ( ! rfbSendOneRectEncodingZlib( cl,
+                                           partialRect.x,
+                                           partialRect.y,
+                                           partialRect.w,
+                                           partialRect.h )) {
+
+            return FALSE;
+        }
+
+        /* Technically, flushing the buffer here is not extrememly
+         * efficient.  However, this improves the overall throughput
+         * of the system over very slow networks.  By flushing
+         * the buffer with every maximum size zlib rectangle, we
+         * improve the pipelining usage of the server CPU, network,
+         * and viewer CPU components.  Insuring that these components
+         * are working in parallel actually improves the performance
+         * seen by the user.
+         * Since, zlib is most useful for slow networks, this flush
+         * is appropriate for the desired behavior of the zlib encoding.
+         */
+        if (( pVNC->ublen > 0 ) &&
+            ( linesToComp == maxLines )) {
+            if (!rfbSendUpdateBuf(cl)) {
+
+                return FALSE;
+            }
+        }
+
+        /* Update remaining and incremental rectangle location. */
+        linesRemaining -= linesToComp;
+        partialRect.y += linesToComp;
+
+    }
+
+    return TRUE;
+
+}
+
+
diff -u -rNp a/hw/xfree86/dixmods/Makefile.am b/hw/xfree86/dixmods/Makefile.am
--- a/hw/xfree86/dixmods/Makefile.am	2006-12-01 22:48:41.000000000 +0000
+++ b/hw/xfree86/dixmods/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -14,6 +14,10 @@ if DBE
 DBEMOD = libdbe.la
 endif
 
+if XCLIPLIST
+XCLIPLISTMOD = libxcliplist.la
+endif
+
 module_LTLIBRARIES = libafb.la \
                      libcfb.la \
                      libcfb32.la \
@@ -37,6 +41,7 @@ INCLUDES = @XORG_INCS@ \
            -I$(top_srcdir)/cfb \
            -I$(top_srcdir)/mfb \
            -I$(top_srcdir)/dbe \
+           -I$(top_srcdir)/xcliplist \
            -I$(top_srcdir)/hw/xfree86/loader \
            -I$(top_srcdir)/miext/shadow \
            -I$(top_srcdir)/GL/glx
@@ -61,6 +66,10 @@ libdbe_la_LDFLAGS = -avoid-version
 libdbe_la_LIBADD = $(top_builddir)/dbe/libdbe.la
 libdbe_la_SOURCES = dbemodule.c
 
+libxcliplist_la_LDFLAGS = -avoid-version
+libxcliplist_la_LIBADD = $(top_builddir)/xcliplist/libxcliplist.la
+libxcliplist_la_SOURCES = $(top_srcdir)/xcliplist/cliplistmod.c
+
 libfb_la_LDFLAGS = -avoid-version
 libfb_la_LIBADD = $(top_builddir)/fb/libfb.la
 libfb_la_SOURCES = $(top_builddir)/fb/fbcmap.c fbmodule.c
diff -u -rNp a/hw/xfree86/Makefile.am b/hw/xfree86/Makefile.am
--- a/hw/xfree86/Makefile.am	2006-12-01 22:48:41.000000000 +0000
+++ b/hw/xfree86/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -8,16 +8,20 @@ if XF86UTILS
 XF86UTILS_SUBDIR = utils
 endif
 
+if XORG_VNC
+VNC_SUBDIR = vnc
+endif
+
 DOC_SUBDIR = doc
 
 SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support parser rac \
           ramdac shadowfb vbe vgahw xaa xf1bpp xf4bpp xf8_16bpp \
 	  xf8_32bpp loader scanpci dixmods exa \
-	  $(DRI_SUBDIR) $(XF86UTILS_SUBDIR) $(DOC_SUBDIR)
+	  $(DRI_SUBDIR) $(XF86UTILS_SUBDIR) $(VNC_SUBDIR) $(DOC_SUBDIR)
 
 DIST_SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support \
                parser rac ramdac shadowfb vbe vgahw xaa xf1bpp xf4bpp \
-               xf8_16bpp xf8_32bpp loader scanpci dixmods dri exa \
+               xf8_16bpp xf8_32bpp loader scanpci dixmods dri vnc exa \
 	       utils doc
 
 bin_PROGRAMS = Xorg
diff -u -rNp a/hw/xfree86/vnc/auth.c b/hw/xfree86/vnc/auth.c
--- a/hw/xfree86/vnc/auth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/auth.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,563 @@
+/*
+ * auth.c - deal with authentication.
+ *
+ * This file implements authentication when setting up an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003-2004 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <string.h>
+#include "rfb.h"
+#include "windowstr.h"
+
+static void rfbSendSecurityType(rfbClientPtr cl, int securityType);
+static void rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType);
+static void rfbSendTunnelingCaps(rfbClientPtr cl);
+static void rfbSendAuthCaps(rfbClientPtr cl);
+static void rfbVncAuthSendChallenge(rfbClientPtr cl);
+
+/*
+ * rfbAuthNewClient is called right after negotiating the protocol
+ * version. Depending on the protocol version, we send either a code
+ * for authentication scheme to be used (protocol 3.3), or a list of
+ * possible "security types" (protocol 3.7).
+ */
+
+void
+rfbAuthNewClient(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int securityType = rfbSecTypeInvalid;
+ 
+    if ((!pVNC->rfbAuthPasswdFile && !pVNC->loginAuthEnabled) || cl->reverseConnection) {
+	securityType = rfbSecTypeNone;
+    } else {
+	if (rfbAuthIsBlocked(cl)) {
+	    rfbLog("Too many authentication failures - client rejected\n");
+	    rfbClientConnFailed(cl, "Too many authentication failures");
+	    return;
+	}
+	if (pVNC->rfbAuthPasswdFile)
+	    securityType = rfbSecTypeVncAuth;
+    }
+ 
+    if (cl->protocol_minor_ver < 7) {
+	/* Make sure we use only RFB 3.3 compatible security types. */
+	if (securityType == rfbSecTypeInvalid) {
+	    rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n");
+	    rfbClientConnFailed(cl, "Your viewer cannot handle required "
+				"authentication methods");
+	    return;
+	}
+	rfbSendSecurityType(cl, securityType);
+    } else {
+	/* Here it's ok when securityType is set to rfbSecTypeInvalid. */
+	rfbSendSecurityTypeList(cl, securityType);
+    }
+}
+ 
+
+/*
+ * Tell the client what security type will be used (protocol 3.3).
+ */
+
+static void
+rfbSendSecurityType(cl, securityType)
+    rfbClientPtr cl;
+    int securityType;
+{
+    CARD32 value32;
+
+    /* Send the value. */
+    value32 = Swap32IfLE(securityType);
+    if (WriteExact(cl->sock, (char *)&value32, 4) < 0) {
+	rfbLogPerror("rfbSendSecurityType: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Decide what to do next. */
+    switch (securityType) {
+    case rfbSecTypeNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbSecTypeVncAuth:
+	/* Begin the standard VNC authentication procedure. */
+	rfbVncAuthSendChallenge(cl);
+	break;
+    default:
+	/* Impossible case (hopefully). */
+	rfbLogPerror("rfbSendSecurityType: assertion failed");
+	rfbCloseSock(cl->pScreen, cl->sock);
+    }
+}
+
+
+/*
+ * Advertise our supported security types (protocol 3.7). The list
+ * will include one standard security type (if primaryType is not set
+ * to rfbSecTypeInvalid), and then one more value telling the client
+ * that we support TightVNC protocol extensions. Thus, currently,
+ * there will be either 1 or 2 items in the list.
+ */
+
+static void
+rfbSendSecurityTypeList(cl, primaryType)
+    rfbClientPtr cl;
+    int primaryType;
+{
+    int count = 1;
+
+    /* Fill in the list of security types in the client structure. */
+    if (primaryType != rfbSecTypeInvalid) {
+	cl->securityTypes[count++] = (CARD8)primaryType;
+    }
+    cl->securityTypes[count] = (CARD8)rfbSecTypeTight;
+    cl->securityTypes[0] = (CARD8)count++;
+
+    /* Send the list. */
+    if (WriteExact(cl->sock, (char *)cl->securityTypes, count) < 0) {
+	rfbLogPerror("rfbSendSecurityTypeList: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientSecurityType. */
+    cl->state = RFB_SECURITY_TYPE;
+}
+
+
+/*
+ * Read the security type chosen by the client (protocol 3.7).
+ */
+
+void
+rfbProcessClientSecurityType(cl)
+    rfbClientPtr cl;
+{
+    int n, count, i;
+    CARD8 chosenType;
+
+    /* Read the security type. */
+    n = ReadExact(cl->sock, (char *)&chosenType, 1);
+    if (n <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientSecurityType: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientSecurityType: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Make sure it was present in the list sent by the server. */
+    count = (int)cl->securityTypes[0];
+    for (i = 1; i <= count; i++) {
+	if (chosenType == cl->securityTypes[i])
+	    break;
+    }
+    if (i > count) {
+	rfbLog("rfbProcessClientSecurityType: "
+	       "wrong security type requested\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Now go to the proper authentication procedure. */
+    switch (chosenType) {
+    case rfbSecTypeNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbSecTypeVncAuth:
+	/* Begin the standard VNC authentication procedure. */
+	rfbVncAuthSendChallenge(cl);
+	break;
+    case rfbSecTypeTight:
+	/* We are lucky: the viewer supports TightVNC extensions. */
+	rfbLog("Enabling TightVNC protocol extensions\n");
+	/* Switch to the protocol 3.7t. */
+	cl->protocol_tightvnc = TRUE;
+	/* Advertise our tunneling capabilities. */
+	rfbSendTunnelingCaps(cl);
+	break;
+    default:
+	/* Impossible case (hopefully). */
+	rfbLog("rfbProcessClientSecurityType: "
+	       "unknown authentication scheme\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+    }
+}
+
+
+/*
+ * Send the list of our tunneling capabilities (protocol 3.7t).
+ */
+
+static void
+rfbSendTunnelingCaps(cl)
+    rfbClientPtr cl;
+{
+    rfbTunnelingCapsMsg caps;
+    CARD32 nTypes = 0;		/* we don't support tunneling yet */
+
+    caps.nTunnelTypes = Swap32IfLE(nTypes);
+    if (WriteExact(cl->sock, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) {
+	rfbLogPerror("rfbSendTunnelingCaps: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    if (nTypes) {
+	/* Dispatch client input to rfbProcessClientTunnelingType(). */
+	cl->state = RFB_TUNNELING_TYPE;
+    } else {
+	rfbSendAuthCaps(cl);
+    }
+}
+
+
+/*
+ * Read tunneling type requested by the client (protocol 3.7t).
+ * NOTE: Currently, we don't support tunneling, and this function
+ *       can never be called.
+ */
+
+void
+rfbProcessClientTunnelingType(cl)
+    rfbClientPtr cl;
+{
+    /* If we were called, then something's really wrong. */
+    rfbLog("rfbProcessClientTunnelingType: not implemented\n");
+    rfbCloseSock(cl->pScreen, cl->sock);
+    return;
+}
+
+
+/*
+ * Send the list of our authentication capabilities to the client
+ * (protocol 3.7t).
+ */
+
+static void
+rfbSendAuthCaps(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    Bool authRequired;
+    rfbAuthenticationCapsMsg caps;
+    rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
+    int count = 0;
+
+    authRequired = ((pVNC->rfbAuthPasswdFile != NULL || pVNC->loginAuthEnabled) &&
+		    !cl->reverseConnection);
+
+    if (authRequired) {
+	if (pVNC->loginAuthEnabled) {
+	    SetCapInfo(&caplist[count], rfbAuthUnixLogin, rfbTightVncVendor);
+	    cl->authCaps[count++] = rfbAuthUnixLogin;
+	}
+	if (pVNC->rfbAuthPasswdFile != NULL) {
+	    SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
+	    cl->authCaps[count++] = rfbAuthVNC;
+	}
+	if (count == 0) {
+	    /* Should never happen. */
+	    rfbLog("rfbSendAuthCaps: assertion failed\n");
+     	    rfbCloseSock(cl->pScreen, cl->sock);
+ 	    return;
+ 	}
+    }
+ 
+    cl->nAuthCaps = count;
+    caps.nAuthTypes = Swap32IfLE((CARD32)count);
+    if (WriteExact(cl->sock, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
+	rfbLogPerror("rfbSendAuthCaps: write");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+ 
+    if (count) {
+	if (WriteExact(cl->sock, (char *)&caplist[0],
+		       count * sz_rfbCapabilityInfo) < 0) {
+	    rfbLogPerror("rfbSendAuthCaps: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+	/* Dispatch client input to rfbProcessClientAuthType. */
+	cl->state = RFB_AUTH_TYPE;
+     } else {
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+	cl->state = RFB_INITIALISATION;
+    }
+}
+ 
+
+/*
+ * Read client's preferred authentication type (protocol 3.7t).
+ */
+
+void
+rfbProcessClientAuthType(cl)
+    rfbClientPtr cl;
+{
+    CARD32 auth_type;
+    int n, i;
+
+    /* Read authentication type selected by the client. */
+    n = ReadExact(cl->sock, (char *)&auth_type, sizeof(auth_type));
+    if (n <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientAuthType: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientAuthType: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    auth_type = Swap32IfLE(auth_type);
+
+    /* Make sure it was present in the list sent by the server. */
+    for (i = 0; i < cl->nAuthCaps; i++) {
+	if (auth_type == cl->authCaps[i])
+	    break;
+    }
+    if (i >= cl->nAuthCaps) {
+	rfbLog("rfbProcessClientAuthType: "
+	       "wrong authentication type requested\n");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    switch (auth_type) {
+    case rfbAuthNone:
+	/* Dispatch client input to rfbProcessClientInitMessage. */
+ 	cl->state = RFB_INITIALISATION;
+	break;
+    case rfbAuthVNC:
+	rfbVncAuthSendChallenge(cl);
+	break;
+    case rfbAuthUnixLogin:
+	/* FIXME: Do (cl->state = RFB_LOGIN_AUTH) instead? */
+	rfbLoginAuthProcessClientMessage(cl);
+	break;
+    default:
+	rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+     }
+}
+ 
+
+/*
+ * Send the authentication challenge.
+ */
+
+static void
+rfbVncAuthSendChallenge(cl)
+    rfbClientPtr cl;
+{
+    vncRandomBytes(cl->authChallenge);
+    if (WriteExact(cl->sock, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
+	rfbLogPerror("rfbVncAuthSendChallenge: write");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+ 	return;
+     }
+
+    /* Dispatch client input to rfbVncAuthProcessResponse. */
+    cl->state = RFB_AUTHENTICATION;
+}
+
+/*
+ * rfbVncAuthProcessResponse is called when the client sends its
+ * authentication response.
+ */
+
+void
+rfbVncAuthProcessResponse(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    char passwdFullControl[9];
+    char passwdViewOnly[9];
+    int numPasswords;
+    Bool ok;
+    int n;
+    CARD8 encryptedChallenge1[CHALLENGESIZE];
+    CARD8 encryptedChallenge2[CHALLENGESIZE];
+    CARD8 response[CHALLENGESIZE];
+    CARD32 authResult;
+
+    n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE);
+    if (n <= 0) {
+	if (n != 0)
+	    rfbLogPerror("rfbVncAuthProcessResponse: read");
+     	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    numPasswords = vncDecryptPasswdFromFile2(pVNC->rfbAuthPasswdFile,
+					     passwdFullControl,
+					     passwdViewOnly);
+    if (numPasswords == 0) {
+	rfbLog("rfbVncAuthProcessResponse: could not get password from %s\n",
+	       pVNC->rfbAuthPasswdFile);
+
+	authResult = Swap32IfLE(rfbVncAuthFailed);
+
+	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	    rfbLogPerror("rfbVncAuthProcessResponse: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    memcpy(encryptedChallenge1, cl->authChallenge, CHALLENGESIZE);
+    vncEncryptBytes(encryptedChallenge1, passwdFullControl);
+    memcpy(encryptedChallenge2, cl->authChallenge, CHALLENGESIZE);
+    vncEncryptBytes(encryptedChallenge2,
+		    (numPasswords == 2) ? passwdViewOnly : passwdFullControl);
+
+    /* Lose the passwords from memory */
+    memset(passwdFullControl, 0, 9);
+    memset(passwdViewOnly, 0, 9);
+
+    ok = FALSE;
+    if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) {
+	rfbLog("Full-control authentication passed by %s\n", cl->host);
+	ok = TRUE;
+	cl->viewOnly = FALSE;
+    } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) {
+	rfbLog("View-only authentication passed by %s\n", cl->host);
+	ok = TRUE;
+	cl->viewOnly = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	    rfbLogPerror("rfbVncAuthProcessResponse: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) {
+	rfbLogPerror("rfbVncAuthProcessResponse: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientInitMessage(). */
+    cl->state = RFB_INITIALISATION;
+}
+
+
+/*
+ * Functions to prevent too many successive authentication failures.
+ * FIXME: This should be performed separately per each client IP.
+ */
+
+/* Maximum authentication failures before blocking connections */
+#define MAX_AUTH_TRIES 5
+
+/* Delay in ms, doubles for each failure over MAX_AUTH_TRIES */
+#define AUTH_TOO_MANY_BASE_DELAY 10 * 1000
+
+/*
+ * This function should not be called directly, it is called by
+ * setting a timer in rfbAuthConsiderBlocking().
+ */
+
+static CARD32
+rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+    rfbClientPtr cl = (rfbClientPtr) arg;
+    VNCSCREENPTR(cl->pScreen);
+    pVNC->rfbAuthTooManyTries = FALSE;
+    return 0;
+}
+
+/*
+ * This function should be called after each authentication failure.
+ * The return value will be true if there was too many failures.
+ */
+
+Bool
+rfbAuthConsiderBlocking(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    int i;
+
+    pVNC->rfbAuthTries++;
+
+    if (pVNC->rfbAuthTries >= MAX_AUTH_TRIES) {
+	CARD32 delay = AUTH_TOO_MANY_BASE_DELAY;
+	for (i = MAX_AUTH_TRIES; i < pVNC->rfbAuthTries; i++)
+	    delay *= 2;
+	pVNC->timer = TimerSet(pVNC->timer, 0, delay, rfbAuthReenable, NULL);
+	pVNC->rfbAuthTooManyTries = TRUE;
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * This function should be called after successful authentication.
+ * It resets the counter of authentication failures. Note that it's
+ * not necessary to clear the rfbAuthTooManyTries flag as it will be
+ * reset by the timer function.
+ */
+
+void
+rfbAuthUnblock(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    pVNC->rfbAuthTries = 0;
+}
+
+/*
+ * This function should be called before authentication process.
+ * The return value will be true if there was too many authentication
+ * failures, and the server should not allow another try.
+ */
+
+Bool
+rfbAuthIsBlocked(rfbClientPtr cl)
+{
+    VNCSCREENPTR(cl->pScreen);
+    return pVNC->rfbAuthTooManyTries;
+}
+
diff -u -rNp a/hw/xfree86/vnc/cmap.c b/hw/xfree86/vnc/cmap.c
--- a/hw/xfree86/vnc/cmap.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/cmap.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,163 @@
+/*
+ * cmap.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1993  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+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 X CONSORTIUM 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 X Consortium 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 X Consortium.
+
+*/
+
+#include "rfb.h"
+
+int
+rfbListInstalledColormaps(pScreen, pmaps)
+    ScreenPtr	pScreen;
+    Colormap	*pmaps;
+{
+    VNCSCREENPTR(pScreen);
+    /* By the time we are processing requests, we can guarantee that there
+     * is always a colormap installed */
+    if (pVNC->rfbInstalledColormap)
+    	*pmaps = pVNC->rfbInstalledColormap->mid;
+
+#if XFREE86VNC
+    pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps;
+    (*pScreen->ListInstalledColormaps)(pScreen, pmaps);
+    pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
+#endif
+
+    return (1);
+}
+
+
+void
+rfbInstallColormap(pmap)
+    ColormapPtr	pmap;
+{
+    VNCSCREENPTR(pmap->pScreen);
+
+    if (pmap != pVNC->rfbInstalledColormap) {
+
+	if(pVNC->rfbInstalledColormap != (ColormapPtr)None)
+	    WalkTree(pmap->pScreen, TellLostMap,
+				 (char *)&pVNC->rfbInstalledColormap->mid);
+	/* Install pmap */
+	pVNC->rfbInstalledColormap = pmap;
+	WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+	rfbSetClientColourMaps(0, 0);
+    }
+#if XFREE86VNC
+    pmap->pScreen->InstallColormap = pVNC->InstallColormap;
+    (*pmap->pScreen->InstallColormap)(pmap);
+    pmap->pScreen->InstallColormap = rfbInstallColormap;
+#endif
+}
+
+void
+rfbUninstallColormap(pmap)
+    ColormapPtr	pmap;
+{
+    VNCSCREENPTR(pmap->pScreen);
+
+    if(pmap == pVNC->rfbInstalledColormap)
+    {
+	if (pmap->mid != pmap->pScreen->defColormap)
+	{
+	    pVNC->rfbInstalledColormap = 
+			(ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+						   RT_COLORMAP);
+	    (*pmap->pScreen->InstallColormap)(pVNC->rfbInstalledColormap);
+	}
+    }
+#if XFREE86VNC
+    pmap->pScreen->UninstallColormap = pVNC->UninstallColormap;
+    (*pmap->pScreen->UninstallColormap)(pmap);
+    pmap->pScreen->UninstallColormap = rfbUninstallColormap;
+#endif
+}
+
+
+/*
+ * rfbStoreColors.  We have a set of pixels but they may be in any order.
+ * If some of them happen to be in continuous ascending order then we can
+ * group them together into a single call to rfbSetClientColourMaps.
+ */
+
+void
+rfbStoreColors(pmap, ndef, pdefs)
+    ColormapPtr pmap;
+    int         ndef;
+    xColorItem  *pdefs;
+{
+    VNCSCREENPTR(pmap->pScreen);
+    int i;
+    int first = -1;
+    int n = 0;
+
+    if (pmap == pVNC->rfbInstalledColormap) {
+	for (i = 0; i < ndef; i++) {
+	    if ((first != -1) && (first + n == pdefs[i].pixel)) {
+		n++;
+	    } else {
+		if (first != -1) {
+		    rfbSetClientColourMaps(first, n);
+		}
+		first = pdefs[i].pixel;
+		n = 1;
+	    }
+	}
+	rfbSetClientColourMaps(first, n);
+    }
+#if XFREE86VNC
+    pmap->pScreen->StoreColors = pVNC->StoreColors;
+    (*pmap->pScreen->StoreColors)(pmap, ndef, pdefs);
+    pmap->pScreen->StoreColors = rfbStoreColors;
+#endif
+}
diff -u -rNp a/hw/xfree86/vnc/corre.c b/hw/xfree86/vnc/corre.c
--- a/hw/xfree86/vnc/corre.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/corre.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,355 @@
+/*
+ * corre.c
+ *
+ * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE).  This
+ * code is based on krw's original javatel rfbserver.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rfb.h"
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version.  If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(CARD8 *data, int w, int h);
+static int subrectEncode16(CARD16 *data, int w, int h);
+static int subrectEncode32(CARD32 *data, int w, int h);
+static CARD32 getBgColour(char *data, int size, int bpp);
+static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
+					  int w, int h);
+
+
+/*
+ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
+ * encoding.
+ */
+
+Bool
+rfbSendRectEncodingCoRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    if (h > cl->correMaxHeight) {
+	return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
+		rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight,
+					 w, h - cl->correMaxHeight));
+    }
+
+    if (w > cl->correMaxWidth) {
+	return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
+		rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
+					 w - cl->correMaxWidth, h));
+    }
+
+    return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
+}
+
+
+
+/*
+ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
+ * rectangle using CoRRE encoding.
+ */
+
+static Bool
+rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbRREHeader hdr;
+    int nSubrects;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize = (pVNC->width * pVNC->height
+		      * (cl->format.bitsPerPixel / 8));
+
+    if (rreBeforeBufSize < maxRawSize) {
+	rreBeforeBufSize = maxRawSize;
+	if (rreBeforeBuf == NULL)
+	    rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
+	else
+	    rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+    }
+
+    if (rreAfterBufSize < maxRawSize) {
+	rreAfterBufSize = maxRawSize;
+	if (rreAfterBuf == NULL)
+	    rreAfterBuf = (char *)xalloc(rreAfterBufSize);
+	else
+	    rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+    }
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, rreBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
+	break;
+    case 16:
+	nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
+	break;
+    case 32:
+	nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
+	break;
+    default:
+	rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+	exit(1);
+    }
+	
+    if (nSubrects < 0) {
+
+	/* RRE encoding was too large, use raw */
+
+	return rfbSendRectEncodingRaw(cl, x, y, w, h);
+    }
+
+    cl->rfbRectanglesSent[rfbEncodingCoRRE]++;
+    cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
+					   + sz_rfbRREHeader + rreAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nSubrects = Swap32IfLE(nSubrects);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader);
+    pVNC->ublen += sz_rfbRREHeader;
+
+    for (i = 0; i < rreAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > rreAfterBufLen) {
+	    bytesToCopy = rreAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background 
+ * colour overwritten by single-coloured rectangles.  It returns the number 
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive 
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp)					      \
+static int								      \
+subrectEncode##bpp(data,w,h)						      \
+    CARD##bpp *data;							      \
+    int w;								      \
+    int h;								      \
+{									      \
+    CARD##bpp cl;							      \
+    rfbCoRRERectangle subrect;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp);		      \
+									      \
+    *((CARD##bpp*)rreAfterBuf) = bg;					      \
+									      \
+    rreAfterBufLen = (bpp/8);						      \
+									      \
+    for (y=0; y<h; y++) {						      \
+      line = data+(y*w);						      \
+      for (x=0; x<w; x++) {						      \
+        if (line[x] != bg) {						      \
+          cl = line[x];							      \
+          hy = y-1;							      \
+          hyflag = 1;							      \
+          for (j=y; j<h; j++) {						      \
+            seg = data+(j*w);						      \
+            if (seg[x] != cl) {break;}					      \
+            i = x;							      \
+            while ((seg[i] == cl) && (i < w)) i += 1;			      \
+            i -= 1;							      \
+            if (j == y) vx = hx = i;					      \
+            if (i < vx) vx = i;						      \
+            if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      \
+          }								      \
+          vy = j-1;							      \
+									      \
+          /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  \
+           *  We'll choose the bigger of the two.			      \
+           */								      \
+          hw = hx-x+1;							      \
+          hh = hy-y+1;							      \
+          vw = vx-x+1;							      \
+          vh = vy-y+1;							      \
+									      \
+          thex = x;							      \
+          they = y;							      \
+									      \
+          if ((hw*hh) > (vw*vh)) {					      \
+            thew = hw;							      \
+            theh = hh;							      \
+          } else {							      \
+            thew = vw;							      \
+            theh = vh;							      \
+          }								      \
+									      \
+          subrect.x = thex;						      \
+          subrect.y = they;						      \
+          subrect.w = thew;						      \
+          subrect.h = theh;						      \
+									      \
+	  newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle;	      \
+          if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize))     \
+	    return -1;							      \
+									      \
+	  numsubs += 1;							      \
+	  *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl;		      \
+	  rreAfterBufLen += (bpp/8);					      \
+	  memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
+	  rreAfterBufLen += sz_rfbCoRRERectangle;			      \
+									      \
+          /*								      \
+           * Now mark the subrect as done.				      \
+           */								      \
+          for (j=they; j < (they+theh); j++) {				      \
+            for (i=thex; i < (thex+thew); i++) {			      \
+              data[j*w+i] = bg;						      \
+            }								      \
+          }								      \
+        }								      \
+      }									      \
+    }									      \
+									      \
+    return numsubs;							      \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static CARD32
+getBgColour(data,size,bpp)
+    char *data;
+    int size;
+    int bpp;
+{
+    
+#define NUMCLRS 256
+  
+  static int counts[NUMCLRS];
+  int i,j,k;
+
+  int maxcount = 0;
+  CARD8 maxclr = 0;
+
+  if (bpp != 8) {
+    if (bpp == 16) {
+      return ((CARD16 *)data)[0];
+    } else if (bpp == 32) {
+      return ((CARD32 *)data)[0];
+    } else {
+      rfbLog("getBgColour: bpp %d?\n",bpp);
+      exit(1);
+    }
+  }
+
+  for (i=0; i<NUMCLRS; i++) {
+    counts[i] = 0;
+  }
+
+  for (j=0; j<size; j++) {
+    k = (int)(((CARD8 *)data)[j]);
+    if (k >= NUMCLRS) {
+      rfbLog("getBgColour: unusual colour = %d\n", k);
+      exit(1);
+    }
+    counts[k] += 1;
+    if (counts[k] > maxcount) {
+      maxcount = counts[k];
+      maxclr = ((CARD8 *)data)[j];
+    }
+  }
+  
+  return maxclr;
+}
diff -u -rNp a/hw/xfree86/vnc/cursor.c b/hw/xfree86/vnc/cursor.c
--- a/hw/xfree86/vnc/cursor.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/cursor.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,405 @@
+/*
+ * cursor.c - support for cursor shape updates.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rfb.h"
+#include "mipointer.h"
+#include "sprite.h"
+#include "cursorstr.h"
+#include "servermd.h"
+
+
+/* Copied from Xvnc/lib/font/util/utilbitmap.c */
+static unsigned char _reverse_byte[0x100] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+
+static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt,
+				  CursorPtr pCursor);
+static int EncodeRichCursorData16 (ScreenPtr pScreen,
+				   char *buf, rfbPixelFormat *fmt,
+				   CursorPtr pCursor);
+static int EncodeRichCursorData32 (ScreenPtr pScreen,
+				   char *buf, rfbPixelFormat *fmt,
+				   CursorPtr pCursor);
+
+
+/*
+ * Send cursor shape either in X-style format or in client pixel format.
+ */
+
+Bool
+rfbSendCursorShape(cl, pScreen)
+    rfbClientPtr cl;
+    ScreenPtr pScreen;
+{
+    VNCSCREENPTR(pScreen);
+    CursorPtr pCursor;
+    rfbFramebufferUpdateRectHeader rect;
+    rfbXCursorColors colors;
+    int saved_ublen;
+    int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes;
+    int i, j;
+    CARD8 *bitmapData;
+    CARD8 bitmapByte;
+
+    if (cl->useRichCursorEncoding) {
+	rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
+    } else {
+	rect.encoding = Swap32IfLE(rfbEncodingXCursor);
+    }
+
+#if XFREE86VNC
+    pCursor = pVNC->pCurs;
+#else
+    pCursor = rfbSpriteGetCursorPtr(pScreen);
+#endif
+
+    /* If there is no cursor, send update with empty cursor data. */
+
+    if ( pCursor != NULL &&
+	 pCursor->bits->width == 1 &&
+	 pCursor->bits->height == 1 &&
+	 pCursor->bits->mask[0] == 0 ) {
+	pCursor = NULL;
+    }
+
+    if (pCursor == NULL) {
+	if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+	rect.r.x = rect.r.y = 0;
+	rect.r.w = rect.r.h = 0;
+	memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	       sz_rfbFramebufferUpdateRectHeader);
+	pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+	cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
+	cl->rfbCursorShapeUpdatesSent++;
+
+	return TRUE;
+    }
+
+    /* Calculate data sizes. */
+
+    bitmapRowBytes = (pCursor->bits->width + 7) / 8;
+    paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1);
+    maskBytes = bitmapRowBytes * pCursor->bits->height;
+    dataBytes = (cl->useRichCursorEncoding) ?
+	(pCursor->bits->width * pCursor->bits->height *
+	 (cl->format.bitsPerPixel / 8)) : maskBytes;
+
+    /* Send buffer contents if needed. */
+
+    if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader +
+	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader +
+	 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
+	return FALSE;		/* FIXME. */
+    }
+
+    saved_ublen = pVNC->ublen;
+
+    /* Prepare rectangle header. */
+
+    rect.r.x = Swap16IfLE(pCursor->bits->xhot);
+    rect.r.y = Swap16IfLE(pCursor->bits->yhot);
+    rect.r.w = Swap16IfLE(pCursor->bits->width);
+    rect.r.h = Swap16IfLE(pCursor->bits->height);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    /* Prepare actual cursor data (depends on encoding used). */
+
+    if (!cl->useRichCursorEncoding) {
+	/* XCursor encoding. */
+	colors.foreRed   = (char)(pCursor->foreRed   >> 8);
+	colors.foreGreen = (char)(pCursor->foreGreen >> 8);
+	colors.foreBlue  = (char)(pCursor->foreBlue  >> 8);
+	colors.backRed   = (char)(pCursor->backRed   >> 8);
+	colors.backGreen = (char)(pCursor->backGreen >> 8);
+	colors.backBlue  = (char)(pCursor->backBlue  >> 8);
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&colors, sz_rfbXCursorColors);
+	pVNC->ublen += sz_rfbXCursorColors;
+
+	bitmapData = (CARD8 *)pCursor->bits->source;
+
+	for (i = 0; i < pCursor->bits->height; i++) {
+	    for (j = 0; j < bitmapRowBytes; j++) {
+		bitmapByte = bitmapData[i * paddedRowBytes + j];
+		if (screenInfo.bitmapBitOrder == LSBFirst) {
+		    bitmapByte = _reverse_byte[bitmapByte];
+		}
+		pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte;
+	    }
+	}
+    } else {
+	/* RichCursor encoding. */
+	switch (cl->format.bitsPerPixel) {
+	case 8:
+	    pVNC->ublen += EncodeRichCursorData8(&pVNC->updateBuf[pVNC->ublen],
+					   &cl->format, pCursor);
+	    break;
+	case 16:
+	    pVNC->ublen += EncodeRichCursorData16(pScreen, &pVNC->updateBuf[pVNC->ublen],
+					    &cl->format, pCursor);
+	    break;
+	case 32:
+	    pVNC->ublen += EncodeRichCursorData32(pScreen, &pVNC->updateBuf[pVNC->ublen],
+					    &cl->format, pCursor);
+	    break;
+	default:
+	    return FALSE;
+	}
+    }
+
+    /* Prepare transparency mask. */
+
+    bitmapData = (CARD8 *)pCursor->bits->mask;
+
+    for (i = 0; i < pCursor->bits->height; i++) {
+	for (j = 0; j < bitmapRowBytes; j++) {
+	    bitmapByte = bitmapData[i * paddedRowBytes + j];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte;
+	}
+    }
+
+    /* Update statistics. */
+
+    cl->rfbCursorShapeBytesSent += (pVNC->ublen - saved_ublen);
+    cl->rfbCursorShapeUpdatesSent++;
+
+    return TRUE;
+}
+
+/*
+ * Send cursor position (PointerPos pseudo-encoding).
+ */
+Bool
+rfbSendCursorPos(cl, pScreen)
+    rfbClientPtr cl;
+    ScreenPtr pScreen;
+{
+    VNCSCREENPTR(pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+#if XFREE86VNC
+    ScreenPtr   pCursorScreen = miPointerCurrentScreen();
+#endif
+    int x, y;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+#if XFREE86VNC
+    if (pScreen == pCursorScreen) 
+        miPointerPosition(&x, &y);
+#else
+    rfbSpriteGetCursorPos(pScreen, &x, &y);
+#endif
+
+    rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
+    rect.r.x = Swap16IfLE((CARD16)x);
+    rect.r.y = Swap16IfLE((CARD16)y);
+    rect.r.w = 0;
+    rect.r.h = 0;
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
+    cl->rfbCursorPosUpdatesSent++;
+
+    if (!rfbSendUpdateBuf(cl))
+	return FALSE;
+
+    cl->cursorX = x;
+    cl->cursorY = y;
+
+    return TRUE;
+}
+
+/*
+ * Code to convert cursor source bitmap to the desired pixel format.
+ */
+
+#define RGB48_TO_PIXEL(fmt,r,g,b)					\
+    (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift |	\
+     ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift |	\
+     ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift)
+
+static int
+EncodeRichCursorData8(buf, fmt, pCursor)
+    char *buf;
+    rfbPixelFormat *fmt;
+    CursorPtr pCursor;
+{
+    int widthPixels, widthBytes;
+    int x, y, b;
+    CARD8 *src;
+    char pix[2];
+    CARD8 bitmapByte;
+
+    pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen,
+				  pCursor->backBlue);
+    pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen,
+				  pCursor->foreBlue);
+
+    src = (CARD8 *)pCursor->bits->source;
+    widthPixels = pCursor->bits->width;
+    widthBytes = PixmapBytePad(widthPixels, 1);
+
+    for (y = 0; y < pCursor->bits->height; y++) {
+	for (x = 0; x < widthPixels / 8; x++) {
+	    bitmapByte = src[y * widthBytes + x];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    for (b = 7; b >= 0; b--) {
+		*buf++ = pix[bitmapByte >> b & 1];
+	    }
+	}
+	if (widthPixels % 8) {
+	    bitmapByte = src[y * widthBytes + x];
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {
+		bitmapByte = _reverse_byte[bitmapByte];
+	    }
+	    for (b = 7; b > 7 - widthPixels % 8; b--) {
+		*buf++ = pix[bitmapByte >> b & 1];
+	    }
+	}
+    }
+
+    return (widthPixels * pCursor->bits->height);
+}
+
+#define DEFINE_RICH_ENCODE(bpp)						 \
+									 \
+static int								 \
+EncodeRichCursorData##bpp(pScreen, buf, fmt, pCursor)			 \
+    ScreenPtr pScreen;							 \
+    char *buf;								 \
+    rfbPixelFormat *fmt;						 \
+    CursorPtr pCursor;							 \
+{									 \
+    VNCSCREENPTR(pScreen);						 \
+    int widthPixels, widthBytes;					 \
+    int x, y, b;							 \
+    CARD8 *src;								 \
+    CARD##bpp pix[2];							 \
+    CARD8 bitmapByte;							 \
+									 \
+    pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed,		 \
+				       pCursor->backGreen,		 \
+				       pCursor->backBlue);		 \
+    pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed,		 \
+				       pCursor->foreGreen,		 \
+				       pCursor->foreBlue);		 \
+    if (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian) {		 \
+	pix[0] = Swap##bpp(pix[0]);					 \
+	pix[1] = Swap##bpp(pix[1]);					 \
+    }									 \
+									 \
+    src = (CARD8 *)pCursor->bits->source;				 \
+    widthPixels = pCursor->bits->width;					 \
+    widthBytes = PixmapBytePad(widthPixels, 1);				 \
+									 \
+    for (y = 0; y < pCursor->bits->height; y++) {			 \
+	for (x = 0; x < widthPixels / 8; x++) {				 \
+	    bitmapByte = src[y * widthBytes + x];			 \
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {		 \
+		bitmapByte = _reverse_byte[bitmapByte];			 \
+	    }								 \
+	    for (b = 7; b >= 0; b--) {					 \
+		memcpy (buf, (char *)&pix[bitmapByte >> b & 1],		 \
+			sizeof(CARD##bpp));				 \
+		buf += sizeof(CARD##bpp);				 \
+	    }								 \
+	}								 \
+	if (widthPixels % 8) {						 \
+	    bitmapByte = src[y * widthBytes + x];			 \
+	    if (screenInfo.bitmapBitOrder == LSBFirst) {		 \
+		bitmapByte = _reverse_byte[bitmapByte];			 \
+	    }								 \
+	    for (b = 7; b > 7 - widthPixels % 8; b--) {			 \
+		memcpy (buf, (char *)&pix[bitmapByte >> b & 1],		 \
+			sizeof(CARD##bpp));				 \
+		buf += sizeof(CARD##bpp);				 \
+	    }								 \
+	}								 \
+    }									 \
+									 \
+    return (widthPixels * pCursor->bits->height * (bpp / 8));		 \
+}
+
+DEFINE_RICH_ENCODE(16)
+DEFINE_RICH_ENCODE(32)
+
diff -u -rNp a/hw/xfree86/vnc/cutpaste.c b/hw/xfree86/vnc/cutpaste.c
--- a/hw/xfree86/vnc/cutpaste.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/cutpaste.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,87 @@
+/*
+ * cutpaste.c - routines to deal with cut & paste buffers / selection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include "rfb.h"
+#include "selection.h"
+#include "input.h"
+
+extern Selection *CurrentSelections;
+extern int NumCurrentSelections;
+
+
+static Bool inSetXCutText = FALSE;
+
+/*
+ * rfbSetXCutText sets the cut buffer to be the given string.  We also clear
+ * the primary selection.  Ideally we'd like to set it to the same thing, but I
+ * can't work out how to do that without some kind of helper X client.
+ */
+
+void
+rfbSetXCutText(char *str, int len)
+{
+    int i = 0;
+
+    inSetXCutText = TRUE;
+    ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING,
+			 8, PropModeReplace, len,
+			 (pointer)str, TRUE);
+    
+    while ((i < NumCurrentSelections) && 
+	   CurrentSelections[i].selection != XA_PRIMARY)
+	i++;
+
+    if (i < NumCurrentSelections) {
+	xEvent event;
+
+	if (CurrentSelections[i].client) {
+	    event.u.u.type = SelectionClear;
+	    event.u.selectionClear.time = GetTimeInMillis();
+	    event.u.selectionClear.window = CurrentSelections[i].window;
+	    event.u.selectionClear.atom = CurrentSelections[i].selection;
+	    (void) TryClientEvents (CurrentSelections[i].client, &event, 1,
+				NoEventMask, NoEventMask /* CantBeFiltered */,
+				NullGrab);
+	}
+
+	CurrentSelections[i].window = None;
+	CurrentSelections[i].pWin = NULL;
+	CurrentSelections[i].client = NullClient;
+    }
+
+    inSetXCutText = FALSE;
+}
+
+
+void rfbGotXCutText(char *str, int len)
+{
+    if (!inSetXCutText)
+	rfbSendServerCutText(str, len);
+}
diff -u -rNp a/hw/xfree86/vnc/draw.c b/hw/xfree86/vnc/draw.c
--- a/hw/xfree86/vnc/draw.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/draw.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2108 @@
+/*
+ * draw.c - drawing routines for the RFB X server.  This is a set of
+ * wrappers around the standard MI/MFB/CFB drawing routines which work out
+ * to a fair approximation the region of the screen being modified by the
+ * drawing.  If the RFB client is ready then the modified region of the screen
+ * is sent to the client, otherwise the modified region will simply grow with
+ * each drawing request until the client is ready.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+#include "rfb.h"
+
+int rfbDeferUpdateTime = 40; /* ms */
+
+
+/****************************************************************************/
+/*
+ * Macro definitions
+ */
+/****************************************************************************/
+
+#define TRC(x) /* (rfbLog x) */
+
+/* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each
+   client */
+
+#define ADD_TO_MODIFIED_REGION(pScreen,reg)				      \
+  {									      \
+      rfbClientPtr cl;							      \
+      for (cl = rfbClientHead; cl; cl = cl->next) {			      \
+	  REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\
+      }									      \
+  }
+
+/* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an
+   update to be sent to each client if there is one pending and the client is
+   ready for it.  */
+
+#define SCHEDULE_FB_UPDATE(pScreen,pVNC)				\
+  if (!pVNC->dontSendFramebufferUpdate) {				\
+      rfbClientPtr cl, nextCl;						\
+      for (cl = rfbClientHead; cl; cl = nextCl) {			\
+	  nextCl = cl->next;						\
+	  if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && 	\
+	      REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) 		\
+	  {								\
+	      rfbScheduleDeferredUpdate(pScreen, cl);			\
+	  }								\
+      }									\
+  }
+
+/* function prototypes */
+
+static void rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl);
+static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl,
+			  RegionPtr src, RegionPtr dst, int dx, int dy);
+#ifdef DEBUG
+static void PrintRegion(ScreenPtr pScreen, RegionPtr reg);
+#endif
+
+/* GC funcs */
+
+static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr);
+static void rfbChangeGC(GCPtr, unsigned long /*mask*/);
+static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/);
+static void rfbDestroyGC(GCPtr);
+static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/,
+			  int /*nrects*/);
+static void rfbDestroyClip(GCPtr);
+static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/);
+
+/* GC ops */
+
+static void rfbFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted);
+static void rfbSetSpans(DrawablePtr 		pDrawable, 
+	    		GCPtr			pGC, 
+	    		char			*psrc, 
+	    		register DDXPointPtr	ppt, 
+	    		int			*pwidth, 
+	    		int			nspans, 
+	    		int			fSorted);
+static void rfbPutImage();
+static RegionPtr rfbCopyArea();
+static RegionPtr rfbCopyPlane();
+static void rfbPolyPoint();
+static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts);
+static void rfbPolySegment();
+static void rfbPolyRectangle();
+static void rfbPolyArc();
+static void rfbFillPolygon();
+static void rfbPolyFillRect();
+static void rfbPolyFillArc();
+static int rfbPolyText8();
+static int rfbPolyText16();
+static void rfbImageText8();
+static void rfbImageText16();
+static void rfbImageGlyphBlt();
+static void rfbPolyGlyphBlt();
+static void rfbPushPixels();
+
+
+static GCFuncs rfbGCFuncs = {
+    rfbValidateGC,
+    rfbChangeGC,
+    rfbCopyGC,
+    rfbDestroyGC,
+    rfbChangeClip,
+    rfbDestroyClip,
+    rfbCopyClip,
+};
+
+
+static GCOps rfbGCOps = {
+    rfbFillSpans,	rfbSetSpans,	rfbPutImage,	
+    rfbCopyArea,	rfbCopyPlane,	rfbPolyPoint,
+    rfbPolylines,	rfbPolySegment,	rfbPolyRectangle,
+    rfbPolyArc,		rfbFillPolygon,	rfbPolyFillRect,
+    rfbPolyFillArc,	rfbPolyText8,	rfbPolyText16,
+    rfbImageText8,	rfbImageText16,	rfbImageGlyphBlt,
+    rfbPolyGlyphBlt,	rfbPushPixels
+};
+
+
+
+/****************************************************************************/
+/*
+ * Screen functions wrapper stuff
+ */
+/****************************************************************************/
+
+#define SCREEN_PROLOGUE(scrn, field)		\
+    ScreenPtr pScreen = scrn;			\
+    VNCSCREENPTR(pScreen); 		\
+    pScreen->field = pVNC->field;
+
+#define SCREEN_EPILOGUE(field, wrapper) \
+    pScreen->field = wrapper;
+
+
+/*
+ * CloseScreen wrapper -- unwrap everything, free the private data
+ * and call the wrapped CloseScreen function.
+ */
+
+Bool
+rfbCloseScreen (int i, ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+#if XFREE86VNC
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+#endif
+    int sock;
+
+    for (sock = 0; sock <= pVNC->maxFd; sock++) {
+	if (FD_ISSET(sock, &pVNC->allFds))
+	    if (sock != pVNC->rfbListenSock && sock != pVNC->httpListenSock) {
+	    	rfbCloseSock(pScreen, sock);
+	    }
+    }
+
+    if (pVNC->rfbListenSock > 0)
+    	if (close(pVNC->rfbListenSock))
+		ErrorF("Close of port %d failed\n",pVNC->rfbPort);
+
+    if (pVNC->httpListenSock > 0)
+    	if (close(pVNC->httpListenSock))
+		ErrorF("Close of port %d failed\n",pVNC->httpPort);
+
+    pScreen->CloseScreen = pVNC->CloseScreen;
+    pScreen->CreateGC = pVNC->CreateGC;
+    pScreen->PaintWindowBackground = pVNC->PaintWindowBackground;
+    pScreen->PaintWindowBorder = pVNC->PaintWindowBorder;
+    pScreen->CopyWindow = pVNC->CopyWindow;
+    pScreen->ClearToBackground = pVNC->ClearToBackground;
+    pScreen->RestoreAreas = pVNC->RestoreAreas;
+    pScreen->WakeupHandler = pVNC->WakeupHandler;
+
+#if XFREE86VNC
+    pScreen->InstallColormap = pVNC->InstallColormap;
+    pScreen->UninstallColormap = pVNC->UninstallColormap;
+    pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps;
+    pScreen->StoreColors = pVNC->StoreColors;
+    pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess;
+
+    xfree(pVNC);
+#endif
+
+    TRC((stderr,"Unwrapped screen functions\n"));
+
+    return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+#if XFREE86VNC
+void
+rfbEnableDisableFBAccess (int index, Bool enable)
+{
+    ScrnInfoPtr pScrn = xf86Screens[index];
+    VNCSCREENPTR(pScrn->pScreen);
+
+    /* 
+     * Blank the screen for security while inputs are disabled.
+     * When VT switching is fixed, we might be able to allow
+     * control even when switched away. 
+     */
+    if (!enable) {
+	WindowPtr pWin = WindowTable[index];
+    	ScreenPtr pScreen = pWin->drawable.pScreen;
+    	GCPtr pGC;
+    	xRectangle rect;
+
+    	rect.x = 0;
+    	rect.y = 0;
+    	rect.width = pScrn->virtualX;
+    	rect.height = pScrn->virtualY;
+
+    	if (!(pGC = GetScratchGC(pScreen->rootDepth, pScreen))) {
+    	    ErrorF("Couldn't blank screen");
+    	} else {
+	    CARD32 attributes[2];
+	    attributes[0] = pScreen->whitePixel;
+	    attributes[1] = pScreen->blackPixel;
+	    (void)ChangeGC(pGC, GCForeground | GCBackground, attributes);
+
+	    ValidateGC((DrawablePtr)pWin, pGC);
+
+  	    (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, 1, &rect);
+
+   	    FreeScratchGC(pGC);
+    	
+	    /* Flush pending packets */
+	    rfbCheckFds(pScreen);
+	    httpCheckFds(pScreen);
+    	}
+    }
+
+    pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess;
+    (*pScrn->EnableDisableFBAccess)(index, enable);
+    pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess;
+}
+#endif
+
+/*
+ * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC
+ * func "ValidateGC" is called).
+ */
+
+Bool
+rfbCreateGC (GCPtr pGC)
+{
+    Bool ret;
+    rfbGCPtr pGCPriv;
+
+    SCREEN_PROLOGUE(pGC->pScreen,CreateGC);
+
+    pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr;
+
+    ret = (*pScreen->CreateGC) (pGC);
+
+    TRC((stderr,"rfbCreateGC called\n"));
+
+    pGCPriv->wrapOps = NULL;
+    pGCPriv->wrapFuncs = pGC->funcs;
+    pGC->funcs = &rfbGCFuncs;
+
+    SCREEN_EPILOGUE(CreateGC,rfbCreateGC);
+
+    return ret;
+}
+
+/*
+ * PaintWindowBackground - the region being modified is just the given region.
+ */
+
+void
+rfbPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground);
+
+    TRC((stderr,"rfbPaintWindowBackground called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen,pRegion);
+
+    (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground);
+}
+
+/*
+ * PaintWindowBorder - the region being modified is just the given region.
+ */
+
+void
+rfbPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder);
+
+    TRC((stderr,"rfbPaintWindowBorder called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen,pRegion);
+
+    (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder);
+}
+
+#ifdef CHROMIUM
+Bool
+rfbRealizeWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,RealizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 1);
+	 }
+    }
+
+    ret = (*pScreen->RealizeWindow)(pWin);
+
+    SCREEN_EPILOGUE(RealizeWindow,rfbRealizeWindow);
+
+    return ret;
+}
+
+Bool
+rfbUnrealizeWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,UnrealizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 0);
+	 }
+    }
+
+    ret = (*pScreen->UnrealizeWindow)(pWin);
+
+    SCREEN_EPILOGUE(UnrealizeWindow,rfbUnrealizeWindow);
+
+    return ret;
+}
+
+Bool
+rfbDestroyWindow(WindowPtr pWin)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    Bool ret;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    rfbSendChromiumWindowShow(wt->CRwinId, 0);
+	 }
+    }
+
+    ret = (*pScreen->DestroyWindow)(pWin);
+
+    SCREEN_EPILOGUE(DestroyWindow,rfbDestroyWindow);
+
+    return ret;
+}
+
+void
+rfbResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib)
+{
+    CRWindowTable *wt = NULL, *nextWt = NULL;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ResizeWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	     rfbSendChromiumMoveResizeWindow(wt->CRwinId, pWin->drawable.x, pWin->drawable.y, w, h);
+	 }
+    }
+
+    (*pScreen->ResizeWindow)(pWin, x, y, w, h, pSib);
+
+    SCREEN_EPILOGUE(ResizeWindow,rfbResizeWindow);
+}
+
+Bool
+rfbPositionWindow(WindowPtr pWin, int x, int y)
+{
+    Bool ret;
+    CRWindowTable *wt, *nextWt;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,PositionWindow);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	     rfbSendChromiumMoveResizeWindow(wt->CRwinId, x, y, pWin->drawable.width, pWin->drawable.height);
+	 }
+    }
+
+    ret = (*pScreen->PositionWindow)(pWin, x, y);
+
+    SCREEN_EPILOGUE(PositionWindow,rfbPositionWindow);
+
+    return ret;
+}
+
+void
+rfbClipNotify(WindowPtr pWin, int x, int y)
+{
+    CRWindowTable *wt, *nextWt;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ClipNotify);
+
+    for (wt = windowTable; wt; wt = nextWt) {
+   	 nextWt = wt->next;
+	 if (wt->XwinId == pWin->drawable.id) {
+	    int numClipRects = REGION_NUM_RECTS(&pWin->clipList);
+	    BoxPtr pClipRects = REGION_RECTS(&pWin->clipList);
+
+	    /* Possible optimization - has the cliplist really? changed */
+
+	    rfbSendChromiumClipList(wt->CRwinId, pClipRects, numClipRects);
+	 }
+    }
+
+    if (*pScreen->ClipNotify) 
+    	(*pScreen->ClipNotify)(pWin, x, y);
+
+    SCREEN_EPILOGUE(ClipNotify,rfbClipNotify);
+}
+#endif /* CHROMIUM */
+
+/*
+ * CopyWindow - the region being modified is the translation of the old
+ * region, clipped to the border clip region of the window.  Note that any
+ * parts of the window which have become newly-visible will not be affected by
+ * this call - a separate PaintWindowBackground/Border will be called to do
+ * that.  If the client will accept CopyRect messages then use rfbCopyRegion to
+ * optimise the pending screen changes into a single "copy region" plus the
+ * ordinary modified region.
+ */
+
+void
+rfbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion)
+{
+    rfbClientPtr cl;
+    RegionRec srcRegion, dstRegion;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow);
+
+    TRC((stderr,"rfbCopyWindow called\n"));
+
+    REGION_NULL(pScreen,&dstRegion);
+    REGION_COPY(pScreen,&dstRegion,pOldRegion);
+    REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion,
+		     pWin->drawable.x - ptOldOrg.x,
+		     pWin->drawable.y - ptOldOrg.y);
+    REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion,
+		     &pWin->borderClip);
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (cl->useCopyRect) {
+	    REGION_NULL(pScreen,&srcRegion);
+	    REGION_COPY(pScreen,&srcRegion,pOldRegion);
+
+	    rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion,
+			  pWin->drawable.x - ptOldOrg.x,
+			  pWin->drawable.y - ptOldOrg.y);
+
+	    REGION_UNINIT(pScreen, &srcRegion);
+
+	} else {
+
+	    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			 &dstRegion);
+	}
+    }
+
+    REGION_UNINIT(pScreen, &dstRegion);
+
+    (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow);
+}
+
+/*
+ * ClearToBackground - when generateExposures is false, the region being
+ * modified is the given rectangle (clipped to the "window clip region").
+ */
+
+void
+rfbClearToBackground (WindowPtr pWin, int x, int y, int w, int h, 
+		      Bool generateExposures)
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground);
+
+    TRC((stderr,"rfbClearToBackground called\n"));
+
+    if (!generateExposures) {
+	box.x1 = x + pWin->drawable.x;
+	box.y1 = y + pWin->drawable.y;
+	box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
+	box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
+
+	SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList);
+
+	ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
+
+	REGION_UNINIT(pScreen, &tmpRegion);
+    }
+
+    (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+    if (!generateExposures) {
+	SCHEDULE_FB_UPDATE(pScreen, pVNC);
+    }
+
+    SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground);
+}
+
+/*
+ * RestoreAreas - just be safe here - the region being modified is the whole
+ * exposed region.
+ */
+
+RegionPtr
+rfbRestoreAreas (WindowPtr pWin, RegionPtr prgnExposed)
+{
+    RegionPtr result;
+    SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas);
+
+    TRC((stderr,"rfbRestoreAreas called\n"));
+
+    ADD_TO_MODIFIED_REGION(pScreen, prgnExposed);
+
+    result = (*pScreen->RestoreAreas) (pWin, prgnExposed);
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas);
+
+    return result;
+}
+
+
+
+/****************************************************************************/
+/*
+ * GC funcs wrapper stuff
+ *
+ * We only really want to wrap the GC ops, but to do this we need to wrap
+ * ValidateGC and so all the other GC funcs must be wrapped as well.
+ */
+/****************************************************************************/
+
+#define GC_FUNC_PROLOGUE(pGC)						\
+    rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr;	\
+    (pGC)->funcs = pGCPriv->wrapFuncs;					\
+    if (pGCPriv->wrapOps)						\
+	(pGC)->ops = pGCPriv->wrapOps;
+
+#define GC_FUNC_EPILOGUE(pGC)		\
+    pGCPriv->wrapFuncs = (pGC)->funcs;	\
+    (pGC)->funcs = &rfbGCFuncs;		\
+    if (pGCPriv->wrapOps) {		\
+	pGCPriv->wrapOps = (pGC)->ops;	\
+	(pGC)->ops = &rfbGCOps;		\
+    }
+
+
+/*
+ * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if
+ * the drawing will be to a viewable window.
+ */
+
+static void
+rfbValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+    VNCSCREENPTR(pGC->pScreen);
+    GC_FUNC_PROLOGUE(pGC);
+
+    TRC((stderr,"rfbValidateGC called\n"));
+
+    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+    
+    pGCPriv->wrapOps = NULL;
+    if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable)
+    {
+	WindowPtr   pWin = (WindowPtr) pDrawable;
+	RegionPtr   pRegion = &pWin->clipList;
+
+	if (pGC->subWindowMode == IncludeInferiors)
+	    pRegion = &pWin->borderClip;
+	if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
+	    pGCPriv->wrapOps = pGC->ops;
+	    TRC((stderr,"rfbValidateGC: wrapped GC ops\n"));
+	}
+    }
+
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+/*
+ * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped
+ * function and then rewrap the funcs and ops.
+ */
+
+static void
+rfbChangeGC (pGC, mask)
+    GCPtr	    pGC;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->ChangeGC) (pGC, mask);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbCopyGC (pGCSrc, mask, pGCDst)
+    GCPtr	    pGCSrc, pGCDst;
+    unsigned long   mask;
+{
+    GC_FUNC_PROLOGUE(pGCDst);
+    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+    GC_FUNC_EPILOGUE(pGCDst);
+}
+
+static void
+rfbDestroyGC (pGC)
+    GCPtr   pGC;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->DestroyGC) (pGC);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbChangeClip (pGC, type, pvalue, nrects)
+    GCPtr   pGC;
+    int		type;
+    pointer	pvalue;
+    int		nrects;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbDestroyClip(pGC)
+    GCPtr	pGC;
+{
+    GC_FUNC_PROLOGUE(pGC);
+    (* pGC->funcs->DestroyClip)(pGC);
+    GC_FUNC_EPILOGUE(pGC);
+}
+
+static void
+rfbCopyClip(pgcDst, pgcSrc)
+    GCPtr pgcDst, pgcSrc;
+{
+    GC_FUNC_PROLOGUE(pgcDst);
+    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
+    GC_FUNC_EPILOGUE(pgcDst);
+}
+
+
+/****************************************************************************/
+/*
+ * GC ops wrapper stuff
+ *
+ * Note that these routines will only have been wrapped for drawing to
+ * viewable windows so we don't need to check each time that the drawable
+ * is a viewable window.
+ */
+/****************************************************************************/
+
+#define GC_OP_PROLOGUE(pDrawable,pGC) \
+    ScreenPtr pScreen = pGC->pScreen;			\
+    VNCSCREENPTR(pScreen);			\
+    rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \
+    GCFuncs *oldFuncs = pGC->funcs; \
+    (void) pScreen; /* silence compiler */ \
+    (pGC)->funcs = pGCPrivate->wrapFuncs; \
+    (pGC)->ops = pGCPrivate->wrapOps;
+
+#define GC_OP_EPILOGUE(pGC) \
+    pGCPrivate->wrapOps = (pGC)->ops; \
+    (pGC)->funcs = oldFuncs; \
+    (pGC)->ops = &rfbGCOps;
+
+
+/*
+ * FillSpans - being very safe - the region being modified is the border clip
+ * region of the window.
+ */
+
+static void
+rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nInit;			/* number of spans to fill */
+    DDXPointPtr pptInit;		/* pointer to list of start points */
+    int		*pwidthInit;		/* pointer to list of n widths */
+    int 	fSorted;
+{
+    GC_OP_PROLOGUE(pDrawable,pGC);
+
+    TRC((stderr,"rfbFillSpans called\n"));
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
+			   &((WindowPtr)pDrawable)->borderClip);
+
+    (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * SetSpans - being very safe - the region being modified is the border clip
+ * region of the window.
+ */
+
+static void
+rfbSetSpans(DrawablePtr 		pDrawable, 
+	    GCPtr			pGC, 
+	    char			*psrc, 
+	    register DDXPointPtr	ppt, 
+	    int				*pwidth, 
+	    int				nspans, 
+	    int				fSorted)
+{
+    GC_OP_PROLOGUE(pDrawable,pGC);
+
+    TRC((stderr,"rfbSetSpans called\n"));
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen,
+			   &((WindowPtr)pDrawable)->borderClip);
+
+    (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PutImage - the region being modified is the rectangle of the
+ * PutImage (clipped to the window clip region).
+ */
+
+static void
+rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits)
+    DrawablePtr	  pDrawable;
+    GCPtr   	  pGC;
+    int		  depth;
+    int	    	  x;
+    int	    	  y;
+    int	    	  w;
+    int	    	  h;
+    int		  leftPad;
+    int	    	  format;
+    char    	  *pBits;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPutImage called\n"));
+
+    box.x1 = x + pDrawable->x;
+    box.y1 = y + pDrawable->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+
+    (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h,
+			   leftPad, format, pBits);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * CopyArea - the region being modified is the destination rectangle (clipped
+ * to the window clip region).
+ * If the client will accept CopyRect messages then use rfbCopyRegion
+ * to optimise the pending screen changes into a single "copy region" plus
+ * the ordinary modified region.
+ */
+
+static RegionPtr
+rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    GCPtr   	  pGC;
+    int	    	  srcx;
+    int	    	  srcy;
+    int	    	  w;
+    int	    	  h;
+    int	    	  dstx;
+    int	    	  dsty;
+{
+    rfbClientPtr cl;
+    RegionPtr rgn;
+    RegionRec srcRegion, dstRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDst, pGC);
+
+    TRC((stderr,"rfbCopyArea called\n"));
+
+    box.x1 = dstx + pDst->x;
+    box.y1 = dsty + pDst->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0);
+    REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion,
+		     					pGC->pCompositeClip);
+
+    if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) {
+	box.x1 = srcx + pSrc->x;
+	box.y1 = srcy + pSrc->y;
+	box.x2 = box.x1 + w;
+	box.y2 = box.y1 + h;
+
+	for (cl = rfbClientHead; cl; cl = cl->next) {
+	    if (cl->useCopyRect) {
+		SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0);
+		REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion,
+				 &((WindowPtr)pSrc)->clipList);
+
+		rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion,
+			      dstx + pDst->x - srcx - pSrc->x,
+			      dsty + pDst->y - srcy - pSrc->y);
+
+		REGION_UNINIT(pSrc->pScreen, &srcRegion);
+
+	    } else {
+
+		REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			     &dstRegion);
+	    }
+	}
+
+    } else {
+
+	ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion);
+    }
+
+    REGION_UNINIT(pDst->pScreen, &dstRegion);
+
+    rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				 dstx, dsty);
+
+    SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+
+    return rgn;
+}
+
+
+/*
+ * CopyPlane - the region being modified is the destination rectangle (clipped
+ * to the window clip region).
+ */
+
+static RegionPtr
+rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane)
+    DrawablePtr	  pSrc;
+    DrawablePtr	  pDst;
+    register GCPtr pGC;
+    int     	  srcx,
+		  srcy;
+    int     	  w,
+		  h;
+    int     	  dstx,
+		  dsty;
+    unsigned long  plane;
+{
+    RegionPtr rgn;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDst, pGC);
+
+    TRC((stderr,"rfbCopyPlane called\n"));
+
+    box.x1 = dstx + pDst->x;
+    box.y1 = dsty + pDst->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDst->pScreen, &tmpRegion);
+
+    rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx, dsty, plane);
+
+    SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+
+    return rgn;
+}
+
+/*
+ * PolyPoint - find the smallest rectangle which encloses the points drawn
+ * (and clip).
+ */
+
+static void
+rfbPolyPoint (pDrawable, pGC, mode, npt, pts)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		mode;		/* Origin or Previous */
+    int		npt;
+    xPoint 	*pts;
+{
+    int i;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyPoint called\n"));
+
+    if (npt) {
+	int minX = pts[0].x, maxX = pts[0].x;
+	int minY = pts[0].y, maxY = pts[0].y;
+
+	if (mode == CoordModePrevious)
+	{
+	    int x = pts[0].x, y = pts[0].y;
+
+	    for (i = 1; i < npt; i++) {
+		x += pts[i].x;
+		y += pts[i].y;
+		if (x < minX) minX = x;
+		if (x > maxX) maxX = x;
+		if (y < minY) minY = y;
+		if (y > maxY) maxY = y;
+	    }
+	}
+	else
+	{
+	    for (i = 1; i < npt; i++) {
+		if (pts[i].x < minX) minX = pts[i].x;
+		if (pts[i].x > maxX) maxX = pts[i].x;
+		if (pts[i].y < minY) minY = pts[i].y;
+		if (pts[i].y > maxY) maxY = pts[i].y;
+	    }
+	}
+
+	box.x1 = minX + pDrawable->x;
+	box.y1 = minY + pDrawable->y;
+	box.x2 = maxX + 1 + pDrawable->x;
+	box.y2 = maxY + 1 + pDrawable->y;
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+
+    if (npt) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyLines - take the union of bounding boxes around each line (and clip).
+ */
+
+static void
+rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts)
+{
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    int i, extra, nlines, lw;
+    int x1, x2, y1, y2;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolylines called\n"));
+
+    if (npt) {
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	if (npt == 1)
+	{
+	    nlines = 1;
+	    rects = (xRectangle *)xalloc(sizeof(xRectangle));
+	    if (!rects) {
+		FatalError("rfbPolylines: xalloc failed\n");
+	    }
+
+	    rects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe here */
+	    rects[0].y = ppts[0].y - lw + pDrawable->y;
+	    rects[0].width = 2*lw;
+	    rects[0].height = 2*lw;
+	}
+	else
+	{
+	    nlines = npt - 1;
+	    rects = (xRectangle *)xalloc(nlines*sizeof(xRectangle));
+	    if (!rects) {
+		FatalError("rfbPolylines: xalloc failed\n");
+	    }
+
+	    /*
+	     * mitered joins can project quite a way from
+	     * the line end; the 11 degree miter limit limits
+	     * this extension to lw / (2 * tan(11/2)), rounded up
+	     * and converted to int yields 6 * lw
+	     */
+
+	    if (pGC->joinStyle == JoinMiter) {
+		extra = 6 * lw;
+	    } else {
+		extra = lw / 2;
+	    }
+
+	    x1 = ppts[0].x + pDrawable->x;
+	    y1 = ppts[0].y + pDrawable->y;
+
+	    for (i = 0; i < nlines; i++) {
+		if (mode == CoordModeOrigin) {
+		    x2 = pDrawable->x + ppts[i+1].x;
+		    y2 = pDrawable->y + ppts[i+1].y;
+		} else {
+		    x2 = x1 + ppts[i+1].x;
+		    y2 = y1 + ppts[i+1].y;
+		}
+
+		if (x1 > x2) {
+		    rects[i].x = x2 - extra;
+		    rects[i].width = x1 - x2 + 1 + 2 * extra;
+		} else {
+		    rects[i].x = x1 - extra;
+		    rects[i].width = x2 - x1 + 1 + 2 * extra;
+		}
+
+		if (y1 > y2) {
+		    rects[i].y = y2 - extra;
+		    rects[i].height = y1 - y2 + 1 + 2 * extra;
+		} else {
+		    rects[i].y = y1 - extra;
+		    rects[i].height = y2 - y1 + 1 + 2 * extra;
+		}
+
+		x1 = x2;
+		y1 = y2;
+	    }
+	}
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nlines, rects,CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+
+    if (npt) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolySegment - take the union of bounding boxes around each segment (and
+ * clip).
+ */
+
+static void
+rfbPolySegment(pDrawable, pGC, nseg, segs)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int		nseg;
+    xSegment	*segs;
+{
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    int i, extra, lw;
+
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolySegment called\n"));
+
+    if (nseg) {
+	rects = (xRectangle *)xalloc(nseg*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolySegment: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < nseg; i++)
+	{
+	    if (segs[i].x1 > segs[i].x2) {
+		rects[i].x = segs[i].x2 - extra + pDrawable->x;
+		rects[i].width = segs[i].x1 - segs[i].x2 + 1 + 2 * extra;
+	    } else {
+		rects[i].x = segs[i].x1 - extra + pDrawable->x;
+		rects[i].width = segs[i].x2 - segs[i].x1 + 1 + 2 * extra;
+	    }
+
+	    if (segs[i].y1 > segs[i].y2) {
+		rects[i].y = segs[i].y2 - extra + pDrawable->y;
+		rects[i].height = segs[i].y1 - segs[i].y2 + 1 + 2 * extra;
+	    } else {
+		rects[i].y = segs[i].y1 - extra + pDrawable->y;
+		rects[i].height = segs[i].y2 - segs[i].y1 + 1 + 2 * extra;
+	    }
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nseg, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+
+    if (nseg) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyRectangle (rectangle outlines) - take the union of bounding boxes
+ * around each line (and clip).
+ */
+
+static void
+rfbPolyRectangle(pDrawable, pGC, nrects, rects)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*rects;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *regRects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyRectangle called\n"));
+
+    if (nrects) {
+	regRects = (xRectangle *)xalloc(nrects*4*sizeof(xRectangle));
+	if (!regRects) {
+	    FatalError("rfbPolyRectangle: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < nrects; i++)
+	{
+	    regRects[i*4].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4].width = rects[i].width + 1 + 2 * extra;
+	    regRects[i*4].height = 1 + 2 * extra;
+
+	    regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4+1].width = 1 + 2 * extra;
+	    regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
+
+	    regRects[i*4+2].x
+		= rects[i].x + rects[i].width - extra + pDrawable->x;
+	    regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
+	    regRects[i*4+2].width = 1 + 2 * extra;
+	    regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
+
+	    regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
+	    regRects[i*4+3].y
+		= rects[i].y + rects[i].height - extra + pDrawable->y;
+	    regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
+	    regRects[i*4+3].height = 1 + 2 * extra;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects*4,
+				    regRects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)regRects);
+    }
+
+    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+
+    if (nrects) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyArc - take the union of bounding boxes around each arc (and clip).
+ * Bounding boxes assume each is a full circle / ellipse.
+ */
+
+static void
+rfbPolyArc(pDrawable, pGC, narcs, arcs)
+    DrawablePtr	pDrawable;
+    register GCPtr	pGC;
+    int		narcs;
+    xArc	*arcs;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyArc called\n"));
+
+    if (narcs) {
+	rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolyArc: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < narcs; i++)
+	{
+	    rects[i].x = arcs[i].x - extra + pDrawable->x;
+	    rects[i].y = arcs[i].y - extra + pDrawable->y;
+	    rects[i].width = arcs[i].width + lw;
+	    rects[i].height = arcs[i].height + lw;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+
+    if (narcs) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * FillPolygon - take bounding box around polygon (and clip).
+ */
+
+static void
+rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts)
+    register DrawablePtr pDrawable;
+    register GCPtr	pGC;
+    int			shape, mode;
+    int			count;
+    DDXPointPtr		pts;
+{
+    int i;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbFillPolygon called\n"));
+
+    if (count) {
+	int minX = pts[0].x, maxX = pts[0].x;
+	int minY = pts[0].y, maxY = pts[0].y;
+
+	if (mode == CoordModePrevious)
+	{
+	    int x = pts[0].x, y = pts[0].y;
+
+	    for (i = 1; i < count; i++) {
+		x += pts[i].x;
+		y += pts[i].y;
+		if (x < minX) minX = x;
+		if (x > maxX) maxX = x;
+		if (y < minY) minY = y;
+		if (y > maxY) maxY = y;
+	    }
+	}
+	else
+	{
+	    for (i = 1; i < count; i++) {
+		if (pts[i].x < minX) minX = pts[i].x;
+		if (pts[i].x > maxX) maxX = pts[i].x;
+		if (pts[i].y < minY) minY = pts[i].y;
+		if (pts[i].y > maxY) maxY = pts[i].y;
+	    }
+	}
+
+	box.x1 = minX + pDrawable->x;
+	box.y1 = minY + pDrawable->y;
+	box.x2 = maxX + 1 + pDrawable->x;
+	box.y2 = maxY + 1 + pDrawable->y;
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyFillRect - take the union of the given rectangles (and clip).
+ */
+
+static void
+rfbPolyFillRect(pDrawable, pGC, nrects, rects)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		nrects;
+    xRectangle	*rects;
+{
+    RegionPtr tmpRegion;
+    xRectangle *regRects;
+    int i;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyFillRect called\n"));
+
+    if (nrects) {
+	regRects = (xRectangle *)xalloc(nrects*sizeof(xRectangle));
+	if (!regRects) {
+	    FatalError("rfbPolyFillRect: xalloc failed\n");
+	}
+
+	for (i = 0; i < nrects; i++) {
+	    regRects[i].x = rects[i].x + pDrawable->x;
+	    regRects[i].y = rects[i].y + pDrawable->y;
+	    regRects[i].width = rects[i].width;
+	    regRects[i].height = rects[i].height;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects, regRects,
+				    CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)regRects);
+    }
+
+    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+
+    if (nrects) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyFillArc - take the union of bounding boxes around each arc (and clip).
+ * Bounding boxes assume each is a full circle / ellipse.
+ */
+
+static void
+rfbPolyFillArc(pDrawable, pGC, narcs, arcs)
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+    int		narcs;
+    xArc	*arcs;
+{
+    int i, extra, lw;
+    RegionPtr tmpRegion;
+    xRectangle *rects;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyFillArc called\n"));
+
+    if (narcs) {
+	rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle));
+	if (!rects) {
+	    FatalError("rfbPolyFillArc: xalloc failed\n");
+	}
+
+	lw = pGC->lineWidth;
+	if (lw == 0)
+	    lw = 1;
+
+	extra = lw / 2;
+
+	for (i = 0; i < narcs; i++)
+	{
+	    rects[i].x = arcs[i].x - extra + pDrawable->x;
+	    rects[i].y = arcs[i].y - extra + pDrawable->y;
+	    rects[i].width = arcs[i].width + lw;
+	    rects[i].height = arcs[i].height + lw;
+	}
+
+	tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE);
+	REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion);
+
+	REGION_DESTROY(pDrawable->pScreen, tmpRegion);
+	xfree((char *)rects);
+    }
+
+    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+
+    if (narcs) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * Get a rough bounding box around n characters of the given font.
+ */
+
+static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox)
+    DrawablePtr pDrawable;
+    FontPtr font;
+    int x, y, n;
+    BoxPtr pbox;
+{
+    int maxAscent, maxDescent, maxCharWidth;
+
+    if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent))
+	maxAscent = FONTASCENT(font);
+    else
+	maxAscent = FONTMAXBOUNDS(font,ascent);
+
+    if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent))
+	maxDescent = FONTDESCENT(font);
+    else
+	maxDescent = FONTMAXBOUNDS(font,descent);
+
+    if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth))
+	maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing);
+    else
+	maxCharWidth = FONTMAXBOUNDS(font,characterWidth);
+
+    pbox->x1 = pDrawable->x + x;
+    pbox->y1 = pDrawable->y + y - maxAscent;
+    pbox->x2 = pbox->x1 + maxCharWidth * n;
+    pbox->y2 = pbox->y1 + maxAscent + maxDescent;
+
+    if (FONTMINBOUNDS(font,leftSideBearing) < 0) {
+	pbox->x1 += FONTMINBOUNDS(font,leftSideBearing);
+    }
+}
+
+
+/*
+ * PolyText8 - use rough bounding box.
+ */
+
+static int
+rfbPolyText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int 	count;
+    char	*chars;
+{
+    int	ret;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyText8 called '%.*s'\n",count,chars));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+    return ret;
+}
+
+/*
+ * PolyText16 - use rough bounding box.
+ */
+
+static int
+rfbPolyText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    int	ret;
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyText16 called\n"));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+    return ret;
+}
+
+/*
+ * ImageText8 - use rough bounding box.
+ */
+
+static void
+rfbImageText8(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    char	*chars;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageText8 called '%.*s'\n",count,chars));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * ImageText16 - use rough bounding box.
+ */
+
+static void
+rfbImageText16(pDrawable, pGC, x, y, count, chars)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int		x, y;
+    int		count;
+    unsigned short *chars;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageText16 called\n"));
+
+    if (count) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+    if (count) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * ImageGlyphBlt - use rough bounding box.
+ */
+
+static void
+rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr 	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer 	pglyphBase;	/* start of array of glyphs */
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbImageGlyphBlt called\n"));
+
+    if (nglyph) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+
+    if (nglyph) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PolyGlyphBlt - use rough bounding box.
+ */
+
+static void
+rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)
+    DrawablePtr pDrawable;
+    GCPtr	pGC;
+    int 	x, y;
+    unsigned int nglyph;
+    CharInfoPtr *ppci;		/* array of character info */
+    pointer	pglyphBase;	/* start of array of glyphs */
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPolyGlyphBlt called\n"));
+
+    if (nglyph) {
+	GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box);
+
+	SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+	REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+	ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+	REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+    }
+
+    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+    if (nglyph) {
+	SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+    }
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+/*
+ * PushPixels - be fairly safe - region modified is intersection of the given
+ * rectangle with the window clip region.
+ */
+
+static void
+rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y)
+    GCPtr	pGC;
+    PixmapPtr	pBitMap;
+    DrawablePtr pDrawable;
+    int		w, h, x, y;
+{
+    RegionRec tmpRegion;
+    BoxRec box;
+    GC_OP_PROLOGUE(pDrawable, pGC);
+
+    TRC((stderr,"rfbPushPixels called\n"));
+
+    box.x1 = x + pDrawable->x;
+    box.y1 = y + pDrawable->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0);
+
+    REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion,
+		     					pGC->pCompositeClip);
+
+    ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion);
+
+    REGION_UNINIT(pDrawable->pScreen, &tmpRegion);
+
+    (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+    SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC);
+
+    GC_OP_EPILOGUE(pGC);
+}
+
+#ifdef RENDER
+void
+rfbComposite(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pMask,
+    PicturePtr pDst,
+    INT16 xSrc,
+    INT16 ySrc,
+    INT16 xMask,
+    INT16 yMask,
+    INT16 xDst,
+    INT16 yDst,
+    CARD16 width,
+    CARD16 height
+){
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    VNCSCREENPTR(pScreen);
+    RegionRec tmpRegion;
+    BoxRec box;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+    box.x1 = pDst->pDrawable->x + xDst;
+    box.y1 = pDst->pDrawable->y + yDst;
+    box.x2 = box.x1 + width;
+    box.y2 = box.y1 + height;
+
+    REGION_INIT(pScreen, &tmpRegion, &box, 0);
+
+    ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion);
+
+    ps->Composite = pVNC->Composite;
+    (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
+		     xMask, yMask, xDst, yDst, width, height);
+    ps->Composite = rfbComposite;
+
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+
+    REGION_UNINIT(pScreen, &tmpRegion);
+}
+#endif /* RENDER */
+
+/****************************************************************************/
+/*
+ * Other functions
+ */
+/****************************************************************************/
+
+/*
+ * rfbCopyRegion.  Args are src and dst regions plus a translation (dx,dy).
+ * Takes these args together with the existing modified region and possibly an
+ * existing copy region and translation.  Produces a combined modified region
+ * plus copy region and translation.  Note that the copy region is the
+ * destination of the copy.
+ *
+ * First we trim parts of src which are invalid (ie in the modified region).
+ * Then we see if there is any overlap between the src and the existing copy
+ * region.  If not then the two copies cannot be combined, so we choose
+ * whichever is bigger to form the basis of a new copy, while the other copy is
+ * just done the hard way by being added to the modified region.  So if the
+ * existing copy is bigger then we simply add the destination of the new copy
+ * to the modified region and we're done.  If the new copy is bigger, we add
+ * the old copy region to the modified region and behave as though there is no
+ * existing copy region.
+ * 
+ * At this stage we now know that either the two copies can be combined, or
+ * that there is no existing copy.  We temporarily add both the existing copy
+ * region and dst to the modified region (this is the entire area of the screen
+ * affected in any way).  Finally we calculate the new copy region, and remove
+ * it from the modified region.
+ *
+ * Note:
+ *   1. The src region is modified by this routine.
+ *   2. When the copy region is empty, copyDX and copyDY MUST be set to zero.
+ */
+
+static void
+rfbCopyRegion(pScreen, cl, src, dst, dx, dy)
+    ScreenPtr pScreen;
+    rfbClientPtr cl;
+    RegionPtr src;
+    RegionPtr dst;
+    int dx, dy;
+{
+    RegionRec tmp;
+
+    /* src = src - modifiedRegion */
+
+    REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion);
+
+    if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+
+	REGION_NULL(pScreen, &tmp);
+	REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion);
+
+	if (REGION_NOTEMPTY(pScreen, &tmp)) {
+
+	    /* if src and copyRegion overlap:
+	         src = src intersect copyRegion */
+
+	    REGION_COPY(pScreen, src, &tmp);
+
+	} else {
+
+	    /* if no overlap, find bigger region */
+
+	    int newArea = (((REGION_EXTENTS(pScreen,src))->x2
+			    - (REGION_EXTENTS(pScreen,src))->x1)
+			   * ((REGION_EXTENTS(pScreen,src))->y2
+			      - (REGION_EXTENTS(pScreen,src))->y1));
+
+	    int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2
+			    - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1)
+			   * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2
+			     - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1));
+
+	    if (oldArea > newArea) {
+
+		/* existing copy is bigger:
+		     modifiedRegion = modifiedRegion union dst
+		     copyRegion = copyRegion - dst
+		     return */
+
+		REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			     dst);
+		REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
+				dst);
+		if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+		    cl->copyDX = 0;
+		    cl->copyDY = 0;
+		}
+		return;
+	    }
+
+	    /* new copy is bigger:
+	         modifiedRegion = modifiedRegion union copyRegion
+		 copyRegion = empty */
+
+	    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+			 &cl->copyRegion);
+	    REGION_EMPTY(pScreen, &cl->copyRegion);
+	    cl->copyDX = cl->copyDY = 0;
+	}
+    }
+
+
+    /* modifiedRegion = modifiedRegion union dst union copyRegion */
+
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst);
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		 &cl->copyRegion);
+
+    /* copyRegion = T(src) intersect dst */
+
+    REGION_TRANSLATE(pScreen, src, dx, dy);
+    REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst);
+
+    /* modifiedRegion = modifiedRegion - copyRegion */
+
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &cl->copyRegion);
+
+    /* combine new translation T with existing translation */
+
+    if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) {
+	cl->copyDX += dx;
+	cl->copyDY += dy;
+    } else {
+	cl->copyDX = 0;
+	cl->copyDY = 0;
+    }
+}
+
+
+/*
+ * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer
+ * goes off.
+ */
+
+static CARD32
+rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+  rfbClientPtr cl = (rfbClientPtr)arg;
+
+  rfbSendFramebufferUpdate(cl->pScreen, cl);
+
+  cl->deferredUpdateScheduled = FALSE;
+  return 0;
+}
+
+
+/*
+ * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro
+ * to schedule an update.
+ */
+
+static void
+rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl)
+{
+    if (rfbDeferUpdateTime != 0) {
+	cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0,
+					   rfbDeferUpdateTime,
+					   rfbDeferredUpdateCallback, cl);
+	cl->deferredUpdateScheduled = TRUE;
+    } else {
+	rfbSendFramebufferUpdate(pScreen, cl);
+    }
+}
+
+
+/*
+ * PrintRegion is useful for debugging.
+ */
+
+#ifdef DEBUG
+static void
+PrintRegion(ScreenPtr pScreen, RegionPtr reg)
+{
+    int nrects = REGION_NUM_RECTS(reg);
+    int i;
+
+    ErrorF("Region num rects %d extents %d,%d %d,%d\n",nrects,
+	   (REGION_EXTENTS(pScreen,reg))->x1,
+	   (REGION_EXTENTS(pScreen,reg))->y1,
+	   (REGION_EXTENTS(pScreen,reg))->x2,
+	   (REGION_EXTENTS(pScreen,reg))->y2);
+
+    for (i = 0; i < nrects; i++) {
+	ErrorF("    rect %d,%d %dx%d\n",
+	       REGION_RECTS(reg)[i].x1,
+	       REGION_RECTS(reg)[i].y1,
+	       REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1,
+	       REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1);
+    }
+}
+#endif
+
+
+/**
+ * Allow scheduling updates from other functions in other files.
+ */
+void
+rfbScheduleUpdate(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    SCHEDULE_FB_UPDATE(pScreen, pVNC);
+}
diff -u -rNp a/hw/xfree86/vnc/hextile.c b/hw/xfree86/vnc/hextile.c
--- a/hw/xfree86/vnc/hextile.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/hextile.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,352 @@
+/*
+ * hextile.c
+ *
+ * Routines to implement Hextile Encoding
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rfb.h"
+
+static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
+static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
+static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
+
+
+/*
+ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
+ */
+
+Bool
+rfbSendRectEncodingHextile(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingHextile);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingHextile]++;
+    cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader;
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	return sendHextiles8(cl, x, y, w, h);
+    case 16:
+	return sendHextiles16(cl, x, y, w, h);
+    case 32:
+	return sendHextiles32(cl, x, y, w, h);
+    }
+
+    rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
+    return FALSE;
+}
+
+
+#define PUT_PIXEL8(pix) (pVNC->updateBuf[pVNC->ublen++] = (pix))
+
+#define PUT_PIXEL16(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1])
+
+#define PUT_PIXEL32(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[2], \
+			  pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[3])
+
+
+#define DEFINE_SEND_HEXTILES(bpp)					      \
+									      \
+									      \
+static Bool subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w,     \
+			       int h, CARD##bpp bg,   			      \
+			       CARD##bpp fg, Bool mono);		      \
+static void testColours##bpp(CARD##bpp *data, int size, Bool *mono,	      \
+			     Bool *solid, CARD##bpp *bg, CARD##bpp *fg);      \
+									      \
+									      \
+/*									      \
+ * rfbSendHextiles							      \
+ */									      \
+									      \
+static Bool								      \
+sendHextiles##bpp(cl, rx, ry, rw, rh)					      \
+    rfbClientPtr cl;							      \
+    int rx, ry, rw, rh;							      \
+{									      \
+    VNCSCREENPTR(cl->pScreen);						      \
+    int x, y, w, h;							      \
+    int startUblen;							      \
+    unsigned char *fbptr;						      \
+    CARD##bpp bg = 0, fg = 0, newBg, newFg;				      \
+    Bool mono, solid;							      \
+    Bool validBg = FALSE;						      \
+    Bool validFg = FALSE;						      \
+    CARD##bpp clientPixelData[16*16*(bpp/8)];				      \
+									      \
+    for (y = ry; y < ry+rh; y += 16) {					      \
+	for (x = rx; x < rx+rw; x += 16) {				      \
+	    w = h = 16;							      \
+	    if (rx+rw - x < 16)						      \
+		w = rx+rw - x;						      \
+	    if (ry+rh - y < 16)						      \
+		h = ry+rh - y;						      \
+									      \
+	    if ((pVNC->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \
+		if (!rfbSendUpdateBuf(cl))				      \
+		    return FALSE;					      \
+	    }								      \
+									      \
+	    fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)	      \
+		     + (x * (pVNC->bitsPerPixel / 8)));		      	      \
+									      \
+	    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,	      \
+			       &pVNC->rfbServerFormat,			      \
+			       &cl->format, fbptr, (char *)clientPixelData,   \
+			       pVNC->paddedWidthInBytes, w, h, x, y); 	      \
+									      \
+	    startUblen = pVNC->ublen;					      \
+	    pVNC->updateBuf[startUblen] = 0;				      \
+	    pVNC->ublen++;						      \
+									      \
+	    testColours##bpp(clientPixelData, w * h,			      \
+			     &mono, &solid, &newBg, &newFg);		      \
+									      \
+	    if (!validBg || (newBg != bg)) {				      \
+		validBg = TRUE;						      \
+		bg = newBg;						      \
+		pVNC->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
+		PUT_PIXEL##bpp(bg);					      \
+	    }								      \
+									      \
+	    if (solid) {						      \
+		cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen;  \
+		continue;						      \
+	    }								      \
+									      \
+	    pVNC->updateBuf[startUblen] |= rfbHextileAnySubrects;	      \
+									      \
+	    if (mono) {							      \
+		if (!validFg || (newFg != fg)) {			      \
+		    validFg = TRUE;					      \
+		    fg = newFg;						      \
+		    pVNC->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
+		    PUT_PIXEL##bpp(fg);					      \
+		}							      \
+	    } else {							      \
+		validFg = FALSE;					      \
+		pVNC->updateBuf[startUblen] |= rfbHextileSubrectsColoured;    \
+	    }								      \
+									      \
+	    if (!subrectEncode##bpp(cl->pScreen, clientPixelData, w, h, bg, fg, mono)) {   \
+		/* encoding was too large, use raw */			      \
+		validBg = FALSE;					      \
+		validFg = FALSE;					      \
+		pVNC->ublen = startUblen;				      \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextileRaw;		      \
+		(*cl->translateFn)(cl->pScreen, cl->translateLookupTable,     \
+				   &pVNC->rfbServerFormat, &cl->format, fbptr,\
+				   (char *)clientPixelData,		      \
+				   pVNC->paddedWidthInBytes, w, h, x, y);     \
+									      \
+		memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)clientPixelData,\
+		       w * h * (bpp/8));				      \
+									      \
+		pVNC->ublen += w * h * (bpp/8);				      \
+	    }								      \
+									      \
+	    cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \
+	}								      \
+    }									      \
+									      \
+    return TRUE;							      \
+}									      \
+									      \
+									      \
+static Bool								      \
+subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, int h,          \
+		   CARD##bpp bg, CARD##bpp fg, Bool mono)		      \
+{									      \
+    VNCSCREENPTR(pScreen);						      \
+    CARD##bpp clientdata;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    int nSubrectsUblen;							      \
+									      \
+    nSubrectsUblen = pVNC->ublen;					      \
+    pVNC->ublen++;							      \
+									      \
+    for (y=0; y<h; y++) {						      \
+	line = data+(y*w);						      \
+	for (x=0; x<w; x++) {						      \
+	    if (line[x] != bg) {					      \
+		clientdata = line[x];					      \
+		hy = y-1;						      \
+		hyflag = 1;						      \
+		for (j=y; j<h; j++) {					      \
+		    seg = data+(j*w);					      \
+		    if (seg[x] != clientdata) {break;}			      \
+		    i = x;						      \
+		    while ((seg[i] == clientdata) && (i < w)) i += 1;	      \
+		    i -= 1;						      \
+		    if (j == y) vx = hx = i;				      \
+		    if (i < vx) vx = i;					      \
+		    if ((hyflag > 0) && (i >= hx)) {			      \
+			hy += 1;					      \
+		    } else {						      \
+			hyflag = 0;					      \
+		    }							      \
+		}							      \
+		vy = j-1;						      \
+									      \
+		/* We now have two possible subrects: (x,y,hx,hy) and	      \
+		 * (x,y,vx,vy).  We'll choose the bigger of the two.	      \
+		 */							      \
+		hw = hx-x+1;						      \
+		hh = hy-y+1;						      \
+		vw = vx-x+1;						      \
+		vh = vy-y+1;						      \
+									      \
+		thex = x;						      \
+		they = y;						      \
+									      \
+		if ((hw*hh) > (vw*vh)) {				      \
+		    thew = hw;						      \
+		    theh = hh;						      \
+		} else {						      \
+		    thew = vw;						      \
+		    theh = vh;						      \
+		}							      \
+									      \
+		if (mono) {						      \
+		    newLen = pVNC->ublen - nSubrectsUblen + 2;		      \
+		} else {						      \
+		    newLen = pVNC->ublen - nSubrectsUblen + bpp/8 + 2;	      \
+		}							      \
+									      \
+		if (newLen > (w * h * (bpp/8)))				      \
+		    return FALSE;					      \
+									      \
+		numsubs += 1;						      \
+									      \
+		if (!mono) PUT_PIXEL##bpp(clientdata);			      \
+									      \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextilePackXY(thex,they); \
+		pVNC->updateBuf[pVNC->ublen++] = rfbHextilePackWH(thew,theh); \
+									      \
+		/*							      \
+		 * Now mark the subrect as done.			      \
+		 */							      \
+		for (j=they; j < (they+theh); j++) {			      \
+		    for (i=thex; i < (thex+thew); i++) {		      \
+			data[j*w+i] = bg;				      \
+		    }							      \
+		}							      \
+	    }								      \
+	}								      \
+    }									      \
+									      \
+    pVNC->updateBuf[nSubrectsUblen] = numsubs;				      \
+									      \
+    return TRUE;							      \
+}									      \
+									      \
+									      \
+/*									      \
+ * testColours() tests if there are one (solid), two (mono) or more	      \
+ * colours in a tile and gets a reasonable guess at the best background	      \
+ * pixel, and the foreground pixel for mono.				      \
+ */									      \
+									      \
+static void								      \
+testColours##bpp(data,size,mono,solid,bg,fg)				      \
+    CARD##bpp *data;							      \
+    int size;								      \
+    Bool *mono;								      \
+    Bool *solid;							      \
+    CARD##bpp *bg;							      \
+    CARD##bpp *fg;							      \
+{									      \
+    CARD##bpp colour1 = 0, colour2 = 0;					      \
+    int n1 = 0, n2 = 0;							      \
+    *mono = TRUE;							      \
+    *solid = TRUE;							      \
+									      \
+    for (; size > 0; size--, data++) {					      \
+									      \
+	if (n1 == 0)							      \
+	    colour1 = *data;						      \
+									      \
+	if (*data == colour1) {						      \
+	    n1++;							      \
+	    continue;							      \
+	}								      \
+									      \
+	if (n2 == 0) {							      \
+	    *solid = FALSE;						      \
+	    colour2 = *data;						      \
+	}								      \
+									      \
+	if (*data == colour2) {						      \
+	    n2++;							      \
+	    continue;							      \
+	}								      \
+									      \
+	*mono = FALSE;							      \
+	break;								      \
+    }									      \
+									      \
+    if (n1 > n2) {							      \
+	*bg = colour1;							      \
+	*fg = colour2;							      \
+    } else {								      \
+	*bg = colour2;							      \
+	*fg = colour1;							      \
+    }									      \
+}
+
+DEFINE_SEND_HEXTILES(8)
+DEFINE_SEND_HEXTILES(16)
+DEFINE_SEND_HEXTILES(32)
diff -u -rNp a/hw/xfree86/vnc/httpd.c b/hw/xfree86/vnc/httpd.c
--- a/hw/xfree86/vnc/httpd.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/httpd.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,520 @@
+/*
+ * httpd.c - a simple HTTP server
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <netdb.h>
+
+#ifndef USE_LIBWRAP
+#define USE_LIBWRAP 0
+#endif
+#if USE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include "rfb.h"
+
+#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \
+    "<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \
+    "<BODY><H1>File Not Found</H1></BODY>\n"
+
+#define OK_STR "HTTP/1.0 200 OK\r\n\r\n"
+
+static void httpProcessInput(ScreenPtr pScreen);
+static Bool compareAndSkip(char **ptr, const char *str);
+static Bool parseParams(const char *request, char *result, int max_bytes);
+static Bool validateString(char *str);
+
+/*
+ * httpInitSockets sets up the TCP socket to listen for HTTP connections.
+ */
+
+Bool
+httpInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (!pVNC->httpDir)
+	return FALSE;
+
+    pVNC->buf_filled = 0;
+
+    if (pVNC->httpPort == 0) {
+	pVNC->httpPort = 5800 + atoi(display) + pScreen->myNum;
+    }
+
+    if ((pVNC->httpListenSock = ListenOnTCPPort(pScreen, pVNC->httpPort)) < 0) {
+	rfbLog("ListenOnTCPPort %d failed\n",pVNC->httpPort);
+	pVNC->httpPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for HTTP connections on TCP port %d\n", pVNC->httpPort);
+    rfbLog("  URL http://%s:%d\n",rfbThisHost,pVNC->httpPort);
+
+    AddEnabledDevice(pVNC->httpListenSock);
+
+    return TRUE;
+}
+
+
+/*
+ * httpCheckFds is called from ProcessInputEvents to check for input on the
+ * HTTP socket(s).  If there is input to process, httpProcessInput is called.
+ */
+
+void
+httpCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+
+    if (!pVNC->httpDir)
+	return;
+
+    FD_ZERO(&fds);
+    FD_SET(pVNC->httpListenSock, &fds);
+    if (pVNC->httpSock >= 0) {
+	FD_SET(pVNC->httpSock, &fds);
+    }
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(max(pVNC->httpSock,pVNC->httpListenSock) + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR) 
+		rfbLogPerror("httpCheckFds: select");
+	return;
+    }
+
+    if ((pVNC->httpSock >= 0) && FD_ISSET(pVNC->httpSock, &fds)) {
+	httpProcessInput(pScreen);
+    }
+
+    if (FD_ISSET(pVNC->httpListenSock, &fds)) {
+	int flags;
+
+	if (pVNC->httpSock >= 0) close(pVNC->httpSock);
+
+	if ((pVNC->httpSock = accept(pVNC->httpListenSock,
+			       (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("httpCheckFds: accept");
+	    return;
+	}
+
+#if USE_LIBWRAP
+	if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr),
+		       STRING_UNKNOWN)) {
+	    rfbLog("Rejected HTTP connection from client %s\n",
+		   inet_ntoa(addr.sin_addr));
+  	    close(pVNC->httpSock);
+  	    pVNC->httpSock = -1;
+  	    return;
+  	}
+#endif
+
+	flags = fcntl (pVNC->httpSock, F_GETFL);
+
+	if (flags == -1 ||
+	fcntl (pVNC->httpSock, F_SETFL, flags | O_NONBLOCK) == -1) {
+	    rfbLogPerror("httpCheckFds: fcntl");
+	    close (pVNC->httpSock);
+	    pVNC->httpSock = -1;
+	    return;
+	}
+
+	AddEnabledDevice(pVNC->httpSock);
+    }
+}
+
+
+static void
+httpCloseSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    close(pVNC->httpSock);
+    RemoveEnabledDevice(pVNC->httpSock);
+    pVNC->httpSock = -1;
+    pVNC->buf_filled = 0;
+}
+
+
+/*
+ * httpProcessInput is called when input is received on the HTTP socket.
+ */
+
+static void
+httpProcessInput(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+    char fullFname[512];
+    char params[1024];
+    char *ptr;
+    char *fname;
+    int maxFnameLen;
+    int fd;
+    Bool performSubstitutions = FALSE;
+    char str[256];
+    struct passwd *user = getpwuid(getuid());
+  
+    if (strlen(pVNC->httpDir) > 255) {
+	rfbLog("-httpd directory too long\n");
+  	httpCloseSock(pScreen);
+	return;
+    }
+    strcpy(fullFname, pVNC->httpDir);
+    fname = &fullFname[strlen(fullFname)];
+    maxFnameLen = 511 - strlen(fullFname);
+  
+    /* Read data from the HTTP client until we get a complete request. */
+    while (1) {
+	ssize_t got = read (pVNC->httpSock, pVNC->buf + pVNC->buf_filled,
+			    sizeof (pVNC->buf) - pVNC->buf_filled - 1);
+
+	if (got <= 0) {
+	    if (got == 0) {
+		rfbLog("httpd: premature connection close\n");
+	    } else {
+		if (errno == EAGAIN) {
+		    return;
+		}
+		rfbLogPerror("httpProcessInput: read");
+	    }
+	    httpCloseSock(pScreen);
+  	    return;
+	}
+  
+	pVNC->buf_filled += got;
+	pVNC->buf[pVNC->buf_filled] = '\0';
+  
+	/* Is it complete yet (is there a blank line)? */
+	if (strstr (pVNC->buf, "\r\r") || strstr (pVNC->buf, "\n\n") ||
+	    strstr (pVNC->buf, "\r\n\r\n") || strstr (pVNC->buf, "\n\r\n\r"))
+	    break;
+    }
+  
+    /* Process the request. */
+    if (strncmp(pVNC->buf, "GET ", 4)) {
+	rfbLog("httpd: no GET line\n");
+	httpCloseSock(pScreen);
+	return;
+    } else {
+	/* Only use the first line. */
+	pVNC->buf[strcspn(pVNC->buf, "\n\r")] = '\0';
+    }
+  
+    if (strlen(pVNC->buf) > maxFnameLen) {
+	rfbLog("httpd: GET line too long\n");
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (sscanf(pVNC->buf, "GET %s HTTP/1.0", fname) != 1) {
+	rfbLog("httpd: couldn't parse GET line\n");
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (fname[0] != '/') {
+	rfbLog("httpd: filename didn't begin with '/'\n");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    if (strchr(fname+1, '/') != NULL) {
+	rfbLog("httpd: asking for file in other directory\n");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+  
+    getpeername(pVNC->httpSock, (struct sockaddr *)&addr, &addrlen);
+    rfbLog("httpd: get '%s' for %s\n", fname+1,
+	   inet_ntoa(addr.sin_addr));
+
+    /* Extract parameters from the URL string if necessary */
+
+    params[0] = '\0';
+    ptr = strchr(fname, '?');
+    if (ptr != NULL) {
+	*ptr = '\0';
+	if (!parseParams(&ptr[1], params, 1024)) {
+	    params[0] = '\0';
+	    rfbLog("httpd: bad parameters in the URL\n");
+	}
+    }
+
+    /* If we were asked for '/', actually read the file index.vnc */
+
+    if (strcmp(fname, "/") == 0) {
+	strcpy(fname, "/index.vnc");
+	rfbLog("httpd: defaulting to '%s'\n", fname+1);
+    }
+
+    /* Substitutions are performed on files ending .vnc */
+
+    if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
+	performSubstitutions = TRUE;
+    }
+
+    /* Open the file */
+
+    if ((fd = open(fullFname, O_RDONLY)) < 0) {
+	rfbLogPerror("httpProcessInput: open");
+	WriteExact(pVNC->httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR));
+	httpCloseSock(pScreen);
+	return;
+    }
+
+    WriteExact(pVNC->httpSock, OK_STR, strlen(OK_STR));
+
+    while (1) {
+	int n = read(fd, pVNC->buf, HTTP_BUF_SIZE-1);
+	if (n < 0) {
+	    rfbLogPerror("httpProcessInput: read");
+	    close(fd);
+	    httpCloseSock(pScreen);
+	    return;
+	}
+
+	if (n == 0)
+	    break;
+
+	if (performSubstitutions) {
+
+	    /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
+	       This won't quite work properly if the .vnc file is longer than
+	       HTTP_BUF_SIZE, but it's reasonable to assume that .vnc files will
+	       always be short. */
+
+	    char *ptr = pVNC->buf;
+	    char *dollar;
+	    pVNC->buf[n] = 0; /* make sure it's null-terminated */
+
+	    while ((dollar = strchr(ptr, '$'))) {
+		WriteExact(pVNC->httpSock, ptr, (dollar - ptr));
+
+		ptr = dollar;
+
+		if (compareAndSkip(&ptr, "$WIDTH")) {
+
+		    sprintf(str, "%d", pVNC->width);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$HEIGHT")) {
+
+		    sprintf(str, "%d", pVNC->height);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {
+
+		    sprintf(str, "%d", pVNC->width);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {
+
+		    sprintf(str, "%d", pVNC->height + 32);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$PORT")) {
+
+		    sprintf(str, "%d", pVNC->rfbPort);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$DESKTOP")) {
+
+		    WriteExact(pVNC->httpSock, desktopName, strlen(desktopName));
+
+		} else if (compareAndSkip(&ptr, "$DISPLAY")) {
+
+		    sprintf(str, "%s:%s", rfbThisHost, display);
+		    WriteExact(pVNC->httpSock, str, strlen(str));
+
+		} else if (compareAndSkip(&ptr, "$USER")) {
+
+		    if (user) {
+			WriteExact(pVNC->httpSock, user->pw_name,
+				   strlen(user->pw_name));
+		    } else {
+			WriteExact(pVNC->httpSock, "?", 1);
+		    }
+
+		} else if (compareAndSkip(&ptr, "$PARAMS")) {
+
+		    if (params[0] != '\0')
+			WriteExact(pVNC->httpSock, params, strlen(params));
+
+		} else {
+		    if (!compareAndSkip(&ptr, "$$"))
+			ptr++;
+
+		    if (WriteExact(pVNC->httpSock, "$", 1) < 0) {
+			close(fd);
+			httpCloseSock(pScreen);
+			return;
+		    }
+		}
+	    }
+	    if (WriteExact(pVNC->httpSock, ptr, (&pVNC->buf[n] - ptr)) < 0)
+		break;
+
+	} else {
+
+	    /* For files not ending .vnc, just write out the buffer */
+
+	    if (WriteExact(pVNC->httpSock, pVNC->buf, n) < 0)
+		break;
+	}
+    }
+
+    close(fd);
+    httpCloseSock(pScreen);
+}
+
+
+static Bool
+compareAndSkip(char **ptr, const char *str)
+{
+    if (strncmp(*ptr, str, strlen(str)) == 0) {
+	*ptr += strlen(str);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * Parse the request tail after the '?' character, and format a sequence
+ * of <param> tags for inclusion into an HTML page with embedded applet.
+ */
+
+static Bool
+parseParams(const char *request, char *result, int max_bytes)
+{
+    char param_request[128];
+    char param_formatted[196];
+    const char *tail;
+    char *delim_ptr;
+    char *value_str;
+    int cur_bytes, len;
+
+    result[0] = '\0';
+    cur_bytes = 0;
+
+    tail = request;
+    for (;;) {
+	/* Copy individual "name=value" string into a buffer */
+	delim_ptr = strchr((char *)tail, '&');
+	if (delim_ptr == NULL) {
+	    if (strlen(tail) >= sizeof(param_request)) {
+		return FALSE;
+	    }
+	    strcpy(param_request, tail);
+	} else {
+	    len = delim_ptr - tail;
+	    if (len >= sizeof(param_request)) {
+		return FALSE;
+	    }
+	    memcpy(param_request, tail, len);
+	    param_request[len] = '\0';
+	}
+
+	/* Split the request into parameter name and value */
+	value_str = strchr(&param_request[1], '=');
+	if (value_str == NULL) {
+	    return FALSE;
+	}
+	*value_str++ = '\0';
+	if (strlen(value_str) == 0) {
+	    return FALSE;
+	}
+
+	/* Validate both parameter name and value */
+	if (!validateString(param_request) || !validateString(value_str)) {
+	    return FALSE;
+	}
+
+	/* Prepare HTML-formatted representation of the name=value pair */
+	len = sprintf(param_formatted,
+		      "<PARAM NAME=\"%s\" VALUE=\"%s\">\n",
+		      param_request, value_str);
+	if (cur_bytes + len + 1 > max_bytes) {
+	    return FALSE;
+	}
+	strcat(result, param_formatted);
+	cur_bytes += len;
+
+	/* Go to the next parameter */
+	if (delim_ptr == NULL) {
+	    break;
+	}
+	tail = delim_ptr + 1;
+    }
+    return TRUE;
+}
+
+/*
+ * Check if the string consists only of alphanumeric characters, '+'
+ * signs, underscores, and dots. Replace all '+' signs with spaces.
+ */
+
+static Bool
+validateString(char *str)
+{
+    char *ptr;
+
+    for (ptr = str; *ptr != '\0'; ptr++) {
+	if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.') {
+	    if (*ptr == '+') {
+		*ptr = ' ';
+	    } else {
+		return FALSE;
+	    }
+	}
+    }
+    return TRUE;
+}
+
diff -u -rNp a/hw/xfree86/vnc/kbdptr.c b/hw/xfree86/vnc/kbdptr.c
--- a/hw/xfree86/vnc/kbdptr.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/kbdptr.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,426 @@
+/*
+ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include "rfb.h"
+#include "X11/X.h"
+#define NEED_EVENTS
+#include "X11/Xproto.h"
+#include "inputstr.h"
+#define XK_CYRILLIC
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include "mi.h"
+#include "mipointer.h"
+
+#if XFREE86VNC
+#ifdef XINPUT
+#  include "xf86Xinput.h"
+#  define Enqueue(ev) xf86eqEnqueue(ev)
+#else
+#  define Enqueue(ev) mieqEnqueue(ev)
+#endif
+#else
+#define Enqueue(ev) mieqEnqueue(ev)
+#endif
+
+#define KEY_IS_PRESSED(keycode) \
+    (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
+
+static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper);
+
+DeviceIntPtr kbdDevice = NULL;
+
+#include "keyboard.h"
+
+/*
+ * Called when the rfbserver receives a rfbKeyEvent event from a client.
+ * Put an X keyboard event into the event queue.
+ */
+void
+KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl)
+{
+    xEvent ev, fake;
+    KeySymsPtr keySyms;
+    int i;
+    int keyCode = 0;
+    int freeIndex = -1;
+    unsigned long time;
+    Bool fakeShiftPress = FALSE;
+    Bool fakeShiftLRelease = FALSE;
+    Bool fakeShiftRRelease = FALSE;
+    Bool shiftMustBeReleased = FALSE;
+    Bool shiftMustBePressed = FALSE;
+
+    if (!kbdDevice) return;
+
+    keySyms = &kbdDevice->key->curKeySyms;
+
+#ifdef CORBA
+    if (cl) {
+	CARD32 clientId = cl->sock;
+	ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+			     32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+#endif
+
+    if (down) {
+	ev.u.u.type = KeyPress;
+    } else {
+	ev.u.u.type = KeyRelease;
+    }
+
+    /* NOTE: This is where it gets hairy for XFree86 servers.
+     * I think the best way to deal with this is invent a new protocol
+     * to send over the wire the remote keyboard type and correctly
+     * handle that as XINPUT extension device (we're part of the way
+     * there for that.
+     *
+     * Alan.
+     */
+#if !XFREE86VNC
+    /* First check if it's one of our predefined keys.  If so then we can make
+       some attempt at allowing an xmodmap inside a VNC desktop behave
+       something like you'd expect - e.g. if keys A & B are swapped over and
+       the VNC client sends an A, then map it to a B when generating the X
+       event.  We don't attempt to do this for keycodes which we make up on the
+       fly because it's too hard... */
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+	if (keySym == map[i]) {
+	    keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY;
+
+	    if (map[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) {
+
+		/* this keycode has more than one symbol associated with it,
+		   so shift state is important */
+
+		if ((i % GLYPHS_PER_KEY) == 0)
+		    shiftMustBeReleased = TRUE;
+		else
+		    shiftMustBePressed = TRUE;
+	    }
+	    break;
+	}
+    }
+#endif
+
+    if (!keyCode) {
+
+	/* not one of our predefined keys - see if it's in the current keyboard
+           mapping (i.e. we've already allocated an extra keycode for it) */
+
+	if (keySyms->mapWidth < 2) {
+	    ErrorF("KbdAddEvent: Sanity check failed - Keyboard mapping has "
+		   "less than 2 keysyms per keycode (KeySym 0x%x)\n",
+                   (unsigned) keySym);
+	    return;
+	}
+
+	for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) {
+	    if (keySym == keySyms->map[i]) {
+		keyCode = MIN_KEY_CODE + i / keySyms->mapWidth;
+
+		if (keySyms->map[(i / keySyms->mapWidth)
+					* keySyms->mapWidth + 1] != NoSymbol) {
+
+		    /* this keycode has more than one symbol associated with
+		       it, so shift state is important */
+
+		    if ((i % keySyms->mapWidth) == 0)
+			shiftMustBeReleased = TRUE;
+		    else
+			shiftMustBePressed = TRUE;
+		}
+		break;
+	    }
+	    if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol)
+		&& (i % keySyms->mapWidth) == 0)
+	    {
+		freeIndex = i;
+	    }
+	}
+    }
+
+    if (!keyCode) {
+	KeySym lower, upper;
+
+	/* we don't have an existing keycode - make one up on the fly and add
+	   it to the keyboard mapping.  Thanks to Vlad Harchev for pointing
+	   out problems with non-ascii capitalisation. */
+
+	if (freeIndex == -1) {
+	    ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n",
+		   (unsigned) keySym);
+	    return;
+	}
+
+	keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth;
+
+	XConvertCase(keySym, &lower, &upper);
+
+	if (lower == upper) {
+	    keySyms->map[freeIndex] = keySym;
+
+	} else {
+	    keySyms->map[freeIndex] = lower;
+	    keySyms->map[freeIndex+1] = upper;
+
+	    if (keySym == lower)
+		shiftMustBeReleased = TRUE;
+	    else
+		shiftMustBePressed = TRUE;
+	}
+
+	SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient);
+
+	ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n",
+	       (unsigned) keySym, keyCode);
+    }
+
+    time = GetTimeInMillis();
+
+    if (down) {
+	if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) {
+	    fakeShiftPress = TRUE;
+	    fake.u.u.type = KeyPress;
+	    fake.u.u.detail = SHIFT_L_KEY_CODE;
+	    fake.u.keyButtonPointer.time = time;
+	    Enqueue(&fake);
+	}
+	if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) {
+	    if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) {
+		fakeShiftLRelease = TRUE;
+		fake.u.u.type = KeyRelease;
+		fake.u.u.detail = SHIFT_L_KEY_CODE;
+		fake.u.keyButtonPointer.time = time;
+		Enqueue(&fake);
+	    }
+	    if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) {
+		fakeShiftRRelease = TRUE;
+		fake.u.u.type = KeyRelease;
+		fake.u.u.detail = SHIFT_R_KEY_CODE;
+		fake.u.keyButtonPointer.time = time;
+		Enqueue(&fake);
+	    }
+	}
+    }
+
+    ev.u.u.detail = keyCode;
+    ev.u.keyButtonPointer.time = time;
+    Enqueue(&ev);
+
+    if (fakeShiftPress) {
+	fake.u.u.type = KeyRelease;
+	fake.u.u.detail = SHIFT_L_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+    if (fakeShiftLRelease) {
+	fake.u.u.type = KeyPress;
+	fake.u.u.detail = SHIFT_L_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+    if (fakeShiftRRelease) {
+	fake.u.u.type = KeyPress;
+	fake.u.u.detail = SHIFT_R_KEY_CODE;
+	fake.u.keyButtonPointer.time = time;
+	Enqueue(&fake);
+    }
+}
+
+/*
+ * Called when the rfbserver receives a rfbPointerEvent event from a client.
+ * Put an X mouse event into the event queue.
+ */
+void
+PtrAddEvent(buttonMask, x, y, cl)
+    int buttonMask;
+    int x;
+    int y;
+    rfbClientPtr cl;
+{
+    xEvent ev;
+    int i;
+    unsigned long time;
+    static int oldButtonMask = 0;
+
+#ifdef CORBA
+    if (cl) {
+	CARD32 clientId = cl->sock;
+	ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+			     32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+#endif
+
+    time = GetTimeInMillis();
+
+    miPointerAbsoluteCursor(x, y, time);
+
+    for (i = 0; i < 5; i++) {
+	if ((buttonMask ^ oldButtonMask) & (1<<i)) {
+	    if (buttonMask & (1<<i)) {
+		ev.u.u.type = ButtonPress;
+		ev.u.u.detail = i + 1;
+		ev.u.keyButtonPointer.time = time;
+	    } else {
+		ev.u.u.type = ButtonRelease;
+		ev.u.u.detail = i + 1;
+		ev.u.keyButtonPointer.time = time;
+	    }
+ 	    Enqueue(&ev);
+	}
+    }
+
+    oldButtonMask = buttonMask;
+}
+
+void
+KbdReleaseAllKeys()
+{
+    int i, j;
+    xEvent ev;
+    unsigned long time = GetTimeInMillis();
+
+    if (!kbdDevice) 
+	return;
+
+    for (i = 0; i < DOWN_LENGTH; i++) {
+	if (kbdDevice->key->down[i] != 0) {
+	    for (j = 0; j < 8; j++) {
+		if (kbdDevice->key->down[i] & (1 << j)) {
+		    ev.u.u.type = KeyRelease;
+		    ev.u.u.detail = (i << 3) | j;
+		    ev.u.keyButtonPointer.time = time;
+		    Enqueue(&ev);
+		}
+	    }
+	}
+    }
+}
+
+
+/* copied from Xlib source */
+
+static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper)
+{
+    *lower = sym;
+    *upper = sym;
+    switch(sym >> 8) {
+    case 0: /* Latin 1 */
+	if ((sym >= XK_A) && (sym <= XK_Z))
+	    *lower += (XK_a - XK_A);
+	else if ((sym >= XK_a) && (sym <= XK_z))
+	    *upper -= (XK_a - XK_A);
+	else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
+	    *lower += (XK_agrave - XK_Agrave);
+	else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
+	    *upper -= (XK_agrave - XK_Agrave);
+	else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
+	    *lower += (XK_oslash - XK_Ooblique);
+	else if ((sym >= XK_oslash) && (sym <= XK_thorn))
+	    *upper -= (XK_oslash - XK_Ooblique);
+	break;
+    case 1: /* Latin 2 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym == XK_Aogonek)
+	    *lower = XK_aogonek;
+	else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+	    *lower += (XK_lstroke - XK_Lstroke);
+	else if (sym >= XK_Scaron && sym <= XK_Zacute)
+	    *lower += (XK_scaron - XK_Scaron);
+	else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+	    *lower += (XK_zcaron - XK_Zcaron);
+	else if (sym == XK_aogonek)
+	    *upper = XK_Aogonek;
+	else if (sym >= XK_lstroke && sym <= XK_sacute)
+	    *upper -= (XK_lstroke - XK_Lstroke);
+	else if (sym >= XK_scaron && sym <= XK_zacute)
+	    *upper -= (XK_scaron - XK_Scaron);
+	else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+	    *upper -= (XK_zcaron - XK_Zcaron);
+	else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+	    *lower += (XK_racute - XK_Racute);
+	else if (sym >= XK_racute && sym <= XK_tcedilla)
+	    *upper -= (XK_racute - XK_Racute);
+	break;
+    case 2: /* Latin 3 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+	    *lower += (XK_hstroke - XK_Hstroke);
+	else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+	    *lower += (XK_gbreve - XK_Gbreve);
+	else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+	    *upper -= (XK_hstroke - XK_Hstroke);
+	else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+	    *upper -= (XK_gbreve - XK_Gbreve);
+	else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+	    *lower += (XK_cabovedot - XK_Cabovedot);
+	else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+	    *upper -= (XK_cabovedot - XK_Cabovedot);
+	break;
+    case 3: /* Latin 4 */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+	    *lower += (XK_rcedilla - XK_Rcedilla);
+	else if (sym >= XK_rcedilla && sym <= XK_tslash)
+	    *upper -= (XK_rcedilla - XK_Rcedilla);
+	else if (sym == XK_ENG)
+	    *lower = XK_eng;
+	else if (sym == XK_eng)
+	    *upper = XK_ENG;
+	else if (sym >= XK_Amacron && sym <= XK_Umacron)
+	    *lower += (XK_amacron - XK_Amacron);
+	else if (sym >= XK_amacron && sym <= XK_umacron)
+	    *upper -= (XK_amacron - XK_Amacron);
+	break;
+    case 6: /* Cyrillic */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+	    *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+	else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+	    *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+	else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+	    *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+	else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+	    *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+        break;
+    case 7: /* Greek */
+	/* Assume the KeySym is a legal value (ignore discontinuities) */
+	if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+	    *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+	else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+		 sym != XK_Greek_iotaaccentdieresis &&
+		 sym != XK_Greek_upsilonaccentdieresis)
+	    *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+	else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+	    *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+	else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+		 sym != XK_Greek_finalsmallsigma)
+	    *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+        break;
+    }
+}
diff -u -rNp a/hw/xfree86/vnc/keyboard.h b/hw/xfree86/vnc/keyboard.h
--- a/hw/xfree86/vnc/keyboard.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/keyboard.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,167 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#define MIN_KEY_CODE		8
+#define MAX_KEY_CODE		255
+#define NO_OF_KEYS		(MAX_KEY_CODE - MIN_KEY_CODE + 1)
+#define GLYPHS_PER_KEY		4
+
+#define CONTROL_L_KEY_CODE	(MIN_KEY_CODE + 29)
+#define CONTROL_R_KEY_CODE	(MIN_KEY_CODE + 101)
+#define SHIFT_L_KEY_CODE	(MIN_KEY_CODE + 42)
+#define SHIFT_R_KEY_CODE	(MIN_KEY_CODE + 54)
+#define META_L_KEY_CODE		(MIN_KEY_CODE + 107)
+#define META_R_KEY_CODE		(MIN_KEY_CODE + 108)
+#define ALT_L_KEY_CODE		(MIN_KEY_CODE + 56)
+#define ALT_R_KEY_CODE		(MIN_KEY_CODE + 105)
+
+static KeySym map[MAX_KEY_CODE * GLYPHS_PER_KEY] = {
+    /* 0x00 */  NoSymbol,       NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x01 */  XK_Escape,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x02 */  XK_1,           XK_exclam,	NoSymbol,	NoSymbol,
+    /* 0x03 */  XK_2,           XK_at,		NoSymbol,	NoSymbol,
+    /* 0x04 */  XK_3,           XK_numbersign,	NoSymbol,	NoSymbol,
+    /* 0x05 */  XK_4,           XK_dollar,	NoSymbol,	NoSymbol,
+    /* 0x06 */  XK_5,           XK_percent,	NoSymbol,	NoSymbol,
+    /* 0x07 */  XK_6,           XK_asciicircum,	NoSymbol,	NoSymbol,
+    /* 0x08 */  XK_7,           XK_ampersand,	NoSymbol,	NoSymbol,
+    /* 0x09 */  XK_8,           XK_asterisk,	NoSymbol,	NoSymbol,
+    /* 0x0a */  XK_9,           XK_parenleft,	NoSymbol,	NoSymbol,
+    /* 0x0b */  XK_0,           XK_parenright,	NoSymbol,	NoSymbol,
+    /* 0x0c */  XK_minus,       XK_underscore,	NoSymbol,	NoSymbol,
+    /* 0x0d */  XK_equal,       XK_plus,	NoSymbol,	NoSymbol,
+    /* 0x0e */  XK_BackSpace,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x0f */  XK_Tab,         XK_ISO_Left_Tab,NoSymbol,	NoSymbol,
+    /* 0x10 */  XK_q,           XK_Q,		NoSymbol,	NoSymbol,
+    /* 0x11 */  XK_w,           XK_W,		NoSymbol,	NoSymbol,
+    /* 0x12 */  XK_e,           XK_E,		NoSymbol,	NoSymbol,
+    /* 0x13 */  XK_r,           XK_R,		NoSymbol,	NoSymbol,
+    /* 0x14 */  XK_t,           XK_T,		NoSymbol,	NoSymbol,
+    /* 0x15 */  XK_y,           XK_Y,		NoSymbol,	NoSymbol,
+    /* 0x16 */  XK_u,           XK_U,		NoSymbol,	NoSymbol,
+    /* 0x17 */  XK_i,           XK_I,		NoSymbol,	NoSymbol,
+    /* 0x18 */  XK_o,           XK_O,		NoSymbol,	NoSymbol,
+    /* 0x19 */  XK_p,           XK_P,		NoSymbol,	NoSymbol,
+    /* 0x1a */  XK_bracketleft, XK_braceleft,	NoSymbol,	NoSymbol,
+    /* 0x1b */  XK_bracketright,XK_braceright,	NoSymbol,	NoSymbol,
+    /* 0x1c */  XK_Return,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x1d */  XK_Control_L,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x1e */  XK_a,           XK_A,		NoSymbol,	NoSymbol,
+    /* 0x1f */  XK_s,           XK_S,		NoSymbol,	NoSymbol,
+    /* 0x20 */  XK_d,           XK_D,		NoSymbol,	NoSymbol,
+    /* 0x21 */  XK_f,           XK_F,		NoSymbol,	NoSymbol,
+    /* 0x22 */  XK_g,           XK_G,		NoSymbol,	NoSymbol,
+    /* 0x23 */  XK_h,           XK_H,		NoSymbol,	NoSymbol,
+    /* 0x24 */  XK_j,           XK_J,		NoSymbol,	NoSymbol,
+    /* 0x25 */  XK_k,           XK_K,		NoSymbol,	NoSymbol,
+    /* 0x26 */  XK_l,           XK_L,		NoSymbol,	NoSymbol,
+    /* 0x27 */  XK_semicolon,   XK_colon,	NoSymbol,	NoSymbol,
+    /* 0x28 */  XK_quoteright,  XK_quotedbl,	NoSymbol,	NoSymbol,
+    /* 0x29 */  XK_quoteleft,	XK_asciitilde,	NoSymbol,	NoSymbol,
+    /* 0x2a */  XK_Shift_L,     NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x2b */  XK_backslash,   XK_bar,		NoSymbol,	NoSymbol,
+    /* 0x2c */  XK_z,           XK_Z,		NoSymbol,	NoSymbol,
+    /* 0x2d */  XK_x,           XK_X,		NoSymbol,	NoSymbol,
+    /* 0x2e */  XK_c,           XK_C,		NoSymbol,	NoSymbol,
+    /* 0x2f */  XK_v,           XK_V,		NoSymbol,	NoSymbol,
+    /* 0x30 */  XK_b,           XK_B,		NoSymbol,	NoSymbol,
+    /* 0x31 */  XK_n,           XK_N,		NoSymbol,	NoSymbol,
+    /* 0x32 */  XK_m,           XK_M,		NoSymbol,	NoSymbol,
+    /* 0x33 */  XK_comma,       XK_less,	NoSymbol,	NoSymbol,
+    /* 0x34 */  XK_period,      XK_greater,	NoSymbol,	NoSymbol,
+    /* 0x35 */  XK_slash,       XK_question,	NoSymbol,	NoSymbol,
+    /* 0x36 */  XK_Shift_R,     NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x37 */  XK_KP_Multiply, NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x38 */  XK_Alt_L,	XK_Meta_L,	NoSymbol,	NoSymbol,
+    /* 0x39 */  XK_space,       NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3a */  XK_Caps_Lock,   NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3b */  XK_F1,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3c */  XK_F2,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3d */  XK_F3,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3e */  XK_F4,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x3f */  XK_F5,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x40 */  XK_F6,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x41 */  XK_F7,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x42 */  XK_F8,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x43 */  XK_F9,          NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x44 */  XK_F10,         NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x45 */  XK_Num_Lock,    NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x46 */  XK_Scroll_Lock,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x47 */  XK_KP_Home,	XK_KP_7,	NoSymbol,	NoSymbol,
+    /* 0x48 */  XK_KP_Up,	XK_KP_8,	NoSymbol,	NoSymbol,
+    /* 0x49 */  XK_KP_Prior,	XK_KP_9,	NoSymbol,	NoSymbol,
+    /* 0x4a */  XK_KP_Subtract, NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x4b */  XK_KP_Left,	XK_KP_4,	NoSymbol,	NoSymbol,
+    /* 0x4c */  XK_KP_Begin,	XK_KP_5,	NoSymbol,	NoSymbol,
+    /* 0x4d */  XK_KP_Right,	XK_KP_6,	NoSymbol,	NoSymbol,
+    /* 0x4e */  XK_KP_Add,      NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x4f */  XK_KP_End,	XK_KP_1,	NoSymbol,	NoSymbol,
+    /* 0x50 */  XK_KP_Down,	XK_KP_2,	NoSymbol,	NoSymbol,
+    /* 0x51 */  XK_KP_Next,	XK_KP_3,	NoSymbol,	NoSymbol,
+    /* 0x52 */  XK_KP_Insert,	XK_KP_0,	NoSymbol,	NoSymbol,
+    /* 0x53 */  XK_KP_Delete,	XK_KP_Decimal,	NoSymbol,	NoSymbol,
+    /* 0x54 */  XK_Sys_Req,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x55 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x56 */  XK_less,	XK_greater,	NoSymbol,	NoSymbol,
+    /* 0x57 */  XK_F11,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x58 */  XK_F12,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x59 */  XK_Home,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5a */  XK_Up,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5b */  XK_Prior,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5c */  XK_Left,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5d */  XK_Begin,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5e */  XK_Right,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x5f */  XK_End,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x60 */  XK_Down,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x61 */  XK_Next,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x62 */  XK_Insert,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x63 */  XK_Delete,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x64 */  XK_KP_Enter,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x65 */  XK_Control_R,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x66 */  XK_Pause,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x67 */  XK_Print,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x68 */  XK_KP_Divide,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x69 */  XK_Alt_R,	XK_Meta_R,	NoSymbol,	NoSymbol,
+    /* 0x6a */  XK_Break,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6b */  XK_Meta_L,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6c */  XK_Meta_R,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6d */  XK_Menu,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6e */  XK_F13,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x6f */  XK_F14,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x70 */  XK_F15,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x71 */  XK_F16,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x72 */  XK_F17,		NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x73 */  XK_backslash,	XK_underscore,	NoSymbol,	NoSymbol,
+    /* 0x74 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x75 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x76 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x77 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x78 */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x79 */  XK_Henkan,	XK_Mode_switch,	NoSymbol,	NoSymbol,
+    /* 0x7a */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7b */  XK_Muhenkan,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7c */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7d */  XK_backslash,	XK_bar,		NoSymbol,	NoSymbol,
+    /* 0x7e */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+    /* 0x7f */  NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
+};
+
+#define N_PREDEFINED_KEYS (sizeof(map) / (sizeof(KeySym) * GLYPHS_PER_KEY))
diff -u -rNp a/hw/xfree86/vnc/loginauth.c b/hw/xfree86/vnc/loginauth.c
--- a/hw/xfree86/vnc/loginauth.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/loginauth.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,141 @@
+/*
+ * loginauth.c - deal with login-style Unix authentication.
+ *
+ * This file implements the UnixLogin authentication protocol when setting up
+ * an RFB connection.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2003 Constantin Kaplinsky.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef linux
+#include </usr/include/shadow.h> /* XXX xserver has a shadow.h file too */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define _XOPEN_SOURCE
+#define __USE_XOPEN /* XXX shouldn't really need this */
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "rfb.h"
+
+void rfbLoginAuthProcessClientMessage(rfbClientPtr cl)
+{
+    int n1 = 0, n2 = 0;
+    CARD32 loginLen, passwdLen, authResult;
+    char *loginBuf, *passwdBuf;
+    struct passwd *ps;
+    char *encPasswd1, *encPasswd2;
+    Bool ok;
+
+    if ((n1 = ReadExact(cl->sock, (char *)&loginLen,
+			sizeof(loginLen))) <= 0 ||
+	(n2 = ReadExact(cl->sock, (char *)&passwdLen,
+			sizeof(passwdLen))) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginLen = Swap32IfLE(loginLen);
+    passwdLen = Swap32IfLE(passwdLen);
+    loginBuf = (char *)xalloc(loginLen + 1);
+    passwdBuf = (char *)xalloc(passwdLen + 1);
+
+    n1 = n2 = 0;
+    if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 ||
+	(n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) {
+	if (n1 != 0 || n2 != 0)
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    loginBuf[loginLen] = '\0';
+    passwdBuf[passwdLen] = '\0';
+
+    encPasswd1 = encPasswd2 = NULL;
+
+    ps = getpwnam(loginBuf);
+    if (ps == NULL) {
+	rfbLog("rfbLoginAuthProcessClientMessage: "
+	       "Cannot get password file entry for \"%s\"\n", loginBuf);
+    } else {
+	encPasswd1 = ps->pw_passwd;
+#ifdef linux
+	if (strlen(ps->pw_passwd) == 1) {
+	    struct spwd *sps;
+
+	    sps = getspnam(loginBuf);
+	    if (sps == NULL) {
+		rfbLog("rfbLoginAuthProcessClientMessage:"
+		       " getspnam() failed for user \"%s\"\n", loginBuf);
+	    } else {
+		encPasswd1 = sps->sp_pwdp;
+	    }
+	}
+#endif
+	encPasswd2 = crypt(passwdBuf, encPasswd1);
+	memset(passwdBuf, 0, strlen(passwdBuf));
+    }
+
+    ok = FALSE;
+    if (encPasswd1 != NULL && encPasswd2 != NULL) {
+	if (strcmp(encPasswd1, encPasswd2) == 0)
+	    ok = TRUE;
+    }
+
+    if (!ok) {
+	rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n",
+	       cl->host);
+
+	if (rfbAuthConsiderBlocking(cl)) {
+	    authResult = Swap32IfLE(rfbVncAuthTooMany);
+	} else {
+	    authResult = Swap32IfLE(rfbVncAuthFailed);
+	}
+
+	if (WriteExact(cl->sock, (char *)&authResult,
+		       sizeof(authResult)) < 0) {
+	    rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	}
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    rfbAuthUnblock(cl);
+
+    cl->login = strdup(loginBuf);
+    rfbLog("Login-style authentication passed for user %s at %s\n",
+	   cl->login, cl->host);
+
+    authResult = Swap32IfLE(rfbVncAuthOK);
+
+    if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) {
+	rfbLogPerror("rfbLoginAuthProcessClientMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    cl->state = RFB_INITIALISATION;
+}
+
diff -u -rNp a/hw/xfree86/vnc/Makefile.am b/hw/xfree86/vnc/Makefile.am
--- a/hw/xfree86/vnc/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/Makefile.am	2007-01-18 09:31:23.000000000 +0000
@@ -0,0 +1,48 @@
+libvnc_la_LTLIBRARIES = libvnc.la
+libvnc_la_CFLAGS = -I$(top_srcdir)/hw/xfree86/common \
+                   -I$(top_srcdir)/hw/xfree86/os-support \
+                   -I$(top_srcdir)/hw/xfree86/os-support/bus \
+                   -I$(top_srcdir)/hw/xfree86/ramdac \
+                   -I$(top_srcdir)/GL/glx \
+                   -I$(top_srcdir)/GL/include \
+		   -I$(top_srcdir)/hw/dmx/vnc \
+                   -I$(top_builddir)/GL/include \
+		   -I@MESA_SOURCE@/include \
+                   -DHAVE_XORG_CONFIG_H \
+                   -DXFree86LOADER \
+                   -DXFREE86VNC=1 \
+                   -DCHROMIUM=1 \
+                   @LIBDRM_CFLAGS@ \
+                   @GL_CFLAGS@
+
+#		   @MODULE_DEFINES@
+#                   @LOADER_DEFINES@
+
+libvnc_la_LDFLAGS = -module -avoid-version
+libvnc_ladir = $(moduledir)/extensions
+libvnc_la_SOURCES = \
+	$(top_srcdir)/hw/dmx/vnc/vncauth.c \
+	$(top_srcdir)/hw/vnc/d3des.c \
+	auth.c \
+	cmap.c \
+	corre.c \
+	cursor.c \
+	cutpaste.c \
+	draw.c \
+	hextile.c \
+	httpd.c \
+	kbdptr.c \
+	loginauth.c \
+	rfbkeyb.c \
+	rfbmouse.c \
+	rfbserver.c \
+	rre.c \
+	sockets.c \
+	stats.c \
+	tight.c \
+	translate.c \
+	vncext.c \
+	vncInit.c \
+	zlib.c
+
+#sdk_HEADERS = vncint.h
diff -u -rNp a/hw/xfree86/vnc/README b/hw/xfree86/vnc/README
--- a/hw/xfree86/vnc/README	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/README	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1 @@
+This directory contains the sources for building the vnc.so server extension module.
diff -u -rNp a/hw/xfree86/vnc/rfb.h b/hw/xfree86/vnc/rfb.h
--- a/hw/xfree86/vnc/rfb.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/rfb.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,726 @@
+/*
+ * rfb.h - header file for RFB DDX implementation.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000-2004 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <zlib.h>
+#include "scrnintstr.h"
+#include "colormapst.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "windowstr.h"
+#include "dixfontstr.h"
+#include "rfbproto.h"
+#include "vncauth.h"
+#include "picturestr.h"
+
+#define _VNC_SERVER
+#include <X11/extensions/vnc.h>
+
+
+
+#if defined(sun) || defined(hpux)
+#define SOCKLEN_T	int
+#else
+#define SOCKLEN_T	socklen_t
+#endif
+
+/* It's a good idea to keep these values a bit greater than required. */
+#define MAX_ENCODINGS 10
+#define MAX_SECURITY_TYPES 4
+#define MAX_TUNNELING_CAPS 16
+#define MAX_AUTH_CAPS 16
+
+/* 
+ * HTTP_BUF_SIZE for http transfers
+ */
+#define HTTP_BUF_SIZE 32768
+
+/*
+ * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the
+ * framebuffer.  So for a max screen width of say 2K with 32-bit pixels this
+ * means 8K minimum.
+ */
+#define UPDATE_BUF_SIZE 30000
+
+#if XFREE86VNC
+#include "xf86.h"
+#include "vncint.h"
+#define VNCSCREENPTR(ptr) \
+	vncScreenPtr pVNC = VNCPTR(ptr)
+#else
+bad!
+#define VNCSCREENPTR(ptr) \
+/* Soon \
+	rfbScreenInfoPtr pVNC = rfbScreen[ptr->myNum] \
+*/ \
+	rfbScreenInfoPtr pVNC = &rfbScreen
+#endif
+
+/*
+ * Per-screen (framebuffer) structure.  There is only one of these, since we
+ * don't allow the X server to have multiple screens.
+ */
+
+typedef struct
+{
+    int			rfbPort;
+    int			rdpPort;
+    int			udpPort;
+    int			rfbListenSock;
+    int			rdpListenSock;
+    int			udpSock;
+    int			httpPort;
+    int			httpListenSock;
+    int			httpSock;
+    char *		httpDir;
+    char		buf[HTTP_BUF_SIZE];
+    Bool		udpSockConnected;
+    char *		rfbAuthPasswdFile;
+    size_t		buf_filled;
+    int			maxFd;
+    fd_set		allFds;
+    Bool		useGetImage;
+    Bool		noCursor;
+    Bool		rfbAlwaysShared;
+    Bool		rfbNeverShared;
+    Bool		rfbDontDisconnect;
+    Bool		rfbUserAccept;
+    Bool		rfbViewOnly;
+    ColormapPtr		savedColormap;
+    ColormapPtr 	rfbInstalledColormap;
+    rfbPixelFormat	rfbServerFormat;
+    Bool		rfbAuthTooManyTries;
+    int			rfbAuthTries;
+    Bool		loginAuthEnabled;
+    struct in_addr	interface;
+    OsTimerPtr 		timer;
+    char updateBuf[UPDATE_BUF_SIZE];
+    int ublen;
+    int width;
+    int paddedWidthInBytes;
+    int height;
+    int depth;
+    int bitsPerPixel;
+    int sizeInBytes;
+    unsigned char *pfbMemory;
+    Pixel blackPixel;
+    Pixel whitePixel;
+
+    /* The following two members are used to minimise the amount of unnecessary
+       drawing caused by cursor movement.  Whenever any drawing affects the
+       part of the screen where the cursor is, the cursor is removed first and
+       then the drawing is done (this is what the sprite routines test for).
+       Afterwards, however, we do not replace the cursor, even when the cursor
+       is logically being moved across the screen.  We only draw the cursor
+       again just as we are about to send the client a framebuffer update.
+
+       We need to be careful when removing and drawing the cursor because of
+       their relationship with the normal drawing routines.  The drawing
+       routines can invoke the cursor routines, but also the cursor routines
+       themselves end up invoking drawing routines.
+
+       Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by
+       doing a CopyArea from a pixmap to the screen, where the pixmap contains
+       the saved contents of the screen under the cursor.  Before doing this,
+       however, we set cursorIsDrawn to FALSE.  Then, when CopyArea is called,
+       it sees that cursorIsDrawn is FALSE and so doesn't feel the need to
+       (recursively!) remove the cursor before doing it.
+
+       Putting up the cursor (rfbSpriteRestoreCursor) involves a call to
+       PushPixels.  While this is happening, cursorIsDrawn must be FALSE so
+       that PushPixels doesn't think it has to remove the cursor first.
+       Obviously cursorIsDrawn is set to TRUE afterwards.
+
+       Another problem we face is that drawing routines sometimes cause a
+       framebuffer update to be sent to the RFB client.  When the RFB client is
+       already waiting for a framebuffer update and some drawing to the
+       framebuffer then happens, the drawing routine sees that the client is
+       ready, so it calls rfbSendFramebufferUpdate.  If the cursor is not drawn
+       at this stage, it must be put up, and so rfbSpriteRestoreCursor is
+       called.  However, if the original drawing routine was actually called
+       from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't
+       want this to happen.  So both the cursor routines set
+       dontSendFramebufferUpdate to TRUE, and all the drawing routines check
+       this before calling rfbSendFramebufferUpdate. */
+
+    Bool cursorIsDrawn;		    /* TRUE if the cursor is currently drawn */
+    Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the
+				       cursor */
+
+    /* wrapped screen functions */
+
+    CloseScreenProcPtr			CloseScreen;
+    CreateGCProcPtr			CreateGC;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    RestoreAreasProcPtr			RestoreAreas;
+    ScreenWakeupHandlerProcPtr 		WakeupHandler;
+#ifdef CHROMIUM
+    RealizeWindowProcPtr		RealizeWindow;
+    UnrealizeWindowProcPtr		UnrealizeWindow;
+    DestroyWindowProcPtr		DestroyWindow;
+    ResizeWindowProcPtr			ResizeWindow;
+    PositionWindowProcPtr		PositionWindow;
+    ClipNotifyProcPtr			ClipNotify;
+#endif
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+#endif
+
+} rfbScreenInfo, *rfbScreenInfoPtr;
+
+
+/*
+ * rfbTranslateFnType is the type of translation functions.
+ */
+
+struct rfbClientRec;
+typedef void (*rfbTranslateFnType)(ScreenPtr pScreen, 
+				   char *table, rfbPixelFormat *in,
+				   rfbPixelFormat *out,
+				   unsigned char *iptr, char *optr,
+				   int bytesBetweenInputLines,
+				   int width, int height,
+				   int x, int y);
+
+
+/*
+ * Per-client structure.
+ */
+
+typedef struct rfbClientRec {
+    int sock;
+    char *host;
+    char *login;
+
+    int protocol_minor_ver;	/* RFB protocol minor version in use. */
+    Bool protocol_tightvnc;	/* TightVNC protocol extensions enabled */
+
+    /* Possible client states: */
+
+    enum {
+	RFB_PROTOCOL_VERSION,	/* establishing protocol version */
+        RFB_SECURITY_TYPE,	/* negotiating security (RFB v.3.7) */
+	RFB_TUNNELING_TYPE,	/* establishing tunneling (RFB v.3.7t) */
+	RFB_AUTH_TYPE,		/* negotiating authentication (RFB v.3.7t) */
+	RFB_AUTHENTICATION,	/* authenticating (VNC authentication) */
+	RFB_INITIALISATION,	/* sending initialisation messages */
+	RFB_NORMAL		/* normal protocol messages */
+    } state;
+
+    Bool viewOnly;		/* Do not accept input from this client. */
+
+    Bool reverseConnection;
+
+    Bool readyForSetColourMapEntries;
+
+    Bool useCopyRect;
+    int preferredEncoding;
+    int correMaxWidth, correMaxHeight;
+
+    /* The list of security types sent to this client (protocol 3.7).
+       Note that the first entry is the number of list items following. */
+
+    CARD8 securityTypes[MAX_SECURITY_TYPES + 1];
+
+    /* Lists of capability codes sent to clients. We remember these
+       lists to restrict clients from choosing those tunneling and
+       authentication types that were not advertised. */
+
+    int nAuthCaps;
+    CARD32 authCaps[MAX_AUTH_CAPS];
+
+    /* This is not useful while we don't support tunneling:
+    int nTunnelingCaps;
+    CARD32 tunnelingCaps[MAX_TUNNELING_CAPS]; */
+
+    /* The following member is only used during VNC authentication */
+
+    CARD8 authChallenge[CHALLENGESIZE];
+
+    /* The following members represent the update needed to get the client's
+       framebuffer from its present state to the current state of our
+       framebuffer.
+
+       If the client does not accept CopyRect encoding then the update is
+       simply represented as the region of the screen which has been modified
+       (modifiedRegion).
+
+       If the client does accept CopyRect encoding, then the update consists of
+       two parts.  First we have a single copy from one region of the screen to
+       another (the destination of the copy is copyRegion), and second we have
+       the region of the screen which has been modified in some other way
+       (modifiedRegion).
+
+       Although the copy is of a single region, this region may have many
+       rectangles.  When sending an update, the copyRegion is always sent
+       before the modifiedRegion.  This is because the modifiedRegion may
+       overlap parts of the screen which are in the source of the copy.
+
+       In fact during normal processing, the modifiedRegion may even overlap
+       the destination copyRegion.  Just before an update is sent we remove
+       from the copyRegion anything in the modifiedRegion. */
+
+    RegionRec copyRegion;	/* the destination region of the copy */
+    int copyDX, copyDY;		/* the translation by which the copy happens */
+
+    RegionRec modifiedRegion;	/* the region of the screen modified in any
+				   other way */
+
+    /* As part of the FramebufferUpdateRequest, a client can express interest
+       in a subrectangle of the whole framebuffer.  This is stored in the
+       requestedRegion member.  In the normal case this is the whole
+       framebuffer if the client is ready, empty if it's not. */
+
+    RegionRec requestedRegion;
+
+    /* The following members represent the state of the "deferred update" timer
+       - when the framebuffer is modified and the client is ready, in most
+       cases it is more efficient to defer sending the update by a few
+       milliseconds so that several changes to the framebuffer can be combined
+       into a single update. */
+
+    Bool deferredUpdateScheduled;
+    OsTimerPtr deferredUpdateTimer;
+
+    /* translateFn points to the translation function which is used to copy
+       and translate a rectangle from the framebuffer to an output buffer. */
+
+    rfbTranslateFnType translateFn;
+
+    char *translateLookupTable;
+
+    rfbPixelFormat format;
+
+    /* statistics */
+
+    int rfbBytesSent[MAX_ENCODINGS];
+    int rfbRectanglesSent[MAX_ENCODINGS];
+    int rfbLastRectMarkersSent;
+    int rfbLastRectBytesSent;
+    int rfbCursorShapeBytesSent;
+    int rfbCursorShapeUpdatesSent;
+    int rfbCursorPosBytesSent;
+    int rfbCursorPosUpdatesSent;
+    int rfbFramebufferUpdateMessagesSent;
+    int rfbRawBytesEquivalent;
+    int rfbKeyEventsRcvd;
+    int rfbPointerEventsRcvd;
+
+    /* zlib encoding -- necessary compression state info per client */
+
+    struct z_stream_s compStream;
+    Bool compStreamInited;
+
+    CARD32 zlibCompressLevel;
+
+    /* tight encoding -- preserve zlib streams' state for each client */
+
+    z_stream zsStruct[4];
+    Bool zsActive[4];
+    int zsLevel[4];
+    int tightCompressLevel;
+    int tightQualityLevel;
+
+    Bool enableLastRectEncoding;   /* client supports LastRect encoding */
+    Bool enableCursorShapeUpdates; /* client supports cursor shape updates */
+    Bool enableCursorPosUpdates;   /* client supports PointerPos updates */
+#ifdef CHROMIUM
+    Bool enableChromiumEncoding;   /* client supports Chromium encoding */
+#endif
+    Bool useRichCursorEncoding;    /* rfbEncodingRichCursor is preferred */
+    Bool cursorWasChanged;         /* cursor shape update should be sent */
+    Bool cursorWasMoved;           /* cursor position update should be sent */
+
+    int cursorX, cursorY;          /* client's cursor position */
+
+    struct rfbClientRec *next;
+
+    ScreenPtr pScreen;
+    int userAccepted;
+
+#ifdef CHROMIUM
+    unsigned int chromium_port;
+    unsigned int chromium_msport;
+#endif
+} rfbClientRec, *rfbClientPtr;
+
+#ifdef CHROMIUM
+typedef struct CRWindowTable {
+	unsigned long CRwinId;
+	unsigned long XwinId;
+	BoxPtr clipRects;
+	int numRects;
+	struct CRWindowTable *next;
+} CRWindowTable, *CRWindowTablePtr;
+
+extern struct CRWindowTable *windowTable;
+#endif
+
+/*
+ * This macro is used to test whether there is a framebuffer update needing to
+ * be sent to the client.
+ */
+
+#define FB_UPDATE_PENDING(cl)                                           \
+    ((!(cl)->enableCursorShapeUpdates && !pVNC->cursorIsDrawn) ||   \
+     ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) ||      \
+     ((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) ||          \
+     REGION_NOTEMPTY(((cl)->pScreen),&(cl)->copyRegion) ||                    \
+     REGION_NOTEMPTY(((cl)->pScreen),&(cl)->modifiedRegion))
+
+/*
+ * This macro creates an empty region (ie. a region with no areas) if it is
+ * given a rectangle with a width or height of zero. It appears that 
+ * REGION_INTERSECT does not quite do the right thing with zero-width
+ * rectangles, but it should with completely empty regions.
+ */
+
+#define SAFE_REGION_INIT(pscreen, preg, rect, size)          \
+{                                                            \
+      if ( ( (rect) ) &&                                     \
+           ( ( (rect)->x2 == (rect)->x1 ) ||                 \
+	     ( (rect)->y2 == (rect)->y1 ) ) ) {              \
+	  REGION_NULL( (pscreen), (preg) ); 		     \
+      } else {                                               \
+	  REGION_INIT( (pscreen), (preg), (rect), (size) );  \
+      }                                                      \
+}
+
+/*
+ * An rfbGCRec is where we store the pointers to the original GC funcs and ops
+ * which we wrap (NULL means not wrapped).
+ */
+
+typedef struct {
+    GCFuncs *wrapFuncs;
+    GCOps *wrapOps;
+} rfbGCRec, *rfbGCPtr;
+
+
+
+/*
+ * Macros for endian swapping.
+ */
+
+#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
+
+#define Swap32(l) (((l) >> 24) | \
+		   (((l) & 0x00ff0000) >> 8)  | \
+		   (((l) & 0x0000ff00) << 8)  | \
+		   ((l) << 24))
+
+static const int rfbEndianTest = 1;
+
+#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s))
+
+#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l))
+
+
+/*
+ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.130).
+ * Normally, using macros is no good, but this macro saves us from
+ * writing constants twice -- it constructs signature names from codes.
+ * Note that "code_sym" argument should be a single symbol, not an expression.
+ */
+
+#define SetCapInfo(cap_ptr, code_sym, vendor)		\
+{							\
+    rfbCapabilityInfo *pcap;				\
+    pcap = (cap_ptr);					\
+    pcap->code = Swap32IfLE(code_sym);			\
+    memcpy(pcap->vendorSignature, (vendor),		\
+	   sz_rfbCapabilityInfoVendor);			\
+    memcpy(pcap->nameSignature, sig_##code_sym,		\
+	   sz_rfbCapabilityInfoName);			\
+}
+
+
+/* init.c */
+
+extern char *desktopName;
+extern char rfbThisHost[];
+extern Atom VNC_LAST_CLIENT_ID;
+
+extern rfbScreenInfo rfbScreen;
+extern int rfbGCIndex;
+
+extern int inetdSock;
+
+extern int rfbBitsPerPixel(int depth);
+extern void rfbLog(char *format, ...);
+extern void rfbLogPerror(char *str);
+
+
+/* sockets.c */
+
+extern int rfbMaxClientWait;
+
+extern Bool rfbInitSockets(ScreenPtr pScreen);
+extern void rfbDisconnectUDPSock(ScreenPtr pScreen);
+extern void rfbCloseSock(ScreenPtr pScreen, int sock);
+extern void rfbCheckFds(ScreenPtr pScreen);
+extern void rfbWaitForClient(int sock);
+extern int rfbConnect(ScreenPtr pScreen, char *host, int port);
+
+extern int ReadExact(int sock, char *buf, int len);
+extern int WriteExact(int sock, char *buf, int len);
+extern int ListenOnTCPPort(ScreenPtr pScreen, int port);
+extern int ListenOnUDPPort(ScreenPtr pScreen, int port);
+extern int ConnectToTcpAddr(char *host, int port);
+
+
+/* cmap.c */
+
+
+extern int rfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps);
+extern void rfbInstallColormap(ColormapPtr pmap);
+extern void rfbUninstallColormap(ColormapPtr pmap);
+extern void rfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs);
+
+
+/* draw.c */
+
+extern int rfbDeferUpdateTime;
+
+extern void
+rfbComposite(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pMask,
+    PicturePtr pDst,
+    INT16 xSrc,
+    INT16 ySrc,
+    INT16 xMask,
+    INT16 yMask,
+    INT16 xDst,
+    INT16 yDst,
+    CARD16 width,
+    CARD16 height
+);
+
+extern void rfbGlyphs(
+    CARD8 op,
+    PicturePtr pSrc,
+    PicturePtr pDst,
+    PictFormatPtr maskFormat,
+    INT16 xSrc,
+    INT16 ySrc,
+    int nlistInit,
+    GlyphListPtr listInit,
+    GlyphPtr *glyphsInit
+);
+extern Bool rfbCloseScreen(int,ScreenPtr);
+extern Bool rfbCreateGC(GCPtr);
+extern void rfbPaintWindowBackground(WindowPtr, RegionPtr, int what);
+extern void rfbPaintWindowBorder(WindowPtr, RegionPtr, int what);
+extern void rfbCopyWindow(WindowPtr, DDXPointRec, RegionPtr);
+#ifdef CHROMIUM
+extern Bool rfbRealizeWindow(WindowPtr); 
+extern Bool rfbUnrealizeWindow(WindowPtr); 
+extern Bool rfbDestroyWindow(WindowPtr);
+extern void rfbResizeWindow(WindowPtr, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib);
+extern Bool rfbPositionWindow(WindowPtr, int x, int y);
+extern void rfbClipNotify(WindowPtr, int x, int y);
+#endif
+extern void rfbClearToBackground(WindowPtr, int x, int y, int w,
+				 int h, Bool generateExposures);
+extern RegionPtr rfbRestoreAreas(WindowPtr, RegionPtr);
+extern void rfbScheduleUpdate(ScreenPtr pScreen);
+
+
+/* cutpaste.c */
+
+extern void rfbSetXCutText(char *str, int len);
+extern void rfbGotXCutText(char *str, int len);
+
+
+/* kbdptr.c */
+
+extern Bool compatibleKbd;
+extern unsigned char ptrAcceleration;
+
+extern void PtrDeviceInit(void);
+extern void PtrDeviceOn(DeviceIntPtr pDev);
+extern void PtrDeviceOff(void);
+extern void PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl);
+extern void PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+
+extern void KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap);
+extern void KbdDeviceOn(void);
+extern void KbdDeviceOff(void);
+extern void KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl);
+extern void KbdReleaseAllKeys(void);
+
+/* rfbmouse.c */
+extern void vncInitMouse(void);
+
+/* rfbkeyb.c */
+extern void vncInitKeyb(void);
+
+
+/* rfbserver.c */
+
+
+extern rfbClientPtr rfbClientHead;
+extern rfbClientPtr pointerClient;
+
+extern void rfbNewClientConnection(ScreenPtr pScreen, int sock);
+extern rfbClientPtr rfbReverseConnection(ScreenPtr pScreen, char *host, int port);
+extern void rfbRootPropertyChange(ScreenPtr pScreen);
+extern void rfbClientConnectionGone(int sock);
+extern void rfbProcessClientMessage(ScreenPtr pScreen, int sock);
+extern void rfbClientConnFailed(rfbClientPtr cl, char *reason);
+extern void rfbNewUDPConnection(int sock);
+extern void rfbProcessUDPInput(ScreenPtr pScreen, int sock);
+extern Bool rfbSendFramebufferUpdate(ScreenPtr pScreen, rfbClientPtr cl);
+extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h);
+extern Bool rfbSendUpdateBuf(rfbClientPtr cl);
+extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour,
+				       int nColours);
+extern void rfbSendBell(void);
+extern void rfbSendServerCutText(char *str, int len);
+extern void rfbUserAllow(int sock, int accept);
+extern void rfbSetClip (WindowPtr pWin, BOOL enable);
+
+extern int GenerateVncConnectedEvent(int sock);
+extern int GenerateVncDisconnectedEvent(int sock);
+
+#ifdef CHROMIUM
+extern void rfbSendChromiumWindowShow(unsigned int winid, unsigned int show);
+extern void rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h);
+extern void rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects);
+#endif
+
+/* translate.c */
+
+extern Bool rfbEconomicTranslate;
+
+extern void rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+			     rfbPixelFormat *out,
+			     unsigned char *iptr, char *optr,
+			     int bytesBetweenInputLines,
+			     int width, int height,
+			     int x, int y);
+extern Bool rfbSetTranslateFunction(rfbClientPtr cl);
+extern void rfbSetClientColourMaps(int firstColour, int nColours);
+extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour,
+				  int nColours);
+
+
+/* httpd.c */
+
+extern Bool httpInitSockets(ScreenPtr pScreen);
+extern void httpCheckFds(ScreenPtr pScreen);
+
+
+/* vncext.c */
+
+#ifdef CHROMIUM
+extern void rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort, unsigned int mothershipPort);
+extern void rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid);
+int GenerateVncChromiumConnectedEvent(int sock);
+#endif
+
+
+/* auth.c */
+
+extern void rfbAuthNewClient(rfbClientPtr cl);
+extern void rfbProcessClientSecurityType(rfbClientPtr cl);
+extern void rfbProcessClientTunnelingType(rfbClientPtr cl);
+extern void rfbProcessClientAuthType(rfbClientPtr cl);
+extern void rfbVncAuthProcessResponse(rfbClientPtr cl);
+
+/* Functions to prevent too many successive authentication failures */
+extern Bool rfbAuthConsiderBlocking(rfbClientPtr cl);
+extern void rfbAuthUnblock(rfbClientPtr cl);
+extern Bool rfbAuthIsBlocked(rfbClientPtr cl);
+
+/* loginauth.c */
+
+extern void rfbLoginAuthProcessClientMessage(rfbClientPtr cl);
+  
+/* rre.c */
+
+extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* corre.c */
+
+extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* hextile.c */
+
+extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w,
+				       int h);
+
+
+/* zlib.c */
+
+/* Minimum zlib rectangle size in bytes.  Anything smaller will
+ * not compress well due to overhead.
+ */
+#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17)
+
+/* Set maximum zlib rectangle size in pixels.  Always allow at least
+ * two scan lines.
+ */
+#define ZLIB_MAX_RECT_SIZE (128*256)
+#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \
+			    ( min * 2 ) : ZLIB_MAX_RECT_SIZE )
+
+extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
+				    int h);
+
+
+/* tight.c */
+
+#define TIGHT_DEFAULT_COMPRESSION  6
+
+extern Bool rfbTightDisableGradient;
+
+extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h);
+extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h);
+
+
+/* cursor.c */
+
+extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen);
+extern Bool rfbSendCursorPos(rfbClientPtr cl, ScreenPtr pScreen);
+
+
+/* stats.c */
+
+extern void rfbResetStats(rfbClientPtr cl);
+extern void rfbPrintStats(rfbClientPtr cl);
diff -u -rNp a/hw/xfree86/vnc/rfbkeyb.c b/hw/xfree86/vnc/rfbkeyb.c
--- a/hw/xfree86/vnc/rfbkeyb.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/rfbkeyb.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,410 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include <stdlib.h>
+
+#define XINPUT
+
+#if XFREE86VNC
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86_OSproc.h>
+#include <X11/extensions/XIproto.h>
+#include "xf86Xinput.h"
+#include <X11/keysym.h>
+#include <mipointer.h>
+
+#else /* XFREE86VNC */
+
+#include <X11/keysym.h>
+#include <dix.h>
+#include <mipointer.h>
+
+#endif /* XFREE86VNC */
+
+#include "rfb.h"
+
+
+extern Bool noXkbExtension;
+extern void rfbSendBell(void);
+extern DeviceIntPtr kbdDevice;
+
+static const char *DEFAULTS[] = {
+    NULL
+};
+
+#include "keyboard.h"
+
+#undef XKB
+#ifdef XKB
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+#include <X11/extensions/XKBsrv.h>
+
+#if XFREE86VNC
+    /* 
+     * would like to use an XkbComponentNamesRec here but can't without
+     * pulling in a bunch of header files. :-(
+     */
+static    char *		xkbkeymap;
+static    char *		xkbkeycodes;
+static    char *		xkbtypes;
+static    char *		xkbcompat;
+static    char *		xkbsymbols;
+static    char *		xkbgeometry;
+static    Bool		xkbcomponents_specified;
+static    char *		xkbrules;
+static    char *		xkbmodel;
+static    char *		xkblayout;
+static    char *		xkbvariant;
+static    char *		xkboptions;
+#endif
+#endif
+
+void
+KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap)
+{
+    int i;
+
+    kbdDevice = pDevice;
+
+    for (i = 0; i < MAP_LENGTH; i++)
+	pModMap[i] = NoSymbol;
+
+    pModMap[CONTROL_L_KEY_CODE] = ControlMask;
+    pModMap[CONTROL_R_KEY_CODE] = ControlMask;
+    pModMap[SHIFT_L_KEY_CODE] = ShiftMask;
+    pModMap[SHIFT_R_KEY_CODE] = ShiftMask;
+    pModMap[META_L_KEY_CODE] = Mod1Mask;
+    pModMap[META_R_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_L_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_R_KEY_CODE] = Mod1Mask;
+
+    pKeySyms->minKeyCode = MIN_KEY_CODE;
+    pKeySyms->maxKeyCode = MAX_KEY_CODE;
+    pKeySyms->mapWidth = GLYPHS_PER_KEY;
+
+    pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym)
+				     * MAP_LENGTH * GLYPHS_PER_KEY);
+
+    if (!pKeySyms->map) {
+	ErrorF("xalloc failed\n");
+	exit(1);
+    }
+
+    for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++)
+	pKeySyms->map[i] = NoSymbol;
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+	pKeySyms->map[i] = map[i];
+    }
+}
+
+
+void
+KbdDeviceOn(void)
+{
+}
+
+
+void
+KbdDeviceOff(void)
+{
+}
+
+
+#if XFREE86VNC
+static int
+xf86rfbKeybControlProc(DeviceIntPtr device, int onoff)
+{
+    KeySymsRec		keySyms;
+    CARD8 		modMap[MAP_LENGTH];
+    DevicePtr pDev = (DevicePtr)device;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT: 
+	KbdDeviceInit(device, &keySyms, modMap);
+#ifdef XKB
+	if (noXkbExtension) {
+#endif
+	    InitKeyboardDeviceStruct(pDev, &keySyms, modMap,
+				 (BellProcPtr)rfbSendBell,
+				 (KbdCtrlProcPtr)NoopDDA);
+#ifdef XKB
+	} else {
+ 	    XkbComponentNamesRec names;
+	    if (XkbInitialMap) {
+	    	if ((xkbkeymap = strchr(XkbInitialMap, '/')) != NULL)
+		    xkbkeymap++;
+	    	else
+		    xkbkeymap = XkbInitialMap;
+	    }
+	    if (xkbkeymap) {
+	    	names.keymap = xkbkeymap;
+	    	names.keycodes = NULL;
+	    	names.types = NULL;
+	    	names.compat = NULL;
+	    	names.symbols = NULL;
+	    	names.geometry = NULL;
+	    } else {
+	    	names.keymap = NULL;
+	    	names.keycodes = xkbkeycodes;
+	    	names.types = xkbtypes;
+	    	names.compat = xkbcompat;
+	    	names.symbols = xkbsymbols;
+	    	names.geometry = xkbgeometry;
+	    }
+	if ((xkbkeymap || xkbcomponents_specified)
+	   && (xkbmodel == NULL || xkblayout == NULL)) {
+		xkbrules = NULL;
+	}
+#if 0
+	XkbSetRulesDflts(xkbrules, xkbmodel,
+			 xkblayout, xkbvariant,
+			 xkboptions);
+#endif
+	XkbInitKeyboardDeviceStruct(device, 
+				    &names,
+				    &keySyms, 
+				    modMap, 
+				    (BellProcPtr)rfbSendBell,
+				    (KbdCtrlProcPtr)NoopDDA);
+    }
+#endif /* XKB */
+	break;
+    case DEVICE_ON: 
+	pDev->on = TRUE;
+	KbdDeviceOn();
+	break;
+    case DEVICE_OFF: 
+	pDev->on = FALSE;
+	KbdDeviceOff();
+	break;
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    KbdDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static void
+xf86rfbKeybUninit(InputDriverPtr	drv,
+	       InputInfoPtr	pInfo,
+	       int		flags)
+{
+    xf86rfbKeybControlProc(pInfo->dev, DEVICE_OFF);
+}
+
+static InputInfoPtr
+xf86rfbKeybInit(InputDriverPtr	drv,
+	     IDevPtr		dev,
+	     int		flags)
+{
+    InputInfoPtr pInfo;
+#ifdef XKB
+    char *s;
+    Bool from;
+#endif
+    if (!(pInfo = xf86AllocateInput(drv, 0)))
+	return NULL;
+
+    /* Initialise the InputInfoRec. */
+    pInfo->name = dev->identifier;
+    pInfo->type_name = "rfbKeyb";
+    pInfo->flags = XI86_KEYBOARD_CAPABLE;
+    pInfo->device_control = xf86rfbKeybControlProc;
+    pInfo->read_input = NULL;
+    pInfo->motion_history_proc = NULL;
+    pInfo->history_size = 0;
+    pInfo->control_proc = NULL;
+    pInfo->close_proc = NULL;
+    pInfo->switch_mode = NULL;
+    pInfo->conversion_proc = NULL;
+    pInfo->reverse_conversion_proc = NULL;
+    pInfo->fd = -1;
+    pInfo->dev = NULL;
+    pInfo->private_flags = 0;
+    pInfo->always_core_feedback = 0;
+    pInfo->conf_idev = dev;
+
+    /* Collect the options, and process the common options. */
+    xf86CollectInputOptions(pInfo, DEFAULTS, NULL);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    
+    /* Mark the device configured */
+    pInfo->flags |= XI86_CONFIGURED;
+
+#ifdef XKB
+  from = X_DEFAULT;
+  if (noXkbExtension)
+    from = X_CMDLINE;
+  else if (xf86FindOption(dev->commonOptions, "XkbDisable")) {
+    noXkbExtension =
+	xf86SetBoolOption(dev->commonOptions, "XkbDisable", FALSE);
+    from = X_CONFIG;
+  }
+  if (noXkbExtension)
+    xf86Msg(from, "XKB: disabled\n");
+
+#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL))
+
+  if (!noXkbExtension && !XkbInitialMap) {
+    if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeymap", NULL))) {
+      xkbkeymap = NULL_IF_EMPTY(s);
+      xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" "
+		"(overrides other XKB settings)\n", xkbkeymap);
+    } else {
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbCompat", NULL))) {
+	xkbcompat = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbTypes", NULL))) {
+	xkbtypes = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeycodes", NULL))) {
+	xkbkeycodes = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbGeometry", NULL))) {
+	xkbgeometry = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbSymbols", NULL))) {
+	xkbsymbols = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbRules", NULL))) {
+	xkbrules = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbModel", NULL))) {
+	xkbmodel = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbLayout", NULL))) {
+	xkblayout = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbVariant", NULL))) {
+	xkbvariant = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s);
+      }
+
+      if ((s = xf86SetStrOption(dev->commonOptions, "XkbOptions", NULL))) {
+	xkboptions = NULL_IF_EMPTY(s);
+	xkbcomponents_specified = TRUE;
+	xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s);
+      }
+    }
+  }
+#undef NULL_IF_EMPTY
+#endif /* XKB */
+
+    /* Return the configured device */
+    return (pInfo);
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec RFBKEYB = {
+    1,				/* driver version */
+    "rfbkeyb",			/* driver name */
+    NULL,			/* identify */
+    xf86rfbKeybInit,		/* pre-init */
+    xf86rfbKeybUninit,		/* un-init */
+    NULL,			/* module */
+    0				/* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+static void
+xf86rfbKeybUnplug(pointer	p)
+{
+}
+
+static pointer
+xf86rfbKeybPlug(pointer	module,
+	    pointer	options,
+	    int		*errmaj,
+	    int		*errmin)
+{
+    xf86AddInputDriver(&RFBKEYB, module, 0);
+
+    return module;
+}
+
+void
+vncInitKeyb(void)
+{
+    xf86AddInputDriver(&RFBKEYB, NULL, 0);
+}
+
+static XF86ModuleVersionInfo xf86rfbKeybVersionRec =
+{
+    "rfbkeyb",
+    "xf4vnc Project, see http://xf4vnc.sf.net",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XF86_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_XINPUT,
+    ABI_XINPUT_VERSION,
+    MOD_CLASS_XINPUT,
+    {0, 0, 0, 0}		/* signature, to be patched into the file by */
+				/* a tool */
+};
+
+XF86ModuleData rfbkeybModuleData = {&xf86rfbKeybVersionRec,
+				  xf86rfbKeybPlug,
+				  xf86rfbKeybUnplug};
+
+#endif /* XFree86LOADER */
+#endif /* XFREE86VNC */
+
diff -u -rNp a/hw/xfree86/vnc/rfbmouse.c b/hw/xfree86/vnc/rfbmouse.c
--- a/hw/xfree86/vnc/rfbmouse.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/rfbmouse.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,240 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#ifndef XINPUT
+#define XINPUT
+#endif
+
+#if XFREE86VNC
+
+#include <misc.h>
+#include <xf86.h>
+#include <xf86_OSproc.h>
+#include <X11/extensions/XIproto.h>
+#include "xf86Xinput.h"
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+
+static const char *DEFAULTS[] = {
+    NULL
+};
+#else
+#include <X11/keysym.h>
+#include <dix.h>
+#include <mipointer.h>
+#endif
+
+#include "rfb.h"
+
+
+unsigned char ptrAcceleration = 50;
+
+void
+PtrDeviceOn(DeviceIntPtr pDev)
+{
+#if 0
+    ptrAcceleration = (unsigned char)pDev->ptrfeed->ctrl.num;
+#endif
+}
+
+void
+PtrDeviceInit(void)
+{
+}
+
+void
+PtrDeviceOff(void)
+{
+}
+
+
+void
+PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl)
+{
+#if 0
+    ptrAcceleration = (char)ctrl->num;
+
+    if (udpSockConnected) {
+	if (write(udpSock, &ptrAcceleration, 1) <= 0) {
+	    ErrorF("PtrDeviceControl: UDP input: write");
+	    rfbDisconnectUDPSock();
+	}
+    }
+#endif
+}
+
+#if XFREE86VNC
+static int
+xf86rfbMouseControlProc(DeviceIntPtr device, int onoff)
+{
+    BYTE map[6];
+    DevicePtr pDev = (DevicePtr)device;
+
+    switch (onoff)
+    {
+    case DEVICE_INIT:
+	PtrDeviceInit();
+	map[1] = 1;
+	map[2] = 2;
+	map[3] = 3;
+	map[4] = 4;
+	map[5] = 5;
+	InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents,
+				PtrDeviceControl,
+				miPointerGetMotionBufferSize());
+	break;
+
+    case DEVICE_ON:
+	pDev->on = TRUE;
+	PtrDeviceOn(device);
+        break;
+
+    case DEVICE_OFF:
+	pDev->on = FALSE;
+	PtrDeviceOff();
+	break;
+
+    case DEVICE_CLOSE:
+	if (pDev->on)
+	    PtrDeviceOff();
+	break;
+    }
+    return Success;
+}
+
+static void
+xf86rfbMouseUninit(InputDriverPtr	drv,
+	       InputInfoPtr	pInfo,
+	       int		flags)
+{
+    xf86rfbMouseControlProc(pInfo->dev, DEVICE_OFF);
+}
+
+static InputInfoPtr
+xf86rfbMouseInit(InputDriverPtr	drv,
+	     IDevPtr		dev,
+	     int		flags)
+{
+    InputInfoPtr pInfo;
+
+    if (!(pInfo = xf86AllocateInput(drv, 0)))
+	return NULL;
+
+    /* Initialise the InputInfoRec. */
+    pInfo->name = dev->identifier;
+    pInfo->type_name = "rfbMouse";
+    pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+    pInfo->device_control = xf86rfbMouseControlProc;
+    pInfo->read_input = NULL;
+    pInfo->motion_history_proc = xf86GetMotionEvents;
+    pInfo->history_size = 0;
+    pInfo->control_proc = NULL;
+    pInfo->close_proc = NULL;
+    pInfo->switch_mode = NULL;
+    pInfo->conversion_proc = NULL;
+    pInfo->reverse_conversion_proc = NULL;
+    pInfo->fd = -1;
+    pInfo->dev = NULL;
+    pInfo->private_flags = 0;
+    pInfo->always_core_feedback = 0;
+    pInfo->conf_idev = dev;
+
+    /* Collect the options, and process the common options. */
+    xf86CollectInputOptions(pInfo, DEFAULTS, NULL);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    
+    /* Mark the device configured */
+    pInfo->flags |= XI86_CONFIGURED;
+
+    /* Return the configured device */
+    return (pInfo);
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec RFBMOUSE = {
+    1,				/* driver version */
+    "rfbmouse",			/* driver name */
+    NULL,			/* identify */
+    xf86rfbMouseInit,		/* pre-init */
+    xf86rfbMouseUninit,		/* un-init */
+    NULL,			/* module */
+    0				/* ref count */
+};
+
+/*
+ ***************************************************************************
+ *
+ * Dynamic loading functions
+ *
+ ***************************************************************************
+ */
+#ifdef XFree86LOADER
+static void
+xf86rfbMouseUnplug(pointer	p)
+{
+}
+
+static pointer
+xf86rfbMousePlug(pointer	module,
+	    pointer	options,
+	    int		*errmaj,
+	    int		*errmin)
+{
+    xf86AddInputDriver(&RFBMOUSE, module, 0);
+
+    return module;
+}
+
+void
+vncInitMouse(void)
+{
+    xf86AddInputDriver(&RFBMOUSE, NULL, 0);
+}
+
+static XF86ModuleVersionInfo xf86rfbMouseVersionRec =
+{
+    "rfbmouse",
+    "xf4vnc Project, see http://xf4vnc.sf.net",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XF86_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_XINPUT,
+    ABI_XINPUT_VERSION,
+    MOD_CLASS_XINPUT,
+    {0, 0, 0, 0}		/* signature, to be patched into the file by */
+				/* a tool */
+};
+
+XF86ModuleData rfbmouseModuleData = {&xf86rfbMouseVersionRec,
+				  xf86rfbMousePlug,
+				  xf86rfbMouseUnplug};
+
+#endif /* XFree86LOADER */
+#endif
diff -u -rNp a/hw/xfree86/vnc/rfbproto.h b/hw/xfree86/vnc/rfbproto.h
--- a/hw/xfree86/vnc/rfbproto.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/rfbproto.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1347 @@
+/*
+ *  Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol, versions 3.3, 3.7 and 3.7t
+ * (protocol 3.7t is effectively 3.7 with TightVNC extensions enabled)
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first).  Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data.  The order of definitions in
+ * this file is as follows:
+ *
+ *  (1) Structures used in several types of message.
+ *  (2) Structures used in the initial handshaking.
+ *  (3) Message types.
+ *  (4) Encoding types.
+ *  (5) For each message type, the form of the data following the type byte.
+ *      Sometimes this is defined by a single structure but the more complex
+ *      messages have to be explained by comments.
+ */
+
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle.  This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+
+typedef struct _rfbRectangle {
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct _rfbPixelFormat {
+
+    CARD8 bitsPerPixel;		/* 8,16,32 only */
+
+    CARD8 depth;		/* 8 to 32 */
+
+    CARD8 bigEndian;		/* True if multi-byte pixels are interpreted
+				   as big endian, or if single-bit-per-pixel
+				   has most significant bit of the byte
+				   corresponding to first (leftmost) pixel. Of
+				   course this is meaningless for 8 bits/pix */
+
+    CARD8 trueColour;		/* If false then we need a "colour map" to
+				   convert pixels to RGB.  If true, xxxMax and
+				   xxxShift specify bits used for red, green
+				   and blue */
+
+    /* the following fields are only meaningful if trueColour is true */
+
+    CARD16 redMax;		/* maximum red value (= 2^n - 1 where n is the
+				   number of bits used for red). Note this
+				   value is always in big endian order. */
+
+    CARD16 greenMax;		/* similar for green */
+
+    CARD16 blueMax;		/* and blue */
+
+    CARD8 redShift;		/* number of shifts needed to get the red
+				   value in a pixel to the least significant
+				   bit. To find the red value from a given
+				   pixel, do the following:
+				   1) Swap pixel value according to bigEndian
+				      (e.g. if bigEndian is false and host byte
+				      order is big endian, then swap).
+				   2) Shift right by redShift.
+				   3) AND with redMax (in host byte order).
+				   4) You now have the red value between 0 and
+				      redMax. */
+
+    CARD8 greenShift;		/* similar for green */
+
+    CARD8 blueShift;		/* and blue */
+
+    CARD8 pad1;
+    CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to describe protocol options such as tunneling methods,
+ * authentication schemes and message types (protocol version 3.7t).
+ */
+
+typedef struct _rfbCapabilityInfo {
+
+    CARD32 code;		/* numeric identifier */
+    CARD8 vendorSignature[4];	/* vendor identification */
+    CARD8 nameSignature[8];	/* abbreviated option name */
+
+} rfbCapabilityInfo;
+
+#define sz_rfbCapabilityInfoVendor 4
+#define sz_rfbCapabilityInfoName 8
+#define sz_rfbCapabilityInfo 16
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define rfbStandardVendor "STDV"
+#define rfbTridiaVncVendor "TRDV"
+#define rfbTightVncVendor "TGHT"
+#define rfbTungstenGraphicsVendor "TGIV"
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports.  These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.7
+ * this is "RFB 003.007\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism.  Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent.  For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK.  This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 7
+#define rfbProtocolFallbackMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13];	/* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*
+ * Negotiation of the security type (protocol version 3.7)
+ *
+ * Once the protocol version has been decided, the server either sends a list
+ * of supported security types, or informs the client about an error (when the
+ * number of security types is 0).  Security type rfbSecTypeTight is used to
+ * enable TightVNC-specific protocol extensions.  The value rfbSecTypeVncAuth
+ * stands for classic VNC authentication.
+ *
+ * The client selects a particular security type from the list provided by the
+ * server.
+ */
+
+#define rfbSecTypeInvalid 0
+#define rfbSecTypeNone 1
+#define rfbSecTypeVncAuth 2
+#define rfbSecTypeTight 16
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Tunneling Capabilities (protocol version 3.7t)
+ *
+ * If the chosen security type is rfbSecTypeTight, the server sends a list of
+ * supported tunneling methods ("tunneling" refers to any additional layer of
+ * data transformation, such as encryption or external compression.)
+ *
+ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported tunneling methods in the order of preference.
+ *
+ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
+ * used, and the client should not send a response requesting a tunneling
+ * method.
+ */
+
+typedef struct _rfbTunnelingCapsMsg {
+    CARD32 nTunnelTypes;
+    /* followed by nTunnelTypes * rfbCapabilityInfo structures */
+} rfbTunnelingCapsMsg;
+
+#define sz_rfbTunnelingCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Tunneling Method Request (protocol version 3.7t)
+ *
+ * If the list of tunneling capabilities sent by the server was not empty, the
+ * client should reply with a 32-bit code specifying a particular tunneling
+ * method.  The following code should be used for no tunneling.
+ */
+
+#define rfbNoTunneling 0
+#define sig_rfbNoTunneling "NOTUNNEL"
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Authentication Capabilities (protocol version 3.7t)
+ *
+ * After setting up tunneling, the server sends a list of supported
+ * authentication schemes.
+ *
+ * nAuthTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported authentication schemes in the order of preference.
+ *
+ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is
+ * necessary, and the client should not send a response requesting an
+ * authentication scheme.
+ */
+
+typedef struct _rfbAuthenticationCapsMsg {
+    CARD32 nAuthTypes;
+    /* followed by nAuthTypes * rfbCapabilityInfo structures */
+} rfbAuthenticationCapsMsg;
+
+#define sz_rfbAuthenticationCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Authentication Scheme Request (protocol version 3.7t)
+ *
+ * If the list of authentication capabilities sent by the server was not empty,
+ * the client should reply with a 32-bit code specifying a particular
+ * authentication scheme.  The following codes are supported.
+ */
+
+#define rfbAuthNone 1
+#define rfbAuthVNC 2
+#define rfbAuthUnixLogin 129
+#define rfbAuthExternal 130
+
+#define sig_rfbAuthNone "NOAUTH__"
+#define sig_rfbAuthVNC "VNCAUTH_"
+#define sig_rfbAuthUnixLogin "ULGNAUTH"
+#define sig_rfbAuthExternal "XTRNAUTH"
+
+
+/*-----------------------------------------------------------------------------
+ * Standard VNC Authentication (all protocol versions)
+ *
+ * Standard authentication result codes are defined below.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct _rfbClientInitMsg {
+    CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct _rfbServerInitMsg {
+    CARD16 framebufferWidth;
+    CARD16 framebufferHeight;
+    rfbPixelFormat format;	/* the server's preferred pixel format */
+    CARD32 nameLength;
+    /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*-----------------------------------------------------------------------------
+ * Server Interaction Capabilities Message (protocol version 3.7t)
+ *
+ * In the protocol version 3.7t, the server informs the client what message
+ * types it supports in addition to ones defined in the protocol version 3.7.
+ * Also, the server sends the list of all supported encodings (note that it's
+ * not necessary to advertise the "raw" encoding sinse it MUST be supported in
+ * RFB 3.x protocols).
+ *
+ * This data immediately follows the server initialisation message.
+ */
+
+typedef struct _rfbInteractionCapsMsg {
+    CARD16 nServerMessageTypes;
+    CARD16 nClientMessageTypes;
+    CARD16 nEncodingTypes;
+    CARD16 pad;			/* reserved, must be 0 */
+    /* followed by nServerMessageTypes * rfbCapabilityInfo structures */
+    /* followed by nClientMessageTypes * rfbCapabilityInfo structures */
+} rfbInteractionCapsMsg;
+
+#define sz_rfbInteractionCapsMsg 8
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants.  Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest.  From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages.  The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+/* Chromium extensions, use higher values */
+#define rfbChromiumStart 50 
+#define rfbChromiumMoveResizeWindow 51
+#define rfbChromiumClipList 52
+#define rfbChromiumWindowShow 53
+
+#define rfbFileListData 130
+#define rfbFileDownloadData 131
+#define rfbFileUploadCancel 132
+#define rfbFileDownloadFailed 133
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListData "FTS_LSDT"
+#define sig_rfbFileDownloadData "FTS_DNDT"
+#define sig_rfbFileUploadCancel "FTS_UPCN"
+#define sig_rfbFileDownloadFailed "FTS_DNFL"
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1	/* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+/* Chromium extensions, use higher values */
+#define rfbChromiumStop 50
+#define rfbChromiumExpose 51
+
+#define rfbFileListRequest 130
+#define rfbFileDownloadRequest 131
+#define rfbFileUploadRequest 132
+#define rfbFileUploadData 133
+#define rfbFileDownloadCancel 134
+#define rfbFileUploadFailed 135
+#define rfbFileCreateDirRequest 136
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListRequest "FTC_LSRQ"
+#define sig_rfbFileDownloadRequest "FTC_DNRQ"
+#define sig_rfbFileUploadRequest "FTC_UPRQ"
+#define sig_rfbFileUploadData "FTC_UPDT"
+#define sig_rfbFileDownloadCancel "FTC_DNCN"
+#define sig_rfbFileUploadFailed "FTC_UPFL"
+#define sig_rfbFileCreateDirRequest "FTC_FCDR"
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw       0
+#define rfbEncodingCopyRect  1
+#define rfbEncodingRRE       2
+#define rfbEncodingCoRRE     4
+#define rfbEncodingHextile   5
+#define rfbEncodingZlib      6
+#define rfbEncodingTight     7
+#define rfbEncodingZlibHex   8
+
+/* signatures for basic encoding types */
+#define sig_rfbEncodingRaw       "RAW_____"
+#define sig_rfbEncodingCopyRect  "COPYRECT"
+#define sig_rfbEncodingRRE       "RRE_____"
+#define sig_rfbEncodingCoRRE     "CORRE___"
+#define sig_rfbEncodingHextile   "HEXTILE_"
+#define sig_rfbEncodingZlib      "ZLIB____"
+#define sig_rfbEncodingTight     "TIGHT___"
+#define sig_rfbEncodingZlibHex   "ZLIBHEX_"
+#define sig_rfbEncodingChromium  "CHROMIUM"
+
+/*
+ * Special encoding numbers:
+ *   0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
+ *   0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data;
+ *   0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions;
+ *   0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet;
+ *   0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor;
+ *   0xFFFFFFF0 .. 0xFFFFFFFF -- not allocated yet.
+ */
+
+#define rfbEncodingCompressLevel0  0xFFFFFF00
+#define rfbEncodingCompressLevel1  0xFFFFFF01
+#define rfbEncodingCompressLevel2  0xFFFFFF02
+#define rfbEncodingCompressLevel3  0xFFFFFF03
+#define rfbEncodingCompressLevel4  0xFFFFFF04
+#define rfbEncodingCompressLevel5  0xFFFFFF05
+#define rfbEncodingCompressLevel6  0xFFFFFF06
+#define rfbEncodingCompressLevel7  0xFFFFFF07
+#define rfbEncodingCompressLevel8  0xFFFFFF08
+#define rfbEncodingCompressLevel9  0xFFFFFF09
+
+#define rfbEncodingXCursor         0xFFFFFF10
+#define rfbEncodingRichCursor      0xFFFFFF11
+#define rfbEncodingPointerPos      0xFFFFFF18
+
+#define rfbEncodingLastRect        0xFFFFFF20
+#define rfbEncodingNewFBSize       0xFFFFFF21
+#define rfbEncodingChromium	   0xFFFFFF2F
+#define rfbEncodingChromium2	   0xFFFFFF30
+
+#define rfbEncodingQualityLevel0   0xFFFFFFE0
+#define rfbEncodingQualityLevel1   0xFFFFFFE1
+#define rfbEncodingQualityLevel2   0xFFFFFFE2
+#define rfbEncodingQualityLevel3   0xFFFFFFE3
+#define rfbEncodingQualityLevel4   0xFFFFFFE4
+#define rfbEncodingQualityLevel5   0xFFFFFFE5
+#define rfbEncodingQualityLevel6   0xFFFFFFE6
+#define rfbEncodingQualityLevel7   0xFFFFFFE7
+#define rfbEncodingQualityLevel8   0xFFFFFFE8
+#define rfbEncodingQualityLevel9   0xFFFFFFE9
+
+/* signatures for "fake" encoding types */
+#define sig_rfbEncodingCompressLevel0  "COMPRLVL"
+#define sig_rfbEncodingXCursor         "X11CURSR"
+#define sig_rfbEncodingRichCursor      "RCHCURSR"
+#define sig_rfbEncodingPointerPos      "POINTPOS"
+#define sig_rfbEncodingLastRect        "LASTRECT"
+#define sig_rfbEncodingNewFBSize       "NEWFBSIZ"
+#define sig_rfbEncodingQualityLevel0   "JPEGQLVL"
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves.  The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct _rfbFramebufferUpdateMsg {
+    CARD8 type;			/* always rfbFramebufferUpdate */
+    CARD8 pad;
+    CARD16 nRects;
+    /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data.  Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct _rfbFramebufferUpdateRectHeader {
+    rfbRectangle r;
+    CARD32 encoding;		/* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding.  Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding.  The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct _rfbCopyRect {
+    CARD16 srcX;
+    CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding.  We have an rfbRREHeader structure
+ * giving the number of subrectangles following.  Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct _rfbRREHeader {
+    CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding.  We have an rfbRREHeader structure giving
+ * the number of subrectangles following.  Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>].  This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct _rfbCoRRERectangle {
+    CARD8 x;
+    CARD8 y;
+    CARD8 w;
+    CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding.  The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order.  If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller.  Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller.  Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits.  If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile).  Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes.  The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ *    the background colour for this tile.  The first non-raw tile in a
+ *    rectangle must have this bit set.  If this bit isn't set then the
+ *    background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ *    the foreground colour to be used for all subrectangles in this tile.
+ *    If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ *    subrectangles following.  If not set, there are no subrectangles (i.e.
+ *    the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ *    value giving the colour of that subrectangle.  If not set, all
+ *    subrectangles are the same colour, the foreground colour;  if the
+ *    ForegroundSpecified bit wasn't set then the foreground is the same as
+ *    the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes.  The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw			(1 << 0)
+#define rfbHextileBackgroundSpecified	(1 << 1)
+#define rfbHextileForegroundSpecified	(1 << 2)
+#define rfbHextileAnySubrects		(1 << 3)
+#define rfbHextileSubrectsColoured	(1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZLIB - zlib compression Encoding.  We have an rfbZlibHeader structure
+ * giving the number of bytes to follow.  Finally the data follows in
+ * zlib compressed format.
+ */
+
+typedef struct _rfbZlibHeader {
+    CARD32 nBytes;
+} rfbZlibHeader;
+
+#define sz_rfbZlibHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Tight Encoding.
+ *
+ *-- The first byte of each Tight-encoded rectangle is a "compression control
+ *   byte". Its format is as follows (bit 0 is the least significant one):
+ *
+ *   bit 0:    if 1, then compression stream 0 should be reset;
+ *   bit 1:    if 1, then compression stream 1 should be reset;
+ *   bit 2:    if 1, then compression stream 2 should be reset;
+ *   bit 3:    if 1, then compression stream 3 should be reset;
+ *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
+ *             if 1001 (0x09), then the compression type is "jpeg",
+ *             if 0xxx, then the compression type is "basic",
+ *             values greater than 1001 are not valid.
+ *
+ * If the compression type is "basic", then bits 6..4 of the
+ * compression control byte (those xxx in 0xxx) specify the following:
+ *
+ *   bits 5-4:  decimal representation is the index of a particular zlib
+ *              stream which should be used for decompressing the data;
+ *   bit 6:     if 1, then a "filter id" byte is following this byte.
+ *
+ *-- The data that follows after the compression control byte described
+ * above depends on the compression type ("fill", "jpeg" or "basic").
+ *
+ *-- If the compression type is "fill", then the only pixel value follows, in
+ * client pixel format (see NOTE 1). This value applies to all pixels of the
+ * rectangle.
+ *
+ *-- If the compression type is "jpeg", the following data stream looks like
+ * this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     JPEG image.
+ *
+ * Data size is compactly represented in one, two or three bytes, according
+ * to the following scheme:
+ *
+ *  0xxxxxxx                    (for values 0..127)
+ *  1xxxxxxx 0yyyyyyy           (for values 128..16383)
+ *  1xxxxxxx 1yyyyyyy zzzzzzzz  (for values 16384..4194303)
+ *
+ * Here each character denotes one bit, xxxxxxx are the least significant 7
+ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the
+ * most significant 8 bits (bits 14-21). For example, decimal value 10000
+ * should be represented as two bytes: binary 10010000 01001110, or
+ * hexadecimal 90 4E.
+ *
+ *-- If the compression type is "basic" and bit 6 of the compression control
+ * byte was set to 1, then the next (second) byte specifies "filter id" which
+ * tells the decoder what filter type was used by the encoder to pre-process
+ * pixel data before the compression. The "filter id" byte can be one of the
+ * following:
+ *
+ *   0:  no filter ("copy" filter);
+ *   1:  "palette" filter;
+ *   2:  "gradient" filter.
+ *
+ *-- If bit 6 of the compression control byte is set to 0 (no "filter id"
+ * byte), or if the filter id is 0, then raw pixel values in the client
+ * format (see NOTE 1) will be compressed. See below details on the
+ * compression.
+ *
+ *-- The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better. 
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ *   P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ *   if (P[i,j] < 0) then P[i,j] := 0;
+ *   if (P[i,j] > MAX) then P[i,j] := MAX;
+ *   D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.
+ *
+ *-- The "palette" filter converts true-color pixel data to indexed colors
+ * and a palette which can consist of 2..256 colors. If the number of colors
+ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to
+ * encode one pixel. 1-bit encoding is performed such way that the most
+ * significant bits correspond to the leftmost pixels, and each raw of pixels
+ * is aligned to the byte boundary. When "palette" filter is used, the
+ * palette is sent before the pixel data. The palette begins with an unsigned
+ * byte which value is the number of colors in the palette minus 1 (i.e. 1
+ * means 2 colors, 255 means 256 colors in the palette). Then follows the
+ * palette itself which consist of pixel values in client pixel format (see
+ * NOTE 1).
+ *
+ *-- The pixel data is compressed using the zlib library. But if the data
+ * size after applying the filter but before the compression is less then 12,
+ * then the data is sent as is, uncompressed. Four separate zlib streams
+ * (0..3) can be used and the decoder should read the actual stream id from
+ * the compression control byte (see NOTE 2).
+ *
+ * If the compression is not used, then the pixel data is sent as is,
+ * otherwise the data stream looks like this:
+ *
+ *   1..3 bytes:  data size (N) in compact representation;
+ *   N bytes:     zlib-compressed data.
+ *
+ * Data size is compactly represented in one, two or three bytes, just like
+ * in the "jpeg" compression method (see above).
+ *
+ *-- NOTE 1. If the color depth is 24, and all three color components are
+ * 8-bit wide, then one pixel in Tight encoding is always represented by
+ * three bytes, where the first byte is red component, the second byte is
+ * green component, and the third byte is blue component of the pixel color
+ * value. This applies to colors in palettes as well.
+ *
+ *-- NOTE 2. The decoder must reset compression streams' states before
+ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
+ * byte are set to 1. Note that the decoder must reset zlib streams even if
+ * the compression type is "fill" or "jpeg".
+ *
+ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
+ * when bits-per-pixel value is either 16 or 32, not 8.
+ *
+ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048
+ * pixels. If a rectangle is wider, it must be split into several rectangles
+ * and each one should be encoded separately.
+ *
+ */
+
+#define rfbTightExplicitFilter         0x04
+#define rfbTightFill                   0x08
+#define rfbTightJpeg                   0x09
+#define rfbTightMaxSubencoding         0x09
+
+/* Filters to improve compression efficiency */
+#define rfbTightFilterCopy             0x00
+#define rfbTightFilterPalette          0x01
+#define rfbTightFilterGradient         0x02
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ZLIBHEX - zlib compressed Hextile Encoding.  Essentially, this is the
+ * hextile encoding with zlib compression on the tiles that can not be
+ * efficiently encoded with one of the other hextile subencodings.  The
+ * new zlib subencoding uses two bytes to specify the length of the
+ * compressed tile and then the compressed data follows.  As with the
+ * raw sub-encoding, the zlib subencoding invalidates the other
+ * values, if they are also set.
+ */
+
+#define rfbHextileZlibRaw		(1 << 5)
+#define rfbHextileZlibHex		(1 << 6)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * XCursor encoding. This is a special encoding used to transmit X-style
+ * cursor shapes from server to clients. Note that for this encoding,
+ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot
+ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB
+ * samples are sent after header in the rfbXCursorColors structure. They
+ * denote foreground and background colors of the cursor. If a client
+ * supports only black-and-white cursors, it should ignore these colors and
+ * assume that foreground is black and background is white. Next, two bitmaps
+ * (1 bits per pixel) follow: first one with actual data (value 0 denotes
+ * background color, value 1 denotes foreground color), second one with
+ * transparency data (bits with zero value mean that these pixels are
+ * transparent). Both bitmaps represent cursor data in a byte stream, from
+ * left to right, from top to bottom, and each row is byte-aligned. Most
+ * significant bits correspond to leftmost pixels. The number of bytes in
+ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor
+ * should be hidden (or default local cursor should be set by the client).
+ */
+
+typedef struct _rfbXCursorColors {
+    CARD8 foreRed;
+    CARD8 foreGreen;
+    CARD8 foreBlue;
+    CARD8 backRed;
+    CARD8 backGreen;
+    CARD8 backBlue;
+} rfbXCursorColors;
+
+#define sz_rfbXCursorColors 6
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RichCursor encoding. This is a special encoding used to transmit cursor
+ * shapes from server to clients. It is similar to the XCursor encoding but
+ * uses client pixel format instead of two RGB colors to represent cursor
+ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader
+ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h).
+ * After header, two pixmaps follow: first one with cursor image in current
+ * client pixel format (like in raw encoding), second with transparency data
+ * (1 bit per pixel, exactly the same format as used for transparency bitmap
+ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or
+ * default local cursor should be set by the client).
+ */
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries.  In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest.  So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct _rfbSetColourMapEntriesMsg {
+    CARD8 type;			/* always rfbSetColourMapEntries */
+    CARD8 redIndex;		/* used to be pad, but used for DirectColor */
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct _rfbBellMsg {
+    CARD8 type;			/* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct _rfbServerCutTextMsg {
+    CARD8 type;			/* always rfbServerCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ChromiumStart - a port number for the crserver
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumStart */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 crServerPort;
+    CARD32 mothershipPort;
+} rfbChromiumStartMsg;
+
+#define sz_rfbChromiumStartMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * ChromiumMoveResizeWindow - move a chromium window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumMoveResizeWindow */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 x;
+    CARD32 y;
+    CARD32 w;
+    CARD32 h;
+} rfbChromiumMoveResizeWindowMsg;
+
+#define sz_rfbChromiumMoveResizeWindowMsg 24
+
+/*-----------------------------------------------------------------------------
+ * ChromiumClipList - send clip list
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumClipList */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 length;
+} rfbChromiumClipListMsg;
+
+#define sz_rfbChromiumClipListMsg 12
+
+/*-----------------------------------------------------------------------------
+ * ChromiumWindowShow - map or unmap a window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumWindowShow */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+    CARD32 show;
+} rfbChromiumWindowShowMsg;
+
+#define sz_rfbChromiumWindowShowMsg 12
+
+/*-----------------------------------------------------------------------------
+ * FileListData
+ */
+
+typedef struct _rfbFileListDataMsg {
+    CARD8 type;
+    CARD8 flags;
+    CARD16 numFiles;
+    CARD16 dataSize;
+    CARD16 compressedSize;
+    /* Followed by SizeData[numFiles] */
+    /* Followed by Filenames[compressedSize] */
+} rfbFileListDataMsg;
+
+#define sz_rfbFileListDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadData
+ */
+
+typedef struct _rfbFileDownloadDataMsg {
+    CARD8 type;
+    CARD8 compressLevel;
+    CARD16 realSize;
+    CARD16 compressedSize;
+    /* Followed by File[copressedSize] */
+} rfbFileDownloadDataMsg;
+
+#define sz_rfbFileDownloadDataMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadCancel
+ */
+
+typedef struct _rfbFileUploadCancelMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileUploadCancelMsg;
+
+#define sz_rfbFileUploadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadFailed
+ */
+
+typedef struct _rfbFileDownloadFailedMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileDownloadFailedMsg;
+
+#define sz_rfbFileDownloadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union _rfbServerToClientMsg {
+    CARD8 type;
+    rfbFramebufferUpdateMsg fu;
+    rfbSetColourMapEntriesMsg scme;
+    rfbBellMsg b;
+    rfbServerCutTextMsg sct;
+    rfbFileListDataMsg fld;
+    rfbFileDownloadDataMsg fdd;
+    rfbFileUploadCancelMsg fuc;
+    rfbFileDownloadFailedMsg fdf;
+    rfbChromiumStartMsg scd;
+    rfbChromiumMoveResizeWindowMsg scm;
+    rfbChromiumClipListMsg sccl;
+    rfbChromiumWindowShowMsg scws;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct _rfbSetPixelFormatMsg {
+    CARD8 type;			/* always rfbSetPixelFormat */
+    CARD8 pad1;
+    CARD16 pad2;
+    rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ *    ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct _rfbFixColourMapEntriesMsg {
+    CARD8 type;			/* always rfbFixColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept.  Put them
+ * in order of preference, if we have any.  We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct _rfbSetEncodingsMsg {
+    CARD8 type;			/* always rfbSetEncodings */
+    CARD8 pad;
+    CARD16 nEncodings;
+    /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update.  If incremental
+ * is true then the client just wants the changes since the last update.  If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct _rfbFramebufferUpdateRequestMsg {
+    CARD8 type;			/* always rfbFramebufferUpdateRequest */
+    CARD8 incremental;
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value.  Other common keys are:
+ *
+ * BackSpace		0xff08
+ * Tab			0xff09
+ * Return or Enter	0xff0d
+ * Escape		0xff1b
+ * Insert		0xff63
+ * Delete		0xffff
+ * Home			0xff50
+ * End			0xff57
+ * Page Up		0xff55
+ * Page Down		0xff56
+ * Left			0xff51
+ * Up			0xff52
+ * Right		0xff53
+ * Down			0xff54
+ * F1			0xffbe
+ * F2			0xffbf
+ * ...			...
+ * F12			0xffc9
+ * Shift		0xffe1
+ * Control		0xffe3
+ * Meta			0xffe7
+ * Alt			0xffe9
+ */
+
+typedef struct _rfbKeyEventMsg {
+    CARD8 type;			/* always rfbKeyEvent */
+    CARD8 down;			/* true if down (press), false if up */
+    CARD16 pad;
+    CARD32 key;			/* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct _rfbPointerEventMsg {
+    CARD8 type;			/* always rfbPointerEvent */
+    CARD8 buttonMask;		/* bits 0-7 are buttons 1-8, 0=up, 1=down */
+    CARD16 x;
+    CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+#define rfbButton4Mask 8
+#define rfbButton5Mask 16
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct _rfbClientCutTextMsg {
+    CARD8 type;			/* always rfbClientCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileListRequest
+ */
+
+typedef struct _rfbFileListRequestMsg {
+    CARD8 type;
+    CARD8 flags;
+    CARD16 dirNameSize;
+    /* Followed by char Dirname[dirNameSize] */
+} rfbFileListRequestMsg;
+
+#define sz_rfbFileListRequestMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadRequest
+ */
+
+typedef struct _rfbFileDownloadRequestMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 fNameSize;
+    CARD32 position;
+    /* Followed by char Filename[fNameSize] */
+} rfbFileDownloadRequestMsg;
+
+#define sz_rfbFileDownloadRequestMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileUploadRequest
+ */
+
+typedef struct _rfbFileUploadRequestMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 fNameSize;
+    CARD32 position;
+    /* Followed by char Filename[fNameSize] */
+} rfbFileUploadRequestMsg;
+
+#define sz_rfbFileUploadRequestMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadData
+ */
+
+typedef struct _rfbFileUploadDataMsg {
+    CARD8 type;
+    CARD8 compressedLevel;
+    CARD16 realSize;
+    CARD16 compressedSize;
+    /* Followed by File[compressedSize]   */
+} rfbFileUploadDataMsg;
+
+#define sz_rfbFileUploadDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadCancel
+ */
+
+typedef struct _rfbFileDownloadCancelMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileDownloadCancelMsg;
+
+#define sz_rfbFileDownloadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileUploadFailed
+ */
+
+typedef struct _rfbFileUploadFailedMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 reasonLen;
+    /* Followed by reason[reasonLen] */
+} rfbFileUploadFailedMsg;
+
+#define sz_rfbFileUploadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileCreateDirRequest
+ */
+
+typedef struct _rfbFileCreateDirRequestMsg {
+    CARD8 type;
+    CARD8 unused;
+    CARD16 dNameLen;
+    CARD32 dModTime;
+    /* Followed by dName[dNameLen] */
+} rfbFileCreateDirRequestMsg;
+ 
+#define sz_rfbFileCreateDirRequestMsg 8
+ 
+/*-----------------------------------------------------------------------------
+ * ChromiumStop - the client has stopped the GL app.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumStop */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 port;
+} rfbChromiumStopMsg;
+
+#define sz_rfbChromiumStopMsg 8
+
+/*-----------------------------------------------------------------------------
+ * ChromiumExpose - redraw the window
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbChromiumExpose */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 winid;
+} rfbChromiumExposeMsg;
+
+#define sz_rfbChromiumExposeMsg 8
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union _rfbClientToServerMsg {
+    CARD8 type;
+    rfbSetPixelFormatMsg spf;
+    rfbFixColourMapEntriesMsg fcme;
+    rfbSetEncodingsMsg se;
+    rfbFramebufferUpdateRequestMsg fur;
+    rfbKeyEventMsg ke;
+    rfbPointerEventMsg pe;
+    rfbClientCutTextMsg cct;
+    rfbFileListRequestMsg flr;
+    rfbFileDownloadRequestMsg fdr;
+    rfbFileUploadRequestMsg fupr;
+    rfbFileUploadDataMsg fud;
+    rfbFileDownloadCancelMsg fdc;
+    rfbFileUploadFailedMsg fuf;
+    rfbFileCreateDirRequestMsg fcdr;
+    rfbChromiumStopMsg csd;
+    rfbChromiumExposeMsg cse;
+} rfbClientToServerMsg;
diff -u -rNp a/hw/xfree86/vnc/rfbserver.c b/hw/xfree86/vnc/rfbserver.c
--- a/hw/xfree86/vnc/rfbserver.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/rfbserver.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,2278 @@
+/*
+ * rfbserver.c - deal with server-side of the RFB protocol.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000-2004 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* Use ``#define CORBA'' to enable CORBA control interface */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "windowstr.h"
+#include "rfb.h"
+#include "input.h"
+#include "mipointer.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+#ifdef CHROMIUM
+#include "mivalidate.h"
+#endif
+#include "sprite.h"
+#include "propertyst.h"
+#include <X11/Xatom.h>
+#include <mi.h>
+
+#ifdef CORBA
+#include <vncserverctrl.h>
+#endif
+
+#ifdef CHROMIUM
+struct CRWindowTable *windowTable = NULL;
+#endif
+
+extern Atom VNC_CONNECT;
+
+rfbClientPtr rfbClientHead = NULL;
+rfbClientPtr pointerClient = NULL;  /* Mutex for pointer events */
+
+static rfbClientPtr rfbNewClient(ScreenPtr pScreen, int sock);
+static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
+static void rfbProcessClientInitMessage(rfbClientPtr cl);
+static void rfbSendInteractionCaps(rfbClientPtr cl);
+static void rfbProcessClientNormalMessage(rfbClientPtr cl);
+static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy);
+static Bool rfbSendLastRectMarker(rfbClientPtr cl);
+
+static char *text = NULL;
+
+void
+rfbRootPropertyChange(ScreenPtr pScreen)
+{
+    PropertyPtr pProp;
+    WindowPtr pWin = WindowTable[pScreen->myNum];
+
+    pProp = wUserProps (pWin);
+
+    while (pProp) {
+        if ((pProp->propertyName == XA_CUT_BUFFER0) && 
+	    (pProp->type == XA_STRING) &&
+	    (pProp->format == 8))
+    	{
+	    /* Ensure we don't keep re-sending cut buffer */
+
+    	    if ( (text && pProp->data && strncmp(text, pProp->data, pProp->size)) || !text)
+	    	rfbGotXCutText(pProp->data, pProp->size);
+
+	    if (text) xfree(text);
+    	    text = xalloc(1 + pProp->size);
+    	    if (! text) return;
+    	    if (pProp->data) memcpy(text, pProp->data, pProp->size);
+    	    text[pProp->size] = '\0';
+
+	    return;
+    	}
+    	if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING)
+	    && (pProp->format == 8) && (pProp->size > 0))
+    	{
+	    int i;
+	    rfbClientPtr cl;
+	    int port = 5500;
+	    char *host = (char *)Xalloc(pProp->size+1);
+	    memcpy(host, pProp->data, pProp->size);
+	    host[pProp->size] = 0;
+	    for (i = 0; i < pProp->size; i++) {
+	    	if (host[i] == ':') {
+		    port = atoi(&host[i+1]);
+		    host[i] = 0;
+	    	}
+	    }
+
+	    cl = rfbReverseConnection(pScreen, host, port);
+
+#ifdef CORBA
+	    if (cl != NULL)
+	    	newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+
+	    ChangeWindowProperty(pWin,
+		 	     pProp->propertyName, pProp->type,
+			     pProp->format, PropModeReplace,
+			     0, NULL,
+			     FALSE
+			     );
+
+	    free(host);
+    	}
+	pProp = pProp->next;
+    }
+}
+
+int
+rfbBitsPerPixel(depth)
+    int depth;
+{
+    if (depth == 1) return 1;
+    else if (depth <= 8) return 8;
+    else if (depth <= 16) return 16;
+    else return 32;
+}
+
+void 
+rfbUserAllow(int sock, int accept)
+{
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (cl->sock == sock) {
+	    cl->userAccepted = accept;
+	}
+    }
+}
+
+/*
+ * rfbNewClientConnection is called from sockets.c when a new connection
+ * comes in.
+ */
+
+void
+rfbNewClientConnection(ScreenPtr pScreen, int sock)
+{
+    rfbClientPtr cl;
+
+    cl = rfbNewClient(pScreen, sock);
+
+    GenerateVncConnectedEvent(sock);
+
+#if XFREE86VNC
+    /* Someone is connected - disable VT switching */
+    xf86EnableVTSwitch(FALSE);
+#endif
+
+#ifdef CORBA
+    if (cl != NULL)
+	newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
+#endif
+}
+
+
+/*
+ * rfbReverseConnection is called by the CORBA stuff to make an outward
+ * connection to a "listening" RFB client.
+ */
+
+rfbClientPtr
+rfbReverseConnection(ScreenPtr pScreen, char *host, int port)
+{
+    int sock;
+    rfbClientPtr cl;
+
+    if ((sock = rfbConnect(pScreen, host, port)) < 0)
+	return (rfbClientPtr)NULL;
+
+    cl = rfbNewClient(pScreen, sock);
+
+    if (cl) {
+	cl->reverseConnection = TRUE;
+    }
+
+    return cl;
+}
+
+
+#ifdef CHROMIUM
+/*
+ * rfbSetClip --
+ * 	Generate expose event.
+ * 	This function is overkill and should be cleaned up, but it
+ * 	works for now.
+ */
+
+void
+rfbSetClip (WindowPtr pWin, BOOL enable)
+{
+    ScreenPtr   pScreen = pWin->drawable.pScreen;
+    WindowPtr	pChild;
+    Bool	WasViewable = (Bool)(pWin->viewable);
+    Bool	anyMarked = FALSE;
+    RegionPtr	pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+    Bool	dosave = FALSE;
+#endif
+    WindowPtr   pLayerWin;
+    BoxRec	box;
+
+    if (WasViewable)
+    {
+	for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+	{
+	    (void) (*pScreen->MarkOverlappedWindows)(pChild,
+						     pChild,
+						     &pLayerWin);
+	}
+	(*pScreen->MarkWindow) (pWin);
+	anyMarked = TRUE;
+	if (pWin->valdata)
+	{
+	    if (HasBorder (pWin))
+	    {
+		RegionPtr	borderVisible;
+
+		borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+		REGION_SUBTRACT(pScreen, borderVisible,
+				&pWin->borderClip, &pWin->winSize);
+		pWin->valdata->before.borderVisible = borderVisible;
+	    }
+	    pWin->valdata->before.resized = TRUE;
+	}
+    }
+    
+    /*
+     * Use REGION_BREAK to avoid optimizations in ValidateTree
+     * that assume the root borderClip can't change well, normally
+     * it doesn't...)
+     */
+    if (enable)
+    {
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = pScreen->width;
+	box.y2 = pScreen->height;
+	REGION_INIT (pScreen, &pWin->winSize, &box, 1);
+	REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
+	if (WasViewable)
+	    REGION_RESET(pScreen, &pWin->borderClip, &box);
+	pWin->drawable.width = pScreen->width;
+	pWin->drawable.height = pScreen->height;
+        REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    else
+    {
+	REGION_EMPTY(pScreen, &pWin->borderClip);
+	REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    
+    ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
+    
+    if (WasViewable)
+    {
+	if (pWin->backStorage)
+	{
+	    pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+	    REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+	}
+
+	if (pWin->firstChild)
+	{
+	    anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
+							   pWin->firstChild,
+							   (WindowPtr *)NULL);
+	}
+	else
+	{
+	    (*pScreen->MarkWindow) (pWin);
+	    anyMarked = TRUE;
+	}
+
+#ifdef DO_SAVE_UNDERS
+	if (DO_SAVE_UNDERS(pWin))
+	{
+	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
+	}
+#endif /* DO_SAVE_UNDERS */
+
+	if (anyMarked)
+	    (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
+    }
+
+    if (pWin->backStorage &&
+	((pWin->backingStore == Always) || WasViewable))
+    {
+	if (!WasViewable)
+	    pOldClip = &pWin->clipList; /* a convenient empty region */
+	bsExposed = (*pScreen->TranslateBackingStore)
+			     (pWin, 0, 0, pOldClip,
+			      pWin->drawable.x, pWin->drawable.y);
+	if (WasViewable)
+	    REGION_DESTROY(pScreen, pOldClip);
+	if (bsExposed)
+	{
+	    RegionPtr	valExposed = NullRegion;
+    
+	    if (pWin->valdata)
+		valExposed = &pWin->valdata->after.exposed;
+	    (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+	    if (valExposed)
+		REGION_EMPTY(pScreen, valExposed);
+	    REGION_DESTROY(pScreen, bsExposed);
+	}
+    }
+    if (WasViewable)
+    {
+	if (anyMarked)
+	    (*pScreen->HandleExposures)(pWin);
+#ifdef DO_SAVE_UNDERS
+	if (dosave)
+	    (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
+#endif /* DO_SAVE_UNDERS */
+	if (anyMarked && pScreen->PostValidateTree)
+	    (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
+    }
+    if (pWin->realized)
+	WindowsRestructured ();
+    FlushAllOutput ();
+}
+#endif /* CHROMIUM */
+
+/*
+ * rfbNewClient is called when a new connection has been made by whatever
+ * means.
+ */
+
+static rfbClientPtr
+rfbNewClient(ScreenPtr pScreen, int sock)
+{
+    rfbProtocolVersionMsg pv;
+    rfbClientPtr cl;
+    BoxRec box;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
+    VNCSCREENPTR(pScreen);
+    int i;
+
+    if (rfbClientHead == NULL) {
+	/* no other clients - make sure we don't think any keys are pressed */
+	KbdReleaseAllKeys();
+    } else {
+	rfbLog("  (other clients");
+	for (cl = rfbClientHead; cl; cl = cl->next) {
+	    rfbLog(" %s",cl->host);
+	}
+	rfbLog(")\n");
+    }
+
+    cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec));
+
+#ifdef CHROMIUM
+    cl->chromium_port = 0; /* no GL application on this port, yet */
+#endif
+    cl->userAccepted = 0; /* user hasn't even approached this yet .... */
+    cl->sock = sock;
+    getpeername(sock, (struct sockaddr *)&addr, &addrlen);
+    cl->host = strdup(inet_ntoa(addr.sin_addr));
+    cl->login = NULL;
+
+    /* Dispatch client input to rfbProcessClientProtocolVersion(). */
+    cl->state = RFB_PROTOCOL_VERSION;
+
+    cl->viewOnly = FALSE;
+    cl->reverseConnection = FALSE;
+    cl->readyForSetColourMapEntries = FALSE;
+    cl->useCopyRect = FALSE;
+    cl->preferredEncoding = rfbEncodingRaw;
+    cl->correMaxWidth = 48;
+    cl->correMaxHeight = 48;
+    cl->pScreen = pScreen;
+
+    REGION_NULL(pScreen,&cl->copyRegion);
+    cl->copyDX = 0;
+    cl->copyDY = 0;
+
+    box.x1 = box.y1 = 0;
+    box.x2 = pVNC->width;
+    box.y2 = pVNC->height;
+    REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
+
+    REGION_NULL(pScreen,&cl->requestedRegion);
+
+    cl->deferredUpdateScheduled = FALSE;
+    cl->deferredUpdateTimer = NULL;
+
+    cl->format = pVNC->rfbServerFormat;
+    cl->translateFn = rfbTranslateNone;
+    cl->translateLookupTable = NULL;
+
+    cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+    cl->tightQualityLevel = -1;
+    for (i = 0; i < 4; i++)
+        cl->zsActive[i] = FALSE;
+
+    cl->enableCursorShapeUpdates = FALSE;
+    cl->enableCursorPosUpdates = FALSE;
+    cl->enableLastRectEncoding = FALSE;
+#ifdef CHROMIUM
+    cl->enableChromiumEncoding = FALSE;
+#endif
+
+    cl->next = rfbClientHead;
+    rfbClientHead = cl;
+
+    rfbResetStats(cl);
+
+    cl->compStreamInited = FALSE;
+    cl->compStream.total_in = 0;
+    cl->compStream.total_out = 0;
+    cl->compStream.zalloc = Z_NULL;
+    cl->compStream.zfree = Z_NULL;
+    cl->compStream.opaque = Z_NULL;
+
+    cl->zlibCompressLevel = 5;
+
+    sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
+	    rfbProtocolMinorVersion);
+
+    if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) {
+	rfbLogPerror("rfbNewClient: write");
+	rfbCloseSock(pScreen, sock);
+	return NULL;
+    }
+
+    return cl;
+}
+
+
+/*
+ * rfbClientConnectionGone is called from sockets.c just after a connection
+ * has gone away.
+ */
+
+void
+rfbClientConnectionGone(sock)
+    int sock;
+{
+    rfbClientPtr cl, prev;
+    int i;
+#if XFREE86VNC
+    int allowvt = TRUE;
+#endif
+
+    for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) {
+	if (sock == cl->sock)
+	    break;
+    }
+
+    if (!cl) {
+	rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock);
+	return;
+    }
+
+    if (cl->login != NULL) {
+	rfbLog("Client %s (%s) gone\n", cl->login, cl->host);
+	free(cl->login);
+    } else {
+	rfbLog("Client %s gone\n", cl->host);
+    }
+    free(cl->host);
+
+    /* Release the compression state structures if any. */
+    if ( cl->compStreamInited == TRUE ) {
+	deflateEnd( &(cl->compStream) );
+    }
+
+    for (i = 0; i < 4; i++) {
+	if (cl->zsActive[i])
+	    deflateEnd(&cl->zsStruct[i]);
+    }
+
+    if (pointerClient == cl)
+	pointerClient = NULL;
+
+#ifdef CORBA
+    destroyConnection(cl);
+#endif
+
+    if (prev)
+	prev->next = cl->next;
+    else
+	rfbClientHead = cl->next;
+
+    REGION_UNINIT(cl->pScreen,&cl->copyRegion);
+    REGION_UNINIT(cl->pScreen,&cl->modifiedRegion);
+    TimerFree(cl->deferredUpdateTimer);
+
+    rfbPrintStats(cl);
+
+    if (cl->translateLookupTable) free(cl->translateLookupTable);
+
+    xfree(cl);
+
+    GenerateVncDisconnectedEvent(sock);
+
+#if XFREE86VNC
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	/* still someone connected */
+	allowvt = FALSE;
+    }
+
+    xf86EnableVTSwitch(allowvt);
+#endif
+}
+
+
+/*
+ * rfbProcessClientMessage is called when there is data to read from a client.
+ */
+
+void
+rfbProcessClientMessage(ScreenPtr pScreen, int sock)
+{
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+	if (sock == cl->sock)
+	    break;
+    }
+
+    if (!cl) {
+	rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock);
+	rfbCloseSock(pScreen, sock);
+	return;
+    }
+
+#ifdef CORBA
+    if (isClosePending(cl)) {
+	rfbLog("Closing connection to client %s\n", cl->host);
+	rfbCloseSock(pScreen, sock);
+	return;
+    }
+#endif
+
+    switch (cl->state) {
+    case RFB_PROTOCOL_VERSION:
+	rfbProcessClientProtocolVersion(cl);
+	break;
+    case RFB_SECURITY_TYPE:	/* protocol 3.7 */
+	rfbProcessClientSecurityType(cl);
+	break;
+    case RFB_TUNNELING_TYPE:	/* protocol 3.7t */
+	rfbProcessClientTunnelingType(cl);
+	break;
+    case RFB_AUTH_TYPE:		/* protocol 3.7t */
+	rfbProcessClientAuthType(cl);
+	break;
+    case RFB_AUTHENTICATION:
+	rfbVncAuthProcessResponse(cl);
+	break;
+    case RFB_INITIALISATION:
+	rfbProcessClientInitMessage(cl);
+	break;
+    default:
+	rfbProcessClientNormalMessage(cl);
+    }
+}
+
+
+/*
+ * rfbProcessClientProtocolVersion is called when the client sends its
+ * protocol version.
+ */
+
+static void
+rfbProcessClientProtocolVersion(cl)
+    rfbClientPtr cl;
+{
+    rfbProtocolVersionMsg pv;
+    int n, major, minor;
+
+    if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientProtocolVersion: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientProtocolVersion: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    pv[sz_rfbProtocolVersionMsg] = 0;
+    if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
+	rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    rfbLog("Using protocol version %d.%d\n", major, minor);
+
+    if (major != rfbProtocolMajorVersion) {
+	rfbLog("RFB protocol version mismatch - server %d.%d, client %d.%d\n",
+		rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Always use one of the two standard versions of the RFB protocol. */
+    cl->protocol_minor_ver = minor;
+    if (minor > rfbProtocolMinorVersion) {
+	cl->protocol_minor_ver = rfbProtocolMinorVersion;
+    } else if (minor < rfbProtocolMinorVersion) {
+	cl->protocol_minor_ver = rfbProtocolFallbackMinorVersion;
+    }
+    if (minor != rfbProtocolMinorVersion &&
+	minor != rfbProtocolFallbackMinorVersion) {
+	rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n",
+	       major, minor, rfbProtocolMajorVersion, cl->protocol_minor_ver);
+    }
+ 
+    /* TightVNC protocol extensions are not enabled yet. */
+    cl->protocol_tightvnc = FALSE;
+
+    rfbAuthNewClient(cl);
+}
+
+/*
+ * rfbClientConnFailed is called when a client connection has failed
+ * before the authentication stage.
+ */
+
+void
+rfbClientConnFailed(cl, reason)
+    rfbClientPtr cl;
+    char *reason;
+{
+    int headerLen, reasonLen;
+    char buf[8];
+
+    headerLen = (cl->protocol_minor_ver >= 7) ? 1 : 4;
+    reasonLen = strlen(reason);
+    ((CARD32 *)buf)[0] = 0;
+    ((CARD32 *)buf)[1] = Swap32IfLE(reasonLen);
+
+    if ( WriteExact(cl->sock, buf, headerLen) < 0 ||
+	 WriteExact(cl->sock, buf + 4, 4) < 0 ||
+	 WriteExact(cl->sock, reason, reasonLen) < 0 ) {
+	rfbLogPerror("rfbClientConnFailed: write");
+    }
+
+    rfbCloseSock(cl->pScreen, cl->sock);
+}
+
+
+/*
+ * rfbProcessClientInitMessage is called when the client sends its
+ * initialisation message.
+ */
+
+static void
+rfbProcessClientInitMessage(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbClientInitMsg ci;
+    char buf[256];
+    rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
+    struct passwd *user;
+    int len, n;
+    rfbClientPtr otherCl, nextCl;
+
+    if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
+	if (n == 0)
+	    rfbLog("rfbProcessClientInitMessage: client gone\n");
+	else
+	    rfbLogPerror("rfbProcessClientInitMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    si->framebufferWidth = Swap16IfLE(pVNC->width);
+    si->framebufferHeight = Swap16IfLE(pVNC->height);
+    si->format = pVNC->rfbServerFormat;
+    si->format.redMax = Swap16IfLE(si->format.redMax);
+    si->format.greenMax = Swap16IfLE(si->format.greenMax);
+    si->format.blueMax = Swap16IfLE(si->format.blueMax);
+
+    user = getpwuid(getuid());
+
+    if (strlen(desktopName) > 128)	/* sanity check on desktop name len */
+	desktopName[128] = 0;
+
+    if (user) {
+	sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)",
+		user->pw_name, desktopName, rfbThisHost, display);
+    } else {
+	sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)",
+		desktopName, rfbThisHost, display);
+    }
+    len = strlen(buf + sz_rfbServerInitMsg);
+    si->nameLength = Swap32IfLE(len);
+
+    if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) {
+	rfbLogPerror("rfbProcessClientInitMessage: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    if (cl->protocol_tightvnc)
+	rfbSendInteractionCaps(cl); /* protocol 3.7t */
+
+    /* Dispatch client input to rfbProcessClientNormalMessage(). */
+    cl->state = RFB_NORMAL;
+
+    if (!cl->reverseConnection &&
+	(pVNC->rfbNeverShared || (!pVNC->rfbAlwaysShared && !ci.shared))) {
+
+	if (pVNC->rfbDontDisconnect) {
+	    for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) {
+		if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+		    rfbLog("-dontdisconnect: Not shared & existing client\n");
+		    rfbLog("  refusing new client %s\n", cl->host);
+		    rfbCloseSock(cl->pScreen, cl->sock);
+		    return;
+		}
+	    }
+	} else {
+	    for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) {
+		nextCl = otherCl->next;
+		if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
+		    rfbLog("Not shared - closing connection to client %s\n",
+			   otherCl->host);
+		    rfbCloseSock(otherCl->pScreen, otherCl->sock);
+		}
+	    }
+	}
+    }
+}
+
+
+/*
+ * rfbSendInteractionCaps is called after sending the server
+ * initialisation message, only if the protocol version is 3.130.
+ * In this function, we send the lists of supported protocol messages
+ * and encodings.
+ */
+
+/* Update these constants on changing capability lists below! */
+#define N_SMSG_CAPS  0
+#define N_CMSG_CAPS  0
+#define N_ENC_CAPS  12
+
+void
+rfbSendInteractionCaps(cl)
+    rfbClientPtr cl;
+{
+    rfbInteractionCapsMsg intr_caps;
+    rfbCapabilityInfo enc_list[N_ENC_CAPS];
+    int i;
+
+    /* Fill in the header structure sent prior to capability lists. */
+    intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
+    intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
+    intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
+    intr_caps.pad = 0;
+
+    /* Supported server->client message types. */
+    /* For future file transfer support:
+    i = 0;
+    SetCapInfo(&smsg_list[i++], rfbFileListData,           rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileDownloadData,       rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileUploadCancel,       rfbTightVncVendor);
+    SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed,     rfbTightVncVendor);
+    if (i != N_SMSG_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    */
+
+    /* Supported client->server message types. */
+    /* For future file transfer support:
+    i = 0;
+    SetCapInfo(&cmsg_list[i++], rfbFileListRequest,        rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest,    rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest,      rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadData,         rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel,     rfbTightVncVendor);
+    SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed,       rfbTightVncVendor);
+    if (i != N_CMSG_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+    */
+
+    /* Encoding types. */
+    i = 0;
+    SetCapInfo(&enc_list[i++],  rfbEncodingCopyRect,       rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingRRE,            rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingCoRRE,          rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingHextile,        rfbStandardVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingZlib,           rfbTridiaVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingTight,          rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingCompressLevel0, rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingQualityLevel0,  rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingXCursor,        rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingRichCursor,     rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingPointerPos,     rfbTightVncVendor);
+    SetCapInfo(&enc_list[i++],  rfbEncodingLastRect,       rfbTightVncVendor);
+    if (i != N_ENC_CAPS) {
+	rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Send header and capability lists */
+    if (WriteExact(cl->sock, (char *)&intr_caps,
+		   sz_rfbInteractionCapsMsg) < 0 ||
+	WriteExact(cl->sock, (char *)&enc_list[0],
+		   sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
+	rfbLogPerror("rfbSendInteractionCaps: write");
+    	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    /* Dispatch client input to rfbProcessClientNormalMessage(). */
+    cl->state = RFB_NORMAL;
+}
+
+
+/*
+ * rfbProcessClientNormalMessage is called when the client has sent a normal
+ * protocol message.
+ */
+
+static void
+rfbProcessClientNormalMessage(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int n;
+    rfbClientToServerMsg msg;
+    char *str;
+
+    if (pVNC->rfbUserAccept) {
+	/* 
+	 * We've asked for another level of user authentication
+	 * If the user has not validated this connected, don't
+	 * process it.
+	 */
+	/*
+ 	 * NOTE: we do it here, so the vncviewer knows it's
+	 * connected, but waiting for the first screen update
+	 */
+	if (cl->userAccepted == VNC_USER_UNDEFINED) {
+	    usleep(10);
+	    return;
+	}
+	if (cl->userAccepted == VNC_USER_DISCONNECT) {
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+    }
+
+    if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) {
+	if (n != 0)
+	    rfbLogPerror("rfbProcessClientNormalMessage: read");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+
+    switch (msg.type) {
+
+    case rfbSetPixelFormat:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbSetPixelFormatMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
+	cl->format.depth = msg.spf.format.depth;
+	cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0);
+	cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0);
+	cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
+	cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
+	cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
+	cl->format.redShift = msg.spf.format.redShift;
+	cl->format.greenShift = msg.spf.format.greenShift;
+	cl->format.blueShift = msg.spf.format.blueShift;
+
+	cl->readyForSetColourMapEntries = TRUE;
+
+	rfbSetTranslateFunction(cl);
+	return;
+
+
+    case rfbFixColourMapEntries:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+	rfbLog("rfbProcessClientNormalMessage: %s",
+		"FixColourMapEntries unsupported\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+
+
+    case rfbSetEncodings:
+    {
+	int i;
+	CARD32 enc;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbSetEncodingsMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
+
+	cl->preferredEncoding = -1;
+	cl->useCopyRect = FALSE;
+	cl->enableCursorShapeUpdates = FALSE;
+	cl->enableCursorPosUpdates = FALSE;
+	cl->enableLastRectEncoding = FALSE;
+#ifdef CHROMIUM
+	cl->enableChromiumEncoding = FALSE;
+#endif
+	cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
+	cl->tightQualityLevel = -1;
+
+	for (i = 0; i < msg.se.nEncodings; i++) {
+	    if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) {
+		if (n != 0)
+		    rfbLogPerror("rfbProcessClientNormalMessage: read");
+		rfbCloseSock(cl->pScreen, cl->sock);
+		return;
+	    }
+	    enc = Swap32IfLE(enc);
+
+	    switch (enc) {
+
+	    case rfbEncodingCopyRect:
+		cl->useCopyRect = TRUE;
+		rfbLog("Using copyrect encoding for client %s\n",
+			   cl->host);
+		break;
+	    case rfbEncodingRaw:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using raw encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingRRE:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using rre encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingCoRRE:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using CoRRE encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingHextile:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using hextile encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingZlib:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using zlib encoding for client %s\n",
+			   cl->host);
+		}
+              break;
+	    case rfbEncodingTight:
+		if (cl->preferredEncoding == -1) {
+		    cl->preferredEncoding = enc;
+		    rfbLog("Using tight encoding for client %s\n",
+			   cl->host);
+		}
+		break;
+	    case rfbEncodingXCursor:
+		rfbLog("Enabling X-style cursor updates for client %s\n",
+		       cl->host);
+		cl->enableCursorShapeUpdates = TRUE;
+		cl->useRichCursorEncoding = FALSE;
+		cl->cursorWasChanged = TRUE;
+		break;
+	    case rfbEncodingRichCursor:
+		if (!cl->enableCursorShapeUpdates) {
+		    rfbLog("Enabling full-color cursor updates for client "
+			   "%s\n", cl->host);
+		    cl->enableCursorShapeUpdates = TRUE;
+		    cl->useRichCursorEncoding = TRUE;
+		    cl->cursorWasChanged = TRUE;
+		}
+		break;
+	    case rfbEncodingPointerPos:
+		if (!cl->enableCursorPosUpdates) {
+		    rfbLog("Enabling cursor position updates for client %s\n",
+			   cl->host);
+		    cl->enableCursorPosUpdates = TRUE;
+		    cl->cursorWasMoved = TRUE;
+		    cl->cursorX = -1;
+		    cl->cursorY = -1;
+		}
+	        break;
+	    case rfbEncodingLastRect:
+		if (!cl->enableLastRectEncoding) {
+		    rfbLog("Enabling LastRect protocol extension for client "
+			   "%s\n", cl->host);
+		    cl->enableLastRectEncoding = TRUE;
+		}
+		break;
+#ifdef CHROMIUM
+	    case rfbEncodingChromium:
+	    case rfbEncodingChromium2:
+		if (!cl->enableChromiumEncoding) {
+		    cl->enableChromiumEncoding = TRUE;
+		    /* This tells OpenGL apps/replicate SPUs that new viewer
+                     * has attached.
+                     */
+    		    GenerateVncChromiumConnectedEvent(cl->sock);
+                    if (enc == rfbEncodingChromium) {
+                        /* Generate exposures for all windows */
+                        WindowPtr pWin = WindowTable[cl->pScreen->myNum];
+                        rfbSetClip(pWin, 1);
+                    }
+                    else {
+                        /* don't generate exposures for Chromium2 because
+                         * that confused DMX.
+                         */
+                    }
+		}
+		break;
+#endif
+	    default:
+		if ( enc >= (CARD32)rfbEncodingCompressLevel0 &&
+		     enc <= (CARD32)rfbEncodingCompressLevel9 ) {
+		    cl->zlibCompressLevel = enc & 0x0F;
+		    cl->tightCompressLevel = enc & 0x0F;
+		    rfbLog("Using compression level %d for client %s\n",
+			   cl->tightCompressLevel, cl->host);
+		} else if ( enc >= (CARD32)rfbEncodingQualityLevel0 &&
+			    enc <= (CARD32)rfbEncodingQualityLevel9 ) {
+		    cl->tightQualityLevel = enc & 0x0F;
+		    rfbLog("Using image quality level %d for client %s\n",
+			   cl->tightQualityLevel, cl->host);
+		} else {
+		    rfbLog("rfbProcessClientNormalMessage: ignoring unknown "
+			   "encoding %d\n", (int)enc);
+		}
+	    }
+	}
+
+	if (cl->preferredEncoding == -1) {
+	    cl->preferredEncoding = rfbEncodingRaw;
+ 	    rfbLog("No encoding specified - using raw encoding for client %s\n",
+			   cl->host);
+	}
+
+	if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
+	    rfbLog("Disabling cursor position updates for client %s\n",
+		   cl->host);
+	    cl->enableCursorPosUpdates = FALSE;
+	}
+
+#if XFREE86VNC
+	/*
+	 * With XFree86 and the hardware cursor's we need to put up the
+	 * cursor again, and if we've detected a cursor shapeless client
+	 * we need to disable hardware cursors.
+	 */
+	if (!cl->enableCursorShapeUpdates)
+	    pVNC->SWCursor = (Bool *)TRUE;
+	else
+	    pVNC->SWCursor = (Bool *)FALSE;
+
+	{
+		int x, y;
+		miPointerPosition(&x, &y);
+		(*pVNC->spriteFuncs->SetCursor)(cl->pScreen, pVNC->pCurs, x, y);
+	}
+#endif
+
+	return;
+    }
+
+
+    case rfbFramebufferUpdateRequest:
+    {
+	RegionRec tmpRegion;
+	BoxRec box;
+
+#ifdef CORBA
+	addCapability(cl, DISPLAY_DEVICE);
+#endif
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	box.x1 = Swap16IfLE(msg.fur.x);
+	box.y1 = Swap16IfLE(msg.fur.y);
+	box.x2 = box.x1 + Swap16IfLE(msg.fur.w);
+	box.y2 = box.y1 + Swap16IfLE(msg.fur.h);
+	SAFE_REGION_INIT(cl->pScreen,&tmpRegion,&box,0);
+
+	REGION_UNION(cl->pScreen, &cl->requestedRegion, &cl->requestedRegion,
+		     &tmpRegion);
+
+	if (!cl->readyForSetColourMapEntries) {
+	    /* client hasn't sent a SetPixelFormat so is using server's */
+	    cl->readyForSetColourMapEntries = TRUE;
+	    if (!cl->format.trueColour) {
+		if (!rfbSetClientColourMap(cl, 0, 0)) {
+		    REGION_UNINIT(cl->pScreen,&tmpRegion);
+		    return;
+		}
+	    }
+	}
+
+	if (!msg.fur.incremental) {
+	    REGION_UNION(cl->pScreen,&cl->modifiedRegion,&cl->modifiedRegion,
+			 &tmpRegion);
+	    REGION_SUBTRACT(cl->pScreen,&cl->copyRegion,&cl->copyRegion,
+			    &tmpRegion);
+	}
+
+	if (FB_UPDATE_PENDING(cl)) {
+	    rfbSendFramebufferUpdate(cl->pScreen, cl);
+	}
+
+	REGION_UNINIT(cl->pScreen,&tmpRegion);
+	return;
+    }
+
+    case rfbKeyEvent:
+
+	cl->rfbKeyEventsRcvd++;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbKeyEventMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+#ifdef CORBA
+	addCapability(cl, KEYBOARD_DEVICE);
+
+	if (!isKeyboardEnabled(cl))
+	    return;
+#endif
+	if (!pVNC->rfbViewOnly && !cl->viewOnly) {
+	    KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl);
+	}
+	return;
+
+
+    case rfbPointerEvent:
+
+	cl->rfbPointerEventsRcvd++;
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbPointerEventMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+#ifdef CORBA
+	addCapability(cl, POINTER_DEVICE);
+
+	if (!isPointerEnabled(cl))
+	    return;
+#endif
+
+	if (pointerClient && (pointerClient != cl))
+	    return;
+
+	if (msg.pe.buttonMask == 0)
+	    pointerClient = NULL;
+	else
+	    pointerClient = cl;
+
+	if (!pVNC->rfbViewOnly && !cl->viewOnly) {
+	    cl->cursorX = (int)Swap16IfLE(msg.pe.x);
+            cl->cursorY = (int)Swap16IfLE(msg.pe.y);
+	    PtrAddEvent(msg.pe.buttonMask, cl->cursorX, cl->cursorY, cl);
+	}
+	return;
+
+
+    case rfbClientCutText:
+
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbClientCutTextMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	msg.cct.length = Swap32IfLE(msg.cct.length);
+
+	str = (char *)xalloc(msg.cct.length);
+
+	if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    xfree(str);
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* NOTE: We do not accept cut text from a view-only client */
+	if (!cl->viewOnly)
+	    rfbSetXCutText(str, msg.cct.length);
+
+	xfree(str);
+	return;
+
+#ifdef CHROMIUM
+    case rfbChromiumStop:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbChromiumStopMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* would we use msg.csd.port ??? */
+
+	cl->chromium_port = 0;
+
+	/* tear down window information */
+    	{
+	    CRWindowTable *wt, *nextWt = NULL;
+
+   	    for (wt = windowTable; wt; wt = nextWt) {
+   	 	nextWt = wt->next;
+		xfree(wt);
+	    }
+
+	    windowTable = NULL;
+	}
+
+	return;
+
+    case rfbChromiumExpose:
+	if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
+			   sz_rfbChromiumExposeMsg - 1)) <= 0) {
+	    if (n != 0)
+		rfbLogPerror("rfbProcessClientNormalMessage: read");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return;
+	}
+
+	/* find the window and re-expose it */
+    	{
+	    CRWindowTable *wt, *nextWt = NULL;
+
+   	    for (wt = windowTable; wt; wt = nextWt) {
+   	 	nextWt = wt->next;
+		if (wt->CRwinId == msg.cse.winid) {
+			WindowPtr pWin;
+	    		pWin = LookupIDByType(wt->XwinId, RT_WINDOW);
+			if (pWin) {
+				miSendExposures(pWin, &pWin->clipList,
+						pWin->drawable.x,
+						pWin->drawable.y);
+				FlushAllOutput();
+			}
+		}
+	    }
+	}
+
+	return;
+#endif
+
+    default:
+
+	rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
+		msg.type);
+	rfbLog(" ... closing connection\n");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return;
+    }
+}
+
+
+
+/*
+ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
+ * the RFB client.
+ */
+
+Bool
+rfbSendFramebufferUpdate(pScreen, cl)
+    ScreenPtr pScreen;
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(pScreen);
+    int i;
+    int nUpdateRegionRects;
+    rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)pVNC->updateBuf;
+    RegionRec updateRegion, updateCopyRegion;
+    int dx, dy;
+    Bool sendCursorShape = FALSE;
+    Bool sendCursorPos = FALSE;
+
+    /*
+     * If this client understands cursor shape updates, cursor should be
+     * removed from the framebuffer. Otherwise, make sure it's put up.
+     */
+
+#if !XFREE86VNC
+    if (cl->enableCursorShapeUpdates) {
+	if (pVNC->cursorIsDrawn)
+	    rfbSpriteRemoveCursor(pScreen);
+	if (!pVNC->cursorIsDrawn && cl->cursorWasChanged)
+	    sendCursorShape = TRUE;
+    } else {
+	if (!pVNC->cursorIsDrawn)
+	    rfbSpriteRestoreCursor(pScreen);
+    }
+#else
+    if (cl->enableCursorShapeUpdates)
+	if (cl->cursorWasChanged) 
+	    sendCursorShape = TRUE;
+#endif
+
+    /*
+     * Do we plan to send cursor position update?
+     */
+
+    if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
+	sendCursorPos = TRUE;
+
+    /*
+     * The modifiedRegion may overlap the destination copyRegion.  We remove
+     * any overlapping bits from the copyRegion (since they'd only be
+     * overwritten anyway).
+     */
+
+    REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
+		    &cl->modifiedRegion);
+
+    /*
+     * The client is interested in the region requestedRegion.  The region
+     * which should be updated now is the intersection of requestedRegion
+     * and the union of modifiedRegion and copyRegion.  If it's empty then
+     * no update is needed.
+     */
+
+    REGION_NULL(pScreen,&updateRegion);
+    REGION_UNION(pScreen, &updateRegion, &cl->copyRegion,
+		 &cl->modifiedRegion);
+    REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion,
+		     &updateRegion);
+
+    if ( !REGION_NOTEMPTY(pScreen,&updateRegion) &&
+	 !sendCursorShape && !sendCursorPos ) {
+	REGION_UNINIT(pScreen,&updateRegion);
+	return TRUE;
+    }
+
+    /*
+     * We assume that the client doesn't have any pixel data outside the
+     * requestedRegion.  In other words, both the source and destination of a
+     * copy must lie within requestedRegion.  So the region we can send as a
+     * copy is the intersection of the copyRegion with both the requestedRegion
+     * and the requestedRegion translated by the amount of the copy.  We set
+     * updateCopyRegion to this.
+     */
+
+    REGION_NULL(pScreen,&updateCopyRegion);
+    REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion,
+		     &cl->requestedRegion);
+    REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY);
+    REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion,
+		     &cl->requestedRegion);
+    dx = cl->copyDX;
+    dy = cl->copyDY;
+
+    /*
+     * Next we remove updateCopyRegion from updateRegion so that updateRegion
+     * is the part of this update which is sent as ordinary pixel data (i.e not
+     * a copy).
+     */
+
+    REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion);
+
+    /*
+     * Finally we leave modifiedRegion to be the remainder (if any) of parts of
+     * the screen which are modified but outside the requestedRegion.  We also
+     * empty both the requestedRegion and the copyRegion - note that we never
+     * carry over a copyRegion for a future update.
+     */
+
+    REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		 &cl->copyRegion);
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &updateRegion);
+    REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
+		    &updateCopyRegion);
+
+    REGION_EMPTY(pScreen, &cl->requestedRegion);
+    REGION_EMPTY(pScreen, &cl->copyRegion);
+    cl->copyDX = 0;
+    cl->copyDY = 0;
+
+    /*
+     * Now send the update.
+     */
+
+    cl->rfbFramebufferUpdateMessagesSent++;
+
+    if (cl->preferredEncoding == rfbEncodingCoRRE) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1)
+				     * ((h-1) / cl->correMaxHeight + 1));
+	}
+    } else if (cl->preferredEncoding == rfbEncodingZlib) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1);
+	}
+    } else if (cl->preferredEncoding == rfbEncodingTight) {
+	nUpdateRegionRects = 0;
+
+	for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	    int x = REGION_RECTS(&updateRegion)[i].x1;
+	    int y = REGION_RECTS(&updateRegion)[i].y1;
+	    int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	    int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+	    int n = rfbNumCodedRectsTight(cl, x, y, w, h);
+	    if (n == 0) {
+		nUpdateRegionRects = 0xFFFF;
+		break;
+	    }
+	    nUpdateRegionRects += n;
+	}
+    } else {
+	nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion);
+    }
+
+    fu->type = rfbFramebufferUpdate;
+    if (nUpdateRegionRects != 0xFFFF) {
+	fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) +
+				nUpdateRegionRects +
+				!!sendCursorShape + !!sendCursorPos);
+    } else {
+	fu->nRects = 0xFFFF;
+    }
+    pVNC->ublen = sz_rfbFramebufferUpdateMsg;
+
+    if (sendCursorShape) {
+	cl->cursorWasChanged = FALSE;
+	if (!rfbSendCursorShape(cl, pScreen))
+	    return FALSE;
+    }
+
+    if (sendCursorPos) {
+	cl->cursorWasMoved = FALSE;
+	if (!rfbSendCursorPos(cl, pScreen))
+ 	    return FALSE;
+    }
+
+    if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) {
+	if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) {
+	    REGION_UNINIT(pScreen,&updateRegion);
+	    REGION_UNINIT(pScreen,&updateCopyRegion);
+	    return FALSE;
+	}
+    }
+
+    REGION_UNINIT(pScreen,&updateCopyRegion);
+
+    for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
+	int x = REGION_RECTS(&updateRegion)[i].x1;
+	int y = REGION_RECTS(&updateRegion)[i].y1;
+	int w = REGION_RECTS(&updateRegion)[i].x2 - x;
+	int h = REGION_RECTS(&updateRegion)[i].y2 - y;
+
+	cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
+				      + w * (cl->format.bitsPerPixel / 8) * h);
+
+	switch (cl->preferredEncoding) {
+	case rfbEncodingRaw:
+	    if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingRRE:
+	    if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingCoRRE:
+	    if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingHextile:
+	    if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingZlib:
+	    if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	case rfbEncodingTight:
+	    if (!rfbSendRectEncodingTight(cl, x, y, w, h)) {
+		REGION_UNINIT(pScreen,&updateRegion);
+		return FALSE;
+	    }
+	    break;
+	}
+    }
+
+    REGION_UNINIT(pScreen,&updateRegion);
+
+    if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl))
+	return FALSE;
+
+    if (!rfbSendUpdateBuf(cl))
+	return FALSE;
+
+    return TRUE;
+}
+
+
+
+/*
+ * Send the copy region as a string of CopyRect encoded rectangles.
+ * The only slightly tricky thing is that we should send the messages in
+ * the correct order so that an earlier CopyRect will not corrupt the source
+ * of a later one.
+ */
+
+static Bool
+rfbSendCopyRegion(cl, reg, dx, dy)
+    rfbClientPtr cl;
+    RegionPtr reg;
+    int dx, dy;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand;
+    int x, y, w, h;
+    rfbFramebufferUpdateRectHeader rect;
+    rfbCopyRect cr;
+
+    nrects = REGION_NUM_RECTS(reg);
+
+    if (dx <= 0) {
+	x_inc = 1;
+    } else {
+	x_inc = -1;
+    }
+
+    if (dy <= 0) {
+	thisRect = 0;
+	y_inc = 1;
+    } else {
+	thisRect = nrects - 1;
+	y_inc = -1;
+    }
+
+    while (nrects > 0) {
+
+	firstInNextBand = thisRect;
+	nrectsInBand = 0;
+
+	while ((nrects > 0) &&
+	       (REGION_RECTS(reg)[firstInNextBand].y1
+		== REGION_RECTS(reg)[thisRect].y1))
+	{
+	    firstInNextBand += y_inc;
+	    nrects--;
+	    nrectsInBand++;
+	}
+
+	if (x_inc != y_inc) {
+	    thisRect = firstInNextBand - y_inc;
+	}
+
+	while (nrectsInBand > 0) {
+	    if ((pVNC->ublen + sz_rfbFramebufferUpdateRectHeader
+		 + sz_rfbCopyRect) > UPDATE_BUF_SIZE)
+	    {
+		if (!rfbSendUpdateBuf(cl))
+		    return FALSE;
+	    }
+
+	    x = REGION_RECTS(reg)[thisRect].x1;
+	    y = REGION_RECTS(reg)[thisRect].y1;
+	    w = REGION_RECTS(reg)[thisRect].x2 - x;
+	    h = REGION_RECTS(reg)[thisRect].y2 - y;
+
+	    rect.r.x = Swap16IfLE(x);
+	    rect.r.y = Swap16IfLE(y);
+	    rect.r.w = Swap16IfLE(w);
+	    rect.r.h = Swap16IfLE(h);
+	    rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
+
+	    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+		   sz_rfbFramebufferUpdateRectHeader);
+	    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+	    cr.srcX = Swap16IfLE(x - dx);
+	    cr.srcY = Swap16IfLE(y - dy);
+
+	    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&cr, sz_rfbCopyRect);
+	    pVNC->ublen += sz_rfbCopyRect;
+
+	    cl->rfbRectanglesSent[rfbEncodingCopyRect]++;
+	    cl->rfbBytesSent[rfbEncodingCopyRect]
+		+= sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
+
+	    thisRect += x_inc;
+	    nrectsInBand--;
+	}
+
+	thisRect = firstInNextBand;
+    }
+
+    return TRUE;
+}
+
+
+/*
+ * Send a given rectangle in raw encoding (rfbEncodingRaw).
+ */
+
+Bool
+rfbSendRectEncodingRaw(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    int nlines;
+    int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
+    unsigned char *fbptr = NULL;
+    int newy = 0;
+
+    if (pVNC->useGetImage) {
+	newy = y;
+    } else {
+    	fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+    }
+
+    /* Flush the buffer to guarantee correct alignment for translateFn(). */
+    if (pVNC->ublen > 0) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingRaw);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingRaw]++;
+    cl->rfbBytesSent[rfbEncodingRaw]
+	+= sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
+
+    nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine;
+
+    while (TRUE) {
+	if (nlines > h)
+	    nlines = h;
+
+    	if (pVNC->useGetImage) {
+    	    (*cl->pScreen->GetImage)((DrawablePtr)WindowTable[cl->pScreen->myNum], x, newy, w, nlines, ZPixmap, ~0, &pVNC->updateBuf[pVNC->ublen]);
+	    newy += nlines;
+    	} else {
+	    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+			   &cl->format, fbptr, &pVNC->updateBuf[pVNC->ublen],
+			   pVNC->paddedWidthInBytes, w, nlines, x, y);
+    	}
+
+	pVNC->ublen += nlines * bytesPerLine;
+	h -= nlines;
+
+	if (h == 0)	/* rect fitted in buffer, do next one */
+	    return TRUE;
+
+	/* buffer full - flush partial rect and do another nlines */
+
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+
+	if (!pVNC->useGetImage)
+	    fbptr += (pVNC->paddedWidthInBytes * nlines);
+
+	nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine;
+	if (nlines == 0) {
+	    rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d "
+		   "bytes per line\n", bytesPerLine);
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    return FALSE;
+	}
+    }
+}
+
+
+/*
+ * Send an empty rectangle with encoding field set to value of
+ * rfbEncodingLastRect to notify client that this is the last
+ * rectangle in framebuffer update ("LastRect" extension of RFB
+ * protocol).
+ */
+
+static Bool
+rfbSendLastRectMarker(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.encoding = Swap32IfLE(rfbEncodingLastRect);
+    rect.r.x = 0;
+    rect.r.y = 0;
+    rect.r.w = 0;
+    rect.r.h = 0;
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbLastRectMarkersSent++;
+    cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+
+    return TRUE;
+}
+
+
+/*
+ * Send the contents of pVNC->updateBuf.  Returns 1 if successful, -1 if
+ * not (errno should be set).
+ */
+
+Bool
+rfbSendUpdateBuf(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+
+    /*
+    int i;
+    for (i = 0; i < pVNC->ublen; i++) {
+	rfbLog("%02x ",((unsigned char *)pVNC->updateBuf)[i]);
+    }
+    rfbLog("\n");
+    */
+
+    if (pVNC->ublen > 0 && WriteExact(cl->sock, pVNC->updateBuf, pVNC->ublen) < 0) {
+	rfbLogPerror("rfbSendUpdateBuf: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    pVNC->ublen = 0;
+    return TRUE;
+}
+
+
+
+/*
+ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
+ * client, using values from the currently installed colormap.
+ */
+
+Bool
+rfbSendSetColourMapEntries(cl, firstColour, nColours)
+    rfbClientPtr cl;
+    int firstColour;
+    int nColours;
+{
+#if !XFREE86VNC
+    VNCSCREENPTR(cl->pScreen);
+#endif
+    char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+    rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+    CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+    EntryPtr pent;
+    EntryPtr redEntry, greenEntry, blueEntry;
+    unsigned short redPart, greenPart, bluePart;
+    int i, len;
+
+    scme->type = rfbSetColourMapEntries;
+    scme->nColours = Swap16IfLE(nColours);
+
+    len = sz_rfbSetColourMapEntriesMsg;
+
+    /* PseudoColor */
+#if XFREE86VNC
+    if (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor) {
+#else
+    if (pVNC->rfbInstalledColormap->class == PseudoColor) {
+#endif
+      scme->firstColour = Swap16IfLE(firstColour);
+#if XFREE86VNC
+      pent = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[firstColour];
+#else
+      pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[firstColour];
+#endif
+      for (i = 0; i < nColours; i++) {
+  	  if (pent->fShared) {
+	      rgb[i*3] = Swap16IfLE(pent->co.shco.red->color);
+	      rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color);
+	      rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color);
+	  } else {
+	      rgb[i*3] = Swap16IfLE(pent->co.local.red);
+	      rgb[i*3+1] = Swap16IfLE(pent->co.local.green);
+	      rgb[i*3+2] = Swap16IfLE(pent->co.local.blue);
+	  }
+	  pent++;
+      }
+    }
+
+    else {
+
+      /* Break the DirectColor pixel into its r/g/b components */
+#if XFREE86VNC
+      redPart   = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->redMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetRed;
+      greenPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->greenMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetGreen;
+      bluePart  = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->blueMask)
+		  >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetBlue;
+#else
+      redPart   = (firstColour & pVNC->rfbInstalledColormap->pVisual->redMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetRed;
+      greenPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->greenMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetGreen;
+      bluePart  = (firstColour & pVNC->rfbInstalledColormap->pVisual->blueMask)
+		  >> pVNC->rfbInstalledColormap->pVisual->offsetBlue;
+#endif
+
+      /*
+       * The firstColour field is only 16 bits. To support 24-bit pixels we
+       * sneak the red component in the 8-bit padding field which we renamed
+       * to redIndex. Green and blue are in firstColour (MSB, LSB respectively).
+       */
+      scme->redIndex    = Swap16IfLE(redPart);
+      scme->firstColour = Swap16IfLE((greenPart << 8) | bluePart);
+
+#if XFREE86VNC
+      redEntry   = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[redPart];
+      greenEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->green[greenPart];
+      blueEntry  = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->blue[bluePart];
+#else
+      redEntry   = (EntryPtr)&pVNC->rfbInstalledColormap->red[redPart];
+      greenEntry = (EntryPtr)&pVNC->rfbInstalledColormap->green[greenPart];
+      blueEntry  = (EntryPtr)&pVNC->rfbInstalledColormap->blue[bluePart];
+#endif
+      for (i = 0; i < nColours; i++) {
+	  if (redEntry->fShared)
+	      rgb[i*3] = Swap16IfLE(redEntry->co.shco.red->color);
+	  else
+	      rgb[i*3] = Swap16IfLE(redEntry->co.local.red);
+
+	  if (greenEntry->fShared)
+	      rgb[i*3+1] = Swap16IfLE(greenEntry->co.shco.green->color);
+	  else
+	      rgb[i*3+1] = Swap16IfLE(greenEntry->co.local.green);
+
+	  if (blueEntry->fShared)
+	      rgb[i*3+2] = Swap16IfLE(blueEntry->co.shco.blue->color);
+	  else
+	      rgb[i*3+2] = Swap16IfLE(blueEntry->co.local.blue);
+
+	  redEntry++;
+	  greenEntry++;
+	  blueEntry++;
+      }
+    }
+
+    len += nColours * 3 * 2;
+
+    if (WriteExact(cl->sock, buf, len) < 0) {
+	rfbLogPerror("rfbSendSetColourMapEntries: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+ * rfbSendBell sends a Bell message to all the clients.
+ */
+
+void
+rfbSendBell()
+{
+    rfbClientPtr cl, nextCl;
+    rfbBellMsg b;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	b.type = rfbBell;
+	if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) {
+	    rfbLogPerror("rfbSendBell: write");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	}
+    }
+}
+
+#ifdef CHROMIUM
+#ifdef sun
+extern int inet_aton(const char *cp, struct in_addr *inp);
+#endif
+
+void
+rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort,
+                     unsigned int mothershipPort)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumStartMsg scd;
+    struct in_addr ip;
+    unsigned int vncipaddress;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	inet_aton(cl->host, &ip);
+	memcpy(&vncipaddress, &ip, sizeof(unsigned int));
+	if (ipaddress == vncipaddress /***&& !cl->chromium_port***/) {
+	    cl->chromium_port = crServerPort;
+	    cl->chromium_msport = mothershipPort;
+    	    scd.type = rfbChromiumStart;
+    	    scd.crServerPort = crServerPort;
+    	    scd.mothershipPort = mothershipPort;
+    	    if (WriteExact(cl->sock, (char *)&scd,
+		       sz_rfbChromiumStartMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumStart: write");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+    	    }
+	    /* We only start one client at at time, so break now! */
+	    break;
+	}
+    }
+}
+
+
+/**
+ * Begin monitoring the given X windowid.
+ * When we detect size/position/visibiliy changes we'll send a 
+ * rfbChromiumMoveResizeWindow, rfbChromiumClipList, or rfbChromiumWindowShow
+ * message to the VNC viewer, passing the corresponding Chromium window id.
+ */
+void
+rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long xwindowid)
+{
+    CRWindowTable *newRec, *wt, *nextWt = NULL;
+
+    if (xwindowid && !cr_windowid) {
+        /* stop monitoring the X window, remove from list */
+        CRWindowTable *prev = NULL;
+        for (wt = windowTable; wt; wt = nextWt) {
+            nextWt = wt->next;
+            if (wt->XwinId == xwindowid) {
+                /* remove */
+                if (prev)
+                    prev->next = wt->next;
+                else
+                windowTable = wt->next;
+                xfree(wt);
+            }
+            else {
+                prev = wt;
+            }
+        }
+        return;
+    }
+
+    /* See if we're already managing this window */
+    for (wt = windowTable; wt; wt = nextWt) {
+        nextWt = wt->next;
+        /* and if so, update it's window ID */
+        if (wt->CRwinId == cr_windowid) {
+            wt->XwinId = xwindowid;
+            return;
+        }
+    }
+
+    /* o.k, new window so create new slot information */
+    newRec = (CRWindowTable *)xalloc(sizeof(CRWindowTable));
+    if (!newRec) {
+        rfbLog("Out of memory allocating CRWindowTable.\n");
+        return;
+    }
+    
+    newRec->next = NULL;
+    newRec->CRwinId = cr_windowid;
+    newRec->XwinId = xwindowid;
+    newRec->clipRects = NULL;
+    newRec->numRects = 0;
+
+    if (!windowTable) {
+        windowTable = newRec;
+    }
+    else {
+        for (wt = windowTable; wt; wt = nextWt) {
+            nextWt = wt->next;
+            if (!wt->next) /* found the next slot */
+                wt->next = newRec;
+        }
+    }
+}
+
+
+void
+rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumMoveResizeWindowMsg scm;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    scm.type = rfbChromiumMoveResizeWindow;
+	    scm.winid = winid;
+	    scm.x = x;
+	    scm.y = y;
+	    scm.w = w;
+	    scm.h = h;
+    	    if (WriteExact(cl->sock, (char *)&scm,
+		       sz_rfbChromiumMoveResizeWindowMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumMoveResizeWindow: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	}
+    }
+}
+
+void
+rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumClipListMsg sccl;
+    int len = sizeof(BoxRec) * numClipRects;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    sccl.type = rfbChromiumClipList;
+	    sccl.winid = winid;
+	    sccl.length = Swap32IfLE(len);
+    	    if (WriteExact(cl->sock, (char *)&sccl,
+		       sz_rfbChromiumClipListMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumClipList: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	    if (WriteExact(cl->sock, (char *)pClipRects, len) < 0) {
+	   	rfbLogPerror("rfbSendChromiumClipList: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+	    }
+	}
+    }
+}
+
+void
+rfbSendChromiumWindowShow(unsigned int winid, unsigned int show)
+{
+    rfbClientPtr cl, nextCl;
+    rfbChromiumWindowShowMsg scws;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	if (!cl->enableChromiumEncoding)
+	    continue;
+	if (cl->chromium_port) {
+    	    scws.type = rfbChromiumWindowShow;
+	    scws.winid = winid;
+	    scws.show = show;
+    	    if (WriteExact(cl->sock, (char *)&scws,
+		       sz_rfbChromiumWindowShowMsg) < 0) {
+	    	rfbLogPerror("rfbSendChromiumWindowShow: write\n");
+	    	rfbCloseSock(cl->pScreen, cl->sock);
+		continue;
+    	    }
+	}
+    }
+}
+#endif /* CHROMIUM */
+
+/*
+ * rfbSendServerCutText sends a ServerCutText message to all the clients.
+ */
+
+void
+rfbSendServerCutText(char *str, int len)
+{
+    rfbClientPtr cl, nextCl = NULL;
+    rfbServerCutTextMsg sct;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	if (cl->state != RFB_NORMAL) continue;
+	nextCl = cl->next;
+	sct.type = rfbServerCutText;
+	sct.length = Swap32IfLE(len);
+	if (WriteExact(cl->sock, (char *)&sct,
+		       sz_rfbServerCutTextMsg) < 0) {
+	    rfbLogPerror("rfbSendServerCutText: write\n");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	    continue;
+	}
+	if (WriteExact(cl->sock, str, len) < 0) {
+	    rfbLogPerror("rfbSendServerCutText: write\n");
+	    rfbCloseSock(cl->pScreen, cl->sock);
+	}
+    }
+}
+
+
+
+
+/*****************************************************************************
+ *
+ * UDP can be used for keyboard and pointer events when the underlying
+ * network is highly reliable.  This is really here to support ORL's
+ * videotile, whose TCP implementation doesn't like sending lots of small
+ * packets (such as 100s of pen readings per second!).
+ */
+
+void
+rfbNewUDPConnection(sock)
+    int sock;
+{
+    if (write(sock, &ptrAcceleration, 1) < 0) {
+	rfbLogPerror("rfbNewUDPConnection: write");
+    }
+}
+
+/*
+ * Because UDP is a message based service, we can't read the first byte and
+ * then the rest of the packet separately like we do with TCP.  We will always
+ * get a whole packet delivered in one go, so we ask read() for the maximum
+ * number of bytes we can possibly get.
+ */
+
+void
+rfbProcessUDPInput(ScreenPtr pScreen, int sock)
+{
+    VNCSCREENPTR(pScreen);
+    int n;
+    rfbClientToServerMsg msg;
+
+    if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) {
+	if (n < 0) {
+	    rfbLogPerror("rfbProcessUDPInput: read");
+	}
+	rfbDisconnectUDPSock(pScreen);
+	return;
+    }
+
+    switch (msg.type) {
+
+    case rfbKeyEvent:
+	if (n != sz_rfbKeyEventMsg) {
+	    rfbLog("rfbProcessUDPInput: key event incorrect length\n");
+	    rfbDisconnectUDPSock(pScreen);
+	    return;
+	}
+	if (!pVNC->rfbViewOnly) {
+	    KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), 0);
+	}
+	break;
+
+    case rfbPointerEvent:
+	if (n != sz_rfbPointerEventMsg) {
+	    rfbLog("rfbProcessUDPInput: ptr event incorrect length\n");
+	    rfbDisconnectUDPSock(pScreen);
+	    return;
+	}
+	if (!pVNC->rfbViewOnly) {
+	    PtrAddEvent(msg.pe.buttonMask,
+			Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), 0);
+	}
+	break;
+
+    default:
+	rfbLog("rfbProcessUDPInput: unknown message type %d\n",
+	       msg.type);
+	rfbDisconnectUDPSock(pScreen);
+    }
+}
diff -u -rNp a/hw/xfree86/vnc/rre.c b/hw/xfree86/vnc/rre.c
--- a/hw/xfree86/vnc/rre.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/rre.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,325 @@
+/*
+ * rre.c
+ *
+ * Routines to implement Rise-and-Run-length Encoding (RRE).  This
+ * code is based on krw's original javatel rfbserver.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rfb.h"
+
+/*
+ * rreBeforeBuf contains pixel data in the client's format.
+ * rreAfterBuf contains the RRE encoded version.  If the RRE encoded version is
+ * larger than the raw data or if it exceeds rreAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int rreBeforeBufSize = 0;
+static char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static char *rreAfterBuf = NULL;
+static int rreAfterBufLen;
+
+static int subrectEncode8(CARD8 *data, int w, int h);
+static int subrectEncode16(CARD16 *data, int w, int h);
+static int subrectEncode32(CARD32 *data, int w, int h);
+static CARD32 getBgColour(char *data, int size, int bpp);
+
+
+/*
+ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
+ */
+
+Bool
+rfbSendRectEncodingRRE(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbRREHeader hdr;
+    int nSubrects;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+		   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize = (pVNC->width * pVNC->height
+		      * (cl->format.bitsPerPixel / 8));
+
+    if (rreBeforeBufSize < maxRawSize) {
+	rreBeforeBufSize = maxRawSize;
+	if (rreBeforeBuf == NULL)
+	    rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
+	else
+	    rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+    }
+
+    if (rreAfterBufSize < maxRawSize) {
+	rreAfterBufSize = maxRawSize;
+	if (rreAfterBuf == NULL)
+	    rreAfterBuf = (char *)xalloc(rreAfterBufSize);
+	else
+	    rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+    }
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, rreBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+	nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
+	break;
+    case 16:
+	nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
+	break;
+    case 32:
+	nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
+	break;
+    default:
+	rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
+	exit(1);
+    }
+	
+    if (nSubrects < 0) {
+
+	/* RRE encoding was too large, use raw */
+
+	return rfbSendRectEncodingRaw(cl, x, y, w, h);
+    }
+
+    cl->rfbRectanglesSent[rfbEncodingRRE]++;
+    cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader
+					 + sz_rfbRREHeader + rreAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingRRE);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nSubrects = Swap32IfLE(nSubrects);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader);
+    pVNC->ublen += sz_rfbRREHeader;
+
+    for (i = 0; i < rreAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > rreAfterBufLen) {
+	    bytesToCopy = rreAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * subrectEncode() encodes the given multicoloured rectangle as a background 
+ * colour overwritten by single-coloured rectangles.  It returns the number 
+ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
+ * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
+ * single-colour rectangle partition is not optimal, but does find the biggest
+ * horizontal or vertical rectangle top-left anchored to each consecutive 
+ * coordinate position.
+ *
+ * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
+ * <subrect> is [<colour><x><y><w><h>].
+ */
+
+#define DEFINE_SUBRECT_ENCODE(bpp)					      \
+static int								      \
+subrectEncode##bpp(data,w,h)						      \
+    CARD##bpp *data;							      \
+    int w;								      \
+    int h;								      \
+{									      \
+    CARD##bpp cl;							      \
+    rfbRectangle subrect;						      \
+    int x,y;								      \
+    int i,j;								      \
+    int hx=0,hy,vx=0,vy;						      \
+    int hyflag;								      \
+    CARD##bpp *seg;							      \
+    CARD##bpp *line;							      \
+    int hw,hh,vw,vh;							      \
+    int thex,they,thew,theh;						      \
+    int numsubs = 0;							      \
+    int newLen;								      \
+    CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp);		      \
+									      \
+    *((CARD##bpp*)rreAfterBuf) = bg;					      \
+									      \
+    rreAfterBufLen = (bpp/8);						      \
+									      \
+    for (y=0; y<h; y++) {						      \
+      line = data+(y*w);						      \
+      for (x=0; x<w; x++) {						      \
+        if (line[x] != bg) {						      \
+          cl = line[x];							      \
+          hy = y-1;							      \
+          hyflag = 1;							      \
+          for (j=y; j<h; j++) {						      \
+            seg = data+(j*w);						      \
+            if (seg[x] != cl) {break;}					      \
+            i = x;							      \
+            while ((seg[i] == cl) && (i < w)) i += 1;			      \
+            i -= 1;							      \
+            if (j == y) vx = hx = i;					      \
+            if (i < vx) vx = i;						      \
+            if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      \
+          }								      \
+          vy = j-1;							      \
+									      \
+          /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  \
+           *  We'll choose the bigger of the two.			      \
+           */								      \
+          hw = hx-x+1;							      \
+          hh = hy-y+1;							      \
+          vw = vx-x+1;							      \
+          vh = vy-y+1;							      \
+									      \
+          thex = x;							      \
+          they = y;							      \
+									      \
+          if ((hw*hh) > (vw*vh)) {					      \
+            thew = hw;							      \
+            theh = hh;							      \
+          } else {							      \
+            thew = vw;							      \
+            theh = vh;							      \
+          }								      \
+									      \
+          subrect.x = Swap16IfLE(thex);					      \
+          subrect.y = Swap16IfLE(they);					      \
+          subrect.w = Swap16IfLE(thew);					      \
+          subrect.h = Swap16IfLE(theh);					      \
+									      \
+	  newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle;		      \
+          if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize))     \
+	    return -1;							      \
+									      \
+	  numsubs += 1;							      \
+	  *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl;		      \
+	  rreAfterBufLen += (bpp/8);					      \
+	  memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle);      \
+	  rreAfterBufLen += sz_rfbRectangle;				      \
+									      \
+          /*								      \
+           * Now mark the subrect as done.				      \
+           */								      \
+          for (j=they; j < (they+theh); j++) {				      \
+            for (i=thex; i < (thex+thew); i++) {			      \
+              data[j*w+i] = bg;						      \
+            }								      \
+          }								      \
+        }								      \
+      }									      \
+    }									      \
+									      \
+    return numsubs;							      \
+}
+
+DEFINE_SUBRECT_ENCODE(8)
+DEFINE_SUBRECT_ENCODE(16)
+DEFINE_SUBRECT_ENCODE(32)
+
+
+/*
+ * getBgColour() gets the most prevalent colour in a byte array.
+ */
+static CARD32
+getBgColour(data,size,bpp)
+    char *data;
+    int size;
+    int bpp;
+{
+    
+#define NUMCLRS 256
+  
+  static int counts[NUMCLRS];
+  int i,j,k;
+
+  int maxcount = 0;
+  CARD8 maxclr = 0;
+
+  if (bpp != 8) {
+    if (bpp == 16) {
+      return ((CARD16 *)data)[0];
+    } else if (bpp == 32) {
+      return ((CARD32 *)data)[0];
+    } else {
+      rfbLog("getBgColour: bpp %d?\n",bpp);
+      exit(1);
+    }
+  }
+
+  for (i=0; i<NUMCLRS; i++) {
+    counts[i] = 0;
+  }
+
+  for (j=0; j<size; j++) {
+    k = (int)(((CARD8 *)data)[j]);
+    if (k >= NUMCLRS) {
+      rfbLog("getBgColour: unusual colour = %d\n", k);
+      exit(1);
+    }
+    counts[k] += 1;
+    if (counts[k] > maxcount) {
+      maxcount = counts[k];
+      maxclr = ((CARD8 *)data)[j];
+    }
+  }
+  
+  return maxclr;
+}
diff -u -rNp a/hw/xfree86/vnc/sockets.c b/hw/xfree86/vnc/sockets.c
--- a/hw/xfree86/vnc/sockets.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/sockets.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,656 @@
+/*
+ * sockets.c - deal with TCP & UDP sockets.
+ *
+ * This code should be independent of any changes in the RFB protocol.  It just
+ * deals with the X server scheduling stuff, calling rfbNewClientConnection and
+ * rfbProcessClientMessage to actually deal with the protocol.  If a socket
+ * needs to be closed for any reason then rfbCloseSock should be called, and
+ * this in turn will call rfbClientConnectionGone.  To make an active
+ * connection out, call rfbConnect - note that this does _not_ call
+ * rfbNewClientConnection.
+ *
+ * This file is divided into two types of function.  Those beginning with
+ * "rfb" are specific to sockets using the RFB protocol.  Those without the
+ * "rfb" prefix are more general socket routines (which are used by the http
+ * code).
+ *
+ * Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN
+ * not EWOULDBLOCK.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "windowstr.h"
+
+#ifndef USE_LIBWRAP
+#define USE_LIBWRAP 0
+#endif
+#if USE_LIBWRAP
+#include <syslog.h>
+#include <tcpd.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif
+
+#include "rfb.h"
+
+int rfbMaxClientWait = 20000;	/* time (ms) after which we decide client has
+				   gone away - needed to stop us hanging */
+
+static struct sockaddr_in udpRemoteAddr;
+
+/*
+ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB
+ * connections.  It does nothing if called again.
+ */
+
+Bool
+rfbInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if (inetdSock != -1) {
+	const int one = 1;
+
+	if (fcntl(inetdSock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("fcntl");
+	    return FALSE;
+	}
+
+	if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("setsockopt");
+	    return FALSE;
+	}
+
+    	AddEnabledDevice(inetdSock);
+    	FD_ZERO(&pVNC->allFds);
+    	FD_SET(inetdSock, &pVNC->allFds);
+    	pVNC->maxFd = inetdSock;
+	return TRUE;
+    }
+
+    if (pVNC->rfbPort == 0) {
+	pVNC->rfbPort = 5900 + atoi(display) + pScreen->myNum;
+    }
+
+    if ((pVNC->rfbListenSock = ListenOnTCPPort(pScreen, pVNC->rfbPort)) < 0) {
+	rfbLogPerror("ListenOnTCPPort");
+	pVNC->rfbPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for VNC connections on TCP port %d\n", pVNC->rfbPort);
+
+    AddEnabledDevice(pVNC->rfbListenSock);
+
+    FD_ZERO(&pVNC->allFds);
+    FD_SET(pVNC->rfbListenSock, &pVNC->allFds);
+    pVNC->maxFd = pVNC->rfbListenSock;
+
+    if (pVNC->udpPort != 0) {
+	rfbLog("rfbInitSockets: listening for input on UDP port %d\n",pVNC->udpPort);
+
+	if ((pVNC->udpSock = ListenOnUDPPort(pScreen, pVNC->udpPort)) < 0) {
+	    rfbLogPerror("ListenOnUDPPort");
+	    return FALSE;
+	}
+	AddEnabledDevice(pVNC->udpSock);
+	FD_SET(pVNC->udpSock, &pVNC->allFds);
+	pVNC->maxFd = max(pVNC->udpSock,pVNC->maxFd);
+    }
+   
+    return TRUE;
+}
+
+
+/*
+ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB
+ * socket(s).  If there is input to process, the appropriate function in the
+ * RFB server code will be called (rfbNewClientConnection,
+ * rfbProcessClientMessage, etc).
+ */
+
+void
+rfbCheckFds(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+#if XFREE86VNC
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+#endif
+    int nfds;
+    fd_set fds;
+    struct timeval tv;
+    struct sockaddr_in addr;
+    SOCKLEN_T addrlen = sizeof(addr);
+    char buf[6];
+    const int one = 1;
+    int sock;
+    static Bool inetdInitDone = FALSE;
+
+    if (!inetdInitDone && inetdSock != -1) {
+	rfbNewClientConnection(pScreen, inetdSock); 
+	inetdInitDone = TRUE;
+    }
+
+    memcpy((char *)&fds, (char *)&pVNC->allFds, sizeof(fd_set));
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    nfds = select(pVNC->maxFd + 1, &fds, NULL, NULL, &tv);
+    if (nfds == 0) {
+	return;
+    }
+    if (nfds < 0) {
+	if (errno != EINTR)
+		rfbLogPerror("rfbCheckFds: select");
+	return;
+    }
+
+    if (pVNC->rfbListenSock != -1 && FD_ISSET(pVNC->rfbListenSock, &fds)) {
+
+	if ((sock = accept(pVNC->rfbListenSock,
+			   (struct sockaddr *)&addr, &addrlen)) < 0) {
+	    rfbLogPerror("rfbCheckFds: accept");
+	    return;
+	}
+
+	if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	    rfbLogPerror("rfbCheckFds: fcntl");
+	    close(sock);
+	    return;
+	}
+
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		       (char *)&one, sizeof(one)) < 0) {
+	    rfbLogPerror("rfbCheckFds: setsockopt");
+	    close(sock);
+	    return;
+	}
+
+	rfbLog("\n");
+
+#if USE_LIBWRAP
+        if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr),
+                       STRING_UNKNOWN)) {
+          rfbLog("Rejected connection from client %s\n",
+                 inet_ntoa(addr.sin_addr));
+          close(sock);
+          return;
+        }
+#endif
+
+	rfbLog("Got VNC connection from client %s\n", inet_ntoa(addr.sin_addr));
+
+	AddEnabledDevice(sock);
+	FD_SET(sock, &pVNC->allFds);
+	pVNC->maxFd = max(sock,pVNC->maxFd);
+
+	rfbNewClientConnection(pScreen, sock);
+
+	FD_CLR(pVNC->rfbListenSock, &fds);
+	if (--nfds == 0)
+	    return;
+    }
+
+    if ((pVNC->udpSock != -1) && FD_ISSET(pVNC->udpSock, &fds)) {
+
+	if (recvfrom(pVNC->udpSock, buf, 1, MSG_PEEK,
+		     (struct sockaddr *)&addr, &addrlen) < 0) {
+
+	    rfbLogPerror("rfbCheckFds: UDP: recvfrom");
+	    rfbDisconnectUDPSock(pScreen);
+
+	} else {
+
+	    if (!pVNC->udpSockConnected ||
+		(memcmp(&addr, &udpRemoteAddr, addrlen) != 0))
+	    {
+		/* new remote end */
+		rfbLog("rfbCheckFds: UDP: got connection\n");
+
+		memcpy(&udpRemoteAddr, &addr, addrlen);
+		pVNC->udpSockConnected = TRUE;
+
+		if (connect(pVNC->udpSock,
+			    (struct sockaddr *)&addr, addrlen) < 0) {
+		    rfbLogPerror("rfbCheckFds: UDP: connect");
+		    rfbDisconnectUDPSock(pScreen);
+		    return;
+		}
+
+		rfbNewUDPConnection(pVNC->udpSock);
+	    }
+
+	    rfbProcessUDPInput(pScreen, pVNC->udpSock);
+	}
+
+	FD_CLR(pVNC->udpSock, &fds);
+	if (--nfds == 0)
+	    return;
+    }
+
+    for (sock = 0; sock <= pVNC->maxFd; sock++) {
+	if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &pVNC->allFds)) {
+#if XFREE86VNC
+	    if (!pScrn->vtSema)
+		rfbCloseSock(pScreen, sock);
+	    else
+#endif
+	    	rfbProcessClientMessage(pScreen, sock);
+	}
+    }
+}
+
+
+void
+rfbDisconnectUDPSock(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+    pVNC->udpSockConnected = FALSE;
+}
+
+
+void
+rfbCloseSock(ScreenPtr pScreen, int sock)
+{
+    VNCSCREENPTR(pScreen);
+    close(sock);
+    RemoveEnabledDevice(sock);
+    FD_CLR(sock, &pVNC->allFds);
+    rfbClientConnectionGone(sock);
+    if (sock == inetdSock)
+	GiveUp(0);
+}
+
+#if 0
+/*
+ * rfbWaitForClient can be called to wait for the RFB client to send us a
+ * message.  When one is received it is processed by calling
+ * rfbProcessClientMessage().
+ */
+
+void
+rfbWaitForClient(sock)
+    int sock;
+{
+    int n;
+    fd_set fds;
+    struct timeval tv;
+
+    FD_ZERO(&fds);
+    FD_SET(sock, &fds);
+    tv.tv_sec = rfbMaxClientWait / 1000;
+    tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
+    n = select(sock+1, &fds, NULL, NULL, &tv);
+    if (n < 0) {
+	rfbLogPerror("rfbWaitForClient: select");
+	exit(1);
+    }
+    if (n == 0) {
+	rfbCloseSock(sock);
+	return;
+    }
+
+    rfbProcessClientMessage(sock);
+}
+#endif
+
+/*
+ * rfbConnect is called to make a connection out to a given TCP address.
+ */
+
+int
+rfbConnect(ScreenPtr pScreen, char *host, int port)
+{
+    VNCSCREENPTR(pScreen);
+    int sock;
+    int one = 1;
+
+    rfbLog("\n");
+    rfbLog("Making connection to client on host %s port %d\n",
+	   host,port);
+
+    if ((sock = ConnectToTcpAddr(host, port)) < 0) {
+	rfbLogPerror("connection failed");
+	return -1;
+    }
+
+    if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+	rfbLogPerror("fcntl failed");
+	close(sock);
+	return -1;
+    }
+
+    if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+		   (char *)&one, sizeof(one)) < 0) {
+	rfbLogPerror("setsockopt failed");
+	close(sock);
+	return -1;
+    }
+
+    AddEnabledDevice(sock);
+    FD_SET(sock, &pVNC->allFds);
+    pVNC->maxFd = max(sock,pVNC->maxFd);
+
+    return sock;
+}
+
+
+
+
+/*
+ * ReadExact reads an exact number of bytes on a TCP socket.  Returns 1 if
+ * those bytes have been read, 0 if the other end has closed, or -1 if an error
+ * occurred (errno is set to ETIMEDOUT if it timed out).
+ */
+
+int
+ReadExact(sock, buf, len)
+    int sock;
+    char *buf;
+    int len;
+{
+    int n;
+    fd_set fds;
+    int tries = 5;
+    struct timeval tv;
+
+    while (len > 0) {
+	n = read(sock, buf, len);
+
+	if (n > 0) {
+
+	    buf += n;
+	    len -= n;
+
+	} else if (n == 0) {
+
+	    return 0;
+
+	} else {
+	    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+		return n;
+	    }
+
+	    do {
+	   	FD_ZERO(&fds);
+	    	FD_SET(sock, &fds);
+	    	tv.tv_sec = rfbMaxClientWait / 1000;
+	    	tv.tv_usec = (rfbMaxClientWait % 1000) * 1000;
+	    	n = select(sock+1, &fds, NULL, NULL, &tv);
+		tries--;
+		
+	    /* We really need to retry if we get EINTR, so spin */
+	    /* If after 5 attempts we're still broke, abort.... */
+
+	    } while ((n < 0 && errno == EINTR) && tries > 0);
+
+	    if (n < 0) {
+		rfbLogPerror("ReadExact: select");
+		return n;
+	    }
+	    if (n == 0) {
+		errno = ETIMEDOUT;
+		return -1;
+	    }
+	}
+    }
+    return 1;
+}
+
+
+
+/*
+ * WriteExact writes an exact number of bytes on a TCP socket.  Returns 1 if
+ * those bytes have been written, or -1 if an error occurred (errno is set to
+ * ETIMEDOUT if it timed out).
+ */
+
+int
+WriteExact(sock, buf, len)
+    int sock;
+    char *buf;
+    int len;
+{
+    int n;
+    fd_set fds;
+    struct timeval tv;
+    int totalTimeWaited = 0;
+
+    while (len > 0) {
+	n = write(sock, buf, len);
+
+	if (n > 0) {
+
+	    buf += n;
+	    len -= n;
+
+	} else if (n == 0) {
+
+	    rfbLog("WriteExact: write returned 0?\n");
+	    return -1;
+
+	} else {
+	    if (errno != EWOULDBLOCK && errno != EAGAIN) {
+		return n;
+	    }
+
+#if 0
+	    /* Retry every 5 seconds until we exceed rfbMaxClientWait.  We
+	       need to do this because select doesn't necessarily return
+	       immediately when the other end has gone away */
+
+	    FD_ZERO(&fds);
+	    FD_SET(sock, &fds);
+	    tv.tv_sec = 5;
+	    tv.tv_usec = 0;
+#else
+	    /* We're in the WakeupHandler now, so don't wait */
+
+	    FD_ZERO(&fds);
+	    FD_SET(sock, &fds);
+	    tv.tv_sec = 0;
+	    tv.tv_usec = 0;
+#endif
+	    n = select(sock+1, NULL, &fds, NULL, &tv);
+#if 0
+	    if (n < 0) {
+		rfbLogPerror("WriteExact: select");
+		return n;
+	    }
+	    if (n == 0) {
+		totalTimeWaited += 5000;
+		if (totalTimeWaited >= rfbMaxClientWait) {
+		    errno = ETIMEDOUT;
+		    return -1;
+		}
+	    } else {
+		totalTimeWaited = 0;
+	    }
+#endif
+	}
+    }
+    return 1;
+}
+
+
+int
+ListenOnTCPPort(ScreenPtr pScreen, int port)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    int sock;
+    int one = 1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = pVNC->interface.s_addr;
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one)) < 0) {
+	close(sock);
+	return -1;
+    }
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	close(sock);
+	return -1;
+    }
+    if (listen(sock, 5) < 0) {
+	close(sock);
+	return -1;
+    }
+
+    return sock;
+}
+
+
+int
+ConnectToTcpAddr(host, port)
+    char *host;
+    int port;
+{
+    struct hostent *hp;
+    int sock, n;
+    struct sockaddr_in addr;
+    int tries = 5;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    if ((addr.sin_addr.s_addr = inet_addr(host)) == -1)
+    {
+	if (!(hp = gethostbyname(host))) {
+	    errno = EINVAL;
+	    return -1;
+	}
+	addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
+    }
+
+    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	return -1;
+    }
+
+    do {
+    	sock = socket(AF_INET, SOCK_STREAM, 0);
+	tries--;
+
+	/* We really need to retry if we get EINTR, so spin */
+	/* If after 5 attempts we're still broke, abort.... */
+
+    } while ((sock < 0 && errno == EINTR) && tries > 0);
+
+    if (sock < 0) {
+	return -1;
+    }
+
+    tries = 5;
+
+    do {
+    	n = connect(sock, (struct sockaddr *)&addr, (sizeof(addr)));
+	tries--;
+
+	/* We really need to retry if we get EINTR, so spin */
+	/* If after 5 attempts we're still broke, abort.... */
+
+    } while ((n < 0 && errno == EINTR) && tries > 0);
+
+    if (n < 0) {
+	close(sock);
+	return -1;
+    }
+
+    return sock;
+}
+
+
+int
+ListenOnUDPPort(ScreenPtr pScreen, int port)
+{
+    VNCSCREENPTR(pScreen);
+    struct sockaddr_in addr;
+    int sock;
+    int one = 1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = pVNC->interface.s_addr;
+
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	return -1;
+    }
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+		   (char *)&one, sizeof(one)) < 0) {
+	return -1;
+    }
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	return -1;
+    }
+
+    return sock;
+}
+
+#if 0
+/*
+ * rdpInitSockets sets up the TCP for RDP
+ * connections.  It does nothing if called again.
+ */
+
+Bool
+rdpInitSockets(ScreenPtr pScreen)
+{
+    VNCSCREENPTR(pScreen);
+
+    if ((pVNC->rdpListenSock = ListenOnTCPPort(pScreen, pVNC->rdpPort)) < 0) {
+	rfbLogPerror("ListenOnTCPPort");
+	pVNC->rdpPort = 0;
+	return FALSE;
+    }
+
+    rfbLog("Listening for RDP connections on TCP port %d\n", pVNC->rdpPort);
+
+    AddEnabledDevice(pVNC->rdpListenSock);
+
+    return TRUE;
+}
+#endif
diff -u -rNp a/hw/xfree86/vnc/sprite.h b/hw/xfree86/vnc/sprite.h
--- a/hw/xfree86/vnc/sprite.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/sprite.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,141 @@
+/*
+ * sprite.h
+ *
+ * software-sprite/sprite drawing - based on misprite
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+
+Copyright (c) 1989  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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
+X CONSORTIUM 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 X Consortium 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 X Consortium.
+*/
+
+typedef struct {
+    Bool	(*RealizeCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/
+);
+    Bool	(*UnrealizeCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/
+);
+    Bool	(*PutUpCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/,
+		int /*x*/,
+		int /*y*/,
+		unsigned long /*source*/,
+		unsigned long /*mask*/
+);
+    Bool	(*SaveUnderCursor)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/
+);
+    Bool	(*RestoreUnderCursor)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/
+);
+    Bool	(*MoveCursor)(
+		ScreenPtr /*pScreen*/,
+		CursorPtr /*pCursor*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/,
+		int /*dx*/,
+		int /*dy*/,
+		unsigned long /*source*/,
+		unsigned long /*mask*/
+);
+    Bool	(*ChangeSave)(
+		ScreenPtr /*pScreen*/,
+		int /*x*/,
+		int /*y*/,
+		int /*w*/,
+		int /*h*/,
+		int /*dx*/,
+		int /*dy*/
+);
+
+} rfbSpriteCursorFuncRec, *rfbSpriteCursorFuncPtr;
+
+extern Bool rfbSpriteInitialize(
+#if NeedFunctionPrototypes
+    ScreenPtr /*pScreen*/,
+    rfbSpriteCursorFuncPtr /*cursorFuncs*/,
+    miPointerScreenFuncPtr /*screenFuncs*/
+#endif
+);
+
+extern void rfbSpriteRestoreCursor(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern void rfbSpriteRemoveCursor(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern CursorPtr rfbSpriteGetCursorPtr(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/
+#endif
+);
+
+extern void rfbSpriteGetCursorPos(
+#if NeedFunctionPrototypes
+    ScreenPtr	/*pScreen*/,
+    int *       /*px*/,
+    int *       /*py*/
+#endif
+);
diff -u -rNp a/hw/xfree86/vnc/stats.c b/hw/xfree86/vnc/stats.c
--- a/hw/xfree86/vnc/stats.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/stats.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * stats.c
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "rfb.h"
+
+static char* encNames[] = {
+    "raw", "copyRect", "RRE", "[encoding 3]", "CoRRE", "hextile",
+    "zlib", "tight", "[encoding 8]", "[encoding 9]"
+};
+
+
+void
+rfbResetStats(rfbClientPtr cl)
+{
+    int i;
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	cl->rfbBytesSent[i] = 0;
+	cl->rfbRectanglesSent[i] = 0;
+    }
+    cl->rfbLastRectMarkersSent = 0;
+    cl->rfbLastRectBytesSent = 0;
+    cl->rfbCursorShapeBytesSent = 0;
+    cl->rfbCursorShapeUpdatesSent = 0;
+    cl->rfbCursorPosBytesSent = 0;
+    cl->rfbCursorPosUpdatesSent = 0;
+    cl->rfbFramebufferUpdateMessagesSent = 0;
+    cl->rfbRawBytesEquivalent = 0;
+    cl->rfbKeyEventsRcvd = 0;
+    cl->rfbPointerEventsRcvd = 0;
+}
+
+void
+rfbPrintStats(rfbClientPtr cl)
+{
+    int i;
+    int totalRectanglesSent = 0;
+    int totalBytesSent = 0;
+
+    rfbLog("Statistics:\n");
+
+    if ((cl->rfbKeyEventsRcvd != 0) || (cl->rfbPointerEventsRcvd != 0))
+	rfbLog("  key events received %d, pointer events %d\n",
+		cl->rfbKeyEventsRcvd, cl->rfbPointerEventsRcvd);
+
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	totalRectanglesSent += cl->rfbRectanglesSent[i];
+	totalBytesSent += cl->rfbBytesSent[i];
+    }
+    totalRectanglesSent += (cl->rfbCursorShapeUpdatesSent +
+			    cl->rfbCursorPosUpdatesSent +
+			    cl->rfbLastRectMarkersSent);
+    totalBytesSent += (cl->rfbCursorShapeBytesSent +
+		       cl->rfbCursorPosBytesSent +
+		       cl->rfbLastRectBytesSent);
+
+    rfbLog("  framebuffer updates %d, rectangles %d, bytes %d\n",
+	    cl->rfbFramebufferUpdateMessagesSent, totalRectanglesSent,
+	    totalBytesSent);
+
+    if (cl->rfbLastRectMarkersSent != 0)
+	rfbLog("    LastRect markers %d, bytes %d\n",
+		cl->rfbLastRectMarkersSent, cl->rfbLastRectBytesSent);
+
+    if (cl->rfbCursorShapeUpdatesSent != 0)
+	rfbLog("    cursor shape updates %d, bytes %d\n",
+		cl->rfbCursorShapeUpdatesSent, cl->rfbCursorShapeBytesSent);
+
+    if (cl->rfbCursorPosUpdatesSent != 0)
+	rfbLog("    cursor position updates %d, bytes %d\n",
+	       cl->rfbCursorPosUpdatesSent, cl->rfbCursorPosBytesSent);
+
+    for (i = 0; i < MAX_ENCODINGS; i++) {
+	if (cl->rfbRectanglesSent[i] != 0)
+	    rfbLog("    %s rectangles %d, bytes %d\n",
+		   encNames[i], cl->rfbRectanglesSent[i], cl->rfbBytesSent[i]);
+    }
+
+    if ((totalBytesSent - cl->rfbBytesSent[rfbEncodingCopyRect]) != 0) {
+	rfbLog("  raw bytes equivalent %d, compression ratio %f\n",
+		cl->rfbRawBytesEquivalent,
+		(double)cl->rfbRawBytesEquivalent
+		/ (double)(totalBytesSent -
+			   cl->rfbBytesSent[rfbEncodingCopyRect] -
+			   cl->rfbCursorShapeBytesSent -
+			   cl->rfbCursorPosBytesSent -
+			   cl->rfbLastRectBytesSent));
+    }
+}
diff -u -rNp a/hw/xfree86/vnc/tableinitcmtemplate.c b/hw/xfree86/vnc/tableinitcmtemplate.c
--- a/hw/xfree86/vnc/tableinitcmtemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/tableinitcmtemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,89 @@
+/*
+ * tableinitcmtemplate.c - template for initialising lookup tables for
+ * translation from a colour map to true colour.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines a function which allocates an
+ * appropriately sized lookup table and initialises it.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT2E(CARD,OUT)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitColourMapSingleTableOUT \
+				CONCAT2E(rfbInitColourMapSingleTable,OUT)
+
+static void
+rfbInitColourMapSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				rfbPixelFormat *out)
+{
+    VNCSCREENPTR(pScreen);
+    int i, r, g, b;
+    OUT_T *t;
+    EntryPtr pent;
+    int nEntries = 1 << in->bitsPerPixel;
+
+    if (*table) free(*table);
+    *table = (char *)malloc(nEntries * sizeof(OUT_T));
+    t = (OUT_T *)*table;
+
+#if XFREE86VNC
+    pent = (EntryPtr)&miInstalledMaps[pScreen->myNum]->red[0];
+#else
+    pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[0];
+#endif
+
+    for (i = 0; i < nEntries; i++) {
+	if (pent->fShared) {
+	    r = pent->co.shco.red->color;
+	    g = pent->co.shco.green->color;
+	    b = pent->co.shco.blue->color;
+	} else {
+	    r = pent->co.local.red;
+	    g = pent->co.local.green;
+	    b = pent->co.local.blue;
+	}
+	t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) |
+		(((g * out->greenMax + 32767) / 65535) << out->greenShift) |
+		(((b * out->blueMax + 32767) / 65535) << out->blueShift));
+#if (OUT != 8)
+	if (out->bigEndian != in->bigEndian) {
+	    t[i] = SwapOUT(t[i]);
+	}
+#endif
+	pent++;
+    }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitColourMapSingleTableOUT
diff -u -rNp a/hw/xfree86/vnc/tableinittctemplate.c b/hw/xfree86/vnc/tableinittctemplate.c
--- a/hw/xfree86/vnc/tableinittctemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/tableinittctemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,142 @@
+/*
+ * tableinittctemplate.c - template for initialising lookup tables for
+ * truecolour to truecolour translation.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with a different definition of the macro OUT.
+ * For each value of OUT, this file defines two functions for initialising
+ * lookup tables.  One is for truecolour translation using a single lookup
+ * table, the other is for truecolour translation using three separate
+ * lookup tables for the red, green and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define OUT_T CONCAT2E(CARD,OUT)
+#define SwapOUT(x) CONCAT2E(Swap,OUT(x))
+#define rfbInitTrueColourSingleTableOUT \
+				CONCAT2E(rfbInitTrueColourSingleTable,OUT)
+#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT)
+#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT)
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+		       int swap);
+
+
+/*
+ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour
+ * translation.
+ */
+
+static void
+rfbInitTrueColourSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				 rfbPixelFormat *out)
+{
+    int i;
+    int inRed, inGreen, inBlue, outRed, outGreen, outBlue;
+    OUT_T *t;
+    int nEntries = 1 << in->bitsPerPixel;
+
+    if (*table) free(*table);
+    *table = (char *)malloc(nEntries * sizeof(OUT_T));
+    t = (OUT_T *)*table;
+
+    for (i = 0; i < nEntries; i++) {
+	inRed   = (i >> in->redShift)   & in->redMax;
+	inGreen = (i >> in->greenShift) & in->greenMax;
+	inBlue  = (i >> in->blueShift)  & in->blueMax;
+
+	outRed   = (inRed   * out->redMax   + in->redMax / 2)   / in->redMax;
+	outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax;
+	outBlue  = (inBlue  * out->blueMax  + in->blueMax / 2)  / in->blueMax;
+
+	t[i] = ((outRed   << out->redShift)   |
+		(outGreen << out->greenShift) |
+		(outBlue  << out->blueShift));
+#if (OUT != 8)
+	if (out->bigEndian != in->bigEndian) {
+	    t[i] = SwapOUT(t[i]);
+	}
+#endif
+    }
+}
+
+
+/*
+ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the
+ * red, green and blue values.
+ */
+
+static void
+rfbInitTrueColourRGBTablesOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+			       rfbPixelFormat *out)
+{
+    OUT_T *redTable;
+    OUT_T *greenTable;
+    OUT_T *blueTable;
+
+    if (*table) free(*table);
+    *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3)
+			    * sizeof(OUT_T));
+    redTable = (OUT_T *)*table;
+    greenTable = redTable + in->redMax + 1;
+    blueTable = greenTable + in->greenMax + 1;
+
+    rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax,
+			   out->redShift, (out->bigEndian != in->bigEndian));
+    rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax,
+			   out->greenShift, (out->bigEndian != in->bigEndian));
+    rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax,
+			   out->blueShift, (out->bigEndian != in->bigEndian));
+}
+
+static void
+rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift,
+		       int swap)
+{
+    int i;
+    int nEntries = inMax + 1;
+
+    for (i = 0; i < nEntries; i++) {
+	table[i] = ((i * outMax + inMax / 2) / inMax) << outShift;
+#if (OUT != 8)
+	if (swap) {
+	    table[i] = SwapOUT(table[i]);
+	}
+#endif
+    }
+}
+
+#undef OUT_T
+#undef SwapOUT
+#undef rfbInitTrueColourSingleTableOUT
+#undef rfbInitTrueColourRGBTablesOUT
+#undef rfbInitOneRGBTableOUT
diff -u -rNp a/hw/xfree86/vnc/tabletranstemplate.c b/hw/xfree86/vnc/tabletranstemplate.c
--- a/hw/xfree86/vnc/tabletranstemplate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/tabletranstemplate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,119 @@
+/*
+ * tabletranstemplate.c - template for translation using lookup tables.
+ *
+ * This file shouldn't be compiled.  It is included multiple times by
+ * translate.c, each time with different definitions of the macros IN and OUT.
+ *
+ * For each pair of values IN and OUT, this file defines two functions for
+ * translating a given rectangle of pixel data.  One uses a single lookup
+ * table, and the other uses three separate lookup tables for the red, green
+ * and blue values.
+ *
+ * I know this code isn't nice to read because of all the macros, but
+ * efficiency is important here.
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#if !defined(IN) || !defined(OUT)
+#error "This file shouldn't be compiled."
+#error "It is included as part of translate.c"
+#endif
+
+#define IN_T CONCAT2E(CARD,IN)
+#define OUT_T CONCAT2E(CARD,OUT)
+#define rfbTranslateWithSingleTableINtoOUT \
+				CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT)
+#define rfbTranslateWithRGBTablesINtoOUT \
+				CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT)
+
+/*
+ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data
+ * using a single lookup table.
+ */
+
+static void
+rfbTranslateWithSingleTableINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+				    rfbPixelFormat *out,
+				    unsigned char *iptr, char *optr,
+				    int bytesBetweenInputLines,
+				    int width, int height,
+				    int x, int y)
+{
+    IN_T *ip = (IN_T *)iptr;
+    OUT_T *op = (OUT_T *)optr;
+    int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+    OUT_T *opLineEnd;
+    OUT_T *t = (OUT_T *)table;
+
+    while (height > 0) {
+	opLineEnd = op + width;
+
+	while (op < opLineEnd) {
+	    *(op++) = t[*(ip++)];
+	}
+
+	ip += ipextra;
+	height--;
+    }
+}
+
+
+/*
+ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data
+ * using three separate lookup tables for the red, green and blue values.
+ */
+
+static void
+rfbTranslateWithRGBTablesINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in,
+				  rfbPixelFormat *out,
+				  unsigned char *iptr, char *optr,
+				  int bytesBetweenInputLines,
+				  int width, int height,
+				  int x, int y)
+{
+    IN_T *ip = (IN_T *)iptr;
+    OUT_T *op = (OUT_T *)optr;
+    int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width;
+    OUT_T *opLineEnd;
+    OUT_T *redTable = (OUT_T *)table;
+    OUT_T *greenTable = redTable + in->redMax + 1;
+    OUT_T *blueTable = greenTable + in->greenMax + 1;
+
+    while (height > 0) {
+	opLineEnd = op + width;
+
+	while (op < opLineEnd) {
+	    *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] |
+		       greenTable[(*ip >> in->greenShift) & in->greenMax] |
+		       blueTable[(*ip >> in->blueShift) & in->blueMax]);
+	    ip++;
+	}
+	ip += ipextra;
+	height--;
+    }
+}
+
+#undef IN_T
+#undef OUT_T
+#undef rfbTranslateWithSingleTableINtoOUT
+#undef rfbTranslateWithRGBTablesINtoOUT
diff -u -rNp a/hw/xfree86/vnc/tight.c b/hw/xfree86/vnc/tight.c
--- a/hw/xfree86/vnc/tight.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/tight.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,1831 @@
+/*
+ * tight.c
+ *
+ * Routines to implement Tight Encoding
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "rfb.h"
+#include <jpeglib.h>
+
+
+/* Note: The following constant should not be changed. */
+#define TIGHT_MIN_TO_COMPRESS 12
+
+/* The parameters below may be adjusted. */
+#define MIN_SPLIT_RECT_SIZE     4096
+#define MIN_SOLID_SUBRECT_SIZE  2048
+#define MAX_SPLIT_TILE_SIZE       16
+
+/* May be set to TRUE with "-lazytight" Xvnc option. */
+Bool rfbTightDisableGradient = FALSE;
+
+/* This variable is set on every rfbSendRectEncodingTight() call. */
+static Bool usePixelFormat24;
+
+
+/* Compression level stuff. The following array contains various
+   encoder parameters for each of 10 compression levels (0..9).
+   Last three parameters correspond to JPEG quality levels (0..9). */
+
+typedef struct TIGHT_CONF_s {
+    int maxRectSize, maxRectWidth;
+    int monoMinRectSize, gradientMinRectSize;
+    int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel;
+    int gradientThreshold, gradientThreshold24;
+    int idxMaxColorsDivisor;
+    int jpegQuality, jpegThreshold, jpegThreshold24;
+} TIGHT_CONF;
+
+static TIGHT_CONF tightConf[10] = {
+    {   512,   32,   6, 65536, 0, 0, 0, 0,   0,   0,   4,  5, 10000, 23000 },
+    {  2048,  128,   6, 65536, 1, 1, 1, 0,   0,   0,   8, 10,  8000, 18000 },
+    {  6144,  256,   8, 65536, 3, 3, 2, 0,   0,   0,  24, 15,  6500, 15000 },
+    { 10240, 1024,  12, 65536, 5, 5, 3, 0,   0,   0,  32, 25,  5000, 12000 },
+    { 16384, 2048,  12, 65536, 6, 6, 4, 0,   0,   0,  32, 37,  4000, 10000 },
+    { 32768, 2048,  12,  4096, 7, 7, 5, 4, 150, 380,  32, 50,  3000,  8000 },
+    { 65536, 2048,  16,  4096, 7, 7, 6, 4, 170, 420,  48, 60,  2000,  5000 },
+    { 65536, 2048,  16,  4096, 8, 8, 7, 5, 180, 450,  64, 70,  1000,  2500 },
+    { 65536, 2048,  32,  8192, 9, 9, 8, 6, 190, 475,  64, 75,   500,  1200 },
+    { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
+};
+
+/* Stuff dealing with palettes. */
+
+typedef struct COLOR_LIST_s {
+    struct COLOR_LIST_s *next;
+    int idx;
+    CARD32 rgb;
+} COLOR_LIST;
+
+typedef struct PALETTE_ENTRY_s {
+    COLOR_LIST *listNode;
+    int numPixels;
+} PALETTE_ENTRY;
+
+typedef struct PALETTE_s {
+    PALETTE_ENTRY entry[256];
+    COLOR_LIST *hash[256];
+    COLOR_LIST list[256];
+} PALETTE;
+
+static int paletteNumColors, paletteMaxColors;
+static CARD32 monoBackground, monoForeground;
+static PALETTE palette;
+
+/* Pointers to dynamically-allocated buffers. */
+
+static int tightBeforeBufSize = 0;
+static char *tightBeforeBuf = NULL;
+
+static int tightAfterBufSize = 0;
+static char *tightAfterBuf = NULL;
+
+static int *prevRowBuf = NULL;
+
+
+/* Prototypes for static functions. */
+
+static void FindBestSolidArea (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 colorValue, int *w_ptr, int *h_ptr);
+static void ExtendSolidArea   (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 colorValue,
+                               int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr);
+static Bool CheckSolidTile    (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile8   (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile16  (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+static Bool CheckSolidTile32  (ScreenPtr pScreen, int x, int y, int w, int h,
+                               CARD32 *colorPtr, Bool needSameColor);
+
+static Bool SendRectSimple    (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendSubrect       (rfbClientPtr cl, int x, int y, int w, int h);
+static Bool SendTightHeader   (rfbClientPtr cl, int x, int y, int w, int h);
+
+static Bool SendSolidRect     (rfbClientPtr cl);
+static Bool SendMonoRect      (rfbClientPtr cl, int w, int h);
+static Bool SendIndexedRect   (rfbClientPtr cl, int w, int h);
+static Bool SendFullColorRect (rfbClientPtr cl, int w, int h);
+static Bool SendGradientRect  (rfbClientPtr cl, int w, int h);
+
+static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen,
+                         int zlibLevel, int zlibStrategy);
+static Bool SendCompressedData(rfbClientPtr cl, int compressedLen);
+
+static void FillPalette8(int count);
+static void FillPalette16(int count);
+static void FillPalette32(int count);
+
+static void PaletteReset(void);
+static int PaletteInsert(CARD32 rgb, int numPixels, int bpp);
+
+static void Pack24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int count);
+
+static void EncodeIndexedRect16(CARD8 *buf, int count);
+static void EncodeIndexedRect32(CARD8 *buf, int count);
+
+static void EncodeMonoRect8(CARD8 *buf, int w, int h);
+static void EncodeMonoRect16(CARD8 *buf, int w, int h);
+static void EncodeMonoRect32(CARD8 *buf, int w, int h);
+
+static void FilterGradient24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient16(ScreenPtr pScreen, CARD16 *buf, rfbPixelFormat *fmt, int w, int h);
+static void FilterGradient32(ScreenPtr pScreen, CARD32 *buf, rfbPixelFormat *fmt, int w, int h);
+
+static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h);
+
+static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h,
+                         int quality);
+static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count);
+
+static void JpegInitDestination(j_compress_ptr cinfo);
+static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo);
+static void JpegTermDestination(j_compress_ptr cinfo);
+static void JpegSetDstManager(j_compress_ptr cinfo);
+
+
+/*
+ * Tight encoding implementation.
+ */
+
+int
+rfbNumCodedRectsTight(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    int maxRectSize, maxRectWidth;
+    int subrectMaxWidth, subrectMaxHeight;
+
+    /* No matter how many rectangles we will send if LastRect markers
+       are used to terminate rectangle stream. */
+    if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE)
+      return 0;
+
+    maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+    maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+    if (w > maxRectWidth || w * h > maxRectSize) {
+        subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        subrectMaxHeight = maxRectSize / subrectMaxWidth;
+        return (((w - 1) / maxRectWidth + 1) *
+                ((h - 1) / subrectMaxHeight + 1));
+    } else {
+        return 1;
+    }
+}
+
+Bool
+rfbSendRectEncodingTight(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int nMaxRows;
+    CARD32 colorValue;
+    int dx, dy, dw, dh;
+    int x_best, y_best, w_best, h_best;
+    unsigned char *fbptr;
+
+    if ( cl->format.depth == 24 && cl->format.redMax == 0xFF &&
+         cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) {
+        usePixelFormat24 = TRUE;
+    } else {
+        usePixelFormat24 = FALSE;
+    }
+
+    if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE)
+        return SendRectSimple(cl, x, y, w, h);
+
+    /* Make sure we can write at least one pixel into tightBeforeBuf. */
+
+    if (tightBeforeBufSize < 4) {
+        tightBeforeBufSize = 4;
+        if (tightBeforeBuf == NULL)
+            tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+        else
+            tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+                                              tightBeforeBufSize);
+    }
+
+    /* Calculate maximum number of rows in one non-solid rectangle. */
+
+    {
+        int maxRectSize, maxRectWidth, nMaxWidth;
+
+        maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+        maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+        nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        nMaxRows = maxRectSize / nMaxWidth;
+    }
+
+    /* Try to find large solid-color areas and send them separately. */
+
+    for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+        /* If a rectangle becomes too large, send its upper part now. */
+
+        if (dy - y >= nMaxRows) {
+            if (!SendRectSimple(cl, x, y, w, nMaxRows))
+                return 0;
+            y += nMaxRows;
+            h -= nMaxRows;
+        }
+
+        dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+            MAX_SPLIT_TILE_SIZE : (y + h - dy);
+
+        for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) {
+
+            dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ?
+                MAX_SPLIT_TILE_SIZE : (x + w - dx);
+
+            if (CheckSolidTile(cl->pScreen, dx, dy, dw, dh, &colorValue, FALSE)) {
+
+                /* Get dimensions of solid-color area. */
+
+                FindBestSolidArea(cl->pScreen, dx, dy, w - (dx - x), h - (dy - y),
+				  colorValue, &w_best, &h_best);
+
+                /* Make sure a solid rectangle is large enough
+                   (or the whole rectangle is of the same color). */
+
+                if ( w_best * h_best != w * h &&
+                     w_best * h_best < MIN_SOLID_SUBRECT_SIZE )
+                    continue;
+
+                /* Try to extend solid rectangle to maximum size. */
+
+                x_best = dx; y_best = dy;
+                ExtendSolidArea(cl->pScreen, x, y, w, h, colorValue,
+                                &x_best, &y_best, &w_best, &h_best);
+
+                /* Send rectangles at top and left to solid-color area. */
+
+                if ( y_best != y &&
+                     !SendRectSimple(cl, x, y, w, y_best-y) )
+                    return FALSE;
+                if ( x_best != x &&
+                     !rfbSendRectEncodingTight(cl, x, y_best,
+                                               x_best-x, h_best) )
+                    return FALSE;
+
+                /* Send solid-color rectangle. */
+
+                if (!SendTightHeader(cl, x_best, y_best, w_best, h_best))
+                    return FALSE;
+
+                fbptr = (pVNC->pfbMemory +
+                         (pVNC->paddedWidthInBytes * y_best) +
+                         (x_best * (pVNC->bitsPerPixel / 8)));
+
+                (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+				   &pVNC->rfbServerFormat,
+                                   &cl->format, fbptr, tightBeforeBuf,
+                                   pVNC->paddedWidthInBytes, 1, 1, 
+				   x_best, y_best);
+
+                if (!SendSolidRect(cl))
+                    return FALSE;
+
+                /* Send remaining rectangles (at right and bottom). */
+
+                if ( x_best + w_best != x + w &&
+                     !rfbSendRectEncodingTight(cl, x_best+w_best, y_best,
+                                               w-(x_best-x)-w_best, h_best) )
+                    return FALSE;
+                if ( y_best + h_best != y + h &&
+                     !rfbSendRectEncodingTight(cl, x, y_best+h_best,
+                                               w, h-(y_best-y)-h_best) )
+                    return FALSE;
+
+                /* Return after all recursive calls are done. */
+
+                return TRUE;
+            }
+
+        }
+
+    }
+
+    /* No suitable solid-color rectangles found. */
+
+    return SendRectSimple(cl, x, y, w, h);
+}
+
+static void
+FindBestSolidArea(pScreen, x, y, w, h, colorValue, w_ptr, h_ptr)
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 colorValue;
+    int *w_ptr, *h_ptr;
+{
+    int dx, dy, dw, dh;
+    int w_prev;
+    int w_best = 0, h_best = 0;
+
+    w_prev = w;
+
+    for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) {
+
+        dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ?
+            MAX_SPLIT_TILE_SIZE : (y + h - dy);
+        dw = (w_prev > MAX_SPLIT_TILE_SIZE) ?
+            MAX_SPLIT_TILE_SIZE : w_prev;
+
+        if (!CheckSolidTile(pScreen, x, dy, dw, dh, &colorValue, TRUE))
+            break;
+
+        for (dx = x + dw; dx < x + w_prev;) {
+            dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ?
+                MAX_SPLIT_TILE_SIZE : (x + w_prev - dx);
+            if (!CheckSolidTile(pScreen, dx, dy, dw, dh, &colorValue, TRUE))
+                break;
+	    dx += dw;
+        }
+
+        w_prev = dx - x;
+        if (w_prev * (dy + dh - y) > w_best * h_best) {
+            w_best = w_prev;
+            h_best = dy + dh - y;
+        }
+    }
+
+    *w_ptr = w_best;
+    *h_ptr = h_best;
+}
+
+static void
+ExtendSolidArea(pScreen, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr)
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 colorValue;
+    int *x_ptr, *y_ptr, *w_ptr, *h_ptr;
+{
+    int cx, cy;
+
+    /* Try to extend the area upwards. */
+    for ( cy = *y_ptr - 1;
+          cy >= y && CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+          cy-- );
+    *h_ptr += *y_ptr - (cy + 1);
+    *y_ptr = cy + 1;
+
+    /* ... downwards. */
+    for ( cy = *y_ptr + *h_ptr;
+          cy < y + h &&
+              CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE);
+          cy++ );
+    *h_ptr += cy - (*y_ptr + *h_ptr);
+
+    /* ... to the left. */
+    for ( cx = *x_ptr - 1;
+          cx >= x && CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+          cx-- );
+    *w_ptr += *x_ptr - (cx + 1);
+    *x_ptr = cx + 1;
+
+    /* ... to the right. */
+    for ( cx = *x_ptr + *w_ptr;
+          cx < x + w &&
+              CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE);
+          cx++ );
+    *w_ptr += cx - (*x_ptr + *w_ptr);
+}
+
+/*
+ * Check if a rectangle is all of the same color. If needSameColor is
+ * set to non-zero, then also check that its color equals to the
+ * *colorPtr value. The result is 1 if the test is successfull, and in
+ * that case new color will be stored in *colorPtr.
+ */
+
+static Bool
+CheckSolidTile(pScreen, x, y, w, h, colorPtr, needSameColor) 
+    ScreenPtr pScreen;
+    int x, y, w, h;
+    CARD32 *colorPtr;
+    Bool needSameColor;
+{
+    VNCSCREENPTR(pScreen);
+    switch(pVNC->rfbServerFormat.bitsPerPixel) {
+    case 32:
+        return CheckSolidTile32(pScreen, x, y, w, h, colorPtr, needSameColor);
+    case 16:
+        return CheckSolidTile16(pScreen, x, y, w, h, colorPtr, needSameColor);
+    default:
+        return CheckSolidTile8(pScreen, x, y, w, h, colorPtr, needSameColor);
+    }
+}
+
+#define DEFINE_CHECK_SOLID_FUNCTION(bpp)                                      \
+                                                                              \
+static Bool                                                                   \
+CheckSolidTile##bpp(pScreen, x, y, w, h, colorPtr, needSameColor)             \
+    ScreenPtr pScreen;							      \
+    int x, y;                                                                 \
+    CARD32 *colorPtr;                                                         \
+    Bool needSameColor;                                                       \
+{                                                                             \
+    VNCSCREENPTR(pScreen);						      \
+    CARD##bpp *fbptr;                                                         \
+    CARD##bpp colorValue;                                                     \
+    int dx, dy;                                                               \
+                                                                              \
+    fbptr = (CARD##bpp *)                                                     \
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * (bpp/8)]; \
+                                                                              \
+    colorValue = *fbptr;                                                      \
+    if (needSameColor && (CARD32)colorValue != *colorPtr)                     \
+        return FALSE;                                                         \
+                                                                              \
+    for (dy = 0; dy < h; dy++) {                                              \
+        for (dx = 0; dx < w; dx++) {                                          \
+            if (colorValue != fbptr[dx])                                      \
+                return FALSE;                                                 \
+        }                                                                     \
+        fbptr = (CARD##bpp *)((CARD8 *)fbptr + pVNC->paddedWidthInBytes);     \
+    }                                                                         \
+                                                                              \
+    *colorPtr = (CARD32)colorValue;                                           \
+    return TRUE;                                                              \
+}
+
+DEFINE_CHECK_SOLID_FUNCTION(8)
+DEFINE_CHECK_SOLID_FUNCTION(16)
+DEFINE_CHECK_SOLID_FUNCTION(32)
+
+static Bool
+SendRectSimple(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    int maxBeforeSize, maxAfterSize;
+    int maxRectSize, maxRectWidth;
+    int subrectMaxWidth, subrectMaxHeight;
+    int dx, dy;
+    int rw, rh;
+
+    maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize;
+    maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth;
+
+    maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8);
+    maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
+
+    if (tightBeforeBufSize < maxBeforeSize) {
+        tightBeforeBufSize = maxBeforeSize;
+        if (tightBeforeBuf == NULL)
+            tightBeforeBuf = (char *)xalloc(tightBeforeBufSize);
+        else
+            tightBeforeBuf = (char *)xrealloc(tightBeforeBuf,
+                                              tightBeforeBufSize);
+    }
+
+    if (tightAfterBufSize < maxAfterSize) {
+        tightAfterBufSize = maxAfterSize;
+        if (tightAfterBuf == NULL)
+            tightAfterBuf = (char *)xalloc(tightAfterBufSize);
+        else
+            tightAfterBuf = (char *)xrealloc(tightAfterBuf,
+                                             tightAfterBufSize);
+    }
+
+    if (w > maxRectWidth || w * h > maxRectSize) {
+        subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
+        subrectMaxHeight = maxRectSize / subrectMaxWidth;
+
+        for (dy = 0; dy < h; dy += subrectMaxHeight) {
+            for (dx = 0; dx < w; dx += maxRectWidth) {
+                rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx;
+                rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
+                if (!SendSubrect(cl, x+dx, y+dy, rw, rh))
+                    return FALSE;
+            }
+        }
+    } else {
+        if (!SendSubrect(cl, x, y, w, h))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+SendSubrect(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    unsigned char *fbptr;
+    Bool success = FALSE;
+
+    /* Send pending data if there is more than 128 bytes. */
+    if (pVNC->ublen > 128) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    if (!SendTightHeader(cl, x, y, w, h))
+        return FALSE;
+
+    fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+             + (x * (pVNC->bitsPerPixel / 8)));
+
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+                       &cl->format, fbptr, tightBeforeBuf,
+                       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    paletteMaxColors = w * h / tightConf[cl->tightCompressLevel].idxMaxColorsDivisor;
+    if ( paletteMaxColors < 2 &&
+         w * h >= tightConf[cl->tightCompressLevel].monoMinRectSize ) {
+        paletteMaxColors = 2;
+    }
+    switch (cl->format.bitsPerPixel) {
+    case 8:
+        FillPalette8(w * h);
+        break;
+    case 16:
+        FillPalette16(w * h);
+        break;
+    default:
+        FillPalette32(w * h);
+    }
+
+    switch (paletteNumColors) {
+    case 0:
+        /* Truecolor image */
+        if (DetectSmoothImage(cl, &cl->format, w, h)) {
+            if (cl->tightQualityLevel != -1) {
+                success = SendJpegRect(cl, x, y, w, h,
+                                  tightConf[cl->tightQualityLevel].jpegQuality);
+            } else {
+                success = SendGradientRect(cl, w, h);
+            }
+        } else {
+            success = SendFullColorRect(cl, w, h);
+        }
+        break;
+    case 1:
+        /* Solid rectangle */
+        success = SendSolidRect(cl);
+        break;
+    case 2:
+        /* Two-color rectangle */
+        success = SendMonoRect(cl, w, h);
+        break;
+    default:
+        /* Up to 256 different colors */
+        if ( paletteNumColors > 96 &&
+             cl->tightQualityLevel != -1 && cl->tightQualityLevel <= 3 &&
+             DetectSmoothImage(cl, &cl->format, w, h) ) {
+            success = SendJpegRect(cl, x, y, w, h,
+                                  tightConf[cl->tightQualityLevel].jpegQuality);
+        } else {
+            success = SendIndexedRect(cl, w, h);
+        }
+    }
+    return success;
+}
+
+static Bool
+SendTightHeader(cl, x, y, w, h)
+    rfbClientPtr cl;
+    int x, y, w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingTight);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+           sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    cl->rfbRectanglesSent[rfbEncodingTight]++;
+    cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
+
+    return TRUE;
+}
+
+/*
+ * Subencoding implementations.
+ */
+
+static Bool
+SendSolidRect(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int len;
+
+    if (usePixelFormat24) {
+        Pack24(cl->pScreen, tightBeforeBuf, &cl->format, 1);
+        len = 3;
+    } else
+        len = cl->format.bitsPerPixel / 8;
+
+    if (pVNC->ublen + 1 + len > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightFill << 4);
+    memcpy (&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, len);
+    pVNC->ublen += len;
+
+    cl->rfbBytesSent[rfbEncodingTight] += len + 1;
+
+    return TRUE;
+}
+
+static Bool
+SendMonoRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 1;
+    int paletteLen, dataLen;
+
+    if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+          2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    /* Prepare tight encoding header. */
+    dataLen = (w + 7) / 8;
+    dataLen *= h;
+
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette;
+    pVNC->updateBuf[pVNC->ublen++] = 1;
+
+    /* Prepare palette, convert image. */
+    switch (cl->format.bitsPerPixel) {
+
+    case 32:
+        EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h);
+
+        ((CARD32 *)tightAfterBuf)[0] = monoBackground;
+        ((CARD32 *)tightAfterBuf)[1] = monoForeground;
+        if (usePixelFormat24) {
+            Pack24(cl->pScreen, tightAfterBuf, &cl->format, 2);
+            paletteLen = 6;
+        } else
+            paletteLen = 8;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteLen);
+        pVNC->ublen += paletteLen;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen;
+        break;
+
+    case 16:
+        EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h);
+
+        ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground;
+        ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, 4);
+        pVNC->ublen += 4;
+        cl->rfbBytesSent[rfbEncodingTight] += 7;
+        break;
+
+    default:
+        EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h);
+
+        pVNC->updateBuf[pVNC->ublen++] = (char)monoBackground;
+        pVNC->updateBuf[pVNC->ublen++] = (char)monoForeground;
+        cl->rfbBytesSent[rfbEncodingTight] += 5;
+    }
+
+    return CompressData(cl, streamId, dataLen,
+                        tightConf[cl->tightCompressLevel].monoZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendIndexedRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 2;
+    int i, entryLen;
+
+    if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 +
+          paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    /* Prepare tight encoding header. */
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette;
+    pVNC->updateBuf[pVNC->ublen++] = (char)(paletteNumColors - 1);
+
+    /* Prepare palette, convert image. */
+    switch (cl->format.bitsPerPixel) {
+
+    case 32:
+        EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h);
+
+        for (i = 0; i < paletteNumColors; i++) {
+            ((CARD32 *)tightAfterBuf)[i] =
+                palette.entry[i].listNode->rgb;
+        }
+        if (usePixelFormat24) {
+            Pack24(cl->pScreen, tightAfterBuf, &cl->format, paletteNumColors);
+            entryLen = 3;
+        } else
+            entryLen = 4;
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * entryLen);
+        pVNC->ublen += paletteNumColors * entryLen;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
+        break;
+
+    case 16:
+        EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h);
+
+        for (i = 0; i < paletteNumColors; i++) {
+            ((CARD16 *)tightAfterBuf)[i] =
+                (CARD16)palette.entry[i].listNode->rgb;
+        }
+
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * 2);
+        pVNC->ublen += paletteNumColors * 2;
+        cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
+        break;
+
+    default:
+        return FALSE;           /* Should never happen. */
+    }
+
+    return CompressData(cl, streamId, w * h,
+                        tightConf[cl->tightCompressLevel].idxZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendFullColorRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 0;
+    int len;
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = 0x00;  /* stream id = 0, no flushing, no filter */
+    cl->rfbBytesSent[rfbEncodingTight]++;
+
+    if (usePixelFormat24) {
+        Pack24(cl->pScreen, tightBeforeBuf, &cl->format, w * h);
+        len = 3;
+    } else
+        len = cl->format.bitsPerPixel / 8;
+
+    return CompressData(cl, streamId, w * h * len,
+                        tightConf[cl->tightCompressLevel].rawZlibLevel,
+                        Z_DEFAULT_STRATEGY);
+}
+
+static Bool
+SendGradientRect(cl, w, h)
+    rfbClientPtr cl;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int streamId = 3;
+    int len;
+
+    if (cl->format.bitsPerPixel == 8)
+        return SendFullColorRect(cl, w, h);
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    if (prevRowBuf == NULL)
+        prevRowBuf = (int *)xalloc(2048 * 3 * sizeof(int));
+
+    pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
+    pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterGradient;
+    cl->rfbBytesSent[rfbEncodingTight] += 2;
+
+    if (usePixelFormat24) {
+        FilterGradient24(cl->pScreen, tightBeforeBuf, &cl->format, w, h);
+        len = 3;
+    } else if (cl->format.bitsPerPixel == 32) {
+        FilterGradient32(cl->pScreen, (CARD32 *)tightBeforeBuf, &cl->format, w, h);
+        len = 4;
+    } else {
+        FilterGradient16(cl->pScreen, (CARD16 *)tightBeforeBuf, &cl->format, w, h);
+        len = 2;
+    }
+
+    return CompressData(cl, streamId, w * h * len,
+                        tightConf[cl->tightCompressLevel].gradientZlibLevel,
+                        Z_FILTERED);
+}
+
+static Bool
+CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy)
+    rfbClientPtr cl;
+    int streamId, dataLen, zlibLevel, zlibStrategy;
+{
+    VNCSCREENPTR(cl->pScreen);
+    z_streamp pz;
+    int err;
+
+    if (dataLen < TIGHT_MIN_TO_COMPRESS) {
+        memcpy(&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, dataLen);
+        pVNC->ublen += dataLen;
+        cl->rfbBytesSent[rfbEncodingTight] += dataLen;
+        return TRUE;
+    }
+
+    pz = &cl->zsStruct[streamId];
+
+    /* Initialize compression stream if needed. */
+    if (!cl->zsActive[streamId]) {
+        pz->zalloc = Z_NULL;
+        pz->zfree = Z_NULL;
+        pz->opaque = Z_NULL;
+
+        err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS,
+                            MAX_MEM_LEVEL, zlibStrategy);
+        if (err != Z_OK)
+            return FALSE;
+
+        cl->zsActive[streamId] = TRUE;
+        cl->zsLevel[streamId] = zlibLevel;
+    }
+
+    /* Prepare buffer pointers. */
+    pz->next_in = (Bytef *)tightBeforeBuf;
+    pz->avail_in = dataLen;
+    pz->next_out = (Bytef *)tightAfterBuf;
+    pz->avail_out = tightAfterBufSize;
+
+    /* Change compression parameters if needed. */
+    if (zlibLevel != cl->zsLevel[streamId]) {
+        if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) {
+            return FALSE;
+        }
+        cl->zsLevel[streamId] = zlibLevel;
+    }
+
+    /* Actual compression. */
+    if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK ||
+         pz->avail_in != 0 || pz->avail_out == 0 ) {
+        return FALSE;
+    }
+
+    return SendCompressedData(cl, tightAfterBufSize - pz->avail_out);
+}
+
+static Bool SendCompressedData(cl, compressedLen)
+    rfbClientPtr cl;
+    int compressedLen;
+{
+    VNCSCREENPTR(cl->pScreen);
+    int i, portionLen;
+
+    pVNC->updateBuf[pVNC->ublen++] = compressedLen & 0x7F;
+    cl->rfbBytesSent[rfbEncodingTight]++;
+    if (compressedLen > 0x7F) {
+        pVNC->updateBuf[pVNC->ublen-1] |= 0x80;
+        pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 7 & 0x7F;
+        cl->rfbBytesSent[rfbEncodingTight]++;
+        if (compressedLen > 0x3FFF) {
+            pVNC->updateBuf[pVNC->ublen-1] |= 0x80;
+            pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 14 & 0xFF;
+            cl->rfbBytesSent[rfbEncodingTight]++;
+        }
+    }
+
+    portionLen = UPDATE_BUF_SIZE;
+    for (i = 0; i < compressedLen; i += portionLen) {
+        if (i + portionLen > compressedLen) {
+            portionLen = compressedLen - i;
+        }
+        if (pVNC->ublen + portionLen > UPDATE_BUF_SIZE) {
+            if (!rfbSendUpdateBuf(cl))
+                return FALSE;
+        }
+        memcpy(&pVNC->updateBuf[pVNC->ublen], &tightAfterBuf[i], portionLen);
+        pVNC->ublen += portionLen;
+    }
+    cl->rfbBytesSent[rfbEncodingTight] += compressedLen;
+    return TRUE;
+}
+
+/*
+ * Code to determine how many different colors used in rectangle.
+ */
+
+static void
+FillPalette8(count)
+    int count;
+{
+    CARD8 *data = (CARD8 *)tightBeforeBuf;
+    CARD8 c0, c1;
+    int i, n0, n1;
+
+    paletteNumColors = 0;
+
+    c0 = data[0];
+    for (i = 1; i < count && data[i] == c0; i++);
+    if (i == count) {
+        paletteNumColors = 1;
+        return;                 /* Solid rectangle */
+    }
+
+    if (paletteMaxColors < 2)
+        return;
+
+    n0 = i;
+    c1 = data[i];
+    n1 = 0;
+    for (i++; i < count; i++) {
+        if (data[i] == c0) {
+            n0++;
+        } else if (data[i] == c1) {
+            n1++;
+        } else
+            break;
+    }
+    if (i == count) {
+        if (n0 > n1) {
+            monoBackground = (CARD32)c0;
+            monoForeground = (CARD32)c1;
+        } else {
+            monoBackground = (CARD32)c1;
+            monoForeground = (CARD32)c0;
+        }
+        paletteNumColors = 2;   /* Two colors */
+    }
+}
+
+#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
+                                                                        \
+static void                                                             \
+FillPalette##bpp(count)                                                 \
+    int count;                                                          \
+{                                                                       \
+    CARD##bpp *data = (CARD##bpp *)tightBeforeBuf;                      \
+    CARD##bpp c0, c1, ci = 0;                                           \
+    int i, n0, n1, ni;                                                  \
+                                                                        \
+    c0 = data[0];                                                       \
+    for (i = 1; i < count && data[i] == c0; i++);                       \
+    if (i >= count) {                                                   \
+        paletteNumColors = 1;   /* Solid rectangle */                   \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    if (paletteMaxColors < 2) {                                         \
+        paletteNumColors = 0;   /* Full-color encoding preferred */     \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    n0 = i;                                                             \
+    c1 = data[i];                                                       \
+    n1 = 0;                                                             \
+    for (i++; i < count; i++) {                                         \
+        ci = data[i];                                                   \
+        if (ci == c0) {                                                 \
+            n0++;                                                       \
+        } else if (ci == c1) {                                          \
+            n1++;                                                       \
+        } else                                                          \
+            break;                                                      \
+    }                                                                   \
+    if (i >= count) {                                                   \
+        if (n0 > n1) {                                                  \
+            monoBackground = (CARD32)c0;                                \
+            monoForeground = (CARD32)c1;                                \
+        } else {                                                        \
+            monoBackground = (CARD32)c1;                                \
+            monoForeground = (CARD32)c0;                                \
+        }                                                               \
+        paletteNumColors = 2;   /* Two colors */                        \
+        return;                                                         \
+    }                                                                   \
+                                                                        \
+    PaletteReset();                                                     \
+    PaletteInsert (c0, (CARD32)n0, bpp);                                \
+    PaletteInsert (c1, (CARD32)n1, bpp);                                \
+                                                                        \
+    ni = 1;                                                             \
+    for (i++; i < count; i++) {                                         \
+        if (data[i] == ci) {                                            \
+            ni++;                                                       \
+        } else {                                                        \
+            if (!PaletteInsert (ci, (CARD32)ni, bpp))                   \
+                return;                                                 \
+            ci = data[i];                                               \
+            ni = 1;                                                     \
+        }                                                               \
+    }                                                                   \
+    PaletteInsert (ci, (CARD32)ni, bpp);                                \
+}
+
+DEFINE_FILL_PALETTE_FUNCTION(16)
+DEFINE_FILL_PALETTE_FUNCTION(32)
+
+
+/*
+ * Functions to operate with palette structures.
+ */
+
+#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF))
+#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF))
+
+static void
+PaletteReset(void)
+{
+    paletteNumColors = 0;
+    memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *));
+}
+
+static int
+PaletteInsert(CARD32 rgb, int numPixels, int bpp)
+{
+    COLOR_LIST *pnode;
+    COLOR_LIST *prev_pnode = NULL;
+    int hash_key, idx, new_idx, count;
+
+    hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
+
+    pnode = palette.hash[hash_key];
+
+    while (pnode != NULL) {
+        if (pnode->rgb == rgb) {
+            /* Such palette entry already exists. */
+            new_idx = idx = pnode->idx;
+            count = palette.entry[idx].numPixels + numPixels;
+            if (new_idx && palette.entry[new_idx-1].numPixels < count) {
+                do {
+                    palette.entry[new_idx] = palette.entry[new_idx-1];
+                    palette.entry[new_idx].listNode->idx = new_idx;
+                    new_idx--;
+                }
+                while (new_idx && palette.entry[new_idx-1].numPixels < count);
+                palette.entry[new_idx].listNode = pnode;
+                pnode->idx = new_idx;
+            }
+            palette.entry[new_idx].numPixels = count;
+            return paletteNumColors;
+        }
+        prev_pnode = pnode;
+        pnode = pnode->next;
+    }
+
+    /* Check if palette is full. */
+    if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) {
+        paletteNumColors = 0;
+        return 0;
+    }
+
+    /* Move palette entries with lesser pixel counts. */
+    for ( idx = paletteNumColors;
+          idx > 0 && palette.entry[idx-1].numPixels < numPixels;
+          idx-- ) {
+        palette.entry[idx] = palette.entry[idx-1];
+        palette.entry[idx].listNode->idx = idx;
+    }
+
+    /* Add new palette entry into the freed slot. */
+    pnode = &palette.list[paletteNumColors];
+    if (prev_pnode != NULL) {
+        prev_pnode->next = pnode;
+    } else {
+        palette.hash[hash_key] = pnode;
+    }
+    pnode->next = NULL;
+    pnode->idx = idx;
+    pnode->rgb = rgb;
+    palette.entry[idx].listNode = pnode;
+    palette.entry[idx].numPixels = numPixels;
+
+    return (++paletteNumColors);
+}
+
+
+/*
+ * Converting 32-bit color samples into 24-bit colors.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void Pack24(pScreen, buf, fmt, count)
+    ScreenPtr pScreen;
+    char *buf;
+    rfbPixelFormat *fmt;
+    int count;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *buf32;
+    CARD32 pix;
+    int r_shift, g_shift, b_shift;
+
+    buf32 = (CARD32 *)buf;
+
+    if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+        r_shift = fmt->redShift;
+        g_shift = fmt->greenShift;
+        b_shift = fmt->blueShift;
+    } else {
+        r_shift = 24 - fmt->redShift;
+        g_shift = 24 - fmt->greenShift;
+        b_shift = 24 - fmt->blueShift;
+    }
+
+    while (count--) {
+        pix = *buf32++;
+        *buf++ = (char)(pix >> r_shift);
+        *buf++ = (char)(pix >> g_shift);
+        *buf++ = (char)(pix >> b_shift);
+    }
+}
+
+
+/*
+ * Converting truecolor samples into palette indices.
+ */
+
+#define DEFINE_IDX_ENCODE_FUNCTION(bpp)                                 \
+                                                                        \
+static void                                                             \
+EncodeIndexedRect##bpp(buf, count)                                      \
+    CARD8 *buf;                                                         \
+    int count;                                                          \
+{                                                                       \
+    COLOR_LIST *pnode;                                                  \
+    CARD##bpp *src;                                                     \
+    CARD##bpp rgb;                                                      \
+    int rep = 0;                                                        \
+                                                                        \
+    src = (CARD##bpp *) buf;                                            \
+                                                                        \
+    while (count--) {                                                   \
+        rgb = *src++;                                                   \
+        while (count && *src == rgb) {                                  \
+            rep++, src++, count--;                                      \
+        }                                                               \
+        pnode = palette.hash[HASH_FUNC##bpp(rgb)];                      \
+        while (pnode != NULL) {                                         \
+            if ((CARD##bpp)pnode->rgb == rgb) {                         \
+                *buf++ = (CARD8)pnode->idx;                             \
+                while (rep) {                                           \
+                    *buf++ = (CARD8)pnode->idx;                         \
+                    rep--;                                              \
+                }                                                       \
+                break;                                                  \
+            }                                                           \
+            pnode = pnode->next;                                        \
+        }                                                               \
+    }                                                                   \
+}
+
+DEFINE_IDX_ENCODE_FUNCTION(16)
+DEFINE_IDX_ENCODE_FUNCTION(32)
+
+#define DEFINE_MONO_ENCODE_FUNCTION(bpp)                                \
+                                                                        \
+static void                                                             \
+EncodeMonoRect##bpp(buf, w, h)                                          \
+    CARD8 *buf;                                                         \
+    int w, h;                                                           \
+{                                                                       \
+    CARD##bpp *ptr;                                                     \
+    CARD##bpp bg;                                                       \
+    unsigned int value, mask;                                           \
+    int aligned_width;                                                  \
+    int x, y, bg_bits;                                                  \
+                                                                        \
+    ptr = (CARD##bpp *) buf;                                            \
+    bg = (CARD##bpp) monoBackground;                                    \
+    aligned_width = w - w % 8;                                          \
+                                                                        \
+    for (y = 0; y < h; y++) {                                           \
+        for (x = 0; x < aligned_width; x += 8) {                        \
+            for (bg_bits = 0; bg_bits < 8; bg_bits++) {                 \
+                if (*ptr++ != bg)                                       \
+                    break;                                              \
+            }                                                           \
+            if (bg_bits == 8) {                                         \
+                *buf++ = 0;                                             \
+                continue;                                               \
+            }                                                           \
+            mask = 0x80 >> bg_bits;                                     \
+            value = mask;                                               \
+            for (bg_bits++; bg_bits < 8; bg_bits++) {                   \
+                mask >>= 1;                                             \
+                if (*ptr++ != bg) {                                     \
+                    value |= mask;                                      \
+                }                                                       \
+            }                                                           \
+            *buf++ = (CARD8)value;                                      \
+        }                                                               \
+                                                                        \
+        mask = 0x80;                                                    \
+        value = 0;                                                      \
+        if (x >= w)                                                     \
+            continue;                                                   \
+                                                                        \
+        for (; x < w; x++) {                                            \
+            if (*ptr++ != bg) {                                         \
+                value |= mask;                                          \
+            }                                                           \
+            mask >>= 1;                                                 \
+        }                                                               \
+        *buf++ = (CARD8)value;                                          \
+    }                                                                   \
+}
+
+DEFINE_MONO_ENCODE_FUNCTION(8)
+DEFINE_MONO_ENCODE_FUNCTION(16)
+DEFINE_MONO_ENCODE_FUNCTION(32)
+
+
+/*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+FilterGradient24(pScreen, buf, fmt, w, h)
+    ScreenPtr pScreen;
+    char *buf;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *buf32;
+    CARD32 pix32;
+    int *prevRowPtr;
+    int shiftBits[3];
+    int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];
+    int prediction;
+    int x, y, c;
+
+    buf32 = (CARD32 *)buf;
+    memset (prevRowBuf, 0, w * 3 * sizeof(int));
+
+    if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) {
+        shiftBits[0] = fmt->redShift;
+        shiftBits[1] = fmt->greenShift;
+        shiftBits[2] = fmt->blueShift;
+    } else {
+        shiftBits[0] = 24 - fmt->redShift;
+        shiftBits[1] = 24 - fmt->greenShift;
+        shiftBits[2] = 24 - fmt->blueShift;
+    }
+
+    for (y = 0; y < h; y++) {
+        for (c = 0; c < 3; c++) {
+            pixUpper[c] = 0;
+            pixHere[c] = 0;
+        }
+        prevRowPtr = prevRowBuf;
+        for (x = 0; x < w; x++) {
+            pix32 = *buf32++;
+            for (c = 0; c < 3; c++) {
+                pixUpperLeft[c] = pixUpper[c];
+                pixLeft[c] = pixHere[c];
+                pixUpper[c] = *prevRowPtr;
+                pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF);
+                *prevRowPtr++ = pixHere[c];
+
+                prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c];
+                if (prediction < 0) {
+                    prediction = 0;
+                } else if (prediction > 0xFF) {
+                    prediction = 0xFF;
+                }
+                *buf++ = (char)(pixHere[c] - prediction);
+            }
+        }
+    }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                             \
+                                                                         \
+static void                                                              \
+FilterGradient##bpp(pScreen, buf, fmt, w, h)                             \
+    ScreenPtr pScreen;							 \
+    CARD##bpp *buf;                                                      \
+    rfbPixelFormat *fmt;                                                 \
+    int w, h;                                                            \
+{                                                                        \
+    VNCSCREENPTR(pScreen);						 \
+    CARD##bpp pix, diff;                                                 \
+    Bool endianMismatch;                                                 \
+    int *prevRowPtr;                                                     \
+    int maxColor[3], shiftBits[3];                                       \
+    int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3];            \
+    int prediction;                                                      \
+    int x, y, c;                                                         \
+                                                                         \
+    memset (prevRowBuf, 0, w * 3 * sizeof(int));                         \
+                                                                         \
+    endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian);    \
+                                                                         \
+    maxColor[0] = fmt->redMax;                                           \
+    maxColor[1] = fmt->greenMax;                                         \
+    maxColor[2] = fmt->blueMax;                                          \
+    shiftBits[0] = fmt->redShift;                                        \
+    shiftBits[1] = fmt->greenShift;                                      \
+    shiftBits[2] = fmt->blueShift;                                       \
+                                                                         \
+    for (y = 0; y < h; y++) {                                            \
+        for (c = 0; c < 3; c++) {                                        \
+            pixUpper[c] = 0;                                             \
+            pixHere[c] = 0;                                              \
+        }                                                                \
+        prevRowPtr = prevRowBuf;                                         \
+        for (x = 0; x < w; x++) {                                        \
+            pix = *buf;                                                  \
+            if (endianMismatch) {                                        \
+                pix = Swap##bpp(pix);                                    \
+            }                                                            \
+            diff = 0;                                                    \
+            for (c = 0; c < 3; c++) {                                    \
+                pixUpperLeft[c] = pixUpper[c];                           \
+                pixLeft[c] = pixHere[c];                                 \
+                pixUpper[c] = *prevRowPtr;                               \
+                pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]);   \
+                *prevRowPtr++ = pixHere[c];                              \
+                                                                         \
+                prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \
+                if (prediction < 0) {                                    \
+                    prediction = 0;                                      \
+                } else if (prediction > maxColor[c]) {                   \
+                    prediction = maxColor[c];                            \
+                }                                                        \
+                diff |= ((pixHere[c] - prediction) & maxColor[c])        \
+                    << shiftBits[c];                                     \
+            }                                                            \
+            if (endianMismatch) {                                        \
+                diff = Swap##bpp(diff);                                  \
+            }                                                            \
+            *buf++ = diff;                                               \
+        }                                                                \
+    }                                                                    \
+}
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+
+/*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+#define JPEG_MIN_RECT_SIZE  4096
+
+#define DETECT_SUBROW_WIDTH    7
+#define DETECT_MIN_WIDTH       8
+#define DETECT_MIN_HEIGHT      8
+
+static int
+DetectSmoothImage (cl, fmt, w, h)
+    rfbClientPtr cl;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    VNCSCREENPTR(cl->pScreen);
+    unsigned long avgError;
+
+    if ( pVNC->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 ||
+         w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) {
+        return 0;
+    }
+
+    if (cl->tightQualityLevel != -1) {
+        if (w * h < JPEG_MIN_RECT_SIZE) {
+            return 0;
+        }
+    } else {
+        if ( rfbTightDisableGradient ||
+             w * h < tightConf[cl->tightCompressLevel].gradientMinRectSize ) {
+            return 0;
+        }
+    }
+
+    if (fmt->bitsPerPixel == 32) {
+        if (usePixelFormat24) {
+            avgError = DetectSmoothImage24(cl, fmt, w, h);
+            if (cl->tightQualityLevel != -1) {
+                return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold24);
+            }
+            return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold24);
+        } else {
+            avgError = DetectSmoothImage32(cl, fmt, w, h);
+        }
+    } else {
+        avgError = DetectSmoothImage16(cl, fmt, w, h);
+    }
+    if (cl->tightQualityLevel != -1) {
+        return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold);
+    }
+    return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold);
+}
+
+static unsigned long
+DetectSmoothImage24 (cl, fmt, w, h)
+    rfbClientPtr cl;
+    rfbPixelFormat *fmt;
+    int w, h;
+{
+    int off;
+    int x, y, d, dx, c;
+    int diffStat[256];
+    int pixelCount = 0;
+    int pix, left[3];
+    unsigned long avgError;
+
+    /* If client is big-endian, color samples begin from the second
+       byte (offset 1) of a 32-bit pixel value. */
+    off = (fmt->bigEndian != 0);
+
+    memset(diffStat, 0, 256*sizeof(int));
+
+    y = 0, x = 0;
+    while (y < h && x < w) {
+        for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {
+            for (c = 0; c < 3; c++) {
+                left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+            }
+            for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {
+                for (c = 0; c < 3; c++) {
+                    pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+                    diffStat[abs(pix - left[c])]++;
+                    left[c] = pix;
+                }
+                pixelCount++;
+            }
+        }
+        if (w > h) {
+            x += h;
+            y = 0;
+        } else {
+            x = 0;
+            y += w;
+        }
+    }
+
+    if (diffStat[0] * 33 / pixelCount >= 95)
+        return 0;
+
+    avgError = 0;
+    for (c = 1; c < 8; c++) {
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+        if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)
+            return 0;
+    }
+    for (; c < 256; c++) {
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);
+    }
+    avgError /= (pixelCount * 3 - diffStat[0]);
+
+    return avgError;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp)                                          \
+                                                                             \
+static unsigned long                                                         \
+DetectSmoothImage##bpp (cl, fmt, w, h)                                       \
+    rfbClientPtr cl;							     \
+    rfbPixelFormat *fmt;                                                     \
+    int w, h;                                                                \
+{                                                                            \
+    VNCSCREENPTR(cl->pScreen);						     \
+    Bool endianMismatch;                                                     \
+    CARD##bpp pix;                                                           \
+    int maxColor[3], shiftBits[3];                                           \
+    int x, y, d, dx, c;                                                      \
+    int diffStat[256];                                                       \
+    int pixelCount = 0;                                                      \
+    int sample, sum, left[3];                                                \
+    unsigned long avgError;                                                  \
+                                                                             \
+    endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian);        \
+                                                                             \
+    maxColor[0] = fmt->redMax;                                               \
+    maxColor[1] = fmt->greenMax;                                             \
+    maxColor[2] = fmt->blueMax;                                              \
+    shiftBits[0] = fmt->redShift;                                            \
+    shiftBits[1] = fmt->greenShift;                                          \
+    shiftBits[2] = fmt->blueShift;                                           \
+                                                                             \
+    memset(diffStat, 0, 256*sizeof(int));                                    \
+                                                                             \
+    y = 0, x = 0;                                                            \
+    while (y < h && x < w) {                                                 \
+        for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) {     \
+            pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d];                \
+            if (endianMismatch) {                                            \
+                pix = Swap##bpp(pix);                                        \
+            }                                                                \
+            for (c = 0; c < 3; c++) {                                        \
+                left[c] = (int)(pix >> shiftBits[c] & maxColor[c]);          \
+            }                                                                \
+            for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) {                  \
+                pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d+dx];         \
+                if (endianMismatch) {                                        \
+                    pix = Swap##bpp(pix);                                    \
+                }                                                            \
+                sum = 0;                                                     \
+                for (c = 0; c < 3; c++) {                                    \
+                    sample = (int)(pix >> shiftBits[c] & maxColor[c]);       \
+                    sum += abs(sample - left[c]);                            \
+                    left[c] = sample;                                        \
+                }                                                            \
+                if (sum > 255)                                               \
+                    sum = 255;                                               \
+                diffStat[sum]++;                                             \
+                pixelCount++;                                                \
+            }                                                                \
+        }                                                                    \
+        if (w > h) {                                                         \
+            x += h;                                                          \
+            y = 0;                                                           \
+        } else {                                                             \
+            x = 0;                                                           \
+            y += w;                                                          \
+        }                                                                    \
+    }                                                                        \
+                                                                             \
+    if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90)                \
+        return 0;                                                            \
+                                                                             \
+    avgError = 0;                                                            \
+    for (c = 1; c < 8; c++) {                                                \
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);     \
+        if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2)             \
+            return 0;                                                        \
+    }                                                                        \
+    for (; c < 256; c++) {                                                   \
+        avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c);     \
+    }                                                                        \
+    avgError /= (pixelCount - diffStat[0]);                                  \
+                                                                             \
+    return avgError;                                                         \
+}
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+
+/*
+ * JPEG compression stuff.
+ */
+
+static struct jpeg_destination_mgr jpegDstManager;
+static Bool jpegError;
+static int jpegDstDataLen;
+
+static Bool
+SendJpegRect(cl, x, y, w, h, quality)
+    rfbClientPtr cl;
+    int x, y, w, h;
+    int quality;
+{
+    VNCSCREENPTR(cl->pScreen);
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    CARD8 *srcBuf;
+    JSAMPROW rowPointer[1];
+    int dy;
+
+    if (pVNC->rfbServerFormat.bitsPerPixel == 8)
+        return SendFullColorRect(cl, w, h);
+
+    srcBuf = (CARD8 *)xalloc(w * 3);
+    if (srcBuf == NULL) {
+        return SendFullColorRect(cl, w, h);
+    }
+    rowPointer[0] = srcBuf;
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+
+    cinfo.image_width = w;
+    cinfo.image_height = h;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, TRUE);
+
+    JpegSetDstManager (&cinfo);
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    for (dy = 0; dy < h; dy++) {
+        PrepareRowForJpeg(cl->pScreen, srcBuf, x, y + dy, w);
+        jpeg_write_scanlines(&cinfo, rowPointer, 1);
+        if (jpegError)
+            break;
+    }
+
+    if (!jpegError)
+        jpeg_finish_compress(&cinfo);
+
+    jpeg_destroy_compress(&cinfo);
+    xfree((char *)srcBuf);
+
+    if (jpegError)
+        return SendFullColorRect(cl, w, h);
+
+    if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) {
+        if (!rfbSendUpdateBuf(cl))
+            return FALSE;
+    }
+
+    pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightJpeg << 4);
+    cl->rfbBytesSent[rfbEncodingTight]++;
+
+    return SendCompressedData(cl, jpegDstDataLen);
+}
+
+static void
+PrepareRowForJpeg(pScreen, dst, x, y, count)
+    ScreenPtr pScreen;
+    CARD8 *dst;
+    int x, y, count;
+{
+    VNCSCREENPTR(pScreen);
+    if (pVNC->rfbServerFormat.bitsPerPixel == 32) {
+        if ( pVNC->rfbServerFormat.redMax == 0xFF &&
+             pVNC->rfbServerFormat.greenMax == 0xFF &&
+             pVNC->rfbServerFormat.blueMax == 0xFF ) {
+            PrepareRowForJpeg24(pScreen, dst, x, y, count);
+        } else {
+            PrepareRowForJpeg32(pScreen, dst, x, y, count);
+        }
+    } else {
+        /* 16 bpp assumed. */
+        PrepareRowForJpeg16(pScreen, dst, x, y, count);
+    }
+}
+
+static void
+PrepareRowForJpeg24(pScreen, dst, x, y, count)
+    ScreenPtr pScreen;
+    CARD8 *dst;
+    int x, y, count;
+{
+    VNCSCREENPTR(pScreen);
+    CARD32 *fbptr;
+    CARD32 pix;
+
+    fbptr = (CARD32 *)
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * 4];
+
+    while (count--) {
+        pix = *fbptr++;
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift);
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift);
+        *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift);
+    }
+}
+
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                                   \
+                                                                            \
+static void                                                                 \
+PrepareRowForJpeg##bpp(pScreen, dst, x, y, count)                           \
+    ScreenPtr pScreen;							    \
+    CARD8 *dst;                                                             \
+    int x, y, count;                                                        \
+{                                                                           \
+    VNCSCREENPTR(pScreen);						    \
+    CARD##bpp *fbptr;                                                       \
+    CARD##bpp pix;                                                          \
+    int inRed, inGreen, inBlue;                                             \
+                                                                            \
+    fbptr = (CARD##bpp *)                                                   \
+        &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes +                        \
+                             x * (bpp / 8)];                                \
+                                                                            \
+    while (count--) {                                                       \
+        pix = *fbptr++;                                                     \
+                                                                            \
+        inRed = (int)                                                       \
+            (pix >> pVNC->rfbServerFormat.redShift   & pVNC->rfbServerFormat.redMax);   \
+        inGreen = (int)                                                     \
+            (pix >> pVNC->rfbServerFormat.greenShift & pVNC->rfbServerFormat.greenMax); \
+        inBlue  = (int)                                                     \
+            (pix >> pVNC->rfbServerFormat.blueShift  & pVNC->rfbServerFormat.blueMax);  \
+                                                                            \
+	*dst++ = (CARD8)((inRed   * 255 + pVNC->rfbServerFormat.redMax / 2) /     \
+                         pVNC->rfbServerFormat.redMax);                           \
+	*dst++ = (CARD8)((inGreen * 255 + pVNC->rfbServerFormat.greenMax / 2) /   \
+                         pVNC->rfbServerFormat.greenMax);                         \
+	*dst++ = (CARD8)((inBlue  * 255 + pVNC->rfbServerFormat.blueMax / 2) /    \
+                         pVNC->rfbServerFormat.blueMax);                          \
+    }                                                                       \
+}
+
+DEFINE_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+static void
+JpegInitDestination(j_compress_ptr cinfo)
+{
+    jpegError = FALSE;
+    jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+    jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+}
+
+static boolean
+JpegEmptyOutputBuffer(j_compress_ptr cinfo)
+{
+    jpegError = TRUE;
+    jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf;
+    jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize;
+
+    return TRUE;
+}
+
+static void
+JpegTermDestination(j_compress_ptr cinfo)
+{
+    jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer;
+}
+
+static void
+JpegSetDstManager(j_compress_ptr cinfo)
+{
+    jpegDstManager.init_destination = JpegInitDestination;
+    jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer;
+    jpegDstManager.term_destination = JpegTermDestination;
+    cinfo->dest = &jpegDstManager;
+}
+
diff -u -rNp a/hw/xfree86/vnc/translate.c b/hw/xfree86/vnc/translate.c
--- a/hw/xfree86/vnc/translate.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/translate.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,497 @@
+/*
+ * translate.c - translate between different pixel formats
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rfb.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+
+static void PrintPixelFormat(rfbPixelFormat *pf);
+static Bool rfbSetClientColourMapBGR233(rfbClientPtr cl);
+
+Bool rfbEconomicTranslate = FALSE;
+
+/*
+ * Some standard pixel formats.
+ */
+
+static const rfbPixelFormat BGR233Format = {
+    8, 8, 0, 1, 7, 7, 3, 0, 3, 6
+};
+
+
+/*
+ * Macro to compare pixel formats.
+ */
+
+#define PF_EQ(x,y)							\
+	((x.bitsPerPixel == y.bitsPerPixel) &&				\
+	 (x.depth == y.depth) &&					\
+	 ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) &&	\
+	 (x.trueColour == y.trueColour) &&				\
+	 (!x.trueColour || ((x.redMax == y.redMax) &&			\
+			    (x.greenMax == y.greenMax) &&		\
+			    (x.blueMax == y.blueMax) &&			\
+			    (x.redShift == y.redShift) &&		\
+			    (x.greenShift == y.greenShift) &&		\
+			    (x.blueShift == y.blueShift))))
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+#define CONCAT4(a,b,c,d) a##b##c##d
+#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
+
+#define OUT 8
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 16
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+#define OUT 32
+#include "tableinittctemplate.c"
+#include "tableinitcmtemplate.c"
+#define IN 8
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 16
+#include "tabletranstemplate.c"
+#undef IN
+#define IN 32
+#include "tabletranstemplate.c"
+#undef IN
+#undef OUT
+
+typedef void (*rfbInitTableFnType)(ScreenPtr pScreen, char **table, rfbPixelFormat *in,
+				   rfbPixelFormat *out);
+
+rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = {
+    rfbInitTrueColourSingleTable8,
+    rfbInitTrueColourSingleTable16,
+    rfbInitTrueColourSingleTable32
+};
+
+rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = {
+    rfbInitColourMapSingleTable8,
+    rfbInitColourMapSingleTable16,
+    rfbInitColourMapSingleTable32
+};
+
+rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = {
+    rfbInitTrueColourRGBTables8,
+    rfbInitTrueColourRGBTables16,
+    rfbInitTrueColourRGBTables32
+};
+
+rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = {
+    { rfbTranslateWithSingleTable8to8,
+      rfbTranslateWithSingleTable8to16,
+      rfbTranslateWithSingleTable8to32 },
+    { rfbTranslateWithSingleTable16to8,
+      rfbTranslateWithSingleTable16to16,
+      rfbTranslateWithSingleTable16to32 },
+    { rfbTranslateWithSingleTable32to8,
+      rfbTranslateWithSingleTable32to16,
+      rfbTranslateWithSingleTable32to32 }
+};
+
+rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = {
+    { rfbTranslateWithRGBTables8to8,
+      rfbTranslateWithRGBTables8to16,
+      rfbTranslateWithRGBTables8to32 },
+    { rfbTranslateWithRGBTables16to8,
+      rfbTranslateWithRGBTables16to16,
+      rfbTranslateWithRGBTables16to32 },
+    { rfbTranslateWithRGBTables32to8,
+      rfbTranslateWithRGBTables32to16,
+      rfbTranslateWithRGBTables32to32 }
+};
+
+
+
+/*
+ * rfbTranslateNone is used when no translation is required.
+ */
+
+void
+rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, rfbPixelFormat *out,
+		 unsigned char *iptr, char *optr, int bytesBetweenInputLines,
+		 int width, int height, int x, int y)
+{
+    VNCSCREENPTR(pScreen);
+    int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
+
+    if (pVNC->useGetImage) {
+    	DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum];
+
+    	/* catch all for other TranslateNone cases - hextile, corre, rre, etc.*/
+    	(*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, optr);
+    } else {
+    	while (height > 0) {
+	    memcpy(optr, iptr, bytesPerOutputLine);
+	    iptr += bytesBetweenInputLines;
+	    optr += bytesPerOutputLine;
+	    height--;
+     	}
+    }
+}
+
+
+/*
+ * rfbSetTranslateFunction sets the translation function.
+ */
+
+Bool
+rfbSetTranslateFunction(cl)
+    rfbClientPtr cl;
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbLog("Pixel format for client %s:\n",cl->host);
+    PrintPixelFormat(&cl->format);
+
+    /*
+     * Check that bits per pixel values are valid
+     */
+
+    if ((pVNC->rfbServerFormat.bitsPerPixel != 8) &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 16) &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 32))
+    {
+	rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
+		"rfbSetTranslateFunction");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if ((cl->format.bitsPerPixel != 8) &&
+	(cl->format.bitsPerPixel != 16) &&
+	(cl->format.bitsPerPixel != 32))
+    {
+	rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
+		"rfbSetTranslateFunction");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if (!pVNC->rfbServerFormat.trueColour &&
+	(pVNC->rfbServerFormat.bitsPerPixel != 8) &&
+#if XFREE86VNC
+	(miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) {
+#else
+	(pVNC->rfbInstalledColormap->class == PseudoColor)) {
+#endif
+	rfbLog("rfbSetTranslateFunction: server has colour map "
+		"but %d-bit - can only cope with 8-bit colour maps\n",
+		pVNC->rfbServerFormat.bitsPerPixel);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    if (!cl->format.trueColour &&
+	(cl->format.bitsPerPixel != 8) &&
+#if XFREE86VNC
+	(miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) {
+#else
+	(pVNC->rfbInstalledColormap->class == PseudoColor) ) {
+#endif
+	rfbLog("rfbSetTranslateFunction: client has colour map "
+		"but %d-bit - can only cope with 8-bit colour maps\n",
+		cl->format.bitsPerPixel);
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    /*
+     * bpp is valid, now work out how to translate
+     */
+
+    if (!cl->format.trueColour) {
+
+	/* ? -> colour map */
+
+	if (!pVNC->rfbServerFormat.trueColour) {
+
+	    /* colour map -> colour map */
+
+#if XFREE86VNC
+	    if (miInstalledMaps[cl->pScreen->myNum]->class == DirectColor) {
+#else
+	    if (pVNC->rfbInstalledColormap->class == DirectColor) {
+#endif
+	      rfbLog("rfbSetTranslateFunction: client is %d-bit DirectColor,"
+ 		     " client has colour map\n",cl->format.bitsPerPixel);
+
+	      cl->translateFn = rfbTranslateWithRGBTablesFns
+			          [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+  	      (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16])
+		   (cl->pScreen, &cl->translateLookupTable,
+		   &pVNC->rfbServerFormat, &cl->format);
+
+	      return rfbSetClientColourMap(cl, 0, 0);
+
+	    /* PseudoColor colormap */
+
+	    } else {
+	      rfbLog("rfbSetTranslateFunction: both 8-bit colour map: "
+		     "no translation needed\n");
+	      cl->translateFn = rfbTranslateNone;
+	      return rfbSetClientColourMap(cl, 0, 0);
+	    }
+	}
+
+	/*
+	 * truecolour -> colour map
+	 *
+	 * Set client's colour map to BGR233, then effectively it's
+	 * truecolour as well
+	 */
+
+	if (!rfbSetClientColourMapBGR233(cl))
+	    return FALSE;
+
+	cl->format = BGR233Format;
+    }
+
+    /* ? -> truecolour */
+
+    if (!pVNC->rfbServerFormat.trueColour) {
+
+	/* colour map -> truecolour */
+
+	rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour,"
+		" server has colour map\n",cl->format.bitsPerPixel);
+
+	cl->translateFn = rfbTranslateWithSingleTableFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	return rfbSetClientColourMap(cl, 0, 0);
+    }
+
+    /* truecolour -> truecolour */
+
+    if (PF_EQ(cl->format,pVNC->rfbServerFormat)) {
+
+	/* client & server the same */
+
+	rfbLog("  no translation needed\n");
+	cl->translateFn = rfbTranslateNone;
+	return TRUE;
+    }
+
+    if ((pVNC->rfbServerFormat.bitsPerPixel < 16) ||
+	(!rfbEconomicTranslate && (pVNC->rfbServerFormat.bitsPerPixel == 16))) {
+
+	/* we can use a single lookup table for <= 16 bpp */
+
+	cl->translateFn = rfbTranslateWithSingleTableFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	(*rfbInitTrueColourSingleTableFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+
+    } else {
+
+	/* otherwise we use three separate tables for red, green and blue */
+
+	cl->translateFn = rfbTranslateWithRGBTablesFns
+			      [pVNC->rfbServerFormat.bitsPerPixel / 16]
+				  [cl->format.bitsPerPixel / 16];
+
+	(*rfbInitTrueColourRGBTablesFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+    }
+
+    return TRUE;
+}
+
+
+
+/*
+ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
+ * just like an 8-bit BGR233 true colour client.
+ */
+
+static Bool
+rfbSetClientColourMapBGR233(rfbClientPtr cl)
+{
+    char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
+    rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
+    CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
+    int i, len;
+    int r, g, b;
+
+    if (cl->format.bitsPerPixel != 8) {
+	rfbLog("%s: client not 8 bits per pixel\n",
+		"rfbSetClientColourMapBGR233");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+
+    scme->type = rfbSetColourMapEntries;
+
+    scme->firstColour = Swap16IfLE(0);
+    scme->nColours = Swap16IfLE(256);
+
+    len = sz_rfbSetColourMapEntriesMsg;
+
+    i = 0;
+
+    for (b = 0; b < 4; b++) {
+	for (g = 0; g < 8; g++) {
+	    for (r = 0; r < 8; r++) {
+		rgb[i++] = Swap16IfLE(r * 65535 / 7);
+		rgb[i++] = Swap16IfLE(g * 65535 / 7);
+		rgb[i++] = Swap16IfLE(b * 65535 / 3);
+	    }
+	}
+    }
+
+    len += 256 * 3 * 2;
+
+    if (WriteExact(cl->sock, buf, len) < 0) {
+	rfbLogPerror("rfbSetClientColourMapBGR233: write");
+	rfbCloseSock(cl->pScreen, cl->sock);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+ * rfbSetClientColourMap is called to set the client's colour map.  If the
+ * client is a true colour client, we simply update our own translation table
+ * and mark the whole screen as having been modified.
+ */
+
+Bool
+rfbSetClientColourMap(cl, firstColour, nColours)
+    rfbClientPtr cl;
+    int firstColour;
+    int nColours;
+{
+    VNCSCREENPTR(cl->pScreen);
+    BoxRec box;
+
+    if (nColours == 0) {
+#if XFREE86VNC
+	nColours = miInstalledMaps[cl->pScreen->myNum]->pVisual->ColormapEntries;
+#else
+	nColours = pVNC->rfbInstalledColormap->pVisual->ColormapEntries;
+#endif
+    }
+
+    if (pVNC->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
+	return TRUE;
+    }
+
+    if (cl->format.trueColour) {
+	(*rfbInitColourMapSingleTableFns
+	    [cl->format.bitsPerPixel / 16]) (cl->pScreen, 
+		    			     &cl->translateLookupTable,
+					     &pVNC->rfbServerFormat, &cl->format);
+
+	REGION_UNINIT(cl->pScreen,&cl->modifiedRegion);
+	box.x1 = box.y1 = 0;
+	box.x2 = pVNC->width;
+	box.y2 = pVNC->height;
+	REGION_INIT(cl->pScreen,&cl->modifiedRegion,&box,0);
+
+	return TRUE;
+    }
+
+    return rfbSendSetColourMapEntries(cl, firstColour, nColours);
+}
+
+
+/*
+ * rfbSetClientColourMaps sets the colour map for each RFB client.
+ */
+
+void
+rfbSetClientColourMaps(firstColour, nColours)
+    int firstColour;
+    int nColours;
+{
+    rfbClientPtr cl, nextCl;
+
+    for (cl = rfbClientHead; cl; cl = nextCl) {
+	nextCl = cl->next;
+	rfbSetClientColourMap(cl, firstColour, nColours);
+    }
+}
+
+
+static void
+PrintPixelFormat(pf)
+    rfbPixelFormat *pf;
+{
+    if (pf->bitsPerPixel == 1) {
+	rfbLog("  1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
+	       (pf->bigEndian ? "most" : "least"));
+    } else {
+	rfbLog("  %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
+	       ((pf->bitsPerPixel == 8) ? ""
+		: (pf->bigEndian ? ", big endian" : ", little endian")));
+	if (pf->trueColour) {
+	    rfbLog("  true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
+		   pf->redMax, pf->greenMax, pf->blueMax,
+		   pf->redShift, pf->greenShift, pf->blueShift);
+	} else {
+	    rfbLog("  uses a colour map (not true colour).\n");
+	}
+    }
+}
diff -u -rNp a/hw/xfree86/vnc/vncauth.h b/hw/xfree86/vnc/vncauth.h
--- a/hw/xfree86/vnc/vncauth.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/vncauth.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* 
+ * vncauth.h - describes the functions provided by the vncauth library.
+ */
+
+#define MAXPWLEN 8
+#define CHALLENGESIZE 16
+
+extern int vncEncryptAndStorePasswd(char *passwd, char *fname);
+extern char *vncDecryptPasswdFromFile(char *fname);
+extern void vncRandomBytes(unsigned char *bytes);
+extern void vncEncryptBytes(unsigned char *bytes, char *passwd);
+
+extern int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname);
+extern int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly);
+
diff -u -rNp a/hw/xfree86/vnc/vncext.c b/hw/xfree86/vnc/vncext.c
--- a/hw/xfree86/vnc/vncext.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/vncext.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,791 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include "rfb.h"
+#include "extnsionst.h"
+#define _VNC_SERVER
+#include <X11/extensions/vncstr.h>
+#ifdef XFree86LOADER
+#include "xf86Module.h"
+#endif
+
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int VncSelectNotify(ClientPtr client, BOOL onoff);
+void VncExtensionInit(void);
+
+static int VncErrorBase;  /* first vnc error number */
+static int VncEventBase;  /* first vnc event number */
+
+#define USE_ORIG_RES_CODE 0
+
+#if USE_ORIG_RES_CODE
+unsigned long VncResourceGeneration = 0;
+
+static RESTYPE VncNotifyList;
+
+static XID faked;
+
+typedef struct _VncNotifyListRec {
+    struct _VncNotifyListRec *next;
+    ClientPtr client;
+} VncNotifyListRec, *VncNotifyListPtr;
+#endif
+
+
+/**
+ * Each X client that uses libVnc to talk to this extension will get
+ * recorded by one of these records.
+ */
+typedef struct _VncClientRec {
+    ClientPtr client;
+    struct _VncClientRec *next;
+    XID fakeID;
+    RESTYPE res;
+} VncClientRec, *VncClientRecPtr;
+
+static VncClientRecPtr ClientsList = NULL;
+
+
+/**
+ * Remove client record from list
+ */
+static void
+VncRemoveClientRecord(ClientPtr client)
+{
+   /* XXX need 'deleteresource' flag? */
+    VncClientRecPtr p = ClientsList, prev = NULL;
+    rfbLog("%s client %p\n", __func__, (void *) client);
+    while (p) {
+        if (p->client == client) {
+            /* remove this one */
+            if (prev)
+                prev->next = p->next;
+            else
+                ClientsList = p->next;
+            xfree(p);
+            return;
+        }
+        prev = p;
+        p = p->next;
+    }
+}
+
+
+/**
+ * This callback will be called by X's resource manager to delete the
+ * given resource.  We create one resource for each client.  When X
+ * deletes the resource, we know the client is going away.
+ */
+static int
+VncDestroyClientResourceCallback(pointer pn, XID id)
+{
+    VncClientRecPtr rec = (VncClientRecPtr) pn;
+    VncRemoveClientRecord(rec->client);
+    return Success;
+}
+
+
+/**
+ * Add a client record to the list of clients (unless already in list).
+ * We'll create a new, unique resource for this client.  This is used
+ * to detect when an X client goes away.
+ */
+static void
+VncSaveClientRecord(ClientPtr client)
+{
+    VncClientRecPtr rec = ClientsList;
+
+    rfbLog("%s saving client %p\n", __func__, (void *) client);
+
+    /* look if already in list */
+    while (rec) {
+        if (rec->client == client) {
+            return; /* already in list */
+        }
+        rec = rec->next;
+    }
+
+    /* allocate new client record */
+    rec = (VncClientRecPtr) xalloc(sizeof(VncClientRec));
+    if (rec) {
+        rec->client = client;
+        rec->fakeID = FakeClientID(client->index);
+        rec->res = CreateNewResourceType(VncDestroyClientResourceCallback);
+        if (!AddResource(rec->fakeID, rec->res, rec)) {
+            xfree(rec);
+        }
+
+        /* insert at head of list */
+        rec->next = ClientsList;
+        ClientsList = rec;
+    }
+}
+
+
+
+static int
+ProcVncQueryVersion(ClientPtr client)
+{
+    xVncQueryVersionReply 	rep;
+
+    REQUEST_SIZE_MATCH(xVncQueryVersionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.majorVersion  	= VNC_MAJOR_VERSION;
+    rep.minorVersion  	= VNC_MINOR_VERSION;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.majorVersion, n);
+	swaps(&rep.minorVersion, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncQueryVersionReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncQueryVersion */
+
+static int
+ProcVncConnection(ClientPtr client)
+{
+    REQUEST(xVncConnectionReq);
+    xVncConnectionReply 	rep;
+
+    rfbUserAllow( stuff->sock, stuff->accept );
+
+    REQUEST_SIZE_MATCH(xVncConnectionReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    rep.sock  		= 0;
+    rep.accept  	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+	swaps(&rep.sock, n);
+	swaps(&rep.accept, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncConnectionReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncConnection */
+
+static int
+ProcVncSelectNotify(ClientPtr client)
+{
+    REQUEST(xVncSelectNotifyReq);
+    xVncSelectNotifyReply 	rep;
+
+    VncSelectNotify(client, stuff->onoff);
+
+    REQUEST_SIZE_MATCH(xVncSelectNotifyReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncSelectNotifyReply),
+			(char *)&rep);
+    return (client->noClientException);
+
+}
+
+static int
+ProcVncListConnections(ClientPtr client)
+{
+    xVncListConnectionsReply 	rep;
+    rfbClientPtr cl;
+    int count = 0;
+    struct in_addr ipaddress;
+    xVncConnectionListInfo Info;
+
+    /* count connections */
+    for (cl = rfbClientHead; cl; cl = cl->next)
+#ifdef CHROMIUM
+    /* 
+     * Fix this, as it should be generic, but we're only using it
+     * for Chromium at the moment, so we only list the connections
+     * that have a valid chromium encoding. We should be able to list
+     * any type requested. FIXME! XXXX
+     * See furthur down this function too!!!
+     */
+	    if (cl->enableChromiumEncoding)
+#endif
+	    	count++;
+
+    REQUEST_SIZE_MATCH(xVncListConnectionsReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.count		= count;
+    rep.length 		= count * sizeof(xVncConnectionListInfo) >> 2;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    	swaps(&rep.count, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncListConnectionsReply),
+			(char *)&rep);
+
+    for (cl = rfbClientHead; cl; cl = cl->next) {
+#ifdef CHROMIUM
+        /* 
+         * Fix this, as it should be generic, but we're only using it
+         * for Chromium at the moment, so we only list the connections
+         * that have a valid chromium encoding. We should be able to list
+         * any type requested. FIXME! XXXX
+         */
+	if (!cl->enableChromiumEncoding)
+	    continue;
+#endif
+	inet_aton(cl->host, &ipaddress);
+	memcpy(&Info, &ipaddress, sizeof(struct in_addr));
+	WriteToClient(client, SIZEOF(xVncConnectionListInfo), (char*)&Info);
+    }
+
+    return (client->noClientException);
+} /* ProcVncListConnections */
+
+#ifdef CHROMIUM
+static int
+ProcVncChromiumStart(ClientPtr client)
+{
+    REQUEST(xVncChromiumStartReq);
+    xVncChromiumStartReply 	rep;
+
+    rfbSendChromiumStart(stuff->ipaddress, stuff->crServerPort, stuff->mothershipPort);
+
+    REQUEST_SIZE_MATCH(xVncChromiumStartReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncChromiumStartReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncChromiumStart */
+
+static int
+ProcVncChromiumMonitor(ClientPtr client)
+{
+    REQUEST(xVncChromiumMonitorReq);
+    xVncChromiumMonitorReply 	rep;
+
+    rfbChromiumMonitorWindowID(stuff->cr_windowid, stuff->windowid);
+
+    REQUEST_SIZE_MATCH(xVncChromiumMonitorReq);
+    rep.type        	= X_Reply;
+    rep.sequenceNumber 	= client->sequence;
+    rep.length         	= 0;
+    if(client->swapped)
+    {
+	register char n;
+    	swaps(&rep.sequenceNumber, n);
+    }
+    (void)WriteToClient(client, SIZEOF(xVncChromiumMonitorReply),
+			(char *)&rep);
+    return (client->noClientException);
+} /* ProcVncChromiumMonitor */
+#endif /* CHROMIUM */
+
+static int
+ProcVncDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_VncQueryVersion:
+	    return ProcVncQueryVersion(client);
+	case X_VncSelectNotify:
+	    return ProcVncSelectNotify(client);
+	case X_VncConnection:
+	    return ProcVncConnection(client);
+	case X_VncListConnections:
+	    return ProcVncListConnections(client);
+#ifdef CHROMIUM
+	case X_VncChromiumStart:
+	    return ProcVncChromiumStart(client);
+	case X_VncChromiumMonitor:
+	    return ProcVncChromiumMonitor(client);
+#endif
+	default:
+	    return BadRequest;
+    }
+} /* ProcVncDispatch */
+
+static int
+SProcVncQueryVersion(ClientPtr client)
+{
+    REQUEST(xVncQueryVersionReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncQueryVersionReq);
+    swaps(&stuff->majorVersion, n);
+    swaps(&stuff->minorVersion,n);
+    return ProcVncQueryVersion(client);
+} /* SProcVncQueryVersion */
+
+static int
+SProcVncSelectNotify(ClientPtr client)
+{
+    REQUEST(xVncSelectNotifyReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncSelectNotifyReq);
+    return ProcVncSelectNotify(client);
+} /* SProcVncSelectNotify */
+
+static int
+SProcVncListConnections(ClientPtr client)
+{
+    REQUEST(xVncListConnectionsReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncListConnectionsReq);
+    return ProcVncListConnections(client);
+} /* SProcVncListConnections */
+
+#ifdef CHROMIUM
+static int
+SProcVncChromiumStart(ClientPtr client)
+{
+    REQUEST(xVncChromiumStartReq);
+    register char 	n;
+
+    swaps(&stuff->ipaddress, n);
+    swaps(&stuff->crServerPort, n);
+    swaps(&stuff->mothershipPort, n);
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncChromiumStartReq);
+    return ProcVncChromiumStart(client);
+} /* SProcVncChromiumStart */
+
+static int
+SProcVncChromiumMonitor(ClientPtr client)
+{
+    REQUEST(xVncChromiumMonitorReq);
+    register char 	n;
+
+    swaps(&stuff->length, n);
+    swaps(&stuff->windowid, n);
+    swaps(&stuff->cr_windowid, n);
+    REQUEST_SIZE_MATCH(xVncChromiumMonitorReq);
+    return ProcVncChromiumMonitor(client);
+} /* SProcVncChromiumMonitor */
+#endif /* CHROMIUM */
+
+static int
+SProcVncConnection(ClientPtr client)
+{
+    REQUEST(xVncConnectionReq);
+    register char 	n;
+
+
+    swaps(&stuff->length, n);
+    REQUEST_SIZE_MATCH(xVncConnectionReq);
+    swaps(&stuff->sock, n);
+    swaps(&stuff->accept,n);
+    return ProcVncConnection(client);
+} /* SProcVncConnection */
+
+static int
+SProcVncDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+
+    switch (stuff->data)
+    {
+	case X_VncQueryVersion:
+	    return SProcVncQueryVersion(client);
+	case X_VncSelectNotify:
+	    return SProcVncSelectNotify(client);
+	case X_VncConnection:
+	    return SProcVncConnection(client);
+	case X_VncListConnections:
+	    return SProcVncListConnections(client);
+#ifdef CHROMIUM
+	case X_VncChromiumStart:
+	    return SProcVncChromiumStart(client);
+	case X_VncChromiumMonitor:
+	    return SProcVncChromiumMonitor(client);
+#endif
+	default:
+	    return BadRequest;
+    }
+} /* SProcVncDispatch */
+
+static void 
+SwapVncConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+
+#ifdef CHROMIUM
+static void 
+SwapVncChromiumConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+#endif
+
+static void 
+SwapVncDisconnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to)
+{
+    to->type = from->type;
+    to->detail = from->detail;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->connected, to->connected);
+}
+
+int
+GenerateVncConnectedEvent(int sock)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+#else
+    VncClientRecPtr pn = ClientsList;
+#endif
+
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncConnectedEvent conn;
+    	  SOCKLEN_T peer_len;
+    	  struct sockaddr_in peer;
+
+    	  conn.type = VncEventBase + XVncConnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+
+    	  peer_len = sizeof(peer);
+    	  if (getpeername(sock, (struct sockaddr *) &peer, &peer_len) == -1)
+		conn.ipaddress = 0;
+   	  else
+		conn.ipaddress = (CARD32)peer.sin_addr.s_addr;
+
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+
+
+
+#ifdef CHROMIUM
+int
+GenerateVncChromiumConnectedEvent(int sock)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr pn;
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+#else
+    VncClientRecPtr pn = ClientsList;
+#endif
+    rfbLog("Enter GenerateVncChromiumConnectedEvent\n");
+    while (pn)
+    {
+	if (pn->client) 
+	{
+    	  xVncConnectedEvent conn;
+    	  SOCKLEN_T peer_len;
+    	  struct sockaddr_in peer;
+
+          rfbLog("Sending XVncChromiumConnected to client %p\n",
+                 (void *) pn->client);
+
+    	  conn.type = VncEventBase + XVncChromiumConnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+
+    	  peer_len = sizeof(peer);
+    	  if (getpeername(sock, (struct sockaddr *)&peer, &peer_len) == -1)
+		conn.ipaddress = 0;
+   	  else
+		conn.ipaddress = (CARD32)peer.sin_addr.s_addr;
+
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+    return 1;
+}
+#endif /* CHROMIUM */
+
+
+int
+GenerateVncDisconnectedEvent(int sock)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr pn;
+
+    pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList);
+#else
+    VncClientRecPtr pn = ClientsList;
+#endif
+    while (pn)
+      {
+	if (pn->client) 
+	{
+    	  xVncDisconnectedEvent conn;
+    	  conn.type = VncEventBase + XVncDisconnected;
+    	  conn.sequenceNumber = pn->client->sequence;
+    	  conn.connected = sock;
+	  (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask,
+				 NoEventMask, NullGrab);
+	}
+	pn = pn->next;
+    }
+
+    return 1;
+}
+
+static void
+VncResetProc(ExtensionEntry *extEntry)
+{
+} /* VncResetProc */
+
+
+
+/**
+ * When the app calls libVnc's XVncSelectNotify() we wind up here.
+ * Either add or remove 'client' from the VncNotifyList depending on 'onoff'.
+ */
+int
+VncSelectNotify(ClientPtr client, BOOL onoff)
+{
+#if USE_ORIG_RES_CODE
+    VncNotifyListPtr head, newRec, tmp, freeRec = NULL;
+
+    rfbLog("%s client %p onoff=%d\n", __func__, (void *) client, (int) onoff);
+    if (!faked)
+	faked = FakeClientID(client->index);
+#else
+    /* ignore onoff param */
+    VncSaveClientRecord(client);
+#endif
+
+#if USE_ORIG_RES_CODE
+    /* Get the first VncNotifyListPtr */
+    head = (VncNotifyListPtr) LookupIDByType(faked, VncNotifyList);
+
+    /* search list for this client */
+    tmp = head;
+    while (tmp) {
+        if (tmp->client == client) {
+            /* found client! */
+            if (!onoff)
+                tmp->client = NULL;
+            return Success;
+        }
+        if (!tmp->client)
+            freeRec = tmp;  /* save ptr to free record */
+        tmp = tmp->next;
+    }
+
+    /* if we get here, we didn't find client in the list */
+
+    if (!onoff) {
+        /* if turning off non-existing client, just return */
+        return Success;
+    }
+
+    /* OK, add new client to list now */
+
+    if (freeRec) {
+        /* re-using a free spot */
+        freeRec->client = client;
+        return Success;
+    }
+
+    /* need to allocate new node */
+    if (!(newRec = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec))))
+        return BadAlloc;
+    /* insert at head, just as AddResource() does!!! */
+    newRec->next = head;
+    newRec->client = client;
+    if (!AddResource(faked, VncNotifyList, newRec)) {
+        xfree(newRec);
+        return BadAlloc;
+    }
+#endif
+    return Success;
+}
+
+
+#if USE_ORIG_RES_CODE
+static int
+VncDestroyNotifyList(pointer pn, XID id)
+{
+    VncNotifyListPtr cpn = (VncNotifyListPtr) pn;
+    rfbLog("%s client %p\n", __func__, (void *) cpn->client);
+    cpn->client = NULL;
+    return Success;
+}
+#endif
+
+static Bool
+CreateResourceTypes(void)
+{
+#if USE_ORIG_RES_CODE
+    if (VncResourceGeneration == serverGeneration)
+        return TRUE;
+
+    VncResourceGeneration = serverGeneration;
+
+    if (!(VncNotifyList = CreateNewResourceType(VncDestroyNotifyList))) {
+        ErrorF("CreateResourceTypes: failed to allocate vnc notify list resource.\n");
+        return FALSE;
+    }
+#endif
+    return TRUE;
+}
+
+
+
+#if XFREE86VNC
+static unsigned long vncCreateScreenResourcesIndex;
+static unsigned long vncExtGeneration = 0;
+extern Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart);
+
+/* copied from miscrinit.c */
+typedef struct
+{
+    pointer pbits; /* pointer to framebuffer */
+    int width;    /* delta to add to a framebuffer addr to move one row down */
+} miScreenInitParmsRec, *miScreenInitParmsPtr;
+
+
+static Bool
+vncCreateScreenResources(ScreenPtr pScreen)
+{
+    int ret = TRUE;
+    CreateScreenResourcesProcPtr CreateScreenResources =
+        (CreateScreenResourcesProcPtr)
+        pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr;
+    miScreenInitParmsPtr pScrInitParms;
+
+    pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate;
+
+    if ( pScreen->CreateScreenResources != vncCreateScreenResources ) {
+        /* Can't find hook we are hung on */
+	xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */,
+                   "vncCreateScreenResources %p called when not in "
+                   "pScreen->CreateScreenResources %p n",
+		   (void *) vncCreateScreenResources,
+                   (void *) pScreen->CreateScreenResources );
+    }
+
+    /* Now do our stuff */
+    VNCInit(pScreen, pScrInitParms->pbits);
+
+    /* Unhook this function ... */
+    pScreen->CreateScreenResources = CreateScreenResources;
+    pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr = NULL;
+
+    /* ... and call the previous CreateScreenResources fuction, if any */
+    if (pScreen->CreateScreenResources) {
+        ret = (*pScreen->CreateScreenResources)(pScreen);
+    }
+
+    return ret;
+}
+#endif
+
+
+
+void
+VncExtensionInit(void)
+{
+    ExtensionEntry	*extEntry;
+
+#if XFREE86VNC
+    if (vncExtGeneration != serverGeneration) {
+	unsigned int i;
+
+	vncExtGeneration = serverGeneration;
+
+    	if ( ((vncCreateScreenResourcesIndex = AllocateScreenPrivateIndex()) < 0) ||
+	     ((vncScreenPrivateIndex = AllocateScreenPrivateIndex()) < 0) ||
+	     ((rfbGCIndex = AllocateGCPrivateIndex()) < 0) )
+		return;
+
+    	for (i = 0 ; i < screenInfo.numScreens; i++) 
+	{
+      	    screenInfo.screens[i]->devPrivates[vncCreateScreenResourcesIndex].ptr
+	 		= (void*)(xf86Screens[i]->pScreen->CreateScreenResources);
+      	    xf86Screens[i]->pScreen->CreateScreenResources = vncCreateScreenResources;
+    	}
+
+	gethostname(rfbThisHost, 255);
+    }
+#endif
+
+    if (!CreateResourceTypes())
+	    return;
+
+    extEntry = AddExtension(VNC_EXTENSION_NAME,
+			    XVncNumberEvents, XVncNumberErrors,
+			    ProcVncDispatch, SProcVncDispatch,
+                            VncResetProc, StandardMinorOpcode);
+
+    VncErrorBase = extEntry->errorBase;
+    VncEventBase = extEntry->eventBase;
+
+    EventSwapVector[VncEventBase + XVncConnected] =
+	(EventSwapPtr)SwapVncConnectedEvent;
+    EventSwapVector[VncEventBase + XVncDisconnected] =
+	(EventSwapPtr)SwapVncDisconnectedEvent;
+#ifdef CHROMIUM
+    EventSwapVector[VncEventBase + XVncChromiumConnected] =
+	(EventSwapPtr)SwapVncChromiumConnectedEvent;
+#endif
+} /* VncExtensionInit */
diff -u -rNp a/hw/xfree86/vnc/vncInit.c b/hw/xfree86/vnc/vncInit.c
--- a/hw/xfree86/vnc/vncInit.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/vncInit.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,640 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#include <netinet/in.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../ramdac/xf86CursorPriv.h"
+#include "rfb.h"
+#include "vncint.h"
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Resources.h"
+#include "xf86Version.h"
+
+int vncScreenPrivateIndex = -1;
+int rfbGCIndex = -1;
+int inetdSock = -1;
+Atom VNC_LAST_CLIENT_ID = 0;
+Atom VNC_CONNECT = 0;
+char *desktopName = "x11";
+char rfbThisHost[256];
+
+extern void VncExtensionInit(void);
+
+Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart);
+
+#ifndef XFree86LOADER
+static unsigned long VNCGeneration = 0;
+#endif
+static const OptionInfoRec *VNCAvailableOptions(void *unused);
+static void rfbWakeupHandler (int i, pointer blockData, unsigned long err, pointer pReadmask);
+
+static Bool vncCursorRealizeCursor(ScreenPtr, CursorPtr);
+static Bool vncCursorUnrealizeCursor(ScreenPtr, CursorPtr);
+static void vncCursorSetCursor(ScreenPtr, CursorPtr, int, int);
+static void vncCursorMoveCursor(ScreenPtr, int, int);
+static Bool vncDisplayCursor(ScreenPtr, CursorPtr);
+
+static miPointerSpriteFuncRec vncCursorSpriteFuncs = {
+   vncCursorRealizeCursor,
+   vncCursorUnrealizeCursor,
+   vncCursorSetCursor,
+   vncCursorMoveCursor
+};
+
+/*
+ * VNC Config options
+ */
+
+typedef enum {
+    OPTION_USEVNC,
+    OPTION_RFBPORT,
+    OPTION_HTTPPORT,
+    OPTION_ALWAYS_SHARED,
+    OPTION_NEVER_SHARED,
+    OPTION_DONT_DISCONNECT,
+    OPTION_HTTPDIR,
+    OPTION_PASSWD_FILE,
+    OPTION_USER_ACCEPT,
+    OPTION_LOCALHOST,
+    OPTION_INTERFACE,
+    OPTION_VIEWONLY,
+    OPTION_LOGIN_AUTH,
+    OPTION_USE_GETIMAGE
+} VNCOpts;
+
+static const OptionInfoRec VNCOptions[] = {
+    {OPTION_USEVNC,		"usevnc",	OPTV_BOOLEAN,	{0}, FALSE },
+    {OPTION_RFBPORT,		"rfbport",	OPTV_INTEGER, 	{0}, FALSE },
+    {OPTION_HTTPPORT,		"httpport",	OPTV_INTEGER, 	{0}, FALSE },
+    {OPTION_ALWAYS_SHARED, 	"alwaysshared", OPTV_BOOLEAN,  	{0}, FALSE },
+    {OPTION_NEVER_SHARED, 	"nevershared", 	OPTV_BOOLEAN,  	{0}, FALSE },
+    {OPTION_DONT_DISCONNECT, 	"dontdisconnect", OPTV_BOOLEAN,	{0}, FALSE },
+    {OPTION_HTTPDIR,		"httpdir",	OPTV_STRING, 	{0}, FALSE },
+    {OPTION_PASSWD_FILE,	"rfbauth",	OPTV_STRING, 	{0}, FALSE },
+    {OPTION_USER_ACCEPT,	"useraccept",	OPTV_BOOLEAN, 	{0}, FALSE },
+    {OPTION_LOCALHOST,		"localhost",	OPTV_BOOLEAN, 	{0}, FALSE },
+    {OPTION_INTERFACE,		"interface",	OPTV_STRING, 	{0}, FALSE },
+    {OPTION_VIEWONLY,		"viewonly",	OPTV_BOOLEAN, 	{0}, FALSE },
+    {OPTION_LOGIN_AUTH,		"loginauth",	OPTV_BOOLEAN, 	{0}, FALSE },
+    {OPTION_USE_GETIMAGE,	"usegetimage",	OPTV_BOOLEAN, 	{0}, FALSE },
+    { -1,			NULL,		OPTV_NONE, 	{0}, FALSE }
+};
+
+/*ARGSUSED*/
+static const OptionInfoRec *
+VNCAvailableOptions(void *unused)
+{
+    return (VNCOptions);
+}
+
+/*
+ * rfbLog prints a time-stamped message to the log file (stderr).
+ */
+
+void rfbLog(char *format, ...)
+{
+    va_list ap;
+    char buf[256];
+    time_t clock;
+
+    time(&clock);
+    strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock));
+    xf86DrvMsgVerb(-1, X_INFO, 1, buf);
+
+    va_start(ap, format);
+    xf86VDrvMsgVerb(-1, X_NONE, 1, format, ap);
+    va_end(ap);
+}
+
+void rfbLogPerror(char *str)
+{
+    rfbLog("");
+    perror(str);
+}
+
+/*
+ * Called by vncCreateScreenResources()
+ */
+Bool
+VNCInit(ScreenPtr pScreen, unsigned char *FBStart)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    VisualPtr visual;
+    vncScreenPtr pScreenPriv;
+    OptionInfoPtr options;
+    char *interface_str = NULL;
+    miPointerScreenPtr PointPriv;
+    xf86CursorScreenPtr xf86CursorPriv;
+#ifdef RENDER
+    PictureScreenPtr	ps;
+#endif
+
+    if (!FBStart)
+	return FALSE;
+
+#ifndef XFree86LOADER
+    if (VNCGeneration != serverGeneration) {
+	VncExtensionInit();
+	VNCGeneration = serverGeneration;
+    }
+#endif
+
+    if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec)))
+	return FALSE;
+
+    if (!(pScreenPriv = xalloc(sizeof(vncScreenRec))))
+	return FALSE;
+
+    pScreen->devPrivates[vncScreenPrivateIndex].ptr = (pointer)pScreenPriv;
+
+    options = xnfalloc(sizeof(VNCOptions));
+    (void)memcpy(options, VNCOptions, sizeof(VNCOptions));
+    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
+
+    if (xf86ReturnOptValBool(options, OPTION_USEVNC, FALSE)) {
+	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VNC enabled\n");
+    } else {
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VNC disabled\n");
+	xfree(options);
+	return FALSE;
+    }
+ 
+    pScreenPriv->rfbAuthTries = 0;
+    pScreenPriv->rfbAuthTooManyTries = FALSE;
+    pScreenPriv->timer = NULL;
+    pScreenPriv->udpPort = 0;
+    pScreenPriv->rfbListenSock = -1;
+    pScreenPriv->udpSock = -1;
+    pScreenPriv->udpSockConnected = FALSE;
+    pScreenPriv->httpListenSock = -1;
+    pScreenPriv->httpSock = -1;
+    pScreenPriv->maxFd = 0;
+    pScreenPriv->rfbAuthPasswdFile = NULL;
+    pScreenPriv->httpDir = NULL;
+    pScreenPriv->rfbInstalledColormap = NULL;
+    pScreenPriv->interface.s_addr = htonl (INADDR_ANY);
+
+    pScreenPriv->rfbPort = 0;
+    xf86GetOptValInteger(options, OPTION_RFBPORT, &pScreenPriv->rfbPort);
+    pScreenPriv->httpPort = 0;
+    xf86GetOptValInteger(options, OPTION_HTTPPORT, &pScreenPriv->httpPort);
+    pScreenPriv->rfbAuthPasswdFile = 
+			xf86GetOptValString(options, OPTION_PASSWD_FILE);
+    pScreenPriv->httpDir =
+			xf86GetOptValString(options, OPTION_HTTPDIR);
+    pScreenPriv->rfbAlwaysShared = FALSE;
+    xf86GetOptValBool(options, OPTION_ALWAYS_SHARED, 
+						&pScreenPriv->rfbAlwaysShared);
+    pScreenPriv->rfbNeverShared = FALSE;
+    xf86GetOptValBool(options, OPTION_NEVER_SHARED, 
+						&pScreenPriv->rfbNeverShared);
+    pScreenPriv->rfbUserAccept = FALSE;
+    xf86GetOptValBool(options, OPTION_USER_ACCEPT,
+						&pScreenPriv->rfbUserAccept);
+    pScreenPriv->useGetImage = FALSE;
+    xf86GetOptValBool(options, OPTION_USE_GETIMAGE,
+						&pScreenPriv->useGetImage);
+    pScreenPriv->rfbViewOnly = FALSE;
+    xf86GetOptValBool(options, OPTION_VIEWONLY,
+						&pScreenPriv->rfbViewOnly);
+    pScreenPriv->rfbDontDisconnect = FALSE;
+    xf86GetOptValBool(options, OPTION_DONT_DISCONNECT, 
+						&pScreenPriv->rfbDontDisconnect);
+    pScreenPriv->loginAuthEnabled = FALSE;
+    xf86GetOptValBool(options, OPTION_LOGIN_AUTH, 
+						&pScreenPriv->loginAuthEnabled);
+
+    if (xf86ReturnOptValBool(options, OPTION_LOCALHOST, FALSE))
+	pScreenPriv->interface.s_addr = htonl (INADDR_LOOPBACK);
+
+    interface_str = xf86GetOptValString(options, OPTION_INTERFACE);
+
+    if (interface_str && pScreenPriv->interface.s_addr == htonl(INADDR_ANY)) {
+	Bool failed = FALSE;
+	struct in_addr got;
+	unsigned long octet;
+	char *p = interface_str, *end;
+	int q;
+
+	for (q = 0; q < 4; q++) {
+	    octet = strtoul (p, &end, 10);
+
+	    if (p == end || octet > 255)
+		failed = TRUE;
+
+	    if ((q < 3 && *end != '.') ||
+	        (q == 3 && *end != '\0'))
+		failed = TRUE;
+
+	    got.s_addr = (got.s_addr << 8) | octet;
+	    p = end + 1;
+	}
+
+	if (!failed)
+	    pScreenPriv->interface.s_addr = htonl (got.s_addr);
+	else
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VNC interface option malformed, not using.\n");
+    }
+
+    xfree(options);
+
+    if (!VNC_LAST_CLIENT_ID)
+    	VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID",
+				  strlen("VNC_LAST_CLIENT_ID"), TRUE);
+    if (!VNC_CONNECT)
+    	VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE);
+
+    rfbInitSockets(pScreen);
+    if (inetdSock == -1)
+    	httpInitSockets(pScreen);
+   
+#ifdef CORBA
+    initialiseCORBA(argc, argv, desktopName);
+#endif
+
+    pScreenPriv->width = pScrn->virtualX;
+    pScreenPriv->height = pScrn->virtualY;
+    pScreenPriv->depth = pScrn->depth;
+    pScreenPriv->paddedWidthInBytes = PixmapBytePad(pScrn->displayWidth, pScrn->depth);
+    pScreenPriv->bitsPerPixel = rfbBitsPerPixel(pScrn->depth);
+    pScreenPriv->pfbMemory = FBStart;
+    pScreenPriv->oldpfbMemory = FBStart;
+
+    pScreenPriv->cursorIsDrawn = TRUE;
+    pScreenPriv->dontSendFramebufferUpdate = FALSE;
+
+    pScreenPriv->CloseScreen = pScreen->CloseScreen;
+    pScreenPriv->CreateGC = pScreen->CreateGC;
+    pScreenPriv->PaintWindowBackground = pScreen->PaintWindowBackground;
+    pScreenPriv->PaintWindowBorder = pScreen->PaintWindowBorder;
+    pScreenPriv->CopyWindow = pScreen->CopyWindow;
+    pScreenPriv->ClearToBackground = pScreen->ClearToBackground;
+    pScreenPriv->RestoreAreas = pScreen->RestoreAreas;
+    pScreenPriv->WakeupHandler = pScreen->WakeupHandler;
+    pScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
+    pScreenPriv->InstallColormap = pScreen->InstallColormap;
+    pScreenPriv->UninstallColormap = pScreen->UninstallColormap;
+    pScreenPriv->ListInstalledColormaps = pScreen->ListInstalledColormaps;
+    pScreenPriv->StoreColors = pScreen->StoreColors;
+    pScreenPriv->DisplayCursor = pScreen->DisplayCursor;
+#ifdef CHROMIUM
+    pScreenPriv->RealizeWindow = pScreen->RealizeWindow;
+    pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow;
+    pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
+    pScreenPriv->PositionWindow = pScreen->PositionWindow;
+    pScreenPriv->ResizeWindow = pScreen->ResizeWindow;
+    pScreenPriv->ClipNotify = pScreen->ClipNotify;
+#endif
+#ifdef RENDER
+    ps = GetPictureScreenIfSet(pScreen);
+    if (ps)
+    	pScreenPriv->Composite = ps->Composite;
+#endif
+    pScreen->CloseScreen = rfbCloseScreen;
+    pScreen->CreateGC = rfbCreateGC;
+    pScreen->PaintWindowBackground = rfbPaintWindowBackground;
+    pScreen->PaintWindowBorder = rfbPaintWindowBorder;
+    pScreen->CopyWindow = rfbCopyWindow;
+    pScreen->ClearToBackground = rfbClearToBackground;
+    pScreen->RestoreAreas = rfbRestoreAreas;
+    pScreen->WakeupHandler = rfbWakeupHandler;
+    pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess;
+    pScreen->InstallColormap = rfbInstallColormap;
+    pScreen->UninstallColormap = rfbUninstallColormap;
+    pScreen->ListInstalledColormaps = rfbListInstalledColormaps;
+    pScreen->StoreColors = rfbStoreColors;
+    pScreen->DisplayCursor = vncDisplayCursor; /* it's defined in here */
+
+#ifdef CHROMIUM
+    pScreen->RealizeWindow = rfbRealizeWindow;
+    pScreen->UnrealizeWindow = rfbUnrealizeWindow;
+    pScreen->DestroyWindow = rfbDestroyWindow;
+    pScreen->PositionWindow = rfbPositionWindow;
+    pScreen->ResizeWindow = rfbResizeWindow;
+    pScreen->ClipNotify = rfbClipNotify;
+#endif
+#ifdef RENDER
+    if (ps)
+    	ps->Composite = rfbComposite;
+#endif
+
+    for (visual = pScreen->visuals; visual->vid != pScreen->rootVisual; visual++)
+	;
+
+    if (!visual) {
+	ErrorF("rfbScreenInit: couldn't find root visual\n");
+	return FALSE;
+    }
+
+    pScreenPriv->rfbServerFormat.bitsPerPixel = pScrn->bitsPerPixel;
+    pScreenPriv->rfbServerFormat.depth = pScrn->depth;
+    pScreenPriv->rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest);
+    pScreenPriv->rfbServerFormat.trueColour = (visual->class == TrueColor);
+    if (pScreenPriv->rfbServerFormat.trueColour) {
+	pScreenPriv->rfbServerFormat.redMax = visual->redMask >> visual->offsetRed;
+	pScreenPriv->rfbServerFormat.greenMax = visual->greenMask >> visual->offsetGreen;
+	pScreenPriv->rfbServerFormat.blueMax = visual->blueMask >> visual->offsetBlue;
+	pScreenPriv->rfbServerFormat.redShift = visual->offsetRed;
+	pScreenPriv->rfbServerFormat.greenShift = visual->offsetGreen;
+	pScreenPriv->rfbServerFormat.blueShift = visual->offsetBlue;
+    } else {
+	pScreenPriv->rfbServerFormat.redMax
+	    = pScreenPriv->rfbServerFormat.greenMax 
+	    = pScreenPriv->rfbServerFormat.blueMax = 0;
+	pScreenPriv->rfbServerFormat.redShift
+	    = pScreenPriv->rfbServerFormat.greenShift 
+	    = pScreenPriv->rfbServerFormat.blueShift = 0;
+    }
+
+    PointPriv = pScreen->devPrivates[miPointerScreenIndex].ptr;
+
+    pScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
+    PointPriv->spriteFuncs = &vncCursorSpriteFuncs;
+
+    if (xf86LoaderCheckSymbol("xf86CursorScreenIndex")) {
+	int *si;
+
+	si = LoaderSymbol("xf86CursorScreenIndex");
+
+	if (*si != -1) {
+    	    xf86CursorPriv = pScreen->devPrivates[*si].ptr;
+
+	    if (xf86CursorPriv) {
+		pScreenPriv->UseHWCursor = xf86CursorPriv->CursorInfoPtr->UseHWCursor;
+		xf86CursorPriv->CursorInfoPtr->UseHWCursor = vncUseHWCursor;
+#ifdef ARGB_CURSOR
+		pScreenPriv->UseHWCursorARGB = xf86CursorPriv->CursorInfoPtr->UseHWCursorARGB;
+		xf86CursorPriv->CursorInfoPtr->UseHWCursorARGB = vncUseHWCursorARGB;
+#endif
+		pScreenPriv->SWCursor = &xf86CursorPriv->SWCursor;
+	    }
+	}
+    }
+
+    return TRUE;
+}
+
+/****** miPointerSpriteFunctions *******/
+
+static Bool
+vncCursorRealizeCursor(ScreenPtr pScreen, CursorPtr pCurs)
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+
+    return (*pScreenPriv->spriteFuncs->RealizeCursor)(pScreen, pCurs);
+}
+
+static Bool
+vncCursorUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCurs)
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+
+    return (*pScreenPriv->spriteFuncs->UnrealizeCursor)(pScreen, pCurs);
+}
+
+static void
+vncCursorSetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y)
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+
+    pScreenPriv->pCurs = pCurs;
+
+    /* Without this call, cursor changes only appear in the viewer when
+     * some other drawing has occured.  Added by BrianP.
+     */
+    rfbScheduleUpdate(pScreen);
+
+#if 0
+    if (pCurs == NullCursor) {	/* means we're supposed to remove the cursor */
+	if (pScreenPriv->cursorIsDrawn)
+	    pScreenPriv->cursorIsDrawn = FALSE;
+	return;
+    } 
+
+    pScreenPriv->cursorIsDrawn = TRUE;
+#endif
+
+    (*pScreenPriv->spriteFuncs->SetCursor)(pScreen, pCurs, x, y);
+}
+
+static void
+vncCursorMoveCursor(ScreenPtr pScreen, int x, int y)
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+    rfbClientPtr cl;
+
+    for (cl = rfbClientHead; cl ; cl = cl->next) {
+	if (cl->enableCursorPosUpdates)
+	    cl->cursorWasMoved = TRUE;
+    }
+
+    (*pScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y);
+}
+
+Bool
+vncUseHWCursor(pScreen, pCursor)
+    ScreenPtr pScreen;
+    CursorPtr pCursor;
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+    rfbClientPtr cl;
+
+    if (!*pScreenPriv->UseHWCursor) {
+	/* If the driver doesn't have a UseHWCursor function we're
+	 * basically saying we can have the HWCursor on all the time 
+	 */
+    	pScreenPriv->SWCursor = (Bool *)FALSE;
+	return TRUE;
+    }
+
+    pScreenPriv->SWCursor = (Bool *)FALSE;
+
+    /* If someone's connected, we revert to software cursor */
+    for (cl = rfbClientHead; cl ; cl = cl->next) {
+	if (!cl->enableCursorShapeUpdates)
+	    pScreenPriv->SWCursor = (Bool *)TRUE;
+    }
+    
+    if (pScreenPriv->SWCursor == (Bool *)TRUE)
+	return FALSE;
+
+    return (*pScreenPriv->UseHWCursor)(pScreen, pCursor);
+}
+
+#ifdef ARGB_CURSOR
+#include "cursorstr.h"
+
+Bool
+vncUseHWCursorARGB(pScreen, pCursor)
+    ScreenPtr pScreen;
+    CursorPtr pCursor;
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+    rfbClientPtr cl;
+
+    if (!*pScreenPriv->UseHWCursorARGB) {
+    	pScreenPriv->SWCursor = (Bool *)TRUE;
+	return FALSE;
+    }
+
+    pScreenPriv->SWCursor = (Bool *)FALSE;
+
+    /* If someone's connected, we revert to software cursor */
+    for (cl = rfbClientHead; cl ; cl = cl->next) {
+	if (!cl->enableCursorShapeUpdates)
+	    pScreenPriv->SWCursor = (Bool *)TRUE;
+    }
+    
+    if (pScreenPriv->SWCursor == (Bool *)TRUE)
+	return FALSE;
+
+    return (*pScreenPriv->UseHWCursorARGB)(pScreen, pCursor);
+}
+#endif
+
+static Bool
+vncDisplayCursor(pScreen, pCursor)
+    ScreenPtr pScreen;
+    CursorPtr pCursor;
+{
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+    rfbClientPtr cl;
+    Bool ret;
+
+    pScreen->DisplayCursor = pScreenPriv->DisplayCursor;
+
+    for (cl = rfbClientHead; cl ; cl = cl->next) {
+	if (cl->enableCursorShapeUpdates)
+	    cl->cursorWasChanged = TRUE;
+    }
+
+    ret = (*pScreen->DisplayCursor)(pScreen, pCursor);
+
+    pScreen->DisplayCursor = vncDisplayCursor;
+
+    return ret;
+}
+
+static void
+rfbWakeupHandler (
+    int 	i,	
+    pointer     blockData,
+    unsigned long err,
+    pointer     pReadmask
+){
+    ScreenPtr      pScreen = screenInfo.screens[i];
+    vncScreenPtr   pScreenPriv = VNCPTR(pScreen);
+    ScrnInfoPtr    pScrn = xf86Screens[pScreen->myNum];
+    int sigstate = xf86BlockSIGIO();
+
+    rfbRootPropertyChange(pScreen); /* Check clipboard */
+
+    if (pScrn->vtSema) {
+    	rfbCheckFds(pScreen);
+    	httpCheckFds(pScreen);
+#ifdef CORBA
+    	corbaCheckFds();
+#endif
+    } else {
+    	rfbCheckFds(pScreen);
+    }
+
+    xf86UnblockSIGIO(sigstate);		    
+
+    pScreen->WakeupHandler = pScreenPriv->WakeupHandler;
+    (*pScreen->WakeupHandler) (i, blockData, err, pReadmask);
+    pScreen->WakeupHandler = rfbWakeupHandler;
+}
+
+#ifdef XFree86LOADER
+static MODULESETUPPROTO(vncSetup);
+
+static XF86ModuleVersionInfo vncVersRec =
+{
+	"vnc",
+	"xf4vnc Project, see http://xf4vnc.sf.net (based on modular X.org)",
+	MODINFOSTRING1,
+	MODINFOSTRING2,
+	XORG_VERSION_CURRENT,
+	1, 1, 0,
+	ABI_CLASS_EXTENSION,
+#if 0
+	ABI_EXTENSION_VERSION,
+#else
+        /* Hack to allow module to work with more servers (vs. 0.3 above) */
+        SET_ABI_VERSION(0, 2),
+#endif
+	MOD_CLASS_EXTENSION,
+	{0,0,0,0}
+};
+
+XF86ModuleData vncModuleData = {
+    &vncVersRec,           /* vers */
+    vncSetup,              /* ModuleSetupProc */
+    NULL                   /* ModuleTearDownProc */
+};
+
+ModuleInfoRec VNC = {
+    1,                     /* moduleVersion */
+    "VNC",                 /* moduleName */
+    NULL,                  /* module pointer */
+    0,                     /* refCount */
+    VNCAvailableOptions,   /* function returning array of OptionsInfoRec */
+};
+
+ExtensionModule vncExtensionModule = {
+        VncExtensionInit,  /* initFunc */
+        "VNC",             /* name */
+        NULL,              /* disablePtr */
+        NULL,              /* setupFunc */
+        NULL               /* initDependencies */
+};
+
+
+/*ARGSUSED*/
+static pointer
+vncSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
+{
+    static Bool Initialised = FALSE;
+
+    if (!Initialised) {
+	Initialised = TRUE;
+#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
+	if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
+#endif
+	xf86AddModuleInfo(&VNC, Module);
+    }
+
+    LoadExtension(&vncExtensionModule, FALSE);
+    /* add mouse/kbd input drivers */
+    vncInitMouse();
+    vncInitKeyb();
+    xf86Msg(X_INFO, "Ignore errors regarding the loading of the rfbmouse & rfbkeyb drivers\n");
+
+    return (pointer)TRUE;
+}
+#endif
diff -u -rNp a/hw/xfree86/vnc/vncint.h b/hw/xfree86/vnc/vncint.h
--- a/hw/xfree86/vnc/vncint.h	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/vncint.h	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#ifndef _VNC_H_
+#define _VNC_H_
+
+#include <xf86Cursor.h>
+/*#include <xf86CursorPriv.h>*/
+
+extern int vncScreenPrivateIndex;
+
+#define VNCPTR(pScreen)\
+   (vncScreenPtr)((pScreen)->devPrivates[vncScreenPrivateIndex].ptr)
+
+typedef struct {
+    int			rfbPort;
+    int			rdpPort;
+    int			udpPort;
+    int			rfbListenSock;
+    int			rdpListenSock;
+    int			udpSock;
+    int			httpPort;
+    int			httpListenSock;
+    int			httpSock;
+    char *		httpDir;
+    char		buf[HTTP_BUF_SIZE];
+    Bool		udpSockConnected;
+    char *		rfbAuthPasswdFile;
+    size_t		buf_filled;
+    int			maxFd;
+    fd_set		allFds;
+    unsigned char *	oldpfbMemory;
+    Bool		useGetImage;
+    Bool		rfbAlwaysShared;
+    Bool		rfbNeverShared;
+    Bool		rfbDontDisconnect;
+    Bool		rfbUserAccept;
+    Bool		rfbViewOnly;
+    unsigned char *	pfbMemory;
+    int 		paddedWidthInBytes;
+    ColormapPtr 	rfbInstalledColormap;
+    ColormapPtr		savedColormap;
+    rfbPixelFormat	rfbServerFormat;
+    Bool		rfbAuthTooManyTries;
+    int			rfbAuthTries;
+    Bool		loginAuthEnabled;
+    struct in_addr	interface;
+    OsTimerPtr 		timer;
+    char 		updateBuf[UPDATE_BUF_SIZE];
+    int 		ublen;
+    int 		width;
+    int 		height;
+    int 		depth;
+    int 		bitsPerPixel;
+
+    /* The following two members are used to minimise the amount of unnecessary
+       drawing caused by cursor movement.  Whenever any drawing affects the
+       part of the screen where the cursor is, the cursor is removed first and
+       then the drawing is done (this is what the sprite routines test for).
+       Afterwards, however, we do not replace the cursor, even when the cursor
+       is logically being moved across the screen.  We only draw the cursor
+       again just as we are about to send the client a framebuffer update.
+
+       We need to be careful when removing and drawing the cursor because of
+       their relationship with the normal drawing routines.  The drawing
+       routines can invoke the cursor routines, but also the cursor routines
+       themselves end up invoking drawing routines.
+
+       Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by
+       doing a CopyArea from a pixmap to the screen, where the pixmap contains
+       the saved contents of the screen under the cursor.  Before doing this,
+       however, we set cursorIsDrawn to FALSE.  Then, when CopyArea is called,
+       it sees that cursorIsDrawn is FALSE and so doesn't feel the need to
+       (recursively!) remove the cursor before doing it.
+
+       Putting up the cursor (rfbSpriteRestoreCursor) involves a call to
+       PushPixels.  While this is happening, cursorIsDrawn must be FALSE so
+       that PushPixels doesn't think it has to remove the cursor first.
+       Obviously cursorIsDrawn is set to TRUE afterwards.
+
+       Another problem we face is that drawing routines sometimes cause a
+       framebuffer update to be sent to the RFB client.  When the RFB client is
+       already waiting for a framebuffer update and some drawing to the
+       framebuffer then happens, the drawing routine sees that the client is
+       ready, so it calls rfbSendFramebufferUpdate.  If the cursor is not drawn
+       at this stage, it must be put up, and so rfbSpriteRestoreCursor is
+       called.  However, if the original drawing routine was actually called
+       from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't
+       want this to happen.  So both the cursor routines set
+       dontSendFramebufferUpdate to TRUE, and all the drawing routines check
+       this before calling rfbSendFramebufferUpdate. */
+
+    Bool cursorIsDrawn;		    /* TRUE if the cursor is currently drawn */
+    Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the
+				       cursor */
+
+    /* wrapped screen functions */
+
+    CloseScreenProcPtr			CloseScreen;
+    CreateGCProcPtr			CreateGC;
+    PaintWindowBackgroundProcPtr	PaintWindowBackground;
+    PaintWindowBorderProcPtr		PaintWindowBorder;
+    CopyWindowProcPtr			CopyWindow;
+    ClearToBackgroundProcPtr		ClearToBackground;
+    RestoreAreasProcPtr			RestoreAreas;
+    ScreenWakeupHandlerProcPtr 		WakeupHandler;
+    InstallColormapProcPtr		InstallColormap;
+    UninstallColormapProcPtr		UninstallColormap;
+    ListInstalledColormapsProcPtr 	ListInstalledColormaps;
+    StoreColorsProcPtr			StoreColors;
+    xf86EnableDisableFBAccessProc	*EnableDisableFBAccess;
+    miPointerSpriteFuncPtr		spriteFuncs;
+    DisplayCursorProcPtr		DisplayCursor;
+    CursorPtr				pCurs;
+    Bool				(*UseHWCursor)(ScreenPtr, CursorPtr);
+    Bool				(*UseHWCursorARGB)(ScreenPtr, CursorPtr);
+    Bool				*SWCursor;
+#ifdef CHROMIUM
+    RealizeWindowProcPtr		RealizeWindow;
+    UnrealizeWindowProcPtr		UnrealizeWindow;
+    DestroyWindowProcPtr		DestroyWindow;
+    ResizeWindowProcPtr			ResizeWindow;
+    PositionWindowProcPtr		PositionWindow;
+    ClipNotifyProcPtr			ClipNotify;
+#endif
+#ifdef RENDER
+    CompositeProcPtr			Composite;
+#endif
+
+} vncScreenRec, *vncScreenPtr;
+
+extern Bool vncUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs);
+extern Bool vncUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs);
+extern void rfbEnableDisableFBAccess (int index, Bool enable);
+
+#endif /* _VNC_H_ */
+
diff -u -rNp a/hw/xfree86/vnc/zlib.c b/hw/xfree86/vnc/zlib.c
--- a/hw/xfree86/vnc/zlib.c	1970-01-01 01:00:00.000000000 +0100
+++ b/hw/xfree86/vnc/zlib.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,306 @@
+/*
+ * zlib.c
+ *
+ * Routines to implement zlib based encoding (deflate).
+ *
+ * Modified for XFree86 4.x by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+/*
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ * For the latest source code, please check:
+ *
+ * http://www.developVNC.org/
+ *
+ * or send email to feedback@developvnc.org.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rfb.h"
+
+/*
+ * zlibBeforeBuf contains pixel data in the client's format.
+ * zlibAfterBuf contains the zlib (deflated) encoding version.
+ * If the zlib compressed/encoded version is
+ * larger than the raw data or if it exceeds zlibAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int zlibBeforeBufSize = 0;
+static char *zlibBeforeBuf = NULL;
+
+static int zlibAfterBufSize = 0;
+static char *zlibAfterBuf = NULL;
+static int zlibAfterBufLen;
+
+/*
+ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
+ *                              rectangle encoding.
+ */
+
+static Bool
+rfbSendOneRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h)
+{
+    VNCSCREENPTR(cl->pScreen);
+    rfbFramebufferUpdateRectHeader rect;
+    rfbZlibHeader hdr;
+    int deflateResult;
+    int previousOut;
+    int i;
+    unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y)
+    	   + (x * (pVNC->bitsPerPixel / 8)));
+
+    int maxRawSize;
+    int maxCompSize;
+
+    maxRawSize = (pVNC->width * pVNC->height
+                  * (cl->format.bitsPerPixel / 8));
+
+    if (zlibBeforeBufSize < maxRawSize) {
+	zlibBeforeBufSize = maxRawSize;
+	if (zlibBeforeBuf == NULL)
+	    zlibBeforeBuf = (char *)xalloc(zlibBeforeBufSize);
+	else
+	    zlibBeforeBuf = (char *)xrealloc(zlibBeforeBuf, zlibBeforeBufSize);
+    }
+
+    /* zlib compression is not useful for very small data sets.
+     * So, we just send these raw without any compression.
+     */
+    if (( w * h * (pVNC->bitsPerPixel / 8)) <
+          VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
+
+        int result;
+
+        /* The translation function (used also by the in raw encoding)
+         * requires 4/2/1 byte alignment in the output buffer (which is
+         * pVNC->updateBuf for the raw encoding) based on the bitsPerPixel of
+         * the viewer/client.  This prevents SIGBUS errors on some
+         * architectures like SPARC, PARISC...
+         */
+        if (( cl->format.bitsPerPixel > 8 ) &&
+            ( pVNC->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
+            if (!rfbSendUpdateBuf(cl))
+                return FALSE;
+        }
+
+        result = rfbSendRectEncodingRaw(cl, x, y, w, h);
+
+        return result;
+
+    }
+
+    /*
+     * zlib requires output buffer to be slightly larger than the input
+     * buffer, in the worst case.
+     */
+    maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
+
+    if (zlibAfterBufSize < maxCompSize) {
+	zlibAfterBufSize = maxCompSize;
+	if (zlibAfterBuf == NULL)
+	    zlibAfterBuf = (char *)xalloc(zlibAfterBufSize);
+	else
+	    zlibAfterBuf = (char *)xrealloc(zlibAfterBuf, zlibAfterBufSize);
+    }
+
+    /* 
+     * Convert pixel data to client format.
+     */
+    (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, 
+		       &pVNC->rfbServerFormat,
+		       &cl->format, fbptr, zlibBeforeBuf,
+		       pVNC->paddedWidthInBytes, w, h, x, y);
+
+    cl->compStream.next_in = ( Bytef * )zlibBeforeBuf;
+    cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
+    cl->compStream.next_out = ( Bytef * )zlibAfterBuf;
+    cl->compStream.avail_out = maxCompSize;
+    cl->compStream.data_type = Z_BINARY;
+
+    /* Initialize the deflation state. */
+    if ( cl->compStreamInited == FALSE ) {
+
+        cl->compStream.total_in = 0;
+        cl->compStream.total_out = 0;
+        cl->compStream.zalloc = Z_NULL;
+        cl->compStream.zfree = Z_NULL;
+        cl->compStream.opaque = Z_NULL;
+
+        deflateInit2( &(cl->compStream),
+                        cl->zlibCompressLevel,
+                        Z_DEFLATED,
+                        MAX_WBITS,
+                        MAX_MEM_LEVEL,
+                        Z_DEFAULT_STRATEGY );
+        /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
+        /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
+        cl->compStreamInited = TRUE;
+
+    }
+
+    previousOut = cl->compStream.total_out;
+
+    /* Perform the compression here. */
+    deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
+
+    /* Find the total size of the resulting compressed data. */
+    zlibAfterBufLen = cl->compStream.total_out - previousOut;
+
+    if ( deflateResult != Z_OK ) {
+        rfbLog("zlib deflation error: %s\n", cl->compStream.msg);
+        return FALSE;
+    }
+
+    /* Note that it is not possible to switch zlib parameters based on
+     * the results of the compression pass.  The reason is
+     * that we rely on the compressor and decompressor states being
+     * in sync.  Compressing and then discarding the results would
+     * cause lose of synchronization.
+     */
+
+    /* Update statics */
+    cl->rfbRectanglesSent[rfbEncodingZlib]++;
+    cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
+					 + sz_rfbZlibHeader + zlibAfterBufLen);
+
+    if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
+	> UPDATE_BUF_SIZE)
+    {
+	if (!rfbSendUpdateBuf(cl))
+	    return FALSE;
+    }
+
+    rect.r.x = Swap16IfLE(x);
+    rect.r.y = Swap16IfLE(y);
+    rect.r.w = Swap16IfLE(w);
+    rect.r.h = Swap16IfLE(h);
+    rect.encoding = Swap32IfLE(rfbEncodingZlib);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,
+	   sz_rfbFramebufferUpdateRectHeader);
+    pVNC->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+    hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
+
+    memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbZlibHeader);
+    pVNC->ublen += sz_rfbZlibHeader;
+
+    for (i = 0; i < zlibAfterBufLen;) {
+
+	int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen;
+
+	if (i + bytesToCopy > zlibAfterBufLen) {
+	    bytesToCopy = zlibAfterBufLen - i;
+	}
+
+	memcpy(&pVNC->updateBuf[pVNC->ublen], &zlibAfterBuf[i], bytesToCopy);
+
+	pVNC->ublen += bytesToCopy;
+	i += bytesToCopy;
+
+	if (pVNC->ublen == UPDATE_BUF_SIZE) {
+	    if (!rfbSendUpdateBuf(cl))
+		return FALSE;
+	}
+    }
+
+    return TRUE;
+
+}
+
+
+/*
+ * rfbSendRectEncodingZlib - send a given rectangle using one or more
+ *                           Zlib encoding rectangles.
+ */
+
+Bool
+rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h)
+{
+    VNCSCREENPTR(cl->pScreen);
+    int  maxLines;
+    int  linesRemaining;
+    rfbRectangle partialRect;
+
+    partialRect.x = x;
+    partialRect.y = y;
+    partialRect.w = w;
+    partialRect.h = h;
+
+    /* Determine maximum pixel/scan lines allowed per rectangle. */
+    maxLines = ( ZLIB_MAX_SIZE(w) / w );
+
+    /* Initialize number of scan lines left to do. */
+    linesRemaining = h;
+
+    /* Loop until all work is done. */
+    while ( linesRemaining > 0 ) {
+
+        int linesToComp;
+
+        if ( maxLines < linesRemaining )
+            linesToComp = maxLines;
+        else
+            linesToComp = linesRemaining;
+
+        partialRect.h = linesToComp;
+
+        /* Encode (compress) and send the next rectangle. */
+        if ( ! rfbSendOneRectEncodingZlib( cl,
+                                           partialRect.x,
+                                           partialRect.y,
+                                           partialRect.w,
+                                           partialRect.h )) {
+
+            return FALSE;
+        }
+
+        /* Technically, flushing the buffer here is not extrememly
+         * efficient.  However, this improves the overall throughput
+         * of the system over very slow networks.  By flushing
+         * the buffer with every maximum size zlib rectangle, we
+         * improve the pipelining usage of the server CPU, network,
+         * and viewer CPU components.  Insuring that these components
+         * are working in parallel actually improves the performance
+         * seen by the user.
+         * Since, zlib is most useful for slow networks, this flush
+         * is appropriate for the desired behavior of the zlib encoding.
+         */
+        if (( pVNC->ublen > 0 ) &&
+            ( linesToComp == maxLines )) {
+            if (!rfbSendUpdateBuf(cl)) {
+
+                return FALSE;
+            }
+        }
+
+        /* Update remaining and incremental rectangle location. */
+        linesRemaining -= linesToComp;
+        partialRect.y += linesToComp;
+
+    }
+
+    return TRUE;
+
+}
+
+
diff -u -rNp a/Makefile.am b/Makefile.am
--- a/Makefile.am	2007-01-18 09:28:15.000000000 +0000
+++ b/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -34,6 +34,10 @@ if DBE
 DBE_DIR=dbe
 endif
 
+if XCLIPLIST
+XCLIPLIST_DIR=xcliplist
+endif
+
 SUBDIRS = \
 	doc \
 	include \
@@ -58,6 +62,7 @@ SUBDIRS = \
 	$(XTRAP_DIR) \
 	$(COMPOSITE_DIR) \
 	$(GLX_DIR) \
+	$(XCLIPLIST_DIR) \
 	exa \
 	hw
 
diff -u -rNp a/mi/miinitext.c b/mi/miinitext.c
--- a/mi/miinitext.c	2006-12-01 22:48:41.000000000 +0000
+++ b/mi/miinitext.c	2007-01-18 09:29:34.000000000 +0000
@@ -79,6 +79,18 @@ SOFTWARE.
 #undef XF86VIDMODE
 #endif
 
+#ifdef VNCSERVER
+#undef COMPOSITE
+#undef DAMAGE
+#undef DBE
+#undef RANDR
+#undef XF86MISC
+#undef XFreeXDGA
+#undef XF86DRI
+#undef XF86VIDMODE
+#undef XFIXES
+#endif
+
 #include "misc.h"
 #include "extension.h"
 #include "micmap.h"
diff -u -rNp a/xcliplist/cliplist.c b/xcliplist/cliplist.c
--- a/xcliplist/cliplist.c	1970-01-01 01:00:00.000000000 +0100
+++ b/xcliplist/cliplist.c	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,128 @@
+/*
+ * Server-side code for the Xcliplist extension
+ */
+
+#if HAVE_DIX_CONFIG_H
+#include "dix-config.h"
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include "windowstr.h"
+
+#define _XCLIPLIST_SERVER_
+#include <X11/extensions/Xclipliststr.h>
+
+
+static int XClipListErrorBase;
+static unsigned char XClipListReqCode = 0;
+
+static void
+XClipListResetProc(ExtensionEntry* extEntry)
+{
+   (void)extEntry;
+}
+
+static int
+ProcXClipListQueryVersion(ClientPtr client)
+{
+   xXClipListQueryVersionReply rep;
+
+   REQUEST_SIZE_MATCH(xXClipListQueryVersionReq);
+   rep.type = X_Reply;
+   rep.length = 0;
+   rep.sequenceNumber = client->sequence;
+   rep.majorVersion = XCLIPLIST_MAJOR_VERSION;
+   rep.minorVersion = XCLIPLIST_MINOR_VERSION;
+   rep.patchVersion = XCLIPLIST_PATCH_VERSION;
+
+   WriteToClient(client, sizeof(xXClipListQueryVersionReply), (char *)&rep);
+   return (client->noClientException);
+}
+
+static int
+ProcXGetClipList(ClientPtr client)
+{
+   xXGetClipListReply	rep;
+   WindowPtr pWin;
+   int i;
+   BoxPtr pClipRects = NULL;
+   short xorig, yorig;
+   REQUEST(xXGetClipListReq);
+   REQUEST_SIZE_MATCH(xXGetClipListReq);
+
+   rep.type = X_Reply;
+   rep.length = 0;
+   rep.sequenceNumber = client->sequence;
+
+   if(!(pWin = (WindowPtr)LOOKUP_DRAWABLE(stuff->windowid, client) ))
+    {
+      client->errorValue = stuff->windowid;
+      return (BadWindow);
+    }
+
+   rep.num_entries = REGION_NUM_RECTS(&pWin->clipList);
+
+   WriteToClient(client, sizeof(xXGetClipListReply), (char *)&rep);
+
+   pClipRects = REGION_RECTS(&pWin->clipList);
+
+   xorig = pWin->drawable.x;
+   yorig = pWin->drawable.y;
+
+   for (i = 0; i < rep.num_entries; i++) {
+      BoxRec box;
+      /* translate clip rect from screen coords to window coords */
+      box.x1 = pClipRects[i].x1 - xorig;
+      box.y1 = pClipRects[i].y1 - yorig;
+      box.x2 = pClipRects[i].x2 - xorig;
+      box.y2 = pClipRects[i].y2 - yorig;
+      /*memcpy(&box, &pClipRects[i], sizeof(BoxRec));*/
+      WriteToClient(client, sizeof(BoxRec), (char *)&box);
+   }
+
+   return (client->noClientException);
+}
+
+static int
+ProcXClipListDispatch (ClientPtr	client)
+{
+   REQUEST(xReq);
+
+   switch (stuff->data) {
+   case X_XClipListQueryVersion:
+      return ProcXClipListQueryVersion(client);
+   case X_XGetClipList:
+      return ProcXGetClipList(client);
+   default:
+      return BadRequest;
+   }
+}
+
+static int
+SProcXClipListDispatch (ClientPtr	client)
+{
+   REQUEST(xReq);
+   (void)stuff;
+   return XClipListErrorBase + XClipListClientNotLocal;
+}
+
+void
+XClipListExtensionInit(void)
+{
+   ExtensionEntry* extEntry;
+
+   if ((extEntry = AddExtension(XCLIPLISTNAME,
+				XClipListNumberEvents,
+				XClipListNumberErrors,
+				ProcXClipListDispatch,
+				SProcXClipListDispatch,
+				XClipListResetProc,
+				StandardMinorOpcode))) {
+      XClipListReqCode = (unsigned char)extEntry->base;
+      XClipListErrorBase = extEntry->errorBase;
+   }
+}
diff -u -rNp a/xcliplist/cliplistmod.c b/xcliplist/cliplistmod.c
--- a/xcliplist/cliplistmod.c	1970-01-01 01:00:00.000000000 +0100
+++ b/xcliplist/cliplistmod.c	2007-01-18 09:31:23.000000000 +0000
@@ -0,0 +1,46 @@
+
+#include "../hw/xfree86/common/xf86Module.h"
+
+extern Bool noTestExtensions;
+
+static MODULESETUPPROTO(xcliplistSetup);
+
+extern void XClipListExtensionInit(INITARGS);
+
+ExtensionModule xcliplistExt = {
+    XClipListExtensionInit,
+    "XClipList",
+    &noTestExtensions,
+    NULL,
+    NULL
+};
+
+static XF86ModuleVersionInfo VersRec = {
+	"XClipList",
+	MODULEVENDORSTRING,
+	MODINFOSTRING1,
+	MODINFOSTRING2,
+        XF86_VERSION_CURRENT, /* XXX fix? */
+	1, 13, 0,
+	ABI_CLASS_EXTENSION,
+#if 0
+	ABI_EXTENSION_VERSION,
+#else
+        /* Hack to allow module to work with more servers (vs. 0.3 above) */
+        SET_ABI_VERSION(0, 2),
+#endif
+	MOD_CLASS_EXTENSION,
+	{0,0,0,0}
+};
+
+XF86ModuleData xcliplistModuleData = { &VersRec, xcliplistSetup, NULL };
+
+static pointer
+xcliplistSetup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+    LoadExtension(&xcliplistExt, FALSE);
+
+    /* Need a non-NULL return value to indicate success */
+    return (pointer)1;
+}
+
diff -u -rNp a/xcliplist/Makefile.am b/xcliplist/Makefile.am
--- a/xcliplist/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ b/xcliplist/Makefile.am	2007-01-18 09:29:34.000000000 +0000
@@ -0,0 +1,18 @@
+#noinst_LTLIBRARIES = libxcliplist.la
+libxcliplist_la_LTLIBRARIES = libxcliplist.la
+
+#AM_CFLAGS = $(DIX_CFLAGS) @SERVER_DEFINES@ @LOADER_DEFINES@
+AM_CFLAGS = $(DIX_CFLAGS)
+
+libxcliplist_la_LDFLAGS = -module -avoid-version
+libxcliplist_ladir = $(moduledir)/extensions
+
+libxcliplist_la_SOURCES = \
+	cliplist.c \
+	cliplistmod.c
+
+##	cliplistmod.c
+
+if XORG
+sdk_HEADERS =
+endif