xorg-x11-server/xorg-server-xf4vnc.patch

24036 lines
711 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff --git a/Makefile.am b/Makefile.am
index e382d58..e655a2b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,6 +30,10 @@ if DBE
DBE_DIR=dbe
endif
+if XCLIPLIST
+XCLIPLIST_DIR=xcliplist
+endif
+
SUBDIRS = \
doc \
include \
@@ -54,6 +58,7 @@ SUBDIRS = \
$(XTRAP_DIR) \
$(COMPOSITE_DIR) \
$(GLX_DIR) \
+ $(XCLIPLIST_DIR) \
exa \
config \
hw
diff --git a/configure.ac b/configure.ac
index 5417bbb..5679cba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -558,6 +558,8 @@ AC_ARG_ENABLE(xfree86-utils, AS_HELP_STRING([--enable-xfree86-utils], [Build
dnl DDXes.
AC_ARG_ENABLE(xorg, AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto])
+AC_ARG_ENABLE(xcliplist, AS_HELP_STRING([--enable-xcliplist], [Build XClipList extension (default: auto)]), [XCLIPLIST=$enableval], [XCLIPLIST=auto])
+AC_ARG_ENABLE(vnc, AS_HELP_STRING([--enable-vnc], [Build Xvnc server (default: yes)]), [VNC=$enableval], [VNC=auto])
AC_ARG_ENABLE(dmx, AS_HELP_STRING([--enable-dmx], [Build DMX server (default: no)]), [DMX=$enableval], [DMX=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])
@@ -998,6 +1000,20 @@ XI_INC='-I$(top_srcdir)/Xi'
AM_CONDITIONAL(XF86UTILS, test "x$XF86UTILS" = xyes)
+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
+
AC_DEFINE(SHAPE, 1, [Support SHAPE extension])
AC_DEFINE(XKB, 1, [Build XKB])
@@ -1193,6 +1209,40 @@ dnl ---------------------------------------------------------------------------
dnl DDX section.
dnl ---------------------------------------------------------------------------
+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 $PIXMAN], [have_vnc=yes], [have_vnc=no])
+if test "x$VNC" = xauto; then
+ VNC="$have_vnc"
+fi
+AC_MSG_RESULT([$VNC])
+AM_CONDITIONAL(VNC, [test "x$VNC" = xyes])
+
+if test "x$VNC" = 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="$CONFIG_LIB $XSERVER_LIBS $FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $XTRAP_LIB $RECORD_LIB $GLX_LIBS $RENDER_LIB $RANDR_LIB $DAMAGE_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $XPSTUBS_LIB $CWRAP_LIB $OS_LIB $LIBS"
+ 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)
+ ${CONFIG_SHELL-/bin/sh} $srcdir/hw/vnc/symlink-vnc.sh \
+ $srcdir/hw/vnc $srcdir/hw/xfree86/vnc && \
+ ${CONFIG_SHELL-/bin/sh} $srcdir/hw/vnc/symlink-vnc.sh \
+ $srcdir/hw/vnc $srcdir/hw/dmx/vnc || \
+ AC_MSG_ERROR([Failed symlinking VNC sources])
+fi
+
dnl Xvfb DDX
AC_MSG_CHECKING([whether to build Xvfb DDX])
@@ -2123,6 +2173,7 @@ Xext/Makefile
Xi/Makefile
xfixes/Makefile
exa/Makefile
+xcliplist/Makefile
hw/Makefile
hw/xfree86/Makefile
hw/xfree86/common/Makefile
@@ -2160,6 +2211,7 @@ hw/xfree86/ramdac/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
@@ -2178,8 +2230,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 --git a/hw/Makefile.am b/hw/Makefile.am
index c2b9571..7ad240e 100644
--- a/hw/Makefile.am
+++ b/hw/Makefile.am
@@ -30,6 +30,10 @@ if XPRINT
XPRINT_SUBDIRS = xprint
endif
+if VNC
+VNC_SUBDIRS = vnc
+endif
+
if XQUARTZ
XQUARTZ_SUBDIRS = xquartz
endif
@@ -40,12 +44,13 @@ SUBDIRS = \
$(XWIN_SUBDIRS) \
$(XVFB_SUBDIRS) \
$(XNEST_SUBDIRS) \
- $(DMX_SUBDIRS) \
- $(KDRIVE_SUBDIRS) \
+ $(DMX_SUBDIRS) \
+ $(VNC_SUBDIRS) \
+ $(KDRIVE_SUBDIRS) \
$(XQUARTZ_SUBDIRS) \
$(XPRINT_SUBDIRS)
-DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xgl xprint
+DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xgl xprint vnc
relink:
for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink ; done
diff --git a/hw/dmx/Makefile.am b/hw/dmx/Makefile.am
index 8457aea..e7cf89f 100644
--- a/hw/dmx/Makefile.am
+++ b/hw/dmx/Makefile.am
@@ -1,6 +1,6 @@
-DIST_SUBDIRS = input config glxProxy examples doc
+DIST_SUBDIRS = input vnc config glxProxy examples doc
-SUBDIRS = input config examples
+SUBDIRS = input vnc config examples
bin_PROGRAMS = Xdmx
if XINERAMA
diff --git a/hw/dmx/dmx-config.h b/hw/dmx/dmx-config.h
index 343fdab..9f7ca47 100644
--- a/hw/dmx/dmx-config.h
+++ b/hw/dmx/dmx-config.h
@@ -72,6 +72,9 @@
/* Enable the DMX extension */
#define DMXEXT
+/* Enable VNC ability */
+#define DMXVNC 1
+
/* Disable the extensions that are not currently supported */
#undef BEZIER
#undef PEXEXT
diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c
index 29dc005..f313e7e 100644
--- a/hw/dmx/dmxinit.c
+++ b/hw/dmx/dmxinit.c
@@ -77,6 +77,10 @@ extern void GlxSetVisualConfigs(
);
#endif /* GLXEXT */
+#ifdef DMXVNC
+extern void VNCInitForDMX(void);
+#endif
+
/* Global variables available to all Xserver/hw/dmx routines. */
int dmxNumScreens;
DMXScreenInfo *dmxScreens;
@@ -812,6 +816,9 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[])
dmxLog(dmxInfo, "Shadow framebuffer support %s\n",
dmxShadowFB ? "enabled" : "disabled");
+#ifdef DMXVNC
+ VNCInitForDMX();
+#endif
}
/* RATS: Assuming the fp string (which comes from the command-line argv
@@ -1045,3 +1052,14 @@ void ddxUseMsg(void)
ErrorF(" Ctrl-Alt-q Quit (core devices only)\n");
ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n");
}
+
+#ifdef DDXTIME
+/** Return wall-clock time in milliseconds. */
+CARD32 GetTimeInMillis(void)
+{
+ struct timeval tp;
+
+ gettimeofday(&tp, 0);
+ return tp.tv_sec * 1000 + tp.tv_usec / 1000;
+}
+#endif
diff --git a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c
index c1aa431..2498a38 100644
--- a/hw/dmx/dmxsync.c
+++ b/hw/dmx/dmxsync.c
@@ -99,9 +99,16 @@ static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout,
TimerForce(dmxSyncTimer);
}
+#ifdef DMXVNC
+extern void rfbWakeupHandlerDMX(void);
+#endif
+
static void dmxSyncWakeupHandler(pointer blockData, int result,
pointer pReadMask)
{
+#ifdef DMXVNC
+ rfbWakeupHandlerDMX();
+#endif
}
/** Request the XSync() batching optimization with the specified \a
diff --git a/hw/dmx/input/Makefile.am b/hw/dmx/input/Makefile.am
index da8de05..1969a0c 100644
--- a/hw/dmx/input/Makefile.am
+++ b/hw/dmx/input/Makefile.am
@@ -65,6 +65,7 @@ AM_CFLAGS = $(DIX_CFLAGS) \
-I$(top_srcdir)/hw/xfree86/common \
$(GLX_INCS) \
-DHAVE_DMX_CONFIG_H \
+ -DDMXVNC=1 \
$(GLX_DEFS) \
@DMXMODULES_CFLAGS@
diff --git a/hw/dmx/input/dmxcommon.c b/hw/dmx/input/dmxcommon.c
index e77bb79..0866c84 100644
--- a/hw/dmx/input/dmxcommon.c
+++ b/hw/dmx/input/dmxcommon.c
@@ -655,7 +655,6 @@ void dmxCommonRestoreState(pointer private)
dmxLogInput(dmxInput, "Keyboard busy, waiting\n");
else
dmxLogInput(dmxInput, "Keyboard error, waiting\n");
-
/* Don't generate X11 protocol for a bit */
for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) {
usleep(250); /* This ends up sleeping only until
diff --git a/hw/dmx/input/dmxinputinit.c b/hw/dmx/input/dmxinputinit.c
index fd4eeaa..7de9546 100644
--- a/hw/dmx/input/dmxinputinit.c
+++ b/hw/dmx/input/dmxinputinit.c
@@ -393,6 +393,10 @@ static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info)
DevicePtr pDev = &pDevice->public;
#endif
+#ifdef DMXVNC
+ vncSetKeyboardDevice(pDevice);
+#endif
+
#ifdef XKB
if (noXkbExtension) {
#endif
@@ -480,6 +484,10 @@ static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
break;
}
if (info.keyClass) {
+#ifdef DMXVNC
+ vncSetKeyboardDevice(pDevice);
+#endif
+
#if 00 /*BP*/
InitKeyClassDeviceStruct(pDevice, &info.keySyms, info.modMap);
#else
@@ -534,6 +542,9 @@ static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
info.maxres[i+1]);
#endif
}
+#ifdef DMXVNC
+ vncSetPointerDevice(pDevice);
+#endif
}
if (info.focusClass) InitFocusClassDeviceStruct(pDevice);
#ifdef XINPUT
diff --git a/hw/dmx/input/dmxinputinit.h b/hw/dmx/input/dmxinputinit.h
index 6f491ed..e6297f0 100644
--- a/hw/dmx/input/dmxinputinit.h
+++ b/hw/dmx/input/dmxinputinit.h
@@ -290,4 +290,9 @@ extern int dmxInputAttachConsole(const char *name, int isCore,
extern int dmxInputAttachBackend(int physicalScreen, int isCore,
int *id);
+#ifdef DMXVNC
+extern void vncSetKeyboardDevice(DeviceIntPtr kbd);
+extern void vncSetPointerDevice(DeviceIntPtr ptr);
+#endif
+
#endif
diff --git a/hw/dmx/vnc/.gitignore b/hw/dmx/vnc/.gitignore
new file mode 100644
index 0000000..d14621f
--- /dev/null
+++ b/hw/dmx/vnc/.gitignore
@@ -0,0 +1,36 @@
+auth.c
+cmap.c
+corre.c
+cursor.c
+cutpaste.c
+d3des.c
+d3des.h
+dispcur.c
+draw.c
+hextile.c
+httpd.c
+kbdptr.c
+keyboard.h
+loginauth.c
+rdp.c
+rfb.h
+rfbkeyb.c
+rfbmouse.c
+rfbproto.h
+rfbserver.c
+rre.c
+sockets.c
+sprite.c
+sprite.h
+spritest.h
+stats.c
+tableinitcmtemplate.c
+tableinittctemplate.c
+tabletranstemplate.c
+tight.c
+translate.c
+vncauth.c
+vncauth.h
+vncext.c
+xistubs.c
+zlib.c
diff --git a/hw/dmx/vnc/Makefile.am b/hw/dmx/vnc/Makefile.am
new file mode 100644
index 0000000..48c07bd
--- /dev/null
+++ b/hw/dmx/vnc/Makefile.am
@@ -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 --git a/hw/dmx/vnc/vncInit.c b/hw/dmx/vnc/vncInit.c
new file mode 100644
index 0000000..5fdf647
--- /dev/null
+++ b/hw/dmx/vnc/vncInit.c
@@ -0,0 +1,453 @@
+/*
+ * 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"
+
+#ifdef HAVE_DMX_CONFIG_H
+#include "dmx-config.h"
+#endif
+
+#ifdef 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)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+
+ (*pScreen->GetImage)(pDrawable,sx,sy,w,h,format,planemask,pdstLine);
+}
+
+
+static void
+SetupVNCScreen(void)
+{
+ vncScreenPtr pScreenPriv;
+ VisualPtr v = NULL;
+ int i;
+
+ 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->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;
+
+ 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);
+}
+
+
+/*
+ * Called by DMX's InitOutput()
+ * Will be called for each X server generation.
+ */
+void
+VNCInitForDMX(void)
+{
+ rfbLog("DMXVNC: Initializing VNC for DMX\n");
+ ErrorF("DMXVNC: Initializing VNC for DMX\n");
+
+ if (TheVNCScreen) {
+ rfbLog("DMXVNC: New server generation\n");
+ }
+ else {
+ rfbLog("DMXVNC: Set up VNC screen\n");
+ SetupVNCScreen();
+ }
+
+ /* Reset the input device pointers. They'll get set later.
+ * This allows successful server regeneration.
+ */
+ vncSetKeyboardDevice(NULL);
+ vncSetPointerDevice(NULL);
+}
+
+
+Bool
+VNCInit(ScreenPtr pScreen, DMXScreenInfo *pScrn)
+{
+ VisualPtr visual;
+ vncScreenPtr pScreenPriv;
+#if 0
+ char *interface_str = NULL;
+#endif
+#ifdef RENDER
+ PictureScreenPtr ps;
+#endif
+
+#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->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;
+}
+
+
+/**
+ * The rfb wake-up handler used when we're compiled into the DMX server.
+ */
+void
+rfbWakeupHandlerDMX(void)
+{
+ ScreenPtr pScreen = TheVNCScreen;
+ rfbRootPropertyChange(pScreen); /* Check clipboard */
+ rfbCheckFds(pScreen);
+ httpCheckFds(pScreen);
+}
diff --git a/hw/dmx/vnc/vncint.h b/hw/dmx/vnc/vncint.h
new file mode 100644
index 0000000..afa84f8
--- /dev/null
+++ b/hw/dmx/vnc/vncint.h
@@ -0,0 +1,153 @@
+/*
+ * 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 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;
+ unsigned 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 --git a/hw/vnc/LICENCE.TXT b/hw/vnc/LICENCE.TXT
new file mode 100644
index 0000000..ae3b531
--- /dev/null
+++ b/hw/vnc/LICENCE.TXT
@@ -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 --git a/hw/vnc/Makefile.am b/hw/vnc/Makefile.am
new file mode 100644
index 0000000..9bf90ec
--- /dev/null
+++ b/hw/vnc/Makefile.am
@@ -0,0 +1,54 @@
+# XXX This Makefile.am probably needs some work.
+
+bin_PROGRAMS = Xvnc
+
+Xvnc_SOURCES = \
+ $(top_srcdir)/fb/fbcmap_mi.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 \
+ 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 -DCHROMIUM=1
+
+Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
+Xvnc_LDADD = \
+ $(XORG_CORE_LIBS) \
+ $(XVNC_LIBS) \
+ $(JPEG_LIBS) \
+ $(CRYPT_LIBS) \
+ $(XSERVER_SYS_LIBS) \
+ $(VNCMODULES_LIBS)
+
+
+relink:
+ rm -f Xvnc && $(MAKE) Xvnc
diff --git a/hw/vnc/README b/hw/vnc/README
new file mode 100644
index 0000000..d65d560
--- /dev/null
+++ b/hw/vnc/README
@@ -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 --git a/hw/vnc/auth.c b/hw/vnc/auth.c
new file mode 100644
index 0000000..f91a1ed
--- /dev/null
+++ b/hw/vnc/auth.c
@@ -0,0 +1,566 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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);
+ (void)cl;
+ 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, cl);
+ 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 --git a/hw/vnc/cmap.c b/hw/vnc/cmap.c
new file mode 100644
index 0000000..2e4514a
--- /dev/null
+++ b/hw/vnc/cmap.c
@@ -0,0 +1,166 @@
+/*
+ * 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.
+
+*/
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 --git a/hw/vnc/corre.c b/hw/vnc/corre.c
new file mode 100644
index 0000000..1a9b4d5
--- /dev/null
+++ b/hw/vnc/corre.c
@@ -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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 unsigned char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static unsigned 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;
+ int maxRawSize = (pVNC->width * pVNC->height
+ * (cl->format.bitsPerPixel / 8));
+
+ if (rreBeforeBufSize < maxRawSize) {
+ rreBeforeBufSize = maxRawSize;
+ if (rreBeforeBuf == NULL)
+ rreBeforeBuf = (unsigned char *)xalloc(rreBeforeBufSize);
+ else
+ rreBeforeBuf = (unsigned char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+ }
+
+ if (rreAfterBufSize < maxRawSize) {
+ rreAfterBufSize = maxRawSize;
+ if (rreAfterBuf == NULL)
+ rreAfterBuf = (unsigned char *)xalloc(rreAfterBufSize);
+ else
+ rreAfterBuf = (unsigned char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+ }
+
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,
+ &pVNC->rfbServerFormat,
+ &cl->format, 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 --git a/hw/vnc/cursor.c b/hw/vnc/cursor.c
new file mode 100644
index 0000000..d355e03
--- /dev/null
+++ b/hw/vnc/cursor.c
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 (unsigned char *buf, rfbPixelFormat *fmt,
+ CursorPtr pCursor);
+static int EncodeRichCursorData16 (ScreenPtr pScreen,
+ unsigned char *buf, rfbPixelFormat *fmt,
+ CursorPtr pCursor);
+static int EncodeRichCursorData32 (ScreenPtr pScreen,
+ unsigned 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(); /*XXX deprecated*/
+#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)
+ unsigned 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; \
+ unsigned 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 --git a/hw/vnc/cutpaste.c b/hw/vnc/cutpaste.c
new file mode 100644
index 0000000..6f57aca
--- /dev/null
+++ b/hw/vnc/cutpaste.c
@@ -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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdio.h>
+#define NEED_EVENTS
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "rfb.h"
+#include "selection.h"
+#include "input.h"
+#include <X11/Xatom.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;
+ Selection *pSel;
+
+ inSetXCutText = TRUE;
+ ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING,
+ 8, PropModeReplace, len,
+ (pointer)str, TRUE);
+
+ if (dixLookupSelection(&pSel, XA_PRIMARY, serverClient, DixSetAttrAccess)) {
+ xEvent event;
+
+ if (pSel->client) {
+ event.u.u.type = SelectionClear;
+ event.u.selectionClear.time = GetTimeInMillis();
+ event.u.selectionClear.window = pSel->window;
+ event.u.selectionClear.atom = pSel->selection;
+ (void) TryClientEvents (pSel->client, &event, 1,
+ NoEventMask, NoEventMask /* CantBeFiltered */,
+ NullGrab);
+ }
+
+ pSel->window = None;
+ pSel->pWin = NULL;
+ pSel->client = NullClient;
+ }
+
+ inSetXCutText = FALSE;
+}
+
+
+void rfbGotXCutText(char *str, int len)
+{
+ if (!inSetXCutText)
+ rfbSendServerCutText(str, len);
+}
diff --git a/hw/vnc/d3des.c b/hw/vnc/d3des.c
new file mode 100644
index 0000000..a4e145f
--- /dev/null
+++ b/hw/vnc/d3des.c
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 --git a/hw/vnc/d3des.h b/hw/vnc/d3des.h
new file mode 100644
index 0000000..ea3da44
--- /dev/null
+++ b/hw/vnc/d3des.h
@@ -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 --git a/hw/vnc/dispcur.c b/hw/vnc/dispcur.c
new file mode 100644
index 0000000..0ccf0a7
--- /dev/null
+++ b/hw/vnc/dispcur.c
@@ -0,0 +1,792 @@
+/*
+ * 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.
+*/
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#define NEED_EVENTS
+# include <X11/X.h>
+# include "rfb.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 "sprite.h"
+# include "gcstruct.h"
+
+#ifdef ARGB_CURSOR
+# include "picturestr.h"
+#endif
+
+/* per-screen private data */
+
+static DevPrivateKey rfbDCScreenKey = &rfbDCScreenKey;
+
+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 (ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs)
+{
+ rfbDCScreenPtr pScreenPriv;
+
+ 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;
+
+ dixSetPrivate(&pScreen->devPrivates, rfbDCScreenKey, 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbDCScreenKey);
+ 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)
+ dixSetPrivate(&pCursor->bits->devPrivates, pScreen, 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 (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, 0);
+ 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;
+ }
+ dixSetPrivate(&pCursor->bits->devPrivates, pScreen, pPriv);
+ return pPriv;
+ }
+ pPriv->pPicture = 0;
+#endif
+ pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0);
+ if (!pPriv->sourceBits)
+ {
+ xfree ((pointer) pPriv);
+ return (rfbDCCursorPtr)NULL;
+ }
+ pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0);
+ if (!pPriv->maskBits)
+ {
+ (*pScreen->DestroyPixmap) (pPriv->sourceBits);
+ xfree ((pointer) pPriv);
+ return (rfbDCCursorPtr)NULL;
+ }
+ dixSetPrivate(&pCursor->bits->devPrivates, pScreen, 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)dixLookupPrivate(&pCursor->bits->devPrivates,
+ pScreen);
+ 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);
+ dixSetPrivate(&pCursor->bits->devPrivates, pScreen, NULL);
+ }
+ return TRUE;
+}
+
+static void
+rfbDCPutBits (DrawablePtr pDrawable, rfbDCCursorPtr pPriv, GCPtr sourceGC, GCPtr maskGC, int x, int y, unsigned w, unsigned h, unsigned long source, unsigned long 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(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, (XID)0, serverClient);
+ 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)dixLookupPrivate(&pCursor->bits->devPrivates,
+ pScreen);
+ if (!pPriv)
+ {
+ pPriv = rfbDCRealize(pScreen, pCursor);
+ if (!pPriv)
+ return FALSE;
+ }
+ pScreenPriv = (rfbDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbDCScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbDCScreenKey);
+ 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, 0);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbDCScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbDCScreenKey);
+ 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)dixLookupPrivate(&pCursor->bits->devPrivates,
+ pScreen);
+ if (!pPriv)
+ {
+ pPriv = rfbDCRealize(pScreen, pCursor);
+ if (!pPriv)
+ return FALSE;
+ }
+ pScreenPriv = (rfbDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbDCScreenKey);
+ 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, 0);
+ if (!pTemp)
+ return FALSE;
+ }
+ if (!pScreenPriv->pMoveGC)
+ {
+ pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp,
+ GCGraphicsExposures, &gcval, &status, (XID)0, serverClient);
+ 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, (XID)0, serverClient);
+ if (!pScreenPriv->pPixSourceGC)
+ return FALSE;
+ }
+ if (!pScreenPriv->pPixMaskGC)
+ {
+ pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp,
+ GCGraphicsExposures, &gcval, &status, (XID)0, serverClient);
+ 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 --git a/hw/vnc/dpmsstubs.c b/hw/vnc/dpmsstubs.c
new file mode 100644
index 0000000..48ee545
--- /dev/null
+++ b/hw/vnc/dpmsstubs.c
@@ -0,0 +1,52 @@
+/* $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 $ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "rfb.h"
+
+#define FALSE 0
+
+Bool DPMSSupported(void)
+{
+ return FALSE;
+}
+
+int DPSMGet(int *level)
+{
+ return -1;
+}
+
+void DPMSSet(int level)
+{
+
+}
diff --git a/hw/vnc/draw.c b/hw/vnc/draw.c
new file mode 100644
index 0000000..631aa20
--- /dev/null
+++ b/hw/vnc/draw.c
@@ -0,0 +1,2021 @@
+/*
+ * 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.
+*/
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *pBits);
+static RegionPtr rfbCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty);
+static RegionPtr rfbCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, register GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long plane);
+static void rfbPolyPoint (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, xPoint *pts);
+static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts);
+static void rfbPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *segs);
+static void rfbPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, xRectangle *rects);
+static void rfbPolyArc(DrawablePtr pDrawable, register GCPtr pGC, int narcs, xArc *arcs);
+static void rfbFillPolygon(register DrawablePtr pDrawable, register GCPtr pGC, int shape, int mode, int count, DDXPointPtr pts);
+static void rfbPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects, xRectangle *rects);
+static void rfbPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *arcs);
+static int rfbPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars);
+static int rfbPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars);
+static void rfbImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars);
+static void rfbImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars);
+static void rfbImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase);
+static void rfbPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase);
+static void rfbPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, int w, int h, int x, int y);
+
+
+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)
+ dixLookupPrivate(&(pGC)->devPrivates, rfbGCKey);
+
+ 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, *prevWt = NULL;
+ Bool ret;
+ SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow);
+
+ /* loop over monitored windows */
+ for (wt = windowTable; wt; wt = nextWt) {
+ nextWt = wt->next;
+ if (wt->XwinId == pWin->drawable.id) {
+ rfbSendChromiumWindowDestroy(wt->CRwinId);
+ /* also remove from list */
+ if (prevWt)
+ prevWt->next = wt->next;
+ else
+ windowTable = wt->next;
+ xfree(wt);
+ }
+ else {
+ prevWt = wt;
+ }
+ }
+
+ 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)dixLookupPrivate(&(pGC)->devPrivates, rfbGCKey); \
+ (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)
+{
+ 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)dixLookupPrivate(&(pGC)->devPrivates, rfbGCKey); \
+ 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(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 (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 (DrawablePtr pSrc, DrawablePtr pDst, register GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int 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 (DrawablePtr pDrawable, GCPtr pGC, int mode, 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(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(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(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(register DrawablePtr pDrawable, register GCPtr pGC, int shape, int 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(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(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(DrawablePtr pDrawable, FontPtr font, int x, int y, int 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(DrawablePtr pDrawable, GCPtr pGC, int x, int 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(DrawablePtr pDrawable, GCPtr pGC, int x, int 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(DrawablePtr pDrawable, GCPtr pGC, int x, int 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(DrawablePtr pDrawable, GCPtr pGC, int x, int 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(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase)
+{
+ 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(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase)
+{
+ 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(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDrawable, int w, int h, int x, int 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 --git a/hw/vnc/hextile.c b/hw/vnc/hextile.c
new file mode 100644
index 0000000..eb5e281
--- /dev/null
+++ b/hw/vnc/hextile.c
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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; \
+ 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; \
+ } \
+ \
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \
+ &pVNC->rfbServerFormat, \
+ &cl->format, (unsigned 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, \
+ (unsigned 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 --git a/hw/vnc/httpd.c b/hw/vnc/httpd.c
new file mode 100644
index 0000000..5f56ad6
--- /dev/null
+++ b/hw/vnc/httpd.c
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 --git a/hw/vnc/init.c b/hw/vnc/init.c
new file mode 100644
index 0000000..a166358
--- /dev/null
+++ b/hw/vnc/init.c
@@ -0,0 +1,1078 @@
+/*
+ * 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 */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef XVNCRELEASE
+#define XVNCRELEASE "X.org/xf4vnc custom version"
+#endif
+
+#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 "scrnintstr.h"
+#include "servermd.h"
+#include "fb.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "dixstruct.h"
+#include <X11/Xatom.h>
+#include <errno.h>
+#include <sys/param.h>
+#include "dix.h"
+#include "micmap.h"
+#include "rfb.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;
+extern char dispatchExceptionAtReset;
+
+extern void VncExtensionInit(void);
+
+static Bool initOutputCalled = FALSE;
+static Bool noCursor = FALSE;
+char *desktopName = "x11";
+
+char rfbThisHost[256];
+
+Atom VNC_LAST_CLIENT_ID;
+Atom VNC_CONNECT;
+
+#if 0
+static HWEventQueueType alwaysCheckForInput[2] = { 0, 1 };
+static HWEventQueueType *mieqCheckForInput[2];
+#endif
+
+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 void
+PointerWarpCursor(ScreenPtr pScreen, int x, int y)
+{
+#if 0
+ DeviceIntPtr pDev = NULL;
+ miPointerSetPosition(pDev, &x, &y, GetTimeInMillis());
+#endif
+}
+
+
+static miPointerScreenFuncRec rfbPointerCursorFuncs = {
+ rfbCursorOffScreen,
+ rfbCrossScreen,
+ PointerWarpCursor,
+ NULL/*dmxeqEnqueue*/,
+ NULL/*dmxeqSwitchScreen*/
+};
+
+
+int inetdSock = -1;
+static char inetdDisplayNumStr[10];
+
+
+void
+DDXRingBell(int volume, int pitch, int duration)
+{
+ /* NO-OP - stub to solve link problem */
+}
+
+
+/*
+ * 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;
+{
+ VNCSCREENPTR(screenInfo.screens[i]);
+ 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;
+
+ 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], "-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;
+ got.s_addr = 0;
+ 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];
+
+ /* 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 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);
+
+ 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 = (SaveScreenProcPtr)rfbAlwaysTrue;
+
+ rfbDCInitialize(pScreen, &rfbPointerCursorFuncs);
+
+ if (noCursor) {
+ pScreen->DisplayCursor = (DisplayCursorProcPtr)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;
+ }
+
+ 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);
+
+ mieqInit();
+
+#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:
+ vncSetKeyboardDevice(pDevice);
+ 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:
+ vncSetKeyboardDevice(NULL);
+ 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,
+ GetMotionHistory,
+ PtrDeviceControl,
+ GetMaximumEventsNum(), 2 /* numAxes */);
+ vncSetPointerDevice(pDevice);
+ break;
+
+ case DEVICE_ON:
+ pDev->on = TRUE;
+ PtrDeviceOn(pDevice);
+ break;
+
+ case DEVICE_OFF:
+ pDev->on = FALSE;
+ PtrDeviceOff();
+ break;
+
+ case DEVICE_CLOSE:
+ vncSetPointerDevice(NULL);
+ if (pDev->on)
+ PtrDeviceOff();
+ break;
+ }
+ return Success;
+}
+
+
+Bool
+LegalModifier(unsigned int key, DeviceIntPtr pDev)
+{
+ return TRUE;
+}
+
+
+void
+ProcessInputEvents(void)
+{
+#if 0
+ if (*mieqCheckForInput[0] != *mieqCheckForInput[1]) {
+#endif
+ mieqProcessInputEvents();
+#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 */
+}
+
+int
+NewInputDeviceRequest(InputOption *options, DeviceIntPtr *pdev)
+{
+ return BadValue;
+}
+
+void
+DeleteInputDeviceRequest(DeviceIntPtr dev)
+{
+}
+
+
+/*
+ * 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 --git a/hw/vnc/kbdptr.c b/hw/vnc/kbdptr.c
new file mode 100644
index 0000000..de31920
--- /dev/null
+++ b/hw/vnc/kbdptr.c
@@ -0,0 +1,458 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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"
+#include "keyboard.h"
+
+#ifdef DMXVNC
+#include "dmxinput.h"
+#endif
+
+#define KEY_IS_PRESSED(keycode) \
+ (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
+
+static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper);
+
+static DeviceIntPtr ptrDevice = NULL, kbdDevice = NULL;
+
+
+void
+vncSetKeyboardDevice(DeviceIntPtr kbd)
+{
+ if (kbdDevice && kbd)
+ return; /* set once */
+ kbdDevice = kbd;
+}
+
+
+void
+vncSetPointerDevice(DeviceIntPtr ptr)
+{
+ if (ptrDevice && ptr)
+ return; /* set once */
+ ptrDevice = ptr;
+}
+
+
+#ifndef DMXVNC
+static void
+EnqueueMotion(DeviceIntPtr ptrDev, int x, int y)
+{
+ xEvent *events = (xEvent*) calloc(sizeof(xEvent), GetMaximumEventsNum());
+ int detail = 0, valuators[2], nevents, i;
+ valuators[0] = x;
+ valuators[1] = y;
+ if (!ptrDev) {
+ ErrorF("VNC: In EnqueueMotion() ptrDev=NULL\n");
+ return;
+ }
+ nevents = GetPointerEvents(events, ptrDev, MotionNotify, detail,
+ POINTER_ABSOLUTE, 0, 2, valuators);
+ for (i = 0; i < nevents; i++)
+ mieqEnqueue(ptrDev, events + i);
+ free(events);
+}
+#endif
+
+
+static void
+EnqueueButton(DeviceIntPtr ptrDev, int type, int detail)
+{
+ xEvent *events = (xEvent*) calloc(sizeof(xEvent), GetMaximumEventsNum());
+ int nevents, i;
+ if (!ptrDev) {
+ ErrorF("VNC: In EnqueueButton() ptrDev=NULL\n");
+ return;
+ }
+ nevents = GetPointerEvents(events, ptrDev, type, detail,
+ POINTER_ABSOLUTE, 0, 0, NULL/*valuators*/);
+ for (i = 0; i < nevents; i++)
+ mieqEnqueue(ptrDev, events + i);
+ free(events);
+}
+
+
+static void
+EnqueueKey(DeviceIntPtr kbdDev, int type, int detail)
+{
+ xEvent *events = (xEvent*) calloc(sizeof(xEvent), GetMaximumEventsNum());
+ int nevents, i;
+ if (!kbdDev) {
+ ErrorF("VNC: In EnqueueKey() kbdDev=NULL\n");
+ return;
+ }
+ nevents = GetKeyboardEvents(events, kbdDev, type, detail);
+ for (i = 0; i < nevents; i++)
+ mieqEnqueue(kbdDev, events + i);
+ free(events);
+}
+
+
+/*
+ * 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)
+{
+ const int type = down ? KeyPress : KeyRelease;
+ KeySymsPtr keySyms;
+ int i;
+ int keyCode = 0;
+ int freeIndex = -1;
+ 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
+
+ /* 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", (int)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",
+ (int)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",
+ (int)keySym, keyCode);
+ }
+
+ if (down) {
+ if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) {
+ fakeShiftPress = TRUE;
+ EnqueueKey(kbdDevice, KeyPress, SHIFT_L_KEY_CODE);
+ }
+ if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) {
+ if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) {
+ fakeShiftLRelease = TRUE;
+ EnqueueKey(kbdDevice, KeyRelease, SHIFT_L_KEY_CODE);
+ }
+ if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) {
+ fakeShiftRRelease = TRUE;
+ EnqueueKey(kbdDevice, KeyRelease, SHIFT_R_KEY_CODE);
+ }
+ }
+ }
+
+ EnqueueKey(kbdDevice, type, keyCode);
+
+ if (fakeShiftPress) {
+ EnqueueKey(kbdDevice, KeyRelease, SHIFT_L_KEY_CODE);
+ }
+ if (fakeShiftLRelease) {
+ EnqueueKey(kbdDevice, KeyPress, SHIFT_L_KEY_CODE);
+ }
+ if (fakeShiftRRelease) {
+ EnqueueKey(kbdDevice, KeyPress, SHIFT_R_KEY_CODE);
+ }
+}
+
+
+/*
+ * Called when the rfbserver receives a rfbPointerEvent event from a client.
+ * Put an X mouse event into the event queue.
+ */
+void
+PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+ int i;
+ 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
+
+#ifdef DMXVNC
+ dmxCoreMotion(&ptrDevice->public, x, y, 0, DMX_BLOCK);
+#else
+ EnqueueMotion(ptrDevice, x, y );
+#endif
+
+ for (i = 0; i < 5; i++) {
+ if ((buttonMask ^ oldButtonMask) & (1<<i)) {
+ int type, detail;
+ if (buttonMask & (1<<i)) {
+ type = ButtonPress;
+ detail = i + 1;
+ } else {
+ type = ButtonRelease;
+ detail = i + 1;
+ }
+ EnqueueButton(ptrDevice, type, detail);
+ }
+ }
+
+ oldButtonMask = buttonMask;
+}
+
+void
+KbdReleaseAllKeys(void)
+{
+ int i, j;
+
+ 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)) {
+ int detail = (i << 3) | j;
+ EnqueueKey(kbdDevice, KeyRelease, detail);
+ }
+ }
+ }
+ }
+}
+
+
+/* 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 --git a/hw/vnc/keyboard.h b/hw/vnc/keyboard.h
new file mode 100644
index 0000000..ab5b1b3
--- /dev/null
+++ b/hw/vnc/keyboard.h
@@ -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 --git a/hw/vnc/loginauth.c b/hw/vnc/loginauth.c
new file mode 100644
index 0000000..7fd5304
--- /dev/null
+++ b/hw/vnc/loginauth.c
@@ -0,0 +1,143 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#ifdef linux
+#include "/usr/include/shadow.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#define _XOPEN_SOURCE
+#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 = (char *)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 --git a/hw/vnc/rdp.c b/hw/vnc/rdp.c
new file mode 100644
index 0000000..867e527
--- /dev/null
+++ b/hw/vnc/rdp.c
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.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 --git a/hw/vnc/rfb.h b/hw/vnc/rfb.h
new file mode 100644
index 0000000..8a6d1ec
--- /dev/null
+++ b/hw/vnc/rfb.h
@@ -0,0 +1,751 @@
+/*
+ * 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.
+ */
+
+#ifndef RFB_H_INCLUDED
+#define RFB_H_INCLUDED
+
+#ifdef HAVE_DMX_CONFIG_H
+#include "dmx-config.h"
+#endif
+
+#ifdef DMXVNC
+#include <dmx.h>
+#else
+#include <dix-config.h>
+#endif
+
+#include <zlib.h>
+#ifdef XFREE86VNC
+#include "xf86.h"
+#endif
+#include "scrnintstr.h"
+#include "colormapst.h"
+#include "dixstruct.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "windowstr.h"
+#include "dixfontstr.h"
+#include "mipointer.h"
+#include <rfbproto.h>
+#include <vncauth.h>
+#define _VNC_SERVER
+#include <X11/extensions/vnc.h>
+#include "picturestr.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
+
+extern DevPrivateKey VNCScreenKey;
+extern DevPrivateKey rfbGCKey;
+
+#if XFREE86VNC || defined(DMXVNC)
+#include "vncint.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 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;
+ unsigned 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 *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 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);
+
+/* dispcur.c */
+extern Bool rfbDCInitialize(ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs);
+
+
+/* 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);
+
+extern void vncSetKeyboardDevice(DeviceIntPtr kbd);
+extern void vncSetPointerDevice(DeviceIntPtr ptr);
+
+
+/* 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 rfbSendChromiumWindowDestroy(unsigned int winid);
+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 *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);
+
+
+/* vncInit.c */
+extern void VNCInitForDMX(void);
+extern void rfbWakeupHandlerDMX(void);
+
+
+/* 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);
+
+
+/* dpms.c */
+
+extern Bool DPMSSupported(void);
+extern int DPSMGet(int *level);
+extern void DPMSSet(int level);
+
+
+#endif /* RFB_H_INCLUDED */
diff --git a/hw/vnc/rfbkeyb.c b/hw/vnc/rfbkeyb.c
new file mode 100644
index 0000000..2405e66
--- /dev/null
+++ b/hw/vnc/rfbkeyb.c
@@ -0,0 +1,405 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#if XFREE86VNC
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include <misc.h>
+#include <xf86.h>
+#if !defined(DGUX)
+#include <xisb.h>
+#endif
+#include <xf86Xinput.h>
+#include <exevents.h> /* Needed for InitValuator/Proximity stuff */
+#include <mipointer.h>
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+#else
+#include <dix.h>
+#include <mipointer.h>
+#endif
+#include "rfb.h"
+
+
+extern void rfbSendBell(void);
+extern DeviceIntPtr kbdDevice;
+
+static const char *DEFAULTS[] = {
+ NULL
+};
+
+#include <X11/keysym.h>
+#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;
+
+ 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:
+ vncSetKeyboardDevice(device);
+ KbdDeviceInit(device, &keySyms, modMap);
+#ifdef XKB
+ if (noXkbExtension) {
+#endif
+ InitKeyboardDeviceStruct(pDev, &keySyms, modMap,
+ (BellProcPtr)rfbSendBell,
+ (KbdCtrlProcPtr)NoopDDA);
+#ifdef XKB
+ } else {
+ XkbComponentNamesRec names;
+ 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:
+ vncSetKeyboardDevice(NULL);
+ 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;
+#if 0
+ pInfo->motion_history_proc = NULL;
+#endif
+ 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) {
+ 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 --git a/hw/vnc/rfbmouse.c b/hw/vnc/rfbmouse.c
new file mode 100644
index 0000000..40e6ec6
--- /dev/null
+++ b/hw/vnc/rfbmouse.c
@@ -0,0 +1,260 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#include <X11/keysym.h>
+#if XFREE86VNC
+#ifndef XFree86LOADER
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include <misc.h>
+#include <xf86.h>
+#if !defined(DGUX)
+#include <xisb.h>
+#endif
+#include <xf86Xinput.h>
+#include <exevents.h> /* Needed for InitValuator/Proximity stuff */
+#include <mipointer.h>
+
+#ifdef XFree86LOADER
+#include <xf86Module.h>
+#endif
+
+static const char *DEFAULTS[] = {
+ NULL
+};
+#else
+#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;
+ void *func1;
+ int (*func2)(void);
+
+ if (LoaderSymbol("GetMotionHistory"))
+ func1 = LoaderSymbol("GetMotionHistory");
+ else
+ func1 = LoaderSymbol("miPointerGetMotionEvents");
+
+ if (LoaderSymbol("GetMotionHistorySize"))
+ func2 = LoaderSymbol("GetMotionHistorySize");
+ else
+ func2 = LoaderSymbol("miPointerGetMotionBufferSize");
+
+
+ switch (onoff)
+ {
+ case DEVICE_INIT:
+ vncSetPointerDevice(device);
+ PtrDeviceInit();
+ map[1] = 1;
+ map[2] = 2;
+ map[3] = 3;
+ map[4] = 4;
+ map[5] = 5;
+ InitPointerDeviceStruct(pDev, map, 5,
+ func1,
+ PtrDeviceControl,
+ (*func2)(), 2);
+ break;
+
+ case DEVICE_ON:
+ pDev->on = TRUE;
+ PtrDeviceOn(device);
+ break;
+
+ case DEVICE_OFF:
+ pDev->on = FALSE;
+ PtrDeviceOff();
+ break;
+
+ case DEVICE_CLOSE:
+ vncSetPointerDevice(NULL);
+ 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;
+#if 0
+ pInfo->motion_history_proc = xf86GetMotionEvents;
+#endif
+ 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 --git a/hw/vnc/rfbproto.h b/hw/vnc/rfbproto.h
new file mode 100644
index 0000000..5ed86c5
--- /dev/null
+++ b/hw/vnc/rfbproto.h
@@ -0,0 +1,1362 @@
+/*
+ * 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 rfbChromiumWindowDestroy 54
+
+#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
+
+/*-----------------------------------------------------------------------------
+ * ChromiumWindowDestroy - destroy a window
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbChromiumWindowDestroy */
+ CARD8 pad1;
+ CARD16 pad2;
+ CARD32 winid;
+} rfbChromiumWindowDestroyMsg;
+
+#define sz_rfbChromiumWindowDestroyMsg 8
+
+/*-----------------------------------------------------------------------------
+ * 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;
+ rfbChromiumWindowDestroyMsg scwd;
+} 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 --git a/hw/vnc/rfbserver.c b/hw/vnc/rfbserver.c
new file mode 100644
index 0000000..b93087f
--- /dev/null
+++ b/hw/vnc/rfbserver.c
@@ -0,0 +1,2308 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 "input.h"
+#include "mipointer.h"
+#if XFREE86VNC
+#include <micmap.h>
+#endif
+#ifdef CHROMIUM
+#include "mivalidate.h"
+#endif
+#include "rfb.h"
+#include "windowstr.h"
+#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; /* list of all VNC clients/viewers */
+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;
+ }
+
+ rfbLog("rfbClientConnectionGone\n");
+
+ if (cl->login != NULL) {
+ rfbLog("VNC Client %s (%s) gone\n", cl->login, cl->host);
+ free(cl->login);
+ } else {
+ rfbLog("VNC 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); /*XXX deprecated*/
+ (*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);
+ }
+
+#ifndef DMXVNC
+ /* don't try to send any pixel data - we'll crash */
+ if (FB_UPDATE_PENDING(cl)) {
+ rfbSendFramebufferUpdate(cl->pScreen, cl);
+ }
+#endif
+
+ 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
+ /*ErrorF("Key event: %d\n", msg.ke.key);*/
+ 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);
+ int newy = y;
+
+ /* 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;
+
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+ &cl->format, &pVNC->updateBuf[pVNC->ublen],
+ pVNC->paddedWidthInBytes, w, nlines, x, newy);
+
+ pVNC->ublen += nlines * bytesPerLine;
+ h -= nlines;
+ newy += 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;
+
+ 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, (char*)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(void)
+{
+ 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
+
+
+/**
+ * This sends a ChromiumStart message to all VNC viewers running on the
+ * host named by ipaddress.
+ * This is done in response to an OpenGL/Chromium app calling
+ * XVncChromiumStart().
+ */
+void
+rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort,
+ unsigned int mothershipPort)
+{
+ rfbClientPtr cl, nextCl;
+ rfbChromiumStartMsg scd;
+ struct in_addr ip;
+ unsigned int vncipaddress;
+
+ /*rfbLog("Enter %s\n", __func__);*/
+ /* loop over vnc viewers/clients */
+ for (cl = rfbClientHead; cl; cl = nextCl) {
+ nextCl = cl->next;
+ /*rfbLog("%s: cl=%p enableCr=%d\n", __func__,
+ (void*) cl, cl->enableChromiumEncoding);
+ */
+ if (!cl->enableChromiumEncoding) {
+ /* viewer is not chromium-enhanced */
+ continue;
+ }
+ inet_aton(cl->host, &ip);
+ memcpy(&vncipaddress, &ip, sizeof(unsigned int));
+ rfbLog("%s: ipaddr=0x%x vncipaddr=0x%x cl->port=%d\n",
+ __func__, ipaddress, vncipaddress, cl->chromium_port);
+ 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 a time, so break now! */
+ break;
+ }
+ }
+ /*rfbLog("Leave %s\n", __func__);*/
+}
+
+
+/**
+ * Begin monitoring the given X windowid.
+ * When we detect size/position/visibility 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 monitoring 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;
+ }
+ }
+ }
+}
+
+void
+rfbSendChromiumWindowDestroy(unsigned int winid)
+{
+ rfbClientPtr cl, nextCl;
+ rfbChromiumWindowDestroyMsg scwd;
+
+ for (cl = rfbClientHead; cl; cl = nextCl) {
+ nextCl = cl->next;
+ if (!cl->enableChromiumEncoding)
+ continue;
+ if (cl->chromium_port) {
+ scwd.type = rfbChromiumWindowDestroy;
+ scwd.winid = winid;
+ if (WriteExact(cl->sock, (char *)&scwd,
+ sz_rfbChromiumWindowDestroyMsg) < 0) {
+ rfbLogPerror("rfbSendChromiumWindowDestroy: 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 --git a/hw/vnc/rre.c b/hw/vnc/rre.c
new file mode 100644
index 0000000..09043c8
--- /dev/null
+++ b/hw/vnc/rre.c
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 unsigned char *rreBeforeBuf = NULL;
+
+static int rreAfterBufSize = 0;
+static unsigned 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;
+ int maxRawSize = (pVNC->width * pVNC->height
+ * (cl->format.bitsPerPixel / 8));
+
+ if (rreBeforeBufSize < maxRawSize) {
+ rreBeforeBufSize = maxRawSize;
+ if (rreBeforeBuf == NULL)
+ rreBeforeBuf = (unsigned char *)xalloc(rreBeforeBufSize);
+ else
+ rreBeforeBuf = (unsigned char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
+ }
+
+ if (rreAfterBufSize < maxRawSize) {
+ rreAfterBufSize = maxRawSize;
+ if (rreAfterBuf == NULL)
+ rreAfterBuf = (unsigned char *)xalloc(rreAfterBufSize);
+ else
+ rreAfterBuf = (unsigned char *)xrealloc(rreAfterBuf, rreAfterBufSize);
+ }
+
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,
+ &pVNC->rfbServerFormat,
+ &cl->format, 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 --git a/hw/vnc/sockets.c b/hw/vnc/sockets.c
new file mode 100644
index 0000000..7eff68c
--- /dev/null
+++ b/hw/vnc/sockets.c
@@ -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_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;
+#if 0
+ int totalTimeWaited = 0;
+#endif
+
+ 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 --git a/hw/vnc/sprite.c b/hw/vnc/sprite.c
new file mode 100644
index 0000000..c1e8685
--- /dev/null
+++ b/hw/vnc/sprite.c
@@ -0,0 +1,2279 @@
+/*
+ * 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.
+*/
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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"
+
+/*
+ * screen wrappers
+ */
+
+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);
+
+static void rfbSpriteSaveDoomedAreas(WindowPtr pWin,
+ RegionPtr pObscured, int dx,
+ int dy);
+static RegionPtr rfbSpriteRestoreAreas(WindowPtr pWin, RegionPtr pRgnExposed);
+static void rfbSpriteComputeSaved(ScreenPtr pScreen);
+
+static DevPrivateKey rfbSpriteScreenKey = &rfbSpriteScreenKey;
+
+#define SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \
+ ((rfbSpriteScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, \
+ rfbSpriteScreenKey))->field)
+
+#define SCREEN_EPILOGUE(pScreen, field, wrapper)\
+ ((pScreen)->field = wrapper)
+
+/*
+ * GC func wrappers
+ */
+
+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,
+};
+
+static DevPrivateKey rfbSpriteGCKey = &rfbSpriteGCKey;
+
+#define GC_FUNC_PROLOGUE(pGC) \
+ rfbSpriteGCPtr pGCPriv = \
+ (rfbSpriteGCPtr)dixLookupPrivate(&(pGC)->devPrivates, rfbSpriteGCKey); \
+ (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) \
+ dixLookupPrivate(&pDrawable->pScreen->devPrivates, \
+ rfbSpriteScreenKey);
+
+#define GC_SETUP(pDrawable, pGC) \
+ GC_SETUP_CHEAP(pDrawable) \
+ rfbSpriteGCPtr pGCPrivate = \
+ (rfbSpriteGCPtr)dixLookupPrivate(&(pGC)->devPrivates, rfbSpriteGCKey); \
+ 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 (ScreenPtr pScreen, CursorPtr pCursor);
+static Bool rfbSpriteUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor);
+static void rfbSpriteSetCursor (ScreenPtr pScreen, CursorPtr pCursor, int x, int y);
+static void rfbSpriteMoveCursor (ScreenPtr pScreen, int x, int y);
+
+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;
+
+ if (!dixRequestPrivate(rfbSpriteGCKey, 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;
+
+ 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;
+ dixSetPrivate(&pScreen->devPrivates, rfbSpriteScreenKey, 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;
+
+ 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;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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;
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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)dixLookupPrivate(&(pGC)->devPrivates, rfbSpriteGCKey);
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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 (ScreenPtr pScreen)
+{
+ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr)
+ dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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;
+{
+ VNCSCREENPTR(pDrawable->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;
+{
+ VNCSCREENPTR(pDrawable->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;
+{
+ VNCSCREENPTR(pDrawable->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;
+ VNCSCREENPTR(pGC->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;
+ VNCSCREENPTR(pGC->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;
+ VNCSCREENPTR(pDrawable->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;
+ VNCSCREENPTR(pDrawable->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;
+ VNCSCREENPTR(pDrawable->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;
+ VNCSCREENPTR(pDrawable->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;
+ VNCSCREENPTR(pDrawable->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;
+ VNCSCREENPTR(pDrawable->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 */
+{
+ VNCSCREENPTR(pDrawable->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;
+{
+ VNCSCREENPTR(pDrawable->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 (DrawablePtr pDraw, FontPtr font, int x, int 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 (DrawablePtr pDraw, GCPtr pGC, int x, int 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 *) xalloc(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 */
+ }
+ xfree(charinfo);
+ return x + w;
+}
+
+static int
+rfbSpritePolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars)
+{
+ int ret;
+ VNCSCREENPTR(pDrawable->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(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars)
+{
+ int ret;
+ VNCSCREENPTR(pDrawable->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;
+{
+ VNCSCREENPTR(pDrawable->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;
+{
+ VNCSCREENPTR(pDrawable->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 */
+{
+ VNCSCREENPTR(pDrawable->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 */
+{
+ VNCSCREENPTR(pDrawable->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(pDrawable->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
+
+/*
+ * miPointer interface routines
+ */
+
+#define SPRITE_PAD 8
+
+static Bool
+rfbSpriteRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
+{
+ rfbSpriteScreenPtr pScreenPriv;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ if (pCursor == pScreenPriv->pCursor)
+ pScreenPriv->checkPixels = TRUE;
+ return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor);
+}
+
+static Bool
+rfbSpriteUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor)
+{
+ rfbSpriteScreenPtr pScreenPriv;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor);
+}
+
+static void
+rfbSpriteSetCursor (ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
+{
+ rfbSpriteScreenPtr pScreenPriv;
+ rfbClientPtr cl, nextCl;
+ VNCSCREENPTR(pScreen);
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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 (ScreenPtr pScreen, int x, int y)
+{
+ rfbSpriteScreenPtr pScreenPriv;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ rfbSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y);
+}
+
+/*
+ * undraw/draw cursor
+ */
+
+void
+rfbSpriteRemoveCursor (pScreen)
+ ScreenPtr pScreen;
+{
+ rfbSpriteScreenPtr pScreenPriv;
+ VNCSCREENPTR(pScreen);
+
+ if (!pVNC->cursorIsDrawn)
+ return;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ 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;
+ Bool status;
+
+ for (cl = rfbClientHead; cl ; cl = cl->next) {
+ if (cl->enableCursorShapeUpdates)
+ cl->cursorWasChanged = TRUE;
+ }
+
+ pPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+ status = (*pPriv->DisplayCursor)(pScreen, pCursor);
+
+ /* send new cursor shape to interested viewers */
+ for (cl = rfbClientHead; cl ; cl = cl->next) {
+ if (cl->cursorWasChanged) {
+ rfbSendFramebufferUpdate(pScreen, cl);
+ }
+ }
+
+ return status;
+}
+
+
+/*
+ * obtain current cursor pointer
+ */
+
+CursorPtr
+rfbSpriteGetCursorPtr (pScreen)
+ ScreenPtr pScreen;
+{
+ rfbSpriteScreenPtr pScreenPriv;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ return pScreenPriv->pCursor;
+}
+
+/*
+ * obtain current cursor position
+ */
+
+void
+rfbSpriteGetCursorPos (pScreen, px, py)
+ ScreenPtr pScreen;
+ int *px, *py;
+{
+ rfbSpriteScreenPtr pScreenPriv;
+
+ pScreenPriv = (rfbSpriteScreenPtr)dixLookupPrivate(&pScreen->devPrivates,
+ rfbSpriteScreenKey);
+
+ *px = pScreenPriv->x;
+ *py = pScreenPriv->y;
+}
+
diff --git a/hw/vnc/sprite.h b/hw/vnc/sprite.h
new file mode 100644
index 0000000..ed34726
--- /dev/null
+++ b/hw/vnc/sprite.h
@@ -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 --git a/hw/vnc/spritest.h b/hw/vnc/spritest.h
new file mode 100644
index 0000000..8593ee0
--- /dev/null
+++ b/hw/vnc/spritest.h
@@ -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 --git a/hw/vnc/stats.c b/hw/vnc/stats.c
new file mode 100644
index 0000000..83366ec
--- /dev/null
+++ b/hw/vnc/stats.c
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 --git a/hw/vnc/symlink-vnc.sh b/hw/vnc/symlink-vnc.sh
new file mode 100755
index 0000000..b4347a1
--- /dev/null
+++ b/hw/vnc/symlink-vnc.sh
@@ -0,0 +1,198 @@
+#!/bin/sh
+
+#
+# A script that symlinks source files from vnc to modular
+#
+# Author: Soren Sandmann (sandmann@redhat.com) (original)
+# adapted for vnc by Alan Hourihane <alanh@fairlite.demon.co.uk>
+
+#
+# Things we would like to do
+#
+# - Check that all the relevant files exist
+# - AUTHORS, autogen.sh, configure.ac, ...
+# - Check that we have actually linked everything
+# - if a file doesn't need to be linked, then it needs
+# to be listed as "not-linked"
+# - Compute diffs between all the files (shouldn't be necessary)
+# - possibly check that files are listet in Makefile.am's
+# - Clean target directory of irrelevant files
+#
+
+check_destinations () {
+ # don't do anything - we are relying on the side
+ # effect of dst_dir
+ true
+}
+
+check_exist() {
+ # Check whether $1 exists
+
+ if [ ! -e $1 ] ; then
+ error "$1 not found"
+ fi
+}
+
+delete_existing() {
+ # Delete $2
+
+ rm -f $2
+}
+
+link_files() {
+ # Link $1 to $2
+
+ if [ ! -e $2 ] ; then
+ ln -s $1 $2
+ fi
+}
+
+main() {
+ check_args $1 $2
+
+ run check_destinations "Creating destination directories"
+ run check_exist "Checking that the source files exist"
+ run delete_existing "Deleting existing files"
+ run link_files "Linking files"
+}
+
+## actual symlinking
+
+symlink_vnc() {
+ src_dir .
+ dst_dir .
+ action d3des.c
+ action d3des.h
+ action auth.c
+ action cmap.c
+ action corre.c
+ action cursor.c
+ action cutpaste.c
+ action dispcur.c
+ action draw.c
+ action hextile.c
+ action httpd.c
+ action kbdptr.c
+ action keyboard.h
+ action loginauth.c
+ action rdp.c
+ action rfb.h
+ action rfbkeyb.c
+ action rfbmouse.c
+ action rfbproto.h
+ action rfbserver.c
+ action rre.c
+ action sockets.c
+ action sprite.c
+ action sprite.h
+ action spritest.h
+ action stats.c
+ action tableinitcmtemplate.c
+ action tableinittctemplate.c
+ action tabletranstemplate.c
+ action tight.c
+ action translate.c
+ action vncauth.c
+ action vncauth.h
+ action vncext.c
+ action xistubs.c
+ action zlib.c
+}
+
+#########
+#
+# Helper functions
+#
+#########
+
+error() {
+ echo
+ echo \ \ \ error:\ \ \ $1
+ exit 1
+}
+
+# printing out what's going on
+run_module() {
+ # $1 module
+ # $2 explanation
+ echo -n $EXPLANATION for $1 module ...\
+ symlink_$1
+ echo DONE
+}
+
+run() {
+ # $1 what to do
+ # $2 explanation
+
+ ACTION=$1 EXPLANATION=$2 run_module vnc
+}
+
+src_dir() {
+ REAL_SRC_DIR=$SRC_DIR/$1
+ if [ ! -d $REAL_SRC_DIR ] ; then
+ error "Source directory $REAL_SRC_DIR does not exist"
+ fi
+}
+
+dst_dir() {
+ REAL_DST_DIR=$DST_DIR/$1
+ if [ ! -d $REAL_DST_DIR ] ; then
+ mkdir -p $REAL_DST_DIR
+ fi
+}
+
+action() {
+ if [ -z $2 ] ; then
+ $ACTION $REAL_SRC_DIR/$1 $REAL_DST_DIR/$1
+ else
+ $ACTION $REAL_SRC_DIR/$1 $REAL_DST_DIR/$2
+ fi
+}
+
+usage() {
+ echo symlink.sh src-dir dst-dir
+ echo src-dir: the xc directory of the monolithic source tree
+ echo dst-dir: the modular source tree containing proto, app, lib, ...
+}
+
+# Check commandline args
+check_args() {
+ if [ -z $1 ] ; then
+ echo Missing source dir
+ usage
+ exit 1
+ fi
+
+ if [ -z $2 ] ; then
+ echo Missing destination dir
+ usage
+ exit 1
+ fi
+
+ if [ ! -d $1 ] ; then
+ echo $1 is not a dir
+ usage
+ exit 1
+ fi
+
+ if [ ! -d $2 ] ; then
+ echo $2 is not a dir
+ usage
+ exit 1
+ fi
+
+ if [ $1 = $2 ] ; then
+ echo source and destination can\'t be the same
+ usage
+ exit 1
+ fi
+
+ D=`dirname "$relpath"`
+ B=`basename "$relpath"`
+ abspath="`cd \"$D\" 2>/dev/null && pwd || echo \"$D\"`/$B"
+
+ SRC_DIR=`( cd $1 ; pwd )`
+ DST_DIR=`(cd $2 ; pwd )`
+}
+
+main $1 $2
diff --git a/hw/vnc/tableinitcmtemplate.c b/hw/vnc/tableinitcmtemplate.c
new file mode 100644
index 0000000..c65c3d2
--- /dev/null
+++ b/hw/vnc/tableinitcmtemplate.c
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 --git a/hw/vnc/tableinittctemplate.c b/hw/vnc/tableinittctemplate.c
new file mode 100644
index 0000000..1af8a06
--- /dev/null
+++ b/hw/vnc/tableinittctemplate.c
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 --git a/hw/vnc/tabletranstemplate.c b/hw/vnc/tabletranstemplate.c
new file mode 100644
index 0000000..d8baa44
--- /dev/null
+++ b/hw/vnc/tabletranstemplate.c
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 *optr,
+ int bytesBetweenInputLines,
+ int width, int height,
+ int x, int y)
+{
+ IN_T *ip;
+ OUT_T *op = (OUT_T *)optr;
+ OUT_T *opLineEnd;
+ OUT_T *t = (OUT_T *)table;
+ DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum];
+ int truewidth = PixmapBytePad(width, in->bitsPerPixel);
+ unsigned char *iptr = malloc(truewidth * height * in->bitsPerPixel / 8);
+ int ipextra = truewidth - width;
+ (*pScreen->GetImage)(pDraw, x, y, truewidth, height, ZPixmap, ~0, (char*)iptr);
+ ip = (IN_T *)iptr;
+
+ while (height > 0) {
+ opLineEnd = op + width;
+
+ while (op < opLineEnd) {
+ *(op++) = t[*(ip++)];
+ }
+
+ ip += ipextra;
+ height--;
+ }
+ free(iptr);
+}
+
+
+/*
+ * 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 *optr,
+ int bytesBetweenInputLines,
+ int width, int height,
+ int x, int y)
+{
+ IN_T *ip;
+ OUT_T *op = (OUT_T *)optr;
+ OUT_T *opLineEnd;
+ OUT_T *redTable = (OUT_T *)table;
+ OUT_T *greenTable = redTable + in->redMax + 1;
+ OUT_T *blueTable = greenTable + in->greenMax + 1;
+ DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum];
+ int truewidth = PixmapBytePad(width, in->bitsPerPixel);
+ unsigned char *iptr = malloc(truewidth * height * in->bitsPerPixel / 8);
+ int ipextra = truewidth - width;
+ (*pScreen->GetImage)(pDraw, x, y, truewidth, height, ZPixmap, ~0, (char*)iptr);
+ ip = (IN_T *)iptr;
+
+ 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--;
+ }
+ free(iptr);
+}
+
+#undef IN_T
+#undef OUT_T
+#undef rfbTranslateWithSingleTableINtoOUT
+#undef rfbTranslateWithRGBTablesINtoOUT
diff --git a/hw/vnc/tight.c b/hw/vnc/tight.c
new file mode 100644
index 0000000..bbe1744
--- /dev/null
+++ b/hw/vnc/tight.c
@@ -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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 unsigned char *tightBeforeBuf = NULL;
+
+static int tightAfterBufSize = 0;
+static unsigned 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, unsigned 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, unsigned 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, const CARD8 *buffer, int w, int h, int quality);
+static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer, int row, int width);
+static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer, int row, int width);
+static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer, int row, int width);
+static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer, int row, int width);
+
+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;
+
+ 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 = (unsigned char *)xalloc(tightBeforeBufSize);
+ else
+ tightBeforeBuf = (unsigned 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;
+
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,
+ &pVNC->rfbServerFormat,
+ &cl->format, 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 = (unsigned char *)xalloc(tightBeforeBufSize);
+ else
+ tightBeforeBuf = (unsigned char *)xrealloc(tightBeforeBuf,
+ tightBeforeBufSize);
+ }
+
+ if (tightAfterBufSize < maxAfterSize) {
+ tightAfterBufSize = maxAfterSize;
+ if (tightAfterBuf == NULL)
+ tightAfterBuf = (unsigned char *)xalloc(tightAfterBufSize);
+ else
+ tightAfterBuf = (unsigned 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);
+ 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;
+
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat,
+ &cl->format, 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, tightBeforeBuf, 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, tightBeforeBuf, 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);
+}
+
+/**
+ * Compress the data in the tightBeforeBuf buffer.
+ * \param dataLen - amount of data in tightBeforeBuf to compress, in bytes
+ */
+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;
+ unsigned 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;
+ unsigned 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;
+
+/**
+ * Send the given image rect with jpeg compression.
+ * \param buffer the source image buffer
+ * \param w width of source image in pixels
+ * \param h height of source image in pixels
+ * \param quality jpeg enoding quality
+ */
+static Bool
+SendJpegRect(rfbClientPtr cl, const CARD8 *buffer, int w, int h,
+ int quality)
+{
+ VNCSCREENPTR(cl->pScreen);
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ CARD8 *srcBuf;
+ JSAMPROW rowPointer[1];
+ int i;
+
+ 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 (i = 0; i < h; i++) {
+ PrepareRowForJpeg(cl->pScreen, srcBuf, buffer, i, 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);
+}
+
+/**
+ * Convert pixel data to format needed for jpeg library.
+ * \dst destination buffer (24bpp)
+ * \buffer source buffer (16 or 32bpp)
+ * \row which image row to prepare/convert
+ * \width width of source buffer, in pixels
+ */
+static void
+PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer,
+ int row, int width)
+{
+ VNCSCREENPTR(pScreen);
+ if (pVNC->rfbServerFormat.bitsPerPixel == 32) {
+ if ( pVNC->rfbServerFormat.redMax == 0xFF &&
+ pVNC->rfbServerFormat.greenMax == 0xFF &&
+ pVNC->rfbServerFormat.blueMax == 0xFF ) {
+ PrepareRowForJpeg24(pScreen, dst, buffer, row, width);
+ } else {
+ PrepareRowForJpeg32(pScreen, dst, buffer, row, width);
+ }
+ } else {
+ /* 16 bpp assumed. */
+ PrepareRowForJpeg16(pScreen, dst, buffer, row, width);
+ }
+}
+
+/**
+ * Src buffer is 32bpp, dst buffer is 24bpp (optimized case).
+ */
+static void
+PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer,
+ int row, int width)
+{
+ VNCSCREENPTR(pScreen);
+ const CARD32 *src = ((const CARD32 *) buffer) + row * width;
+ while (width--) {
+ CARD32 pix = *src++;
+ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift);
+ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift);
+ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift);
+ }
+}
+
+/**
+ * PrepareRowForJpeg16/32: convert 16bpp or 32bpp pixels to 24bpp
+ */
+#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \
+ \
+static void \
+PrepareRowForJpeg##bpp(ScreenPtr pScreen, CARD8 *dst, const CARD8 *buffer, \
+ int row, int width) \
+{ \
+ VNCSCREENPTR(pScreen); \
+ CARD##bpp *fbptr; \
+ CARD##bpp pix; \
+ int inRed, inGreen, inBlue; \
+ \
+ fbptr = ((CARD##bpp *) buffer) + row * width; \
+ \
+ while (width--) { \
+ 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 --git a/hw/vnc/translate.c b/hw/vnc/translate.c
new file mode 100644
index 0000000..b9ab53e
--- /dev/null
+++ b/hw/vnc/translate.c
@@ -0,0 +1,502 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#include <stdio.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 *optr, int bytesBetweenInputLines,
+ int width, int height, int x, int y)
+{
+ VNCSCREENPTR(pScreen);
+ DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum];
+ int truewidth = PixmapBytePad(width, in->bitsPerPixel) / 4;
+
+ if ((x + truewidth > pVNC->width) || truewidth != width) {
+ unsigned char *buffer = malloc(truewidth * height * in->bitsPerPixel / 8);
+ unsigned char *buf = buffer;
+
+ (*pScreen->GetImage)(pDraw, x, y, truewidth, height, ZPixmap, ~0, (char*)buf);
+ while (height--) {
+ memcpy(optr, buf, width * in->bitsPerPixel / 8);
+ optr += width * in->bitsPerPixel / 8;
+ buf += truewidth * in->bitsPerPixel / 8;
+ }
+ free(buffer);
+ return;
+ }
+
+ (*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, (char*)optr);
+}
+
+
+/*
+ * 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 --git a/hw/vnc/vncauth.c b/hw/vnc/vncauth.c
new file mode 100644
index 0000000..a70cfa5
--- /dev/null
+++ b/hw/vnc/vncauth.c
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.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.
+ *
+ * NOTE: The file name of "-" denotes stdout.
+ */
+
+int
+vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname)
+{
+ FILE *fp;
+ int bytesToWrite, bytesWrote;
+ unsigned char encryptedPasswd[16] = {
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0
+ };
+
+ if (strcmp(fname, "-") != 0) {
+ fp = fopen(fname, "w");
+ if (fp == NULL) {
+ return 0;
+ }
+ chmod(fname, S_IRUSR|S_IWUSR);
+ } else {
+ fp = stdout;
+ }
+
+ strncpy((char*)encryptedPasswd, passwd, 8);
+ if (passwdViewOnly != NULL)
+ strncpy((char*)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);
+
+ if (fp != stdout) {
+ 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;
+ unsigned 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 --git a/hw/vnc/vncauth.h b/hw/vnc/vncauth.h
new file mode 100644
index 0000000..adc280b
--- /dev/null
+++ b/hw/vnc/vncauth.h
@@ -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 --git a/hw/vnc/vncext.c b/hw/vnc/vncext.c
new file mode 100644
index 0000000..80a3433
--- /dev/null
+++ b/hw/vnc/vncext.c
@@ -0,0 +1,800 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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>
+
+DevPrivateKey vncCreateScreenResourcesKey = &vncCreateScreenResourcesKey;
+DevPrivateKey rfbGCKey = &rfbGCKey;
+
+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
+ rfbLog("GenerateVncDisconnectedEvent\n");
+ 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;
+}
+
+
+
+static unsigned long vncExtGeneration = 0;
+#if XFREE86VNC
+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)
+ dixLookupPrivate(&pScreen->devPrivates, vncCreateScreenResourcesKey);
+ 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;
+ dixSetPrivate(&pScreen->devPrivates, vncCreateScreenResourcesKey, 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 (vncExtGeneration != serverGeneration) {
+ unsigned int i;
+
+ vncExtGeneration = serverGeneration;
+
+ // no allocation needed for screen privates
+ if (!dixRequestPrivate(rfbGCKey, sizeof(rfbGCRec)))
+ return;
+
+#if XFREE86VNC
+ for (i = 0 ; i < screenInfo.numScreens; i++)
+ {
+ dixSetPrivate(&screenInfo.screens[i]->devPrivates,
+ vncCreateScreenResourcesKey,
+ xf86Screens[i]->pScreen->CreateScreenResources);
+ xf86Screens[i]->pScreen->CreateScreenResources = vncCreateScreenResources;
+ }
+#endif
+
+ gethostname(rfbThisHost, 255);
+ }
+
+ 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 --git a/hw/vnc/xistubs.c b/hw/vnc/xistubs.c
new file mode 100644
index 0000000..011ac9e
--- /dev/null
+++ b/hw/vnc/xistubs.c
@@ -0,0 +1,323 @@
+/* $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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 --git a/hw/vnc/zlib.c b/hw/vnc/zlib.c
new file mode 100644
index 0000000..4863fb4
--- /dev/null
+++ b/hw/vnc/zlib.c
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+
+#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 unsigned char *zlibBeforeBuf = NULL;
+
+static int zlibAfterBufSize = 0;
+static unsigned 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;
+ int maxRawSize;
+ int maxCompSize;
+
+ maxRawSize = (pVNC->width * pVNC->height
+ * (cl->format.bitsPerPixel / 8));
+
+ if (zlibBeforeBufSize < maxRawSize) {
+ zlibBeforeBufSize = maxRawSize;
+ if (zlibBeforeBuf == NULL)
+ zlibBeforeBuf = (unsigned char *)xalloc(zlibBeforeBufSize);
+ else
+ zlibBeforeBuf = (unsigned 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 = (unsigned char *)xalloc(zlibAfterBufSize);
+ else
+ zlibAfterBuf = (unsigned char *)xrealloc(zlibAfterBuf, zlibAfterBufSize);
+ }
+
+ /*
+ * Convert pixel data to client format.
+ */
+ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable,
+ &pVNC->rfbServerFormat,
+ &cl->format, 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 --git a/hw/xfree86/Makefile.am b/hw/xfree86/Makefile.am
index 03c2c3a..06329a8 100644
--- a/hw/xfree86/Makefile.am
+++ b/hw/xfree86/Makefile.am
@@ -4,6 +4,10 @@ if DRI
DRI_SUBDIR = dri
endif
+if VNC
+VNC_SUBDIR = vnc
+endif
+
if DRI2
DRI2_SUBDIR = dri2
endif
@@ -24,13 +28,13 @@ DOC_SUBDIR = doc
SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support parser rac \
ramdac shadowfb vbe vgahw xaa $(MFB_SUBDIR) $(CFB_SUBDIR) \
- xf8_16bpp loader dixmods exa modes \
+ xf8_16bpp loader dixmods exa modes $(VNC_SUBDIR) \
$(DRI_SUBDIR) $(DRI2_SUBDIR) $(XF86UTILS_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 dixmods dri dri2 exa modes \
- utils doc
+ utils doc vnc
bin_PROGRAMS = Xorg
diff --git a/hw/xfree86/dixmods/Makefile.am b/hw/xfree86/dixmods/Makefile.am
index efc5f4a..98d7302 100644
--- a/hw/xfree86/dixmods/Makefile.am
+++ b/hw/xfree86/dixmods/Makefile.am
@@ -14,6 +14,10 @@ if DBE
DBEMOD = libdbe.la
endif
+if XCLIPLIST
+XCLIPLISTMOD = libxcliplist.la
+endif
+
if AFB
AFBMOD = libafb.la
endif
@@ -36,6 +40,7 @@ module_LTLIBRARIES = $(AFBMOD) \
extsmoduledir = $(moduledir)/extensions
extsmodule_LTLIBRARIES = librecord.la \
$(DBEMOD) \
+ $(XCLIPLISTMOD) \
$(GLXMODS) \
$(XTRAPMOD)
@@ -45,6 +50,7 @@ fontsmodule_LTLIBRARIES = libfreetype.la
AM_CFLAGS = @XORG_CFLAGS@ @DIX_CFLAGS@
INCLUDES = @XORG_INCS@ \
-I$(top_srcdir)/dbe \
+ -I$(top_srcdir)/xcliplist \
-I$(top_srcdir)/hw/xfree86/loader \
-I$(top_srcdir)/miext/shadow \
-I$(top_srcdir)/GL/glx
@@ -69,6 +75,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_mi.c fbmodule.c
diff --git a/hw/xfree86/vnc/.gitignore b/hw/xfree86/vnc/.gitignore
new file mode 100644
index 0000000..d14621f
--- /dev/null
+++ b/hw/xfree86/vnc/.gitignore
@@ -0,0 +1,36 @@
+auth.c
+cmap.c
+corre.c
+cursor.c
+cutpaste.c
+d3des.c
+d3des.h
+dispcur.c
+draw.c
+hextile.c
+httpd.c
+kbdptr.c
+keyboard.h
+loginauth.c
+rdp.c
+rfb.h
+rfbkeyb.c
+rfbmouse.c
+rfbproto.h
+rfbserver.c
+rre.c
+sockets.c
+sprite.c
+sprite.h
+spritest.h
+stats.c
+tableinitcmtemplate.c
+tableinittctemplate.c
+tabletranstemplate.c
+tight.c
+translate.c
+vncauth.c
+vncauth.h
+vncext.c
+xistubs.c
+zlib.c
diff --git a/hw/xfree86/vnc/Makefile.am b/hw/xfree86/vnc/Makefile.am
new file mode 100644
index 0000000..6f5cd76
--- /dev/null
+++ b/hw/xfree86/vnc/Makefile.am
@@ -0,0 +1,51 @@
+AM_CFLAGS = $(DIX_CFLAGS)
+
+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)/mi \
+ -I$(top_srcdir)/render \
+ -I$(top_srcdir)/GL/glx \
+ -I$(top_srcdir)/GL/include \
+ -I$(top_builddir)/GL/include \
+ -I@MESA_SOURCE@/include \
+ -DHAVE_XORG_CONFIG_H \
+ -DHAVE_DIX_CONFIG_H \
+ -DXFree86LOADER \
+ -DXFREE86VNC=1 \
+ -DCHROMIUM=1 \
+ $(AM_CFLAGS)
+
+libvnc_la_LIBADD = -ljpeg -lcrypt
+libvnc_la_LDFLAGS = -module -avoid-version
+libvnc_ladir = $(moduledir)/extensions
+libvnc_la_SOURCES = \
+ 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 \
+ vncInit.c \
+ vncauth.c \
+ vncext.c \
+ zlib.c
+
+#sdk_HEADERS = vncint.h
diff --git a/hw/xfree86/vnc/README b/hw/xfree86/vnc/README
new file mode 100644
index 0000000..64aa888
--- /dev/null
+++ b/hw/xfree86/vnc/README
@@ -0,0 +1 @@
+This directory contains the sources for building the vnc.so server extension module.
diff --git a/hw/xfree86/vnc/vncInit.c b/hw/xfree86/vnc/vncInit.c
new file mode 100644
index 0000000..e07ac8f
--- /dev/null
+++ b/hw/xfree86/vnc/vncInit.c
@@ -0,0 +1,618 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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 inetdSock = -1;
+Atom VNC_LAST_CLIENT_ID = 0;
+Atom VNC_CONNECT = 0;
+char *desktopName = "x11";
+char rfbThisHost[256];
+
+DevPrivateKey VNCScreenKey = &VNCScreenKey;
+
+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,
+} 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 },
+ { -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 (!(pScreenPriv = xalloc(sizeof(vncScreenRec))))
+ return FALSE;
+
+ dixSetPrivate(&pScreen->devPrivates, VNCScreenKey, 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->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 = dixLookupPrivate(&(pScreen)->devPrivates, miPointerScreenKey);
+
+ pScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
+ PointPriv->spriteFuncs = &vncCursorSpriteFuncs;
+
+ xf86CursorPriv = dixLookupPrivate(&(pScreen)->devPrivates, xf86CursorScreenKey);
+
+ 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)
+{
+ 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 --git a/hw/xfree86/vnc/vncint.h b/hw/xfree86/vnc/vncint.h
new file mode 100644
index 0000000..43aeaae
--- /dev/null
+++ b/hw/xfree86/vnc/vncint.h
@@ -0,0 +1,151 @@
+/*
+ * 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 <../ramdac/xf86Cursor.h>
+
+#define VNCPTR(pScreen)\
+ (vncScreenPtr)(dixLookupPrivate(&(pScreen)->devPrivates, VNCScreenKey))
+
+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 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;
+ unsigned 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 --git a/mi/miinitext.c b/mi/miinitext.c
index 3c55eeb..4cb6584 100644
--- a/mi/miinitext.c
+++ b/mi/miinitext.c
@@ -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 --git a/xcliplist/Makefile.am b/xcliplist/Makefile.am
new file mode 100644
index 0000000..3f13acc
--- /dev/null
+++ b/xcliplist/Makefile.am
@@ -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
diff --git a/xcliplist/cliplist.c b/xcliplist/cliplist.c
new file mode 100644
index 0000000..290eb79
--- /dev/null
+++ b/xcliplist/cliplist.c
@@ -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 --git a/xcliplist/cliplistmod.c b/xcliplist/cliplistmod.c
new file mode 100644
index 0000000..c365ca2
--- /dev/null
+++ b/xcliplist/cliplistmod.c
@@ -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;
+}
+