From 903ab057689e33dc4a502ae8ae260e48ca1382ba1abf1c29cf93e346fdc15776 Mon Sep 17 00:00:00 2001 From: OBS User unknown Date: Mon, 15 Jan 2007 00:00:17 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/xorg-x11-server?expand=0&rev=5 --- 0018-vnc-support.txt | 59203 ++++++++++++++++++++++++++++++++++++ 0018-vnc-support.txt.diff | 21 + 0018-vnc-support.txt.mbox | 187 + xorg-x11-server.changes | 7 + xorg-x11-server.spec | 58 +- 5 files changed, 59475 insertions(+), 1 deletion(-) create mode 100644 0018-vnc-support.txt create mode 100644 0018-vnc-support.txt.diff create mode 100644 0018-vnc-support.txt.mbox diff --git a/0018-vnc-support.txt b/0018-vnc-support.txt new file mode 100644 index 0000000..439025c --- /dev/null +++ b/0018-vnc-support.txt @@ -0,0 +1,59203 @@ +From 76c92b4af6b33da219439ecafab83f6500a5108b Mon Sep 17 00:00:00 2001 +From: Christiaan Welvaart +Date: Fri, 3 Nov 2006 14:44:06 -0300 +Subject: [PATCH] vnc support + +VNC support, adapted from http://xf4vnc.sourceforge.net/ CVS +--- + Makefile.am | 5 + configure.ac | 99 + + fb/fbcmap.c | 2 + hw/Makefile.am | 7 + hw/dmx/Makefile.am | 14 + hw/dmx/dmx.h | 4 + hw/dmx/dmxinit.c | 7 + hw/dmx/dmxsync.c | 4 + hw/dmx/input/Makefile.am | 4 + hw/dmx/input/dmxinputinit.c | 7 + hw/dmx/vnc/Makefile.am | 43 + + hw/dmx/vnc/auth.c | 562 ++++++++ + hw/dmx/vnc/cmap.c | 163 ++ + hw/dmx/vnc/corre.c | 355 +++++ + hw/dmx/vnc/cursor.c | 401 +++++ + hw/dmx/vnc/cutpaste.c | 87 + + hw/dmx/vnc/d3des.c | 440 ++++++ + hw/dmx/vnc/d3des.h | 51 + + hw/dmx/vnc/dispcur.c | 804 +++++++++++ + hw/dmx/vnc/draw.c | 2097 +++++++++++++++++++++++++++++ + hw/dmx/vnc/hextile.c | 352 +++++ + hw/dmx/vnc/httpd.c | 520 +++++++ + hw/dmx/vnc/kbdptr.c | 446 ++++++ + hw/dmx/vnc/keyboard.h | 167 ++ + hw/dmx/vnc/loginauth.c | 142 ++ + hw/dmx/vnc/rdp.c | 145 ++ + hw/dmx/vnc/rfb.h | 697 ++++++++++ + hw/dmx/vnc/rfbkeyb.c | 412 ++++++ + hw/dmx/vnc/rfbmouse.c | 243 +++ + hw/dmx/vnc/rfbproto.h | 1347 ++++++++++++++++++ + hw/dmx/vnc/rfbserver.c | 2265 +++++++++++++++++++++++++++++++ + hw/dmx/vnc/rre.c | 325 ++++ + hw/dmx/vnc/sockets.c | 656 +++++++++ + hw/dmx/vnc/sprite.c | 2491 ++++++++++++++++++++++++++++++++++ + hw/dmx/vnc/sprite.h | 141 ++ + hw/dmx/vnc/spritest.h | 138 ++ + hw/dmx/vnc/stats.c | 113 ++ + hw/dmx/vnc/tableinitcmtemplate.c | 89 + + hw/dmx/vnc/tableinittctemplate.c | 142 ++ + hw/dmx/vnc/tabletranstemplate.c | 119 ++ + hw/dmx/vnc/tight.c | 1827 +++++++++++++++++++++++++ + hw/dmx/vnc/translate.c | 496 +++++++ + hw/dmx/vnc/vncInit.c | 436 ++++++ + hw/dmx/vnc/vncauth.c | 239 +++ + hw/dmx/vnc/vncauth.h | 34 + hw/dmx/vnc/vncext.c | 689 +++++++++ + hw/dmx/vnc/vncint.h | 154 ++ + hw/dmx/vnc/xistubs.c | 319 ++++ + hw/dmx/vnc/zlib.c | 306 ++++ + hw/vnc/LICENCE.TXT | 340 +++++ + hw/vnc/Makefile.am | 54 + + hw/vnc/README | 14 + hw/vnc/auth.c | 562 ++++++++ + hw/vnc/cmap.c | 163 ++ + hw/vnc/corre.c | 353 +++++ + hw/vnc/cursor.c | 404 ++++++ + hw/vnc/cutpaste.c | 87 + + hw/vnc/d3des.c | 434 ++++++ + hw/vnc/dispcur.c | 804 +++++++++++ + hw/vnc/dpmsstubs.c | 48 + + hw/vnc/draw.c | 2108 +++++++++++++++++++++++++++++ + hw/vnc/hextile.c | 351 +++++ + hw/vnc/httpd.c | 516 +++++++ + hw/vnc/init.c | 1066 +++++++++++++++ + hw/vnc/kbdptr.c | 425 ++++++ + hw/vnc/keyboard.h | 167 ++ + hw/vnc/loginauth.c | 138 ++ + hw/vnc/rdp.c | 142 ++ + hw/vnc/rfb.h | 725 ++++++++++ + hw/vnc/rfbkeyb.c | 412 ++++++ + hw/vnc/rfbmouse.c | 244 +++ + hw/vnc/rfbproto.h | 1347 ++++++++++++++++++ + hw/vnc/rfbserver.c | 2273 +++++++++++++++++++++++++++++++ + hw/vnc/rre.c | 323 ++++ + hw/vnc/sockets.c | 654 +++++++++ + hw/vnc/sprite.c | 2491 ++++++++++++++++++++++++++++++++++ + hw/vnc/sprite.h | 141 ++ + hw/vnc/spritest.h | 138 ++ + hw/vnc/stats.c | 113 ++ + hw/vnc/tableinitcmtemplate.c | 89 + + hw/vnc/tableinittctemplate.c | 142 ++ + hw/vnc/tabletranstemplate.c | 119 ++ + hw/vnc/tight.c | 1824 +++++++++++++++++++++++++ + hw/vnc/translate.c | 496 +++++++ + hw/vnc/vncauth.h | 33 + hw/vnc/vncext.c | 794 +++++++++++ + hw/vnc/xistubs.c | 319 ++++ + hw/vnc/zlib.c | 309 ++++ + hw/xfree86/Makefile.am | 8 + hw/xfree86/common/xf86.h | 4 + hw/xfree86/dixmods/Makefile.am | 9 + hw/xfree86/vnc/Makefile.am | 45 + + hw/xfree86/vnc/README | 1 + hw/xfree86/vnc/auth.c | 563 ++++++++ + hw/xfree86/vnc/cmap.c | 163 ++ + hw/xfree86/vnc/corre.c | 355 +++++ + hw/xfree86/vnc/cursor.c | 405 ++++++ + hw/xfree86/vnc/cutpaste.c | 87 + + hw/xfree86/vnc/draw.c | 2108 +++++++++++++++++++++++++++++ + hw/xfree86/vnc/hextile.c | 352 +++++ + hw/xfree86/vnc/httpd.c | 520 +++++++ + hw/xfree86/vnc/kbdptr.c | 426 ++++++ + hw/xfree86/vnc/keyboard.h | 167 ++ + hw/xfree86/vnc/loginauth.c | 141 ++ + hw/xfree86/vnc/rfb.h | 726 ++++++++++ + hw/xfree86/vnc/rfbkeyb.c | 410 ++++++ + hw/xfree86/vnc/rfbmouse.c | 240 +++ + hw/xfree86/vnc/rfbproto.h | 1347 ++++++++++++++++++ + hw/xfree86/vnc/rfbserver.c | 2278 +++++++++++++++++++++++++++++++ + hw/xfree86/vnc/rre.c | 325 ++++ + hw/xfree86/vnc/sockets.c | 656 +++++++++ + hw/xfree86/vnc/sprite.h | 141 ++ + hw/xfree86/vnc/stats.c | 113 ++ + hw/xfree86/vnc/tableinitcmtemplate.c | 89 + + hw/xfree86/vnc/tableinittctemplate.c | 142 ++ + hw/xfree86/vnc/tabletranstemplate.c | 119 ++ + hw/xfree86/vnc/tight.c | 1831 +++++++++++++++++++++++++ + hw/xfree86/vnc/translate.c | 497 +++++++ + hw/xfree86/vnc/vncInit.c | 640 +++++++++ + hw/xfree86/vnc/vncauth.h | 34 + hw/xfree86/vnc/vncext.c | 791 +++++++++++ + hw/xfree86/vnc/vncint.h | 155 ++ + hw/xfree86/vnc/zlib.c | 306 ++++ + mi/mieq.c | 4 + mi/miinitext.c | 12 + xcliplist/Makefile.am | 18 + xcliplist/cliplist.c | 128 ++ + xcliplist/cliplistmod.c | 46 + + 128 files changed, 58163 insertions(+), 7 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 08a17f5..d75fb9d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -34,6 +34,10 @@ if DBE + DBE_DIR=dbe + endif + ++if XCLIPLIST ++XCLIPLIST_DIR=xcliplist ++endif ++ + SUBDIRS = \ + doc \ + include \ +@@ -58,6 +62,7 @@ SUBDIRS = \ + $(XTRAP_DIR) \ + $(COMPOSITE_DIR) \ + $(GLX_DIR) \ ++ $(XCLIPLIST_DIR) \ + exa \ + hw + +diff --git a/configure.ac b/configure.ac +index 4915cdb..1d03481 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -431,7 +431,13 @@ AC_ARG_ENABLE(xinput, AS_HELP_ST + + dnl DDXes. + AC_ARG_ENABLE(xorg, AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto]) ++AC_ARG_ENABLE(xorg_vnc, AS_HELP_STRING([--enable-xorg-vnc], [Build vnc module for Xorg (default: no)]), [XORG_VNC=$enableval], [XORG_VNC=no]) + AC_ARG_ENABLE(dmx, AS_HELP_STRING([--enable-dmx], [Build DMX server (default: auto)]), [DMX=$enableval], [DMX=auto]) ++AC_ARG_ENABLE(xdmx_vnc, AS_HELP_STRING([--enable-xdmx-vnc], [Enable VNC support for Xdmx (default: no)]), [XDMX_VNC=$enableval], [XDMX_VNC=no]) ++ ++AC_ARG_ENABLE(xcliplist, AS_HELP_STRING([--enable-xcliplist], [Build XClipList extension (default: auto)]), [XCLIPLIST=$enableval], [XCLIPLIST=auto]) ++AC_ARG_ENABLE(xvnc, AS_HELP_STRING([--enable-xvnc], [Build Xvnc server (default: no)]), [XVNC=$enableval], [XVNC=no]) ++ + AC_ARG_ENABLE(xvfb, AS_HELP_STRING([--enable-xvfb], [Build Xvfb server (default: yes)]), [XVFB=$enableval], [XVFB=yes]) + AC_ARG_ENABLE(xnest, AS_HELP_STRING([--enable-xnest], [Build Xnest server (default: auto)]), [XNEST=$enableval], [XNEST=auto]) + AC_ARG_ENABLE(xwin, AS_HELP_STRING([--enable-xwin], [Build XWin server (default: auto)]), [XWIN=$enableval], [XWIN=auto]) +@@ -764,6 +770,20 @@ if test "x$XINPUT" = xyes; then + XI_INC='-I$(top_srcdir)/Xi' + fi + ++if test "x$XCLIPLIST" = xauto; then ++ if test "x$XORG" = xno; then ++ XCLIPLIST=no ++ else ++ PKG_CHECK_MODULES([XCLIPLIST], [xcliplistproto xcliplist], [XCLIPLIST=yes], [XCLIPLIST=no]) ++ fi ++fi ++AM_CONDITIONAL(XCLIPLIST, [test "x$XCLIPLIST" = xyes]) ++if test "x$XCLIPLIST" = xyes; then ++ AC_DEFINE(XCLIPLIST, 1, [Support XClipList extension]) ++ REQUIRED_MODULES="$REQUIRED_MODULES xcliplistproto" ++ XCLIPLIST_LIB='$(top_builddir)/xcliplist/libxcliplist.la' ++fi ++ + AM_CONDITIONAL(XF86UTILS, test "x$XF86UTILS" = xyes) + + AC_DEFINE(SHAPE, 1, [Support SHAPE extension]) +@@ -877,6 +897,8 @@ MI_EXT_LIB='$(top_builddir)/mi/libmiext. + MI_INC='-I$(top_srcdir)/mi' + FB_LIB='$(top_builddir)/fb/libfb.la' + FB_INC='-I$(top_srcdir)/fb' ++MFB_LIB='$(top_builddir)/mfb/libmfb.la' ++MFB_INC='-I$(top_srcdir)/mfb' + MIEXT_SHADOW_INC='-I$(top_srcdir)/miext/shadow' + MIEXT_SHADOW_LIB='$(top_builddir)/miext/shadow/libshadow.la' + XPSTUBS_LIB='$(top_builddir)/dix/libxpstubs.la' +@@ -995,6 +1023,72 @@ AM_CONDITIONAL([DMX_BUILD_LNX], [test "x + AM_CONDITIONAL([DMX_BUILD_USB], [test "x$DMX_BUILD_USB" = xyes]) + + ++ ++dnl VNC DDX ++ ++AC_MSG_CHECKING([whether to build Xvnc DDX]) ++PKG_CHECK_MODULES([VNCMODULES], [xmuu xext x11 xrender xfont xi vncproto xau $XDMCP_MODULES], [have_vnc=yes], [have_vnc=no]) ++if test "x$XVNC" = xauto; then ++ XVNC="$have_vnc" ++fi ++AC_MSG_RESULT([$XVNC]) ++AM_CONDITIONAL(XVNC, [test "x$XVNC" = xyes]) ++ ++if test "x$XVNC" = xyes; then ++ if test "x$have_vnc" = xno; then ++ AC_MSG_ERROR([Xvnc build explicitly requested, but required ++ modules not found.]) ++ fi ++ XVNC_CFLAGS="-DVNCSERVER -DHAVE_XVNC_CONFIG_H" ++ AC_SUBST([XVNC_CFLAGS]) ++ VNC_INCLUDES="$XEXT_INC $RENDER_INC $XTRAP_INC $RECORD_INC" ++ XVNC_LIBS="$GLX_LIBS $MFB_LIB $FB_LIB $MI_LIB $XEXT_LIB $RENDER_LIB $XTRAP_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $OS_LIB $CWRAP_LIB" ++ AC_SUBST([XVNC_LIBS]) ++ ++ if test "x$GLX" = xyes; then ++ PKG_CHECK_MODULES([GL], [glproto]) ++ fi ++ PKG_CHECK_MODULES([XVNCCONFIG_DEP], [xaw7 xmu xt xpm x11]) ++ AC_SUBST(XVNCCONFIG_DEP_CFLAGS) ++ AC_SUBST(XVNCCONFIG_DEP_LIBS) ++fi ++ ++ ++dnl Xorg VNC module ++ ++AC_MSG_CHECKING([whether to build Xorg VNC module]) ++ ++if test "x$XORG_VNC" = xauto; then ++ XORG_VNC="$have_vnc" ++fi ++AC_MSG_RESULT([$XORG_VNC]) ++AM_CONDITIONAL(XORG_VNC, [test "x$XORG_VNC" = xyes]) ++ ++if test "x$XORG_VNC" = xyes; then ++ if test "x$have_vnc" = xno; then ++ AC_MSG_ERROR([VNC module build explicitly requested, but required ++ modules not found.]) ++ fi ++fi ++ ++ ++dnl VNC support for Xdmx ++AC_MSG_CHECKING([whether to build Xdmx VNC support]) ++ ++if test "x$XDMX_VNC" = xauto; then ++ XDMX_VNC="$have_vnc" ++fi ++AC_MSG_RESULT([$XDMX_VNC]) ++AM_CONDITIONAL(XDMX_VNC, [test "x$XDMX_VNC" = xyes]) ++ ++if test "x$XDMX_VNC" = xyes; then ++ if test "x$have_vnc" = xno; then ++ AC_MSG_ERROR([VNC support for Xdmx explicitly requested, but required ++ modules not found.]) ++ fi ++fi ++ ++ + dnl Xvfb DDX + + AC_MSG_CHECKING([whether to build Xvfb DDX]) +@@ -1370,7 +1463,7 @@ AM_CONDITIONAL([LINUX_ALPHA], [test "x$l + AM_CONDITIONAL([LNXACPI], [test "x$linux_acpi" = xyes]) + AM_CONDITIONAL([SOLARIS_USL_CONSOLE], [test "x$solaris_usl_console" = xyes]) + AM_CONDITIONAL([SOLARIS_ASM_INLINE], [test "x$solaris_asm_inline" = xyes]) +-AM_CONDITIONAL(MFB, [test "x$XORG" = xyes]) ++AM_CONDITIONAL(MFB, [test "x$XORG" = xyes || test "x$XVNC" = xyes]) + AM_CONDITIONAL(CFB, [test "x$XORG" = xyes]) + AM_CONDITIONAL(AFB, [test "x$XORG" = xyes]) + +@@ -1737,6 +1830,7 @@ Xext/Makefile + Xi/Makefile + xfixes/Makefile + exa/Makefile ++xcliplist/Makefile + hw/Makefile + hw/xfree86/Makefile + hw/xfree86/common/Makefile +@@ -1773,6 +1867,7 @@ hw/xfree86/scanpci/Makefile + hw/xfree86/shadowfb/Makefile + hw/xfree86/vbe/Makefile + hw/xfree86/vgahw/Makefile ++hw/xfree86/vnc/Makefile + hw/xfree86/x86emu/Makefile + hw/xfree86/xaa/Makefile + hw/xfree86/xf1bpp/Makefile +@@ -1793,8 +1888,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/fb/fbcmap.c b/fb/fbcmap.c +index 762c51c..a289d22 100644 +--- a/fb/fbcmap.c ++++ b/fb/fbcmap.c +@@ -39,7 +39,7 @@ #include "colormapst.h" + #include "resource.h" + #include "fb.h" + +-#ifndef XFree86Server ++#if !defined(XFree86Server) && !defined(VNCSERVER) + ColormapPtr FbInstalledMaps[MAXSCREENS]; + + int +diff --git a/hw/Makefile.am b/hw/Makefile.am +index 4c35a58..bc50e4f 100644 +--- a/hw/Makefile.am ++++ b/hw/Makefile.am +@@ -30,6 +30,10 @@ if KDRIVE + XPRINT_SUBDIRS = xprint + endif + ++if XVNC ++VNC_SUBDIRS = vnc ++endif ++ + # need to add darwin support here + + SUBDIRS = \ +@@ -40,9 +44,10 @@ SUBDIRS = \ + $(XNEST_SUBDIRS) \ + $(DMX_SUBDIRS) \ + $(KDRIVE_SUBDIRS) \ ++ $(VNC_SUBDIRS) \ + $(XPRINT_SUBDIRS) + +-DIST_SUBDIRS = dmx xfree86 vfb xnest xwin darwin kdrive xgl xprint ++DIST_SUBDIRS = dmx xfree86 vfb xnest xwin darwin kdrive xgl xprint vnc + + relink: + for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink ; done +diff --git a/hw/dmx/Makefile.am b/hw/dmx/Makefile.am +index 93abd7a..05740a2 100644 +--- a/hw/dmx/Makefile.am ++++ b/hw/dmx/Makefile.am +@@ -1,6 +1,9 @@ +-DIST_SUBDIRS = input config glxProxy examples doc ++DIST_SUBDIRS = input vnc config glxProxy examples doc + +-SUBDIRS = input config examples ++if XDMX_VNC ++DMXVNC_SUBDIR = vnc ++endif ++SUBDIRS = input $(DMXVNC_SUBDIR) config examples + bin_PROGRAMS = Xdmx + + if XINERAMA +@@ -92,6 +95,13 @@ Xdmx_CFLAGS = @SERVER_DEFINES@ \ + $(DMX_CFLAGS) \ + @DMXMODULES_CFLAGS@ + ++if XDMX_VNC ++Xdmx_LDADD += vnc/libdmxvnc.a \ ++ -ljpeg -lcrypt ++Xdmx_CFLAGS += $(DIX_CFLAGS) \ ++ -DDMXVNC=1 ++endif ++ + # Man page + appmandir = $(APP_MAN_DIR) + +diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c +index ddc4d2b..da926f4 100644 +--- a/hw/dmx/dmxinit.c ++++ b/hw/dmx/dmxinit.c +@@ -78,6 +78,10 @@ #endif /* GLXEXT */ + ); + #endif /* GLXEXT */ + ++#ifdef DMXVNC ++extern void VNCInit2(void); ++#endif ++ + /* Global variables available to all Xserver/hw/dmx routines. */ + int dmxNumScreens; + DMXScreenInfo *dmxScreens; +@@ -813,6 +817,9 @@ #endif + + dmxLog(dmxInfo, "Shadow framebuffer support %s\n", + dmxShadowFB ? "enabled" : "disabled"); ++#ifdef DMXVNC ++ VNCInit2(); ++#endif + } + + /* RATS: Assuming the fp string (which comes from the command-line argv +diff --git a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c +index 02e2446..10ca40d 100644 +--- a/hw/dmx/dmxsync.c ++++ b/hw/dmx/dmxsync.c +@@ -103,6 +103,10 @@ static void dmxSyncBlockHandler(pointer + static void dmxSyncWakeupHandler(pointer blockData, int result, + pointer pReadMask) + { ++#ifdef DMXVNC ++ extern void rfbWakeupHandler2(void); ++ rfbWakeupHandler2(); ++#endif + } + + /** Request the XSync() batching optimization with the specified \a +diff --git a/hw/dmx/input/Makefile.am b/hw/dmx/input/Makefile.am +index d37c2a9..a12b35f 100644 +--- a/hw/dmx/input/Makefile.am ++++ b/hw/dmx/input/Makefile.am +@@ -68,4 +68,8 @@ AM_CFLAGS = @SERVER_DEFINES@ \ + $(GLX_DEFS) \ + @DMXMODULES_CFLAGS@ + ++if XDMX_VNC ++AM_CFLAGS += -DDMXVNC=1 ++endif ++ + EXTRA_DIST = dmxdetach.c +diff --git a/hw/dmx/input/dmxinputinit.c b/hw/dmx/input/dmxinputinit.c +index c81eb84..bca5bcc 100644 +--- a/hw/dmx/input/dmxinputinit.c ++++ b/hw/dmx/input/dmxinputinit.c +@@ -342,6 +342,13 @@ #else + DevicePtr pDev = &pDevice->public; + #endif + ++#ifdef DMXVNC ++ { ++ extern void vncSetKeyboardDevice(DeviceIntPtr kbd); ++ vncSetKeyboardDevice(pDevice); ++ } ++#endif ++ + #ifdef XKB + if (noXkbExtension) { + #endif +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/auth.c b/hw/dmx/vnc/auth.c +new file mode 100644 +index 0000000..06b6b51 +--- /dev/null ++++ b/hw/dmx/vnc/auth.c +@@ -0,0 +1,562 @@ ++/* ++ * auth.c - deal with authentication. ++ * ++ * This file implements authentication when setting up an RFB connection. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2003-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "rfb.h" ++#include "windowstr.h" ++ ++static void rfbSendSecurityType(rfbClientPtr cl, int securityType); ++static void rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType); ++static void rfbSendTunnelingCaps(rfbClientPtr cl); ++static void rfbSendAuthCaps(rfbClientPtr cl); ++static void rfbVncAuthSendChallenge(rfbClientPtr cl); ++ ++/* ++ * rfbAuthNewClient is called right after negotiating the protocol ++ * version. Depending on the protocol version, we send either a code ++ * for authentication scheme to be used (protocol 3.3), or a list of ++ * possible "security types" (protocol 3.7). ++ */ ++ ++void ++rfbAuthNewClient(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int securityType = rfbSecTypeInvalid; ++ ++ if ((!pVNC->rfbAuthPasswdFile && !pVNC->loginAuthEnabled) || cl->reverseConnection) { ++ securityType = rfbSecTypeNone; ++ } else { ++ if (rfbAuthIsBlocked(cl)) { ++ rfbLog("Too many authentication failures - client rejected\n"); ++ rfbClientConnFailed(cl, "Too many authentication failures"); ++ return; ++ } ++ if (pVNC->rfbAuthPasswdFile) ++ securityType = rfbSecTypeVncAuth; ++ } ++ ++ if (cl->protocol_minor_ver < 7) { ++ /* Make sure we use only RFB 3.3 compatible security types. */ ++ if (securityType == rfbSecTypeInvalid) { ++ rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n"); ++ rfbClientConnFailed(cl, "Your viewer cannot handle required " ++ "authentication methods"); ++ return; ++ } ++ rfbSendSecurityType(cl, securityType); ++ } else { ++ /* Here it's ok when securityType is set to rfbSecTypeInvalid. */ ++ rfbSendSecurityTypeList(cl, securityType); ++ } ++} ++ ++ ++/* ++ * Tell the client what security type will be used (protocol 3.3). ++ */ ++ ++static void ++rfbSendSecurityType(cl, securityType) ++ rfbClientPtr cl; ++ int securityType; ++{ ++ CARD32 value32; ++ ++ /* Send the value. */ ++ value32 = Swap32IfLE(securityType); ++ if (WriteExact(cl->sock, (char *)&value32, 4) < 0) { ++ rfbLogPerror("rfbSendSecurityType: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Decide what to do next. */ ++ switch (securityType) { ++ case rfbSecTypeNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbSecTypeVncAuth: ++ /* Begin the standard VNC authentication procedure. */ ++ rfbVncAuthSendChallenge(cl); ++ break; ++ default: ++ /* Impossible case (hopefully). */ ++ rfbLogPerror("rfbSendSecurityType: assertion failed"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Advertise our supported security types (protocol 3.7). The list ++ * will include one standard security type (if primaryType is not set ++ * to rfbSecTypeInvalid), and then one more value telling the client ++ * that we support TightVNC protocol extensions. Thus, currently, ++ * there will be either 1 or 2 items in the list. ++ */ ++ ++static void ++rfbSendSecurityTypeList(cl, primaryType) ++ rfbClientPtr cl; ++ int primaryType; ++{ ++ int count = 1; ++ ++ /* Fill in the list of security types in the client structure. */ ++ if (primaryType != rfbSecTypeInvalid) { ++ cl->securityTypes[count++] = (CARD8)primaryType; ++ } ++ cl->securityTypes[count] = (CARD8)rfbSecTypeTight; ++ cl->securityTypes[0] = (CARD8)count++; ++ ++ /* Send the list. */ ++ if (WriteExact(cl->sock, (char *)cl->securityTypes, count) < 0) { ++ rfbLogPerror("rfbSendSecurityTypeList: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientSecurityType. */ ++ cl->state = RFB_SECURITY_TYPE; ++} ++ ++ ++/* ++ * Read the security type chosen by the client (protocol 3.7). ++ */ ++ ++void ++rfbProcessClientSecurityType(cl) ++ rfbClientPtr cl; ++{ ++ int n, count, i; ++ CARD8 chosenType; ++ ++ /* Read the security type. */ ++ n = ReadExact(cl->sock, (char *)&chosenType, 1); ++ if (n <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientSecurityType: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientSecurityType: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Make sure it was present in the list sent by the server. */ ++ count = (int)cl->securityTypes[0]; ++ for (i = 1; i <= count; i++) { ++ if (chosenType == cl->securityTypes[i]) ++ break; ++ } ++ if (i > count) { ++ rfbLog("rfbProcessClientSecurityType: " ++ "wrong security type requested\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Now go to the proper authentication procedure. */ ++ switch (chosenType) { ++ case rfbSecTypeNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbSecTypeVncAuth: ++ /* Begin the standard VNC authentication procedure. */ ++ rfbVncAuthSendChallenge(cl); ++ break; ++ case rfbSecTypeTight: ++ /* We are lucky: the viewer supports TightVNC extensions. */ ++ rfbLog("Enabling TightVNC protocol extensions\n"); ++ /* Switch to the protocol 3.7t. */ ++ cl->protocol_tightvnc = TRUE; ++ /* Advertise our tunneling capabilities. */ ++ rfbSendTunnelingCaps(cl); ++ break; ++ default: ++ /* Impossible case (hopefully). */ ++ rfbLog("rfbProcessClientSecurityType: " ++ "unknown authentication scheme\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Send the list of our tunneling capabilities (protocol 3.7t). ++ */ ++ ++static void ++rfbSendTunnelingCaps(cl) ++ rfbClientPtr cl; ++{ ++ rfbTunnelingCapsMsg caps; ++ CARD32 nTypes = 0; /* we don't support tunneling yet */ ++ ++ caps.nTunnelTypes = Swap32IfLE(nTypes); ++ if (WriteExact(cl->sock, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) { ++ rfbLogPerror("rfbSendTunnelingCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (nTypes) { ++ /* Dispatch client input to rfbProcessClientTunnelingType(). */ ++ cl->state = RFB_TUNNELING_TYPE; ++ } else { ++ rfbSendAuthCaps(cl); ++ } ++} ++ ++ ++/* ++ * Read tunneling type requested by the client (protocol 3.7t). ++ * NOTE: Currently, we don't support tunneling, and this function ++ * can never be called. ++ */ ++ ++void ++rfbProcessClientTunnelingType(cl) ++ rfbClientPtr cl; ++{ ++ /* If we were called, then something's really wrong. */ ++ rfbLog("rfbProcessClientTunnelingType: not implemented\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++} ++ ++ ++/* ++ * Send the list of our authentication capabilities to the client ++ * (protocol 3.7t). ++ */ ++ ++static void ++rfbSendAuthCaps(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ Bool authRequired; ++ rfbAuthenticationCapsMsg caps; ++ rfbCapabilityInfo caplist[MAX_AUTH_CAPS]; ++ int count = 0; ++ ++ authRequired = ((pVNC->rfbAuthPasswdFile != NULL || pVNC->loginAuthEnabled) && ++ !cl->reverseConnection); ++ ++ if (authRequired) { ++ if (pVNC->loginAuthEnabled) { ++ SetCapInfo(&caplist[count], rfbAuthUnixLogin, rfbTightVncVendor); ++ cl->authCaps[count++] = rfbAuthUnixLogin; ++ } ++ if (pVNC->rfbAuthPasswdFile != NULL) { ++ SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor); ++ cl->authCaps[count++] = rfbAuthVNC; ++ } ++ if (count == 0) { ++ /* Should never happen. */ ++ rfbLog("rfbSendAuthCaps: assertion failed\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ ++ cl->nAuthCaps = count; ++ caps.nAuthTypes = Swap32IfLE((CARD32)count); ++ if (WriteExact(cl->sock, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) { ++ rfbLogPerror("rfbSendAuthCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (count) { ++ if (WriteExact(cl->sock, (char *)&caplist[0], ++ count * sz_rfbCapabilityInfo) < 0) { ++ rfbLogPerror("rfbSendAuthCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ /* Dispatch client input to rfbProcessClientAuthType. */ ++ cl->state = RFB_AUTH_TYPE; ++ } else { ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ } ++} ++ ++ ++/* ++ * Read client's preferred authentication type (protocol 3.7t). ++ */ ++ ++void ++rfbProcessClientAuthType(cl) ++ rfbClientPtr cl; ++{ ++ CARD32 auth_type; ++ int n, i; ++ ++ /* Read authentication type selected by the client. */ ++ n = ReadExact(cl->sock, (char *)&auth_type, sizeof(auth_type)); ++ if (n <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientAuthType: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientAuthType: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ auth_type = Swap32IfLE(auth_type); ++ ++ /* Make sure it was present in the list sent by the server. */ ++ for (i = 0; i < cl->nAuthCaps; i++) { ++ if (auth_type == cl->authCaps[i]) ++ break; ++ } ++ if (i >= cl->nAuthCaps) { ++ rfbLog("rfbProcessClientAuthType: " ++ "wrong authentication type requested\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ switch (auth_type) { ++ case rfbAuthNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbAuthVNC: ++ rfbVncAuthSendChallenge(cl); ++ break; ++ case rfbAuthUnixLogin: ++ /* FIXME: Do (cl->state = RFB_LOGIN_AUTH) instead? */ ++ rfbLoginAuthProcessClientMessage(cl); ++ break; ++ default: ++ rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Send the authentication challenge. ++ */ ++ ++static void ++rfbVncAuthSendChallenge(cl) ++ rfbClientPtr cl; ++{ ++ vncRandomBytes(cl->authChallenge); ++ if (WriteExact(cl->sock, (char *)cl->authChallenge, CHALLENGESIZE) < 0) { ++ rfbLogPerror("rfbVncAuthSendChallenge: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbVncAuthProcessResponse. */ ++ cl->state = RFB_AUTHENTICATION; ++} ++ ++/* ++ * rfbVncAuthProcessResponse is called when the client sends its ++ * authentication response. ++ */ ++ ++void ++rfbVncAuthProcessResponse(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ char passwdFullControl[9]; ++ char passwdViewOnly[9]; ++ int numPasswords; ++ Bool ok; ++ int n; ++ CARD8 encryptedChallenge1[CHALLENGESIZE]; ++ CARD8 encryptedChallenge2[CHALLENGESIZE]; ++ CARD8 response[CHALLENGESIZE]; ++ CARD32 authResult; ++ ++ n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE); ++ if (n <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbVncAuthProcessResponse: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ numPasswords = vncDecryptPasswdFromFile2(pVNC->rfbAuthPasswdFile, ++ passwdFullControl, ++ passwdViewOnly); ++ if (numPasswords == 0) { ++ rfbLog("rfbVncAuthProcessResponse: could not get password from %s\n", ++ pVNC->rfbAuthPasswdFile); ++ ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ memcpy(encryptedChallenge1, cl->authChallenge, CHALLENGESIZE); ++ vncEncryptBytes(encryptedChallenge1, passwdFullControl); ++ memcpy(encryptedChallenge2, cl->authChallenge, CHALLENGESIZE); ++ vncEncryptBytes(encryptedChallenge2, ++ (numPasswords == 2) ? passwdViewOnly : passwdFullControl); ++ ++ /* Lose the passwords from memory */ ++ memset(passwdFullControl, 0, 9); ++ memset(passwdViewOnly, 0, 9); ++ ++ ok = FALSE; ++ if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) { ++ rfbLog("Full-control authentication passed by %s\n", cl->host); ++ ok = TRUE; ++ cl->viewOnly = FALSE; ++ } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) { ++ rfbLog("View-only authentication passed by %s\n", cl->host); ++ ok = TRUE; ++ cl->viewOnly = TRUE; ++ } ++ ++ if (!ok) { ++ rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n", ++ cl->host); ++ ++ if (rfbAuthConsiderBlocking(cl)) { ++ authResult = Swap32IfLE(rfbVncAuthTooMany); ++ } else { ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ } ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ rfbAuthUnblock(cl); ++ ++ authResult = Swap32IfLE(rfbVncAuthOK); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientInitMessage(). */ ++ cl->state = RFB_INITIALISATION; ++} ++ ++ ++/* ++ * Functions to prevent too many successive authentication failures. ++ * FIXME: This should be performed separately per each client IP. ++ */ ++ ++/* Maximum authentication failures before blocking connections */ ++#define MAX_AUTH_TRIES 5 ++ ++/* Delay in ms, doubles for each failure over MAX_AUTH_TRIES */ ++#define AUTH_TOO_MANY_BASE_DELAY 10 * 1000 ++ ++/* ++ * This function should not be called directly, it is called by ++ * setting a timer in rfbAuthConsiderBlocking(). ++ */ ++ ++static CARD32 ++rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg) ++{ ++ rfbClientPtr cl = (rfbClientPtr) arg; ++ VNCSCREENPTR(cl->pScreen); ++ pVNC->rfbAuthTooManyTries = FALSE; ++ return 0; ++} ++ ++/* ++ * This function should be called after each authentication failure. ++ * The return value will be true if there was too many failures. ++ */ ++ ++Bool ++rfbAuthConsiderBlocking(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int i; ++ ++ pVNC->rfbAuthTries++; ++ ++ if (pVNC->rfbAuthTries >= MAX_AUTH_TRIES) { ++ CARD32 delay = AUTH_TOO_MANY_BASE_DELAY; ++ for (i = MAX_AUTH_TRIES; i < pVNC->rfbAuthTries; i++) ++ delay *= 2; ++ pVNC->timer = TimerSet(pVNC->timer, 0, delay, rfbAuthReenable, NULL); ++ pVNC->rfbAuthTooManyTries = TRUE; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function should be called after successful authentication. ++ * It resets the counter of authentication failures. Note that it's ++ * not necessary to clear the rfbAuthTooManyTries flag as it will be ++ * reset by the timer function. ++ */ ++ ++void ++rfbAuthUnblock(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ pVNC->rfbAuthTries = 0; ++} ++ ++/* ++ * This function should be called before authentication process. ++ * The return value will be true if there was too many authentication ++ * failures, and the server should not allow another try. ++ */ ++ ++Bool ++rfbAuthIsBlocked(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ return pVNC->rfbAuthTooManyTries; ++} ++ +diff --git a/hw/dmx/vnc/cmap.c b/hw/dmx/vnc/cmap.c +new file mode 100644 +index 0000000..88aad12 +--- /dev/null ++++ b/hw/dmx/vnc/cmap.c +@@ -0,0 +1,163 @@ ++/* ++ * cmap.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1993 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR ++OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall ++not be used in advertising or otherwise to promote the sale, use or ++other dealings in this Software without prior written authorization ++from the X Consortium. ++ ++*/ ++ ++#include "rfb.h" ++ ++int ++rfbListInstalledColormaps(pScreen, pmaps) ++ ScreenPtr pScreen; ++ Colormap *pmaps; ++{ ++ VNCSCREENPTR(pScreen); ++ /* By the time we are processing requests, we can guarantee that there ++ * is always a colormap installed */ ++ if (pVNC->rfbInstalledColormap) ++ *pmaps = pVNC->rfbInstalledColormap->mid; ++ ++#if XFREE86VNC ++ pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps; ++ (*pScreen->ListInstalledColormaps)(pScreen, pmaps); ++ pScreen->ListInstalledColormaps = rfbListInstalledColormaps; ++#endif ++ ++ return (1); ++} ++ ++ ++void ++rfbInstallColormap(pmap) ++ ColormapPtr pmap; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ ++ if (pmap != pVNC->rfbInstalledColormap) { ++ ++ if(pVNC->rfbInstalledColormap != (ColormapPtr)None) ++ WalkTree(pmap->pScreen, TellLostMap, ++ (char *)&pVNC->rfbInstalledColormap->mid); ++ /* Install pmap */ ++ pVNC->rfbInstalledColormap = pmap; ++ WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); ++ ++ rfbSetClientColourMaps(0, 0); ++ } ++#if XFREE86VNC ++ pmap->pScreen->InstallColormap = pVNC->InstallColormap; ++ (*pmap->pScreen->InstallColormap)(pmap); ++ pmap->pScreen->InstallColormap = rfbInstallColormap; ++#endif ++} ++ ++void ++rfbUninstallColormap(pmap) ++ ColormapPtr pmap; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ ++ if(pmap == pVNC->rfbInstalledColormap) ++ { ++ if (pmap->mid != pmap->pScreen->defColormap) ++ { ++ pVNC->rfbInstalledColormap = ++ (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, ++ RT_COLORMAP); ++ (*pmap->pScreen->InstallColormap)(pVNC->rfbInstalledColormap); ++ } ++ } ++#if XFREE86VNC ++ pmap->pScreen->UninstallColormap = pVNC->UninstallColormap; ++ (*pmap->pScreen->UninstallColormap)(pmap); ++ pmap->pScreen->UninstallColormap = rfbUninstallColormap; ++#endif ++} ++ ++ ++/* ++ * rfbStoreColors. We have a set of pixels but they may be in any order. ++ * If some of them happen to be in continuous ascending order then we can ++ * group them together into a single call to rfbSetClientColourMaps. ++ */ ++ ++void ++rfbStoreColors(pmap, ndef, pdefs) ++ ColormapPtr pmap; ++ int ndef; ++ xColorItem *pdefs; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ int i; ++ int first = -1; ++ int n = 0; ++ ++ if (pmap == pVNC->rfbInstalledColormap) { ++ for (i = 0; i < ndef; i++) { ++ if ((first != -1) && (first + n == pdefs[i].pixel)) { ++ n++; ++ } else { ++ if (first != -1) { ++ rfbSetClientColourMaps(first, n); ++ } ++ first = pdefs[i].pixel; ++ n = 1; ++ } ++ } ++ rfbSetClientColourMaps(first, n); ++ } ++#if XFREE86VNC ++ pmap->pScreen->StoreColors = pVNC->StoreColors; ++ (*pmap->pScreen->StoreColors)(pmap, ndef, pdefs); ++ pmap->pScreen->StoreColors = rfbStoreColors; ++#endif ++} +diff --git a/hw/dmx/vnc/corre.c b/hw/dmx/vnc/corre.c +new file mode 100644 +index 0000000..ec1c917 +--- /dev/null ++++ b/hw/dmx/vnc/corre.c +@@ -0,0 +1,355 @@ ++/* ++ * corre.c ++ * ++ * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This ++ * code is based on krw's original javatel rfbserver. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include "rfb.h" ++ ++/* ++ * rreBeforeBuf contains pixel data in the client's format. ++ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is ++ * larger than the raw data or if it exceeds rreAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int rreBeforeBufSize = 0; ++static char *rreBeforeBuf = NULL; ++ ++static int rreAfterBufSize = 0; ++static char *rreAfterBuf = NULL; ++static int rreAfterBufLen; ++ ++static int subrectEncode8(CARD8 *data, int w, int h); ++static int subrectEncode16(CARD16 *data, int w, int h); ++static int subrectEncode32(CARD32 *data, int w, int h); ++static CARD32 getBgColour(char *data, int size, int bpp); ++static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y, ++ int w, int h); ++ ++ ++/* ++ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE ++ * encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingCoRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ if (h > cl->correMaxHeight) { ++ return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) && ++ rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, ++ w, h - cl->correMaxHeight)); ++ } ++ ++ if (w > cl->correMaxWidth) { ++ return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) && ++ rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y, ++ w - cl->correMaxWidth, h)); ++ } ++ ++ return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h); ++} ++ ++ ++ ++/* ++ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256) ++ * rectangle using CoRRE encoding. ++ */ ++ ++static Bool ++rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbRREHeader hdr; ++ int nSubrects; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (rreBeforeBufSize < maxRawSize) { ++ rreBeforeBufSize = maxRawSize; ++ if (rreBeforeBuf == NULL) ++ rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); ++ else ++ rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); ++ } ++ ++ if (rreAfterBufSize < maxRawSize) { ++ rreAfterBufSize = maxRawSize; ++ if (rreAfterBuf == NULL) ++ rreAfterBuf = (char *)xalloc(rreAfterBufSize); ++ else ++ rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); ++ } ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, rreBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); ++ break; ++ case 16: ++ nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); ++ break; ++ case 32: ++ nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); ++ break; ++ default: ++ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); ++ exit(1); ++ } ++ ++ if (nSubrects < 0) { ++ ++ /* RRE encoding was too large, use raw */ ++ ++ return rfbSendRectEncodingRaw(cl, x, y, w, h); ++ } ++ ++ cl->rfbRectanglesSent[rfbEncodingCoRRE]++; ++ cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbRREHeader + rreAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingCoRRE); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nSubrects = Swap32IfLE(nSubrects); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader); ++ pVNC->ublen += sz_rfbRREHeader; ++ ++ for (i = 0; i < rreAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > rreAfterBufLen) { ++ bytesToCopy = rreAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * subrectEncode() encodes the given multicoloured rectangle as a background ++ * colour overwritten by single-coloured rectangles. It returns the number ++ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't ++ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The ++ * single-colour rectangle partition is not optimal, but does find the biggest ++ * horizontal or vertical rectangle top-left anchored to each consecutive ++ * coordinate position. ++ * ++ * The coding scheme is simply [...] where each ++ * is []. ++ */ ++ ++#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 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) { ++ 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/dmx/vnc/cursor.c b/hw/dmx/vnc/cursor.c +new file mode 100644 +index 0000000..caed042 +--- /dev/null ++++ b/hw/dmx/vnc/cursor.c +@@ -0,0 +1,401 @@ ++/* ++ * cursor.c - support for cursor shape updates. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include "rfb.h" ++#include "mipointer.h" ++#include "sprite.h" ++#include "cursorstr.h" ++#include "servermd.h" ++ ++ ++/* Copied from Xvnc/lib/font/util/utilbitmap.c */ ++static unsigned char _reverse_byte[0x100] = { ++ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, ++ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, ++ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, ++ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, ++ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, ++ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, ++ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, ++ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, ++ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, ++ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, ++ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, ++ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, ++ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, ++ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, ++ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, ++ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, ++ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, ++ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, ++ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, ++ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, ++ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, ++ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, ++ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, ++ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, ++ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, ++ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, ++ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, ++ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, ++ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, ++ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, ++ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, ++ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff ++}; ++ ++ ++static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++static int EncodeRichCursorData16 (ScreenPtr pScreen, ++ char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++static int EncodeRichCursorData32 (ScreenPtr pScreen, ++ char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++ ++ ++/* ++ * Send cursor shape either in X-style format or in client pixel format. ++ */ ++ ++Bool ++rfbSendCursorShape(cl, pScreen) ++ rfbClientPtr cl; ++ ScreenPtr pScreen; ++{ ++ VNCSCREENPTR(pScreen); ++ CursorPtr pCursor; ++ rfbFramebufferUpdateRectHeader rect; ++ rfbXCursorColors colors; ++ int saved_ublen; ++ int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes; ++ int i, j; ++ CARD8 *bitmapData; ++ CARD8 bitmapByte; ++ ++ if (cl->useRichCursorEncoding) { ++ rect.encoding = Swap32IfLE(rfbEncodingRichCursor); ++ } else { ++ rect.encoding = Swap32IfLE(rfbEncodingXCursor); ++ } ++ ++ pCursor = pVNC->pCurs; ++ ++ /* If there is no cursor, send update with empty cursor data. */ ++ ++ if ( pCursor != NULL && ++ pCursor->bits->width == 1 && ++ pCursor->bits->height == 1 && ++ pCursor->bits->mask[0] == 0 ) { ++ pCursor = NULL; ++ } ++ ++ if (pCursor == NULL) { ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ rect.r.x = rect.r.y = 0; ++ rect.r.w = rect.r.h = 0; ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ cl->rfbCursorShapeUpdatesSent++; ++ ++ return TRUE; ++ } ++ ++ /* Calculate data sizes. */ ++ ++ bitmapRowBytes = (pCursor->bits->width + 7) / 8; ++ paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1); ++ maskBytes = bitmapRowBytes * pCursor->bits->height; ++ dataBytes = (cl->useRichCursorEncoding) ? ++ (pCursor->bits->width * pCursor->bits->height * ++ (cl->format.bitsPerPixel / 8)) : maskBytes; ++ ++ /* Send buffer contents if needed. */ ++ ++ if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + ++ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + ++ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { ++ return FALSE; /* FIXME. */ ++ } ++ ++ saved_ublen = pVNC->ublen; ++ ++ /* Prepare rectangle header. */ ++ ++ rect.r.x = Swap16IfLE(pCursor->bits->xhot); ++ rect.r.y = Swap16IfLE(pCursor->bits->yhot); ++ rect.r.w = Swap16IfLE(pCursor->bits->width); ++ rect.r.h = Swap16IfLE(pCursor->bits->height); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ /* Prepare actual cursor data (depends on encoding used). */ ++ ++ if (!cl->useRichCursorEncoding) { ++ /* XCursor encoding. */ ++ colors.foreRed = (char)(pCursor->foreRed >> 8); ++ colors.foreGreen = (char)(pCursor->foreGreen >> 8); ++ colors.foreBlue = (char)(pCursor->foreBlue >> 8); ++ colors.backRed = (char)(pCursor->backRed >> 8); ++ colors.backGreen = (char)(pCursor->backGreen >> 8); ++ colors.backBlue = (char)(pCursor->backBlue >> 8); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&colors, sz_rfbXCursorColors); ++ pVNC->ublen += sz_rfbXCursorColors; ++ ++ bitmapData = (CARD8 *)pCursor->bits->source; ++ ++ for (i = 0; i < pCursor->bits->height; i++) { ++ for (j = 0; j < bitmapRowBytes; j++) { ++ bitmapByte = bitmapData[i * paddedRowBytes + j]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte; ++ } ++ } ++ } else { ++ /* RichCursor encoding. */ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ pVNC->ublen += EncodeRichCursorData8(&pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ case 16: ++ pVNC->ublen += EncodeRichCursorData16(pScreen, &pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ case 32: ++ pVNC->ublen += EncodeRichCursorData32(pScreen, &pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ default: ++ return FALSE; ++ } ++ } ++ ++ /* Prepare transparency mask. */ ++ ++ bitmapData = (CARD8 *)pCursor->bits->mask; ++ ++ for (i = 0; i < pCursor->bits->height; i++) { ++ for (j = 0; j < bitmapRowBytes; j++) { ++ bitmapByte = bitmapData[i * paddedRowBytes + j]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte; ++ } ++ } ++ ++ /* Update statistics. */ ++ ++ cl->rfbCursorShapeBytesSent += (pVNC->ublen - saved_ublen); ++ cl->rfbCursorShapeUpdatesSent++; ++ ++ return TRUE; ++} ++ ++/* ++ * Send cursor position (PointerPos pseudo-encoding). ++ */ ++Bool ++rfbSendCursorPos(cl, pScreen) ++ rfbClientPtr cl; ++ ScreenPtr pScreen; ++{ ++ VNCSCREENPTR(pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++#if XFREE86VNC ++ ScreenPtr pCursorScreen = miPointerCurrentScreen(); ++#endif ++ int x, y; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++#if XFREE86VNC ++ if (pScreen == pCursorScreen) ++ miPointerPosition(&x, &y); ++#else ++ rfbSpriteGetCursorPos(pScreen, &x, &y); ++#endif ++ ++ rect.encoding = Swap32IfLE(rfbEncodingPointerPos); ++ rect.r.x = Swap16IfLE((CARD16)x); ++ rect.r.y = Swap16IfLE((CARD16)y); ++ rect.r.w = 0; ++ rect.r.h = 0; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ cl->rfbCursorPosUpdatesSent++; ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ cl->cursorX = x; ++ cl->cursorY = y; ++ ++ return TRUE; ++} ++ ++/* ++ * Code to convert cursor source bitmap to the desired pixel format. ++ */ ++ ++#define RGB48_TO_PIXEL(fmt,r,g,b) \ ++ (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift | \ ++ ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift | \ ++ ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift) ++ ++static int ++EncodeRichCursorData8(buf, fmt, pCursor) ++ char *buf; ++ rfbPixelFormat *fmt; ++ CursorPtr pCursor; ++{ ++ int widthPixels, widthBytes; ++ int x, y, b; ++ CARD8 *src; ++ char pix[2]; ++ CARD8 bitmapByte; ++ ++ pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen, ++ pCursor->backBlue); ++ pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen, ++ pCursor->foreBlue); ++ ++ src = (CARD8 *)pCursor->bits->source; ++ widthPixels = pCursor->bits->width; ++ widthBytes = PixmapBytePad(widthPixels, 1); ++ ++ for (y = 0; y < pCursor->bits->height; y++) { ++ for (x = 0; x < widthPixels / 8; x++) { ++ bitmapByte = src[y * widthBytes + x]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ for (b = 7; b >= 0; b--) { ++ *buf++ = pix[bitmapByte >> b & 1]; ++ } ++ } ++ if (widthPixels % 8) { ++ bitmapByte = src[y * widthBytes + x]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ for (b = 7; b > 7 - widthPixels % 8; b--) { ++ *buf++ = pix[bitmapByte >> b & 1]; ++ } ++ } ++ } ++ ++ return (widthPixels * pCursor->bits->height); ++} ++ ++#define DEFINE_RICH_ENCODE(bpp) \ ++ \ ++static int \ ++EncodeRichCursorData##bpp(pScreen, buf, fmt, pCursor) \ ++ ScreenPtr pScreen; \ ++ char *buf; \ ++ rfbPixelFormat *fmt; \ ++ CursorPtr pCursor; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ int widthPixels, widthBytes; \ ++ int x, y, b; \ ++ CARD8 *src; \ ++ CARD##bpp pix[2]; \ ++ CARD8 bitmapByte; \ ++ \ ++ pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed, \ ++ pCursor->backGreen, \ ++ pCursor->backBlue); \ ++ pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed, \ ++ pCursor->foreGreen, \ ++ pCursor->foreBlue); \ ++ if (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian) { \ ++ pix[0] = Swap##bpp(pix[0]); \ ++ pix[1] = Swap##bpp(pix[1]); \ ++ } \ ++ \ ++ src = (CARD8 *)pCursor->bits->source; \ ++ widthPixels = pCursor->bits->width; \ ++ widthBytes = PixmapBytePad(widthPixels, 1); \ ++ \ ++ for (y = 0; y < pCursor->bits->height; y++) { \ ++ for (x = 0; x < widthPixels / 8; x++) { \ ++ bitmapByte = src[y * widthBytes + x]; \ ++ if (screenInfo.bitmapBitOrder == LSBFirst) { \ ++ bitmapByte = _reverse_byte[bitmapByte]; \ ++ } \ ++ for (b = 7; b >= 0; b--) { \ ++ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ ++ sizeof(CARD##bpp)); \ ++ buf += sizeof(CARD##bpp); \ ++ } \ ++ } \ ++ if (widthPixels % 8) { \ ++ bitmapByte = src[y * widthBytes + x]; \ ++ if (screenInfo.bitmapBitOrder == LSBFirst) { \ ++ bitmapByte = _reverse_byte[bitmapByte]; \ ++ } \ ++ for (b = 7; b > 7 - widthPixels % 8; b--) { \ ++ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ ++ sizeof(CARD##bpp)); \ ++ buf += sizeof(CARD##bpp); \ ++ } \ ++ } \ ++ } \ ++ \ ++ return (widthPixels * pCursor->bits->height * (bpp / 8)); \ ++} ++ ++DEFINE_RICH_ENCODE(16) ++DEFINE_RICH_ENCODE(32) ++ +diff --git a/hw/dmx/vnc/cutpaste.c b/hw/dmx/vnc/cutpaste.c +new file mode 100644 +index 0000000..13aebbb +--- /dev/null ++++ b/hw/dmx/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 ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#define NEED_EVENTS ++#include ++#include ++#include ++#include "rfb.h" ++#include "selection.h" ++#include "input.h" ++ ++extern Selection *CurrentSelections; ++extern int NumCurrentSelections; ++ ++ ++static Bool inSetXCutText = FALSE; ++ ++/* ++ * rfbSetXCutText sets the cut buffer to be the given string. We also clear ++ * the primary selection. Ideally we'd like to set it to the same thing, but I ++ * can't work out how to do that without some kind of helper X client. ++ */ ++ ++void ++rfbSetXCutText(char *str, int len) ++{ ++ int i = 0; ++ ++ inSetXCutText = TRUE; ++ ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING, ++ 8, PropModeReplace, len, ++ (pointer)str, TRUE); ++ ++ while ((i < NumCurrentSelections) && ++ CurrentSelections[i].selection != XA_PRIMARY) ++ i++; ++ ++ if (i < NumCurrentSelections) { ++ xEvent event; ++ ++ if (CurrentSelections[i].client) { ++ event.u.u.type = SelectionClear; ++ event.u.selectionClear.time = GetTimeInMillis(); ++ event.u.selectionClear.window = CurrentSelections[i].window; ++ event.u.selectionClear.atom = CurrentSelections[i].selection; ++ (void) TryClientEvents (CurrentSelections[i].client, &event, 1, ++ NoEventMask, NoEventMask /* CantBeFiltered */, ++ NullGrab); ++ } ++ ++ CurrentSelections[i].window = None; ++ CurrentSelections[i].pWin = NULL; ++ CurrentSelections[i].client = NullClient; ++ } ++ ++ inSetXCutText = FALSE; ++} ++ ++ ++void rfbGotXCutText(char *str, int len) ++{ ++ if (!inSetXCutText) ++ rfbSendServerCutText(str, len); ++} +diff --git a/hw/dmx/vnc/d3des.c b/hw/dmx/vnc/d3des.c +new file mode 100644 +index 0000000..8a358ce +--- /dev/null ++++ b/hw/dmx/vnc/d3des.c +@@ -0,0 +1,440 @@ ++/* ++ * This is D3DES (V5.09) by Richard Outerbridge with the double and ++ * triple-length support removed for use in VNC. Also the bytebit[] array ++ * has been reversed so that the most significant bit in each byte of the ++ * key is ignored, not the least significant. ++ * ++ * These changes are: ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++/* D3DES (V5.09) - ++ * ++ * A portable, public domain, version of the Data Encryption Standard. ++ * ++ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. ++ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation ++ * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis ++ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, ++ * for humouring me on. ++ * ++ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. ++ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. ++ */ ++ ++#include "d3des.h" ++ ++static void scrunch(unsigned char *, unsigned long *); ++static void unscrun(unsigned long *, unsigned char *); ++static void desfunc(unsigned long *, unsigned long *); ++static void cookey(unsigned long *); ++ ++static unsigned long KnL[32] = { 0L }; ++static unsigned long KnR[32] = { 0L }; ++static unsigned long Kn3[32] = { 0L }; ++static unsigned char Df_Key[24] = { ++ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, ++ 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, ++ 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 }; ++ ++static unsigned short bytebit[8] = { ++ 01, 02, 04, 010, 020, 040, 0100, 0200 }; ++ ++static unsigned long bigbyte[24] = { ++ 0x800000L, 0x400000L, 0x200000L, 0x100000L, ++ 0x80000L, 0x40000L, 0x20000L, 0x10000L, ++ 0x8000L, 0x4000L, 0x2000L, 0x1000L, ++ 0x800L, 0x400L, 0x200L, 0x100L, ++ 0x80L, 0x40L, 0x20L, 0x10L, ++ 0x8L, 0x4L, 0x2L, 0x1L }; ++ ++/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ ++ ++static unsigned char pc1[56] = { ++ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, ++ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, ++ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, ++ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; ++ ++static unsigned char totrot[16] = { ++ 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; ++ ++static unsigned char pc2[48] = { ++ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, ++ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, ++ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, ++ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; ++ ++void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */ ++unsigned char *key; ++int edf; ++{ ++ register int i, j, l, m, n; ++ unsigned char pc1m[56], pcr[56]; ++ unsigned long kn[32]; ++ ++ for ( j = 0; j < 56; j++ ) { ++ l = pc1[j]; ++ m = l & 07; ++ pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; ++ } ++ for( i = 0; i < 16; i++ ) { ++ if( edf == DE1 ) m = (15 - i) << 1; ++ else m = i << 1; ++ n = m + 1; ++ kn[m] = kn[n] = 0L; ++ for( j = 0; j < 28; j++ ) { ++ l = j + totrot[i]; ++ if( l < 28 ) pcr[j] = pc1m[l]; ++ else pcr[j] = pc1m[l - 28]; ++ } ++ for( j = 28; j < 56; j++ ) { ++ l = j + totrot[i]; ++ if( l < 56 ) pcr[j] = pc1m[l]; ++ else pcr[j] = pc1m[l - 28]; ++ } ++ for( j = 0; j < 24; j++ ) { ++ if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; ++ if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; ++ } ++ } ++ cookey(kn); ++ return; ++ } ++ ++static void cookey(raw1) ++register unsigned long *raw1; ++{ ++ register unsigned long *cook, *raw0; ++ unsigned long dough[32]; ++ register int i; ++ ++ cook = dough; ++ for( i = 0; i < 16; i++, raw1++ ) { ++ raw0 = raw1++; ++ *cook = (*raw0 & 0x00fc0000L) << 6; ++ *cook |= (*raw0 & 0x00000fc0L) << 10; ++ *cook |= (*raw1 & 0x00fc0000L) >> 10; ++ *cook++ |= (*raw1 & 0x00000fc0L) >> 6; ++ *cook = (*raw0 & 0x0003f000L) << 12; ++ *cook |= (*raw0 & 0x0000003fL) << 16; ++ *cook |= (*raw1 & 0x0003f000L) >> 4; ++ *cook++ |= (*raw1 & 0x0000003fL); ++ } ++ usekey(dough); ++ return; ++ } ++ ++void cpkey(into) ++register unsigned long *into; ++{ ++ register unsigned long *from, *endp; ++ ++ from = KnL, endp = &KnL[32]; ++ while( from < endp ) *into++ = *from++; ++ return; ++ } ++ ++void usekey(from) ++register unsigned long *from; ++{ ++ register unsigned long *to, *endp; ++ ++ to = KnL, endp = &KnL[32]; ++ while( to < endp ) *to++ = *from++; ++ return; ++ } ++ ++void des(inblock, outblock) ++unsigned char *inblock, *outblock; ++{ ++ unsigned long work[2]; ++ ++ scrunch(inblock, work); ++ desfunc(work, KnL); ++ unscrun(work, outblock); ++ return; ++ } ++ ++static void scrunch(outof, into) ++register unsigned char *outof; ++register unsigned long *into; ++{ ++ *into = (*outof++ & 0xffL) << 24; ++ *into |= (*outof++ & 0xffL) << 16; ++ *into |= (*outof++ & 0xffL) << 8; ++ *into++ |= (*outof++ & 0xffL); ++ *into = (*outof++ & 0xffL) << 24; ++ *into |= (*outof++ & 0xffL) << 16; ++ *into |= (*outof++ & 0xffL) << 8; ++ *into |= (*outof & 0xffL); ++ return; ++ } ++ ++static void unscrun(outof, into) ++register unsigned long *outof; ++register unsigned char *into; ++{ ++ *into++ = (*outof >> 24) & 0xffL; ++ *into++ = (*outof >> 16) & 0xffL; ++ *into++ = (*outof >> 8) & 0xffL; ++ *into++ = *outof++ & 0xffL; ++ *into++ = (*outof >> 24) & 0xffL; ++ *into++ = (*outof >> 16) & 0xffL; ++ *into++ = (*outof >> 8) & 0xffL; ++ *into = *outof & 0xffL; ++ return; ++ } ++ ++static unsigned long SP1[64] = { ++ 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, ++ 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, ++ 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, ++ 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, ++ 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, ++ 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, ++ 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, ++ 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, ++ 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, ++ 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, ++ 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, ++ 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, ++ 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, ++ 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, ++ 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, ++ 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; ++ ++static unsigned long SP2[64] = { ++ 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, ++ 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, ++ 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, ++ 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, ++ 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, ++ 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, ++ 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, ++ 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, ++ 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, ++ 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, ++ 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, ++ 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, ++ 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, ++ 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, ++ 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, ++ 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; ++ ++static unsigned long SP3[64] = { ++ 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, ++ 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, ++ 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, ++ 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, ++ 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, ++ 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, ++ 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, ++ 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, ++ 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, ++ 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, ++ 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, ++ 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, ++ 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, ++ 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, ++ 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, ++ 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; ++ ++static unsigned long SP4[64] = { ++ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, ++ 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, ++ 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, ++ 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, ++ 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, ++ 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, ++ 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, ++ 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, ++ 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, ++ 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, ++ 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, ++ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, ++ 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, ++ 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, ++ 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, ++ 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; ++ ++static unsigned long SP5[64] = { ++ 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, ++ 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, ++ 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, ++ 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, ++ 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, ++ 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, ++ 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, ++ 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, ++ 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, ++ 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, ++ 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, ++ 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, ++ 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, ++ 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, ++ 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, ++ 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; ++ ++static unsigned long SP6[64] = { ++ 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, ++ 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, ++ 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, ++ 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, ++ 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, ++ 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, ++ 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, ++ 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, ++ 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, ++ 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, ++ 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, ++ 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, ++ 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, ++ 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, ++ 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, ++ 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; ++ ++static unsigned long SP7[64] = { ++ 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, ++ 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, ++ 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, ++ 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, ++ 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, ++ 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, ++ 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, ++ 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, ++ 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, ++ 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, ++ 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, ++ 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, ++ 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, ++ 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, ++ 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, ++ 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; ++ ++static unsigned long SP8[64] = { ++ 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, ++ 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, ++ 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, ++ 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, ++ 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, ++ 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, ++ 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, ++ 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, ++ 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, ++ 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, ++ 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, ++ 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, ++ 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, ++ 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, ++ 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, ++ 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; ++ ++static void desfunc(block, keys) ++register unsigned long *block, *keys; ++{ ++ register unsigned long fval, work, right, leftt; ++ register int round; ++ ++ leftt = block[0]; ++ right = block[1]; ++ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; ++ right ^= work; ++ leftt ^= (work << 4); ++ work = ((leftt >> 16) ^ right) & 0x0000ffffL; ++ right ^= work; ++ leftt ^= (work << 16); ++ work = ((right >> 2) ^ leftt) & 0x33333333L; ++ leftt ^= work; ++ right ^= (work << 2); ++ work = ((right >> 8) ^ leftt) & 0x00ff00ffL; ++ leftt ^= work; ++ right ^= (work << 8); ++ right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; ++ work = (leftt ^ right) & 0xaaaaaaaaL; ++ leftt ^= work; ++ right ^= work; ++ leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; ++ ++ for( round = 0; round < 8; round++ ) { ++ work = (right << 28) | (right >> 4); ++ work ^= *keys++; ++ fval = SP7[ work & 0x3fL]; ++ fval |= SP5[(work >> 8) & 0x3fL]; ++ fval |= SP3[(work >> 16) & 0x3fL]; ++ fval |= SP1[(work >> 24) & 0x3fL]; ++ work = right ^ *keys++; ++ fval |= SP8[ work & 0x3fL]; ++ fval |= SP6[(work >> 8) & 0x3fL]; ++ fval |= SP4[(work >> 16) & 0x3fL]; ++ fval |= SP2[(work >> 24) & 0x3fL]; ++ leftt ^= fval; ++ work = (leftt << 28) | (leftt >> 4); ++ work ^= *keys++; ++ fval = SP7[ work & 0x3fL]; ++ fval |= SP5[(work >> 8) & 0x3fL]; ++ fval |= SP3[(work >> 16) & 0x3fL]; ++ fval |= SP1[(work >> 24) & 0x3fL]; ++ work = leftt ^ *keys++; ++ fval |= SP8[ work & 0x3fL]; ++ fval |= SP6[(work >> 8) & 0x3fL]; ++ fval |= SP4[(work >> 16) & 0x3fL]; ++ fval |= SP2[(work >> 24) & 0x3fL]; ++ right ^= fval; ++ } ++ ++ right = (right << 31) | (right >> 1); ++ work = (leftt ^ right) & 0xaaaaaaaaL; ++ leftt ^= work; ++ right ^= work; ++ leftt = (leftt << 31) | (leftt >> 1); ++ work = ((leftt >> 8) ^ right) & 0x00ff00ffL; ++ right ^= work; ++ leftt ^= (work << 8); ++ work = ((leftt >> 2) ^ right) & 0x33333333L; ++ right ^= work; ++ leftt ^= (work << 2); ++ work = ((right >> 16) ^ leftt) & 0x0000ffffL; ++ leftt ^= work; ++ right ^= (work << 16); ++ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; ++ leftt ^= work; ++ right ^= (work << 4); ++ *block++ = right; ++ *block = leftt; ++ return; ++ } ++ ++/* Validation sets: ++ * ++ * Single-length key, single-length plaintext - ++ * Key : 0123 4567 89ab cdef ++ * Plain : 0123 4567 89ab cde7 ++ * Cipher : c957 4425 6a5e d31d ++ * ++ * Double-length key, single-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 ++ * Plain : 0123 4567 89ab cde7 ++ * Cipher : 7f1d 0a77 826b 8aff ++ * ++ * Double-length key, double-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 ++ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff ++ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 ++ * ++ * Triple-length key, single-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 ++ * Plain : 0123 4567 89ab cde7 ++ * Cipher : de0b 7c06 ae5e 0ed5 ++ * ++ * Triple-length key, double-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 ++ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff ++ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 ++ * ++ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery ++ **********************************************************************/ +diff --git a/hw/dmx/vnc/d3des.h b/hw/dmx/vnc/d3des.h +new file mode 100644 +index 0000000..ea3da44 +--- /dev/null ++++ b/hw/dmx/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/dmx/vnc/dispcur.c b/hw/dmx/vnc/dispcur.c +new file mode 100644 +index 0000000..ceea9fa +--- /dev/null ++++ b/hw/dmx/vnc/dispcur.c +@@ -0,0 +1,804 @@ ++/* ++ * dispcur.c ++ * ++ * cursor display routines - based on midispcur.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#if HAVE_DMX_CONFIG_H ++#include "dmx-config.h" ++#endif ++ ++#define NEED_EVENTS ++# include "X11/X.h" ++# include "misc.h" ++# include "input.h" ++# include "cursorstr.h" ++# include "windowstr.h" ++# include "regionstr.h" ++# include "dixstruct.h" ++# include "scrnintstr.h" ++# include "servermd.h" ++# include "mipointer.h" ++# include "sprite.h" ++# include "gcstruct.h" ++ ++#ifdef ARGB_CURSOR ++# include "picturestr.h" ++#endif ++ ++/* per-screen private data */ ++ ++static int rfbDCScreenIndex; ++static unsigned long rfbDCGeneration = 0; ++ ++static Bool rfbDCCloseScreen(int index, ScreenPtr pScreen); ++ ++typedef struct { ++ GCPtr pSourceGC, pMaskGC; ++ GCPtr pSaveGC, pRestoreGC; ++ GCPtr pMoveGC; ++ GCPtr pPixSourceGC, pPixMaskGC; ++ CloseScreenProcPtr CloseScreen; ++ PixmapPtr pSave, pTemp; ++#ifdef ARGB_CURSOR ++ PicturePtr pRootPicture; ++ PicturePtr pTempPicture; ++#endif ++} rfbDCScreenRec, *rfbDCScreenPtr; ++ ++/* per-cursor per-screen private data */ ++typedef struct { ++ PixmapPtr sourceBits; /* source bits */ ++ PixmapPtr maskBits; /* mask bits */ ++#ifdef ARGB_CURSOR ++ PicturePtr pPicture; ++#endif ++} rfbDCCursorRec, *rfbDCCursorPtr; ++ ++/* ++ * sprite/cursor method table ++ */ ++ ++static Bool rfbDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); ++static Bool rfbDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); ++static Bool rfbDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor, ++ int x, int y, unsigned long source, ++ unsigned long mask); ++static Bool rfbDCSaveUnderCursor(ScreenPtr pScreen, int x, int y, ++ int w, int h); ++static Bool rfbDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y, ++ int w, int h); ++static Bool rfbDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor, ++ int x, int y, int w, int h, int dx, int dy, ++ unsigned long source, unsigned long mask); ++static Bool rfbDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h, ++ int dx, int dy); ++ ++static rfbSpriteCursorFuncRec rfbDCFuncs = { ++ rfbDCRealizeCursor, ++ rfbDCUnrealizeCursor, ++ rfbDCPutUpCursor, ++ rfbDCSaveUnderCursor, ++ rfbDCRestoreUnderCursor, ++ rfbDCMoveCursor, ++ rfbDCChangeSave, ++}; ++ ++Bool ++rfbDCInitialize (pScreen, screenFuncs) ++ ScreenPtr pScreen; ++ miPointerScreenFuncPtr screenFuncs; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ ++ if (rfbDCGeneration != serverGeneration) ++ { ++ rfbDCScreenIndex = AllocateScreenPrivateIndex (); ++ if (rfbDCScreenIndex < 0) ++ return FALSE; ++ rfbDCGeneration = serverGeneration; ++ } ++ pScreenPriv = (rfbDCScreenPtr) xalloc (sizeof (rfbDCScreenRec)); ++ if (!pScreenPriv) ++ return FALSE; ++ ++ /* ++ * initialize the entire private structure to zeros ++ */ ++ ++ pScreenPriv->pSourceGC = ++ pScreenPriv->pMaskGC = ++ pScreenPriv->pSaveGC = ++ pScreenPriv->pRestoreGC = ++ pScreenPriv->pMoveGC = ++ pScreenPriv->pPixSourceGC = ++ pScreenPriv->pPixMaskGC = NULL; ++#ifdef ARGB_CURSOR ++ pScreenPriv->pRootPicture = NULL; ++ pScreenPriv->pTempPicture = NULL; ++#endif ++ ++ pScreenPriv->pSave = pScreenPriv->pTemp = NULL; ++ ++ pScreenPriv->CloseScreen = pScreen->CloseScreen; ++ pScreen->CloseScreen = rfbDCCloseScreen; ++ ++ pScreen->devPrivates[rfbDCScreenIndex].ptr = (pointer) pScreenPriv; ++ ++ if (!rfbSpriteInitialize (pScreen, &rfbDCFuncs, screenFuncs)) ++ { ++ xfree ((pointer) pScreenPriv); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++#define tossGC(gc) (gc ? FreeGC (gc, (GContext) 0) : 0) ++#define tossPix(pix) (pix ? (*pScreen->DestroyPixmap) (pix) : TRUE) ++#define tossPict(pict) (pict ? FreePicture (pict, 0) : 0) ++ ++static Bool ++rfbDCCloseScreen (index, pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pScreen->CloseScreen = pScreenPriv->CloseScreen; ++ tossGC (pScreenPriv->pSourceGC); ++ tossGC (pScreenPriv->pMaskGC); ++ tossGC (pScreenPriv->pSaveGC); ++ tossGC (pScreenPriv->pRestoreGC); ++ tossGC (pScreenPriv->pMoveGC); ++ tossGC (pScreenPriv->pPixSourceGC); ++ tossGC (pScreenPriv->pPixMaskGC); ++ tossPix (pScreenPriv->pSave); ++ tossPix (pScreenPriv->pTemp); ++#ifdef ARGB_CURSOR ++ tossPict (pScreenPriv->pRootPicture); ++ tossPict (pScreenPriv->pTempPicture); ++#endif ++ xfree ((pointer) pScreenPriv); ++ return (*pScreen->CloseScreen) (index, pScreen); ++} ++ ++static Bool ++rfbDCRealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ if (pCursor->bits->refcnt <= 1) ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; ++ return TRUE; ++} ++ ++#ifdef ARGB_CURSOR ++#define EnsurePicture(picture,draw,win) (picture || rfbDCMakePicture(&picture,draw,win)) ++ ++static VisualPtr ++rfbDCGetWindowVisual (WindowPtr pWin) ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ VisualID vid = wVisual (pWin); ++ int i; ++ ++ for (i = 0; i < pScreen->numVisuals; i++) ++ if (pScreen->visuals[i].vid == vid) ++ return &pScreen->visuals[i]; ++ return 0; ++} ++ ++static PicturePtr ++rfbDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) ++{ ++ ScreenPtr pScreen = pDraw->pScreen; ++ VisualPtr pVisual; ++ PictFormatPtr pFormat; ++ XID subwindow_mode = IncludeInferiors; ++ PicturePtr pPicture; ++ int error; ++ ++ pVisual = rfbDCGetWindowVisual (pWin); ++ if (!pVisual) ++ return 0; ++ pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); ++ if (!pFormat) ++ return 0; ++ pPicture = CreatePicture (0, pDraw, pFormat, ++ CPSubwindowMode, &subwindow_mode, ++ serverClient, &error); ++ *ppPicture = pPicture; ++ return pPicture; ++} ++#endif ++ ++static rfbDCCursorPtr ++rfbDCRealize (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbDCCursorPtr pPriv; ++ GCPtr pGC; ++ XID gcvals[3]; ++ ++ pPriv = (rfbDCCursorPtr) xalloc (sizeof (rfbDCCursorRec)); ++ if (!pPriv) ++ return (rfbDCCursorPtr)NULL; ++#ifdef ARGB_CURSOR ++ if (pCursor->bits->argb) ++ { ++ PixmapPtr pPixmap; ++ PictFormatPtr pFormat; ++ int error; ++ ++ pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); ++ if (!pFormat) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ ++ pPriv->sourceBits = 0; ++ pPriv->maskBits = 0; ++ pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, ++ pCursor->bits->height, 32); ++ if (!pPixmap) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pGC = GetScratchGC (32, pScreen); ++ if (!pGC) ++ { ++ (*pScreen->DestroyPixmap) (pPixmap); ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ ValidateGC (&pPixmap->drawable, pGC); ++ (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, ++ 0, 0, pCursor->bits->width, ++ pCursor->bits->height, ++ 0, ZPixmap, (char *) pCursor->bits->argb); ++ FreeScratchGC (pGC); ++ pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, ++ pFormat, 0, 0, serverClient, &error); ++ (*pScreen->DestroyPixmap) (pPixmap); ++ if (!pPriv->pPicture) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; ++ return pPriv; ++ } ++ pPriv->pPicture = 0; ++#endif ++ pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); ++ if (!pPriv->sourceBits) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); ++ if (!pPriv->maskBits) ++ { ++ (*pScreen->DestroyPixmap) (pPriv->sourceBits); ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; ++ ++ /* create the two sets of bits, clipping as appropriate */ ++ ++ pGC = GetScratchGC (1, pScreen); ++ if (!pGC) ++ { ++ (void) rfbDCUnrealizeCursor (pScreen, pCursor); ++ return (rfbDCCursorPtr)NULL; ++ } ++ ++ ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->source); ++ gcvals[0] = GXand; ++ ChangeGC (pGC, GCFunction, gcvals); ++ ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->mask); ++ ++ /* mask bits -- pCursor->mask & ~pCursor->source */ ++ gcvals[0] = GXcopy; ++ ChangeGC (pGC, GCFunction, gcvals); ++ ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->mask); ++ gcvals[0] = GXandInverted; ++ ChangeGC (pGC, GCFunction, gcvals); ++ ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->source); ++ FreeScratchGC (pGC); ++ return pPriv; ++} ++ ++static Bool ++rfbDCUnrealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbDCCursorPtr pPriv; ++ ++ pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; ++ if (pPriv && (pCursor->bits->refcnt <= 1)) ++ { ++ if (pPriv->sourceBits) ++ (*pScreen->DestroyPixmap) (pPriv->sourceBits); ++ if (pPriv->maskBits) ++ (*pScreen->DestroyPixmap) (pPriv->maskBits); ++#ifdef ARGB_CURSOR ++ if (pPriv->pPicture) ++ FreePicture (pPriv->pPicture, 0); ++#endif ++ xfree ((pointer) pPriv); ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; ++ } ++ return TRUE; ++} ++ ++static void ++rfbDCPutBits (pDrawable, pPriv, sourceGC, maskGC, x, y, w, h, source, mask) ++ DrawablePtr pDrawable; ++ GCPtr sourceGC, maskGC; ++ int x, y; ++ unsigned w, h; ++ rfbDCCursorPtr pPriv; ++ unsigned long source, mask; ++{ ++ XID gcvals[1]; ++ ++ if (sourceGC->fgPixel != source) ++ { ++ gcvals[0] = source; ++ DoChangeGC (sourceGC, GCForeground, gcvals, 0); ++ } ++ if (sourceGC->serialNumber != pDrawable->serialNumber) ++ ValidateGC (pDrawable, sourceGC); ++ (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); ++ if (maskGC->fgPixel != mask) ++ { ++ gcvals[0] = mask; ++ DoChangeGC (maskGC, GCForeground, gcvals, 0); ++ } ++ if (maskGC->serialNumber != pDrawable->serialNumber) ++ ValidateGC (pDrawable, maskGC); ++ (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); ++} ++ ++#define EnsureGC(gc,win) (gc || rfbDCMakeGC(&gc, win)) ++ ++static GCPtr ++rfbDCMakeGC(ppGC, pWin) ++ GCPtr *ppGC; ++ WindowPtr pWin; ++{ ++ GCPtr pGC; ++ int status; ++ XID gcvals[2]; ++ ++ gcvals[0] = IncludeInferiors; ++ gcvals[1] = FALSE; ++ pGC = CreateGC((DrawablePtr)pWin, ++ GCSubwindowMode|GCGraphicsExposures, gcvals, &status); ++ if (pGC && pWin->drawable.pScreen->DrawGuarantee) ++ (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); ++ *ppGC = pGC; ++ return pGC; ++} ++ ++static Bool ++rfbDCPutUpCursor (pScreen, pCursor, x, y, source, mask) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++ int x, y; ++ unsigned long source, mask; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ rfbDCCursorPtr pPriv; ++ WindowPtr pWin; ++ ++ pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; ++ if (!pPriv) ++ { ++ pPriv = rfbDCRealize(pScreen, pCursor); ++ if (!pPriv) ++ return FALSE; ++ } ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pWin = WindowTable[pScreen->myNum]; ++#ifdef ARGB_CURSOR ++ if (pPriv->pPicture) ++ { ++ if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin)) ++ return FALSE; ++ CompositePicture (PictOpOver, ++ pPriv->pPicture, ++ NULL, ++ pScreenPriv->pRootPicture, ++ 0, 0, 0, 0, ++ x, y, ++ pCursor->bits->width, ++ pCursor->bits->height); ++ } ++ else ++#endif ++ { ++ if (!EnsureGC(pScreenPriv->pSourceGC, pWin)) ++ return FALSE; ++ if (!EnsureGC(pScreenPriv->pMaskGC, pWin)) ++ { ++ FreeGC (pScreenPriv->pSourceGC, (GContext) 0); ++ pScreenPriv->pSourceGC = 0; ++ return FALSE; ++ } ++ rfbDCPutBits ((DrawablePtr)pWin, pPriv, ++ pScreenPriv->pSourceGC, pScreenPriv->pMaskGC, ++ x, y, pCursor->bits->width, pCursor->bits->height, ++ source, mask); ++ } ++ return TRUE; ++} ++ ++static Bool ++rfbDCSaveUnderCursor (pScreen, x, y, w, h) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ PixmapPtr pSave; ++ WindowPtr pWin; ++ GCPtr pGC; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pSave = pScreenPriv->pSave; ++ pWin = WindowTable[pScreen->myNum]; ++ if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) ++ { ++ if (pSave) ++ (*pScreen->DestroyPixmap) (pSave); ++ pScreenPriv->pSave = pSave = ++ (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth); ++ if (!pSave) ++ return FALSE; ++ } ++ if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pSaveGC; ++ if (pSave->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pSave, pGC); ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, y, w, h, 0, 0); ++ return TRUE; ++} ++ ++static Bool ++rfbDCRestoreUnderCursor (pScreen, x, y, w, h) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ PixmapPtr pSave; ++ WindowPtr pWin; ++ GCPtr pGC; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pSave = pScreenPriv->pSave; ++ pWin = WindowTable[pScreen->myNum]; ++ if (!pSave) ++ return FALSE; ++ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pRestoreGC; ++ if (pWin->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pWin, pGC); ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, 0, w, h, x, y); ++ return TRUE; ++} ++ ++static Bool ++rfbDCChangeSave (pScreen, x, y, w, h, dx, dy) ++ ScreenPtr pScreen; ++ int x, y, w, h, dx, dy; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ PixmapPtr pSave; ++ WindowPtr pWin; ++ GCPtr pGC; ++ int sourcex, sourcey, destx, desty, copyw, copyh; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pSave = pScreenPriv->pSave; ++ pWin = WindowTable[pScreen->myNum]; ++ /* ++ * restore the bits which are about to get trashed ++ */ ++ if (!pSave) ++ return FALSE; ++ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pRestoreGC; ++ if (pWin->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pWin, pGC); ++ /* ++ * copy the old bits to the screen. ++ */ ++ if (dy > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, h - dy, w, dy, x + dx, y + h); ++ } ++ else if (dy < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, 0, w, -dy, x + dx, y + dy); ++ } ++ if (dy >= 0) ++ { ++ desty = y + dy; ++ sourcey = 0; ++ copyh = h - dy; ++ } ++ else ++ { ++ desty = y; ++ sourcey = - dy; ++ copyh = h + dy; ++ } ++ if (dx > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ w - dx, sourcey, dx, copyh, x + w, desty); ++ } ++ else if (dx < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, sourcey, -dx, copyh, x + dx, desty); ++ } ++ if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pSaveGC; ++ if (pSave->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pSave, pGC); ++ /* ++ * move the bits that are still valid within the pixmap ++ */ ++ if (dx >= 0) ++ { ++ sourcex = 0; ++ destx = dx; ++ copyw = w - dx; ++ } ++ else ++ { ++ destx = 0; ++ sourcex = - dx; ++ copyw = w + dx; ++ } ++ if (dy >= 0) ++ { ++ sourcey = 0; ++ desty = dy; ++ copyh = h - dy; ++ } ++ else ++ { ++ desty = 0; ++ sourcey = -dy; ++ copyh = h + dy; ++ } ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC, ++ sourcex, sourcey, copyw, copyh, destx, desty); ++ /* ++ * copy the new bits from the screen into the remaining areas of the ++ * pixmap ++ */ ++ if (dy > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, y, w, dy, 0, 0); ++ } ++ else if (dy < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, y + h + dy, w, -dy, 0, h + dy); ++ } ++ if (dy >= 0) ++ { ++ desty = dy; ++ sourcey = y + dy; ++ copyh = h - dy; ++ } ++ else ++ { ++ desty = 0; ++ sourcey = y; ++ copyh = h + dy; ++ } ++ if (dx > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, sourcey, dx, copyh, 0, desty); ++ } ++ else if (dx < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x + w + dx, sourcey, -dx, copyh, w + dx, desty); ++ } ++ return TRUE; ++} ++ ++static Bool ++rfbDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++ int x, y, w, h, dx, dy; ++ unsigned long source, mask; ++{ ++ rfbDCCursorPtr pPriv; ++ rfbDCScreenPtr pScreenPriv; ++ int status; ++ WindowPtr pWin; ++ GCPtr pGC; ++ XID gcval = FALSE; ++ PixmapPtr pTemp; ++ ++ pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; ++ if (!pPriv) ++ { ++ pPriv = rfbDCRealize(pScreen, pCursor); ++ if (!pPriv) ++ return FALSE; ++ } ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pWin = WindowTable[pScreen->myNum]; ++ pTemp = pScreenPriv->pTemp; ++ if (!pTemp || ++ pTemp->drawable.width != pScreenPriv->pSave->drawable.width || ++ pTemp->drawable.height != pScreenPriv->pSave->drawable.height) ++ { ++ if (pTemp) ++ (*pScreen->DestroyPixmap) (pTemp); ++#ifdef ARGB_CURSOR ++ if (pScreenPriv->pTempPicture) ++ { ++ FreePicture (pScreenPriv->pTempPicture, 0); ++ pScreenPriv->pTempPicture = 0; ++ } ++#endif ++ pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap) ++ (pScreen, w, h, pScreenPriv->pSave->drawable.depth); ++ if (!pTemp) ++ return FALSE; ++ } ++ if (!pScreenPriv->pMoveGC) ++ { ++ pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp, ++ GCGraphicsExposures, &gcval, &status); ++ if (!pScreenPriv->pMoveGC) ++ return FALSE; ++ } ++ /* ++ * copy the saved area to a temporary pixmap ++ */ ++ pGC = pScreenPriv->pMoveGC; ++ if (pGC->serialNumber != pTemp->drawable.serialNumber) ++ ValidateGC ((DrawablePtr) pTemp, pGC); ++ (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave, ++ (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0); ++ ++ /* ++ * draw the cursor in the temporary pixmap ++ */ ++#ifdef ARGB_CURSOR ++ if (pPriv->pPicture) ++ { ++ if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin)) ++ return FALSE; ++ CompositePicture (PictOpOver, ++ pPriv->pPicture, ++ NULL, ++ pScreenPriv->pTempPicture, ++ 0, 0, 0, 0, ++ dx, dy, ++ pCursor->bits->width, ++ pCursor->bits->height); ++ } ++ else ++#endif ++ { ++ if (!pScreenPriv->pPixSourceGC) ++ { ++ pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp, ++ GCGraphicsExposures, &gcval, &status); ++ if (!pScreenPriv->pPixSourceGC) ++ return FALSE; ++ } ++ if (!pScreenPriv->pPixMaskGC) ++ { ++ pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp, ++ GCGraphicsExposures, &gcval, &status); ++ if (!pScreenPriv->pPixMaskGC) ++ return FALSE; ++ } ++ rfbDCPutBits ((DrawablePtr)pTemp, pPriv, ++ pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC, ++ dx, dy, pCursor->bits->width, pCursor->bits->height, ++ source, mask); ++ } ++ ++ /* ++ * copy the temporary pixmap onto the screen ++ */ ++ ++ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pRestoreGC; ++ if (pWin->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pWin, pGC); ++ ++ (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin, ++ pGC, ++ 0, 0, w, h, x, y); ++ return TRUE; ++} +diff --git a/hw/dmx/vnc/draw.c b/hw/dmx/vnc/draw.c +new file mode 100644 +index 0000000..4154dd5 +--- /dev/null ++++ b/hw/dmx/vnc/draw.c +@@ -0,0 +1,2097 @@ ++/* ++ * draw.c - drawing routines for the RFB X server. This is a set of ++ * wrappers around the standard MI/MFB/CFB drawing routines which work out ++ * to a fair approximation the region of the screen being modified by the ++ * drawing. If the RFB client is ready then the modified region of the screen ++ * is sent to the client, otherwise the modified region will simply grow with ++ * each drawing request until the client is ready. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#include "rfb.h" ++ ++int rfbDeferUpdateTime = 40; /* ms */ ++ ++ ++/****************************************************************************/ ++/* ++ * Macro definitions ++ */ ++/****************************************************************************/ ++ ++#define TRC(x) /* (rfbLog x) */ ++ ++/* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each ++ client */ ++ ++#define ADD_TO_MODIFIED_REGION(pScreen,reg) \ ++ { \ ++ rfbClientPtr cl; \ ++ for (cl = rfbClientHead; cl; cl = cl->next) { \ ++ REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\ ++ } \ ++ } ++ ++/* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an ++ update to be sent to each client if there is one pending and the client is ++ ready for it. */ ++ ++#define SCHEDULE_FB_UPDATE(pScreen,pVNC) \ ++ if (!pVNC->dontSendFramebufferUpdate) { \ ++ rfbClientPtr cl, nextCl; \ ++ for (cl = rfbClientHead; cl; cl = nextCl) { \ ++ nextCl = cl->next; \ ++ if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && \ ++ REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) \ ++ { \ ++ rfbScheduleDeferredUpdate(pScreen, cl); \ ++ } \ ++ } \ ++ } ++ ++/* function prototypes */ ++ ++static void rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl); ++static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl, ++ RegionPtr src, RegionPtr dst, int dx, int dy); ++#ifdef DEBUG ++static void PrintRegion(ScreenPtr pScreen, RegionPtr reg); ++#endif ++ ++/* GC funcs */ ++ ++static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr); ++static void rfbChangeGC(GCPtr, unsigned long /*mask*/); ++static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/); ++static void rfbDestroyGC(GCPtr); ++static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/, ++ int /*nrects*/); ++static void rfbDestroyClip(GCPtr); ++static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/); ++ ++/* GC ops */ ++ ++static void rfbFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted); ++static void rfbSetSpans(DrawablePtr pDrawable, ++ GCPtr pGC, ++ char *psrc, ++ register DDXPointPtr ppt, ++ int *pwidth, ++ int nspans, ++ int fSorted); ++static void rfbPutImage(); ++static RegionPtr rfbCopyArea(); ++static RegionPtr rfbCopyPlane(); ++static void rfbPolyPoint(); ++static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts); ++static void rfbPolySegment(); ++static void rfbPolyRectangle(); ++static void rfbPolyArc(); ++static void rfbFillPolygon(); ++static void rfbPolyFillRect(); ++static void rfbPolyFillArc(); ++static int rfbPolyText8(); ++static int rfbPolyText16(); ++static void rfbImageText8(); ++static void rfbImageText16(); ++static void rfbImageGlyphBlt(); ++static void rfbPolyGlyphBlt(); ++static void rfbPushPixels(); ++ ++ ++static GCFuncs rfbGCFuncs = { ++ rfbValidateGC, ++ rfbChangeGC, ++ rfbCopyGC, ++ rfbDestroyGC, ++ rfbChangeClip, ++ rfbDestroyClip, ++ rfbCopyClip, ++}; ++ ++ ++static GCOps rfbGCOps = { ++ rfbFillSpans, rfbSetSpans, rfbPutImage, ++ rfbCopyArea, rfbCopyPlane, rfbPolyPoint, ++ rfbPolylines, rfbPolySegment, rfbPolyRectangle, ++ rfbPolyArc, rfbFillPolygon, rfbPolyFillRect, ++ rfbPolyFillArc, rfbPolyText8, rfbPolyText16, ++ rfbImageText8, rfbImageText16, rfbImageGlyphBlt, ++ rfbPolyGlyphBlt, rfbPushPixels ++}; ++ ++ ++ ++/****************************************************************************/ ++/* ++ * Screen functions wrapper stuff ++ */ ++/****************************************************************************/ ++ ++#define SCREEN_PROLOGUE(scrn, field) \ ++ ScreenPtr pScreen = scrn; \ ++ VNCSCREENPTR(pScreen); \ ++ pScreen->field = pVNC->field; ++ ++#define SCREEN_EPILOGUE(field, wrapper) \ ++ pScreen->field = wrapper; ++ ++ ++/* ++ * CloseScreen wrapper -- unwrap everything, free the private data ++ * and call the wrapped CloseScreen function. ++ */ ++ ++Bool ++rfbCloseScreen (int i, ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++#if XFREE86VNC ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++#endif ++ int sock; ++ ++ for (sock = 0; sock <= pVNC->maxFd; sock++) { ++ if (FD_ISSET(sock, &pVNC->allFds)) ++ if (sock != pVNC->rfbListenSock && sock != pVNC->httpListenSock) { ++ rfbCloseSock(pScreen, sock); ++ } ++ } ++ ++ if (pVNC->rfbListenSock > 0) ++ if (close(pVNC->rfbListenSock)) ++ ErrorF("Close of port %d failed\n",pVNC->rfbPort); ++ ++ if (pVNC->httpListenSock > 0) ++ if (close(pVNC->httpListenSock)) ++ ErrorF("Close of port %d failed\n",pVNC->httpPort); ++ ++ pScreen->CloseScreen = pVNC->CloseScreen; ++ pScreen->CreateGC = pVNC->CreateGC; ++ pScreen->PaintWindowBackground = pVNC->PaintWindowBackground; ++ pScreen->PaintWindowBorder = pVNC->PaintWindowBorder; ++ pScreen->CopyWindow = pVNC->CopyWindow; ++ pScreen->ClearToBackground = pVNC->ClearToBackground; ++ pScreen->RestoreAreas = pVNC->RestoreAreas; ++ pScreen->WakeupHandler = pVNC->WakeupHandler; ++ ++#if XFREE86VNC ++ pScreen->InstallColormap = pVNC->InstallColormap; ++ pScreen->UninstallColormap = pVNC->UninstallColormap; ++ pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps; ++ pScreen->StoreColors = pVNC->StoreColors; ++ pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess; ++ ++ xfree(pVNC); ++#endif ++ ++ TRC((stderr,"Unwrapped screen functions\n")); ++ ++ return (*pScreen->CloseScreen) (i, pScreen); ++} ++ ++#if XFREE86VNC ++void ++rfbEnableDisableFBAccess (int index, Bool enable) ++{ ++ ScrnInfoPtr pScrn = xf86Screens[index]; ++ VNCSCREENPTR(pScrn->pScreen); ++ ++ /* ++ * Blank the screen for security while inputs are disabled. ++ * When VT switching is fixed, we might be able to allow ++ * control even when switched away. ++ */ ++ if (!enable) { ++ WindowPtr pWin = WindowTable[index]; ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ GCPtr pGC; ++ xRectangle rect; ++ ++ rect.x = 0; ++ rect.y = 0; ++ rect.width = pScrn->virtualX; ++ rect.height = pScrn->virtualY; ++ ++ if (!(pGC = GetScratchGC(pScreen->rootDepth, pScreen))) { ++ ErrorF("Couldn't blank screen"); ++ } else { ++ CARD32 attributes[2]; ++ attributes[0] = pScreen->whitePixel; ++ attributes[1] = pScreen->blackPixel; ++ (void)ChangeGC(pGC, GCForeground | GCBackground, attributes); ++ ++ ValidateGC((DrawablePtr)pWin, pGC); ++ ++ (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, 1, &rect); ++ ++ FreeScratchGC(pGC); ++ ++ /* Flush pending packets */ ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++ } ++ } ++ ++ pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess; ++ (*pScrn->EnableDisableFBAccess)(index, enable); ++ pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess; ++} ++#endif ++ ++/* ++ * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC ++ * func "ValidateGC" is called). ++ */ ++ ++Bool ++rfbCreateGC (GCPtr pGC) ++{ ++ Bool ret; ++ rfbGCPtr pGCPriv; ++ ++ SCREEN_PROLOGUE(pGC->pScreen,CreateGC); ++ ++ pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr; ++ ++ ret = (*pScreen->CreateGC) (pGC); ++ ++ TRC((stderr,"rfbCreateGC called\n")); ++ ++ pGCPriv->wrapOps = NULL; ++ pGCPriv->wrapFuncs = pGC->funcs; ++ pGC->funcs = &rfbGCFuncs; ++ ++ SCREEN_EPILOGUE(CreateGC,rfbCreateGC); ++ ++ return ret; ++} ++ ++/* ++ * PaintWindowBackground - the region being modified is just the given region. ++ */ ++ ++void ++rfbPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what) ++{ ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground); ++ ++ TRC((stderr,"rfbPaintWindowBackground called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen,pRegion); ++ ++ (*pScreen->PaintWindowBackground) (pWin, pRegion, what); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground); ++} ++ ++/* ++ * PaintWindowBorder - the region being modified is just the given region. ++ */ ++ ++void ++rfbPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what) ++{ ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder); ++ ++ TRC((stderr,"rfbPaintWindowBorder called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen,pRegion); ++ ++ (*pScreen->PaintWindowBorder) (pWin, pRegion, what); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder); ++} ++ ++#ifdef CHROMIUM ++Bool ++rfbRealizeWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,RealizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 1); ++ } ++ } ++ ++ ret = (*pScreen->RealizeWindow)(pWin); ++ ++ SCREEN_EPILOGUE(RealizeWindow,rfbRealizeWindow); ++ ++ return ret; ++} ++ ++Bool ++rfbUnrealizeWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,UnrealizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 0); ++ } ++ } ++ ++ ret = (*pScreen->UnrealizeWindow)(pWin); ++ ++ SCREEN_EPILOGUE(UnrealizeWindow,rfbUnrealizeWindow); ++ ++ return ret; ++} ++ ++Bool ++rfbDestroyWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 0); ++ } ++ } ++ ++ ret = (*pScreen->DestroyWindow)(pWin); ++ ++ SCREEN_EPILOGUE(DestroyWindow,rfbDestroyWindow); ++ ++ return ret; ++} ++ ++void ++rfbResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ResizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumMoveResizeWindow(wt->CRwinId, pWin->drawable.x, pWin->drawable.y, w, h); ++ } ++ } ++ ++ (*pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); ++ ++ SCREEN_EPILOGUE(ResizeWindow,rfbResizeWindow); ++} ++ ++Bool ++rfbPositionWindow(WindowPtr pWin, int x, int y) ++{ ++ Bool ret; ++ CRWindowTable *wt, *nextWt; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PositionWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumMoveResizeWindow(wt->CRwinId, x, y, pWin->drawable.width, pWin->drawable.height); ++ } ++ } ++ ++ ret = (*pScreen->PositionWindow)(pWin, x, y); ++ ++ SCREEN_EPILOGUE(PositionWindow,rfbPositionWindow); ++ ++ return ret; ++} ++ ++void ++rfbClipNotify(WindowPtr pWin, int x, int y) ++{ ++ CRWindowTable *wt, *nextWt; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ClipNotify); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ int numClipRects = REGION_NUM_RECTS(&pWin->clipList); ++ BoxPtr pClipRects = REGION_RECTS(&pWin->clipList); ++ ++ /* Possible optimization - has the cliplist really? changed */ ++ ++ rfbSendChromiumClipList(wt->CRwinId, pClipRects, numClipRects); ++ } ++ } ++ ++ if (*pScreen->ClipNotify) ++ (*pScreen->ClipNotify)(pWin, x, y); ++ ++ SCREEN_EPILOGUE(ClipNotify,rfbClipNotify); ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * CopyWindow - the region being modified is the translation of the old ++ * region, clipped to the border clip region of the window. Note that any ++ * parts of the window which have become newly-visible will not be affected by ++ * this call - a separate PaintWindowBackground/Border will be called to do ++ * that. If the client will accept CopyRect messages then use rfbCopyRegion to ++ * optimise the pending screen changes into a single "copy region" plus the ++ * ordinary modified region. ++ */ ++ ++void ++rfbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) ++{ ++ rfbClientPtr cl; ++ RegionRec srcRegion, dstRegion; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow); ++ ++ TRC((stderr,"rfbCopyWindow called\n")); ++ ++ REGION_NULL(pScreen,&dstRegion); ++ REGION_COPY(pScreen,&dstRegion,pOldRegion); ++ REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion, ++ pWin->drawable.x - ptOldOrg.x, ++ pWin->drawable.y - ptOldOrg.y); ++ REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion, ++ &pWin->borderClip); ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->useCopyRect) { ++ REGION_NULL(pScreen,&srcRegion); ++ REGION_COPY(pScreen,&srcRegion,pOldRegion); ++ ++ rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion, ++ pWin->drawable.x - ptOldOrg.x, ++ pWin->drawable.y - ptOldOrg.y); ++ ++ REGION_UNINIT(pScreen, &srcRegion); ++ ++ } else { ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &dstRegion); ++ } ++ } ++ ++ REGION_UNINIT(pScreen, &dstRegion); ++ ++ (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow); ++} ++ ++/* ++ * ClearToBackground - when generateExposures is false, the region being ++ * modified is the given rectangle (clipped to the "window clip region"). ++ */ ++ ++void ++rfbClearToBackground (WindowPtr pWin, int x, int y, int w, int h, ++ Bool generateExposures) ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground); ++ ++ TRC((stderr,"rfbClearToBackground called\n")); ++ ++ if (!generateExposures) { ++ box.x1 = x + pWin->drawable.x; ++ box.y1 = y + pWin->drawable.y; ++ box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); ++ box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); ++ ++ SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pScreen, &tmpRegion); ++ } ++ ++ (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); ++ ++ if (!generateExposures) { ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ } ++ ++ SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground); ++} ++ ++/* ++ * RestoreAreas - just be safe here - the region being modified is the whole ++ * exposed region. ++ */ ++ ++RegionPtr ++rfbRestoreAreas (WindowPtr pWin, RegionPtr prgnExposed) ++{ ++ RegionPtr result; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas); ++ ++ TRC((stderr,"rfbRestoreAreas called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, prgnExposed); ++ ++ result = (*pScreen->RestoreAreas) (pWin, prgnExposed); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas); ++ ++ return result; ++} ++ ++ ++ ++/****************************************************************************/ ++/* ++ * GC funcs wrapper stuff ++ * ++ * We only really want to wrap the GC ops, but to do this we need to wrap ++ * ValidateGC and so all the other GC funcs must be wrapped as well. ++ */ ++/****************************************************************************/ ++ ++#define GC_FUNC_PROLOGUE(pGC) \ ++ rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \ ++ (pGC)->funcs = pGCPriv->wrapFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ (pGC)->ops = pGCPriv->wrapOps; ++ ++#define GC_FUNC_EPILOGUE(pGC) \ ++ pGCPriv->wrapFuncs = (pGC)->funcs; \ ++ (pGC)->funcs = &rfbGCFuncs; \ ++ if (pGCPriv->wrapOps) { \ ++ pGCPriv->wrapOps = (pGC)->ops; \ ++ (pGC)->ops = &rfbGCOps; \ ++ } ++ ++ ++/* ++ * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if ++ * the drawing will be to a viewable window. ++ */ ++ ++static void ++rfbValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) ++{ ++ /*VNCSCREENPTR(pGC->pScreen);*/ ++ GC_FUNC_PROLOGUE(pGC); ++ ++ TRC((stderr,"rfbValidateGC called\n")); ++ ++ (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); ++ ++ pGCPriv->wrapOps = NULL; ++ if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) ++ { ++ WindowPtr pWin = (WindowPtr) pDrawable; ++ RegionPtr pRegion = &pWin->clipList; ++ ++ if (pGC->subWindowMode == IncludeInferiors) ++ pRegion = &pWin->borderClip; ++ if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) { ++ pGCPriv->wrapOps = pGC->ops; ++ TRC((stderr,"rfbValidateGC: wrapped GC ops\n")); ++ } ++ } ++ ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++/* ++ * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped ++ * function and then rewrap the funcs and ops. ++ */ ++ ++static void ++rfbChangeGC (pGC, mask) ++ GCPtr pGC; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->ChangeGC) (pGC, mask); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbCopyGC (pGCSrc, mask, pGCDst) ++ GCPtr pGCSrc, pGCDst; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE(pGCDst); ++ (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); ++ GC_FUNC_EPILOGUE(pGCDst); ++} ++ ++static void ++rfbDestroyGC (pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->DestroyGC) (pGC); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbChangeClip (pGC, type, pvalue, nrects) ++ GCPtr pGC; ++ int type; ++ pointer pvalue; ++ int nrects; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbDestroyClip(pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (* pGC->funcs->DestroyClip)(pGC); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbCopyClip(pgcDst, pgcSrc) ++ GCPtr pgcDst, pgcSrc; ++{ ++ GC_FUNC_PROLOGUE(pgcDst); ++ (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); ++ GC_FUNC_EPILOGUE(pgcDst); ++} ++ ++ ++/****************************************************************************/ ++/* ++ * GC ops wrapper stuff ++ * ++ * Note that these routines will only have been wrapped for drawing to ++ * viewable windows so we don't need to check each time that the drawable ++ * is a viewable window. ++ */ ++/****************************************************************************/ ++ ++#define GC_OP_PROLOGUE(pDrawable,pGC) \ ++ ScreenPtr pScreen = pGC->pScreen; \ ++ VNCSCREENPTR(pScreen); \ ++ rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \ ++ GCFuncs *oldFuncs = pGC->funcs; \ ++ (void) pScreen; /* silence compiler */ \ ++ (pGC)->funcs = pGCPrivate->wrapFuncs; \ ++ (pGC)->ops = pGCPrivate->wrapOps; ++ ++#define GC_OP_EPILOGUE(pGC) \ ++ pGCPrivate->wrapOps = (pGC)->ops; \ ++ (pGC)->funcs = oldFuncs; \ ++ (pGC)->ops = &rfbGCOps; ++ ++ ++/* ++ * FillSpans - being very safe - the region being modified is the border clip ++ * region of the window. ++ */ ++ ++static void ++rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nInit; /* number of spans to fill */ ++ DDXPointPtr pptInit; /* pointer to list of start points */ ++ int *pwidthInit; /* pointer to list of n widths */ ++ int fSorted; ++{ ++ GC_OP_PROLOGUE(pDrawable,pGC); ++ ++ TRC((stderr,"rfbFillSpans called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, ++ &((WindowPtr)pDrawable)->borderClip); ++ ++ (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * SetSpans - being very safe - the region being modified is the border clip ++ * region of the window. ++ */ ++ ++static void ++rfbSetSpans(DrawablePtr pDrawable, ++ GCPtr pGC, ++ char *psrc, ++ register DDXPointPtr ppt, ++ int *pwidth, ++ int nspans, ++ int fSorted) ++{ ++ GC_OP_PROLOGUE(pDrawable,pGC); ++ ++ TRC((stderr,"rfbSetSpans called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, ++ &((WindowPtr)pDrawable)->borderClip); ++ ++ (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PutImage - the region being modified is the rectangle of the ++ * PutImage (clipped to the window clip region). ++ */ ++ ++static void ++rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int depth; ++ int x; ++ int y; ++ int w; ++ int h; ++ int leftPad; ++ int format; ++ char *pBits; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPutImage called\n")); ++ ++ box.x1 = x + pDrawable->x; ++ box.y1 = y + pDrawable->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ ++ (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, ++ leftPad, format, pBits); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * CopyArea - the region being modified is the destination rectangle (clipped ++ * to the window clip region). ++ * If the client will accept CopyRect messages then use rfbCopyRegion ++ * to optimise the pending screen changes into a single "copy region" plus ++ * the ordinary modified region. ++ */ ++ ++static RegionPtr ++rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ GCPtr pGC; ++ int srcx; ++ int srcy; ++ int w; ++ int h; ++ int dstx; ++ int dsty; ++{ ++ rfbClientPtr cl; ++ RegionPtr rgn; ++ RegionRec srcRegion, dstRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDst, pGC); ++ ++ TRC((stderr,"rfbCopyArea called\n")); ++ ++ box.x1 = dstx + pDst->x; ++ box.y1 = dsty + pDst->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0); ++ REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion, ++ pGC->pCompositeClip); ++ ++ if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) { ++ box.x1 = srcx + pSrc->x; ++ box.y1 = srcy + pSrc->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->useCopyRect) { ++ SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0); ++ REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion, ++ &((WindowPtr)pSrc)->clipList); ++ ++ rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion, ++ dstx + pDst->x - srcx - pSrc->x, ++ dsty + pDst->y - srcy - pSrc->y); ++ ++ REGION_UNINIT(pSrc->pScreen, &srcRegion); ++ ++ } else { ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &dstRegion); ++ } ++ } ++ ++ } else { ++ ++ ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion); ++ } ++ ++ REGION_UNINIT(pDst->pScreen, &dstRegion); ++ ++ rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty); ++ ++ SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++ ++ return rgn; ++} ++ ++ ++/* ++ * CopyPlane - the region being modified is the destination rectangle (clipped ++ * to the window clip region). ++ */ ++ ++static RegionPtr ++rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ register GCPtr pGC; ++ int srcx, ++ srcy; ++ int w, ++ h; ++ int dstx, ++ dsty; ++ unsigned long plane; ++{ ++ RegionPtr rgn; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDst, pGC); ++ ++ TRC((stderr,"rfbCopyPlane called\n")); ++ ++ box.x1 = dstx + pDst->x; ++ box.y1 = dsty + pDst->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDst->pScreen, &tmpRegion); ++ ++ rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty, plane); ++ ++ SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++ ++ return rgn; ++} ++ ++/* ++ * PolyPoint - find the smallest rectangle which encloses the points drawn ++ * (and clip). ++ */ ++ ++static void ++rfbPolyPoint (pDrawable, pGC, mode, npt, pts) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; /* Origin or Previous */ ++ int npt; ++ xPoint *pts; ++{ ++ int i; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyPoint called\n")); ++ ++ if (npt) { ++ int minX = pts[0].x, maxX = pts[0].x; ++ int minY = pts[0].y, maxY = pts[0].y; ++ ++ if (mode == CoordModePrevious) ++ { ++ int x = pts[0].x, y = pts[0].y; ++ ++ for (i = 1; i < npt; i++) { ++ x += pts[i].x; ++ y += pts[i].y; ++ if (x < minX) minX = x; ++ if (x > maxX) maxX = x; ++ if (y < minY) minY = y; ++ if (y > maxY) maxY = y; ++ } ++ } ++ else ++ { ++ for (i = 1; i < npt; i++) { ++ if (pts[i].x < minX) minX = pts[i].x; ++ if (pts[i].x > maxX) maxX = pts[i].x; ++ if (pts[i].y < minY) minY = pts[i].y; ++ if (pts[i].y > maxY) maxY = pts[i].y; ++ } ++ } ++ ++ box.x1 = minX + pDrawable->x; ++ box.y1 = minY + pDrawable->y; ++ box.x2 = maxX + 1 + pDrawable->x; ++ box.y2 = maxY + 1 + pDrawable->y; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); ++ ++ if (npt) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyLines - take the union of bounding boxes around each line (and clip). ++ */ ++ ++static void ++rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts) ++{ ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ int i, extra, nlines, lw; ++ int x1, x2, y1, y2; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolylines called\n")); ++ ++ if (npt) { ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ if (npt == 1) ++ { ++ nlines = 1; ++ rects = (xRectangle *)xalloc(sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolylines: xalloc failed\n"); ++ } ++ ++ rects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe here */ ++ rects[0].y = ppts[0].y - lw + pDrawable->y; ++ rects[0].width = 2*lw; ++ rects[0].height = 2*lw; ++ } ++ else ++ { ++ nlines = npt - 1; ++ rects = (xRectangle *)xalloc(nlines*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolylines: xalloc failed\n"); ++ } ++ ++ /* ++ * mitered joins can project quite a way from ++ * the line end; the 11 degree miter limit limits ++ * this extension to lw / (2 * tan(11/2)), rounded up ++ * and converted to int yields 6 * lw ++ */ ++ ++ if (pGC->joinStyle == JoinMiter) { ++ extra = 6 * lw; ++ } else { ++ extra = lw / 2; ++ } ++ ++ x1 = ppts[0].x + pDrawable->x; ++ y1 = ppts[0].y + pDrawable->y; ++ ++ for (i = 0; i < nlines; i++) { ++ if (mode == CoordModeOrigin) { ++ x2 = pDrawable->x + ppts[i+1].x; ++ y2 = pDrawable->y + ppts[i+1].y; ++ } else { ++ x2 = x1 + ppts[i+1].x; ++ y2 = y1 + ppts[i+1].y; ++ } ++ ++ if (x1 > x2) { ++ rects[i].x = x2 - extra; ++ rects[i].width = x1 - x2 + 1 + 2 * extra; ++ } else { ++ rects[i].x = x1 - extra; ++ rects[i].width = x2 - x1 + 1 + 2 * extra; ++ } ++ ++ if (y1 > y2) { ++ rects[i].y = y2 - extra; ++ rects[i].height = y1 - y2 + 1 + 2 * extra; ++ } else { ++ rects[i].y = y1 - extra; ++ rects[i].height = y2 - y1 + 1 + 2 * extra; ++ } ++ ++ x1 = x2; ++ y1 = y2; ++ } ++ } ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nlines, rects,CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); ++ ++ if (npt) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolySegment - take the union of bounding boxes around each segment (and ++ * clip). ++ */ ++ ++static void ++rfbPolySegment(pDrawable, pGC, nseg, segs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nseg; ++ xSegment *segs; ++{ ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ int i, extra, lw; ++ ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolySegment called\n")); ++ ++ if (nseg) { ++ rects = (xRectangle *)xalloc(nseg*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolySegment: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < nseg; i++) ++ { ++ if (segs[i].x1 > segs[i].x2) { ++ rects[i].x = segs[i].x2 - extra + pDrawable->x; ++ rects[i].width = segs[i].x1 - segs[i].x2 + 1 + 2 * extra; ++ } else { ++ rects[i].x = segs[i].x1 - extra + pDrawable->x; ++ rects[i].width = segs[i].x2 - segs[i].x1 + 1 + 2 * extra; ++ } ++ ++ if (segs[i].y1 > segs[i].y2) { ++ rects[i].y = segs[i].y2 - extra + pDrawable->y; ++ rects[i].height = segs[i].y1 - segs[i].y2 + 1 + 2 * extra; ++ } else { ++ rects[i].y = segs[i].y1 - extra + pDrawable->y; ++ rects[i].height = segs[i].y2 - segs[i].y1 + 1 + 2 * extra; ++ } ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nseg, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); ++ ++ if (nseg) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyRectangle (rectangle outlines) - take the union of bounding boxes ++ * around each line (and clip). ++ */ ++ ++static void ++rfbPolyRectangle(pDrawable, pGC, nrects, rects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *rects; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *regRects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyRectangle called\n")); ++ ++ if (nrects) { ++ regRects = (xRectangle *)xalloc(nrects*4*sizeof(xRectangle)); ++ if (!regRects) { ++ FatalError("rfbPolyRectangle: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < nrects; i++) ++ { ++ regRects[i*4].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4].width = rects[i].width + 1 + 2 * extra; ++ regRects[i*4].height = 1 + 2 * extra; ++ ++ regRects[i*4+1].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4+1].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4+1].width = 1 + 2 * extra; ++ regRects[i*4+1].height = rects[i].height + 1 + 2 * extra; ++ ++ regRects[i*4+2].x ++ = rects[i].x + rects[i].width - extra + pDrawable->x; ++ regRects[i*4+2].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4+2].width = 1 + 2 * extra; ++ regRects[i*4+2].height = rects[i].height + 1 + 2 * extra; ++ ++ regRects[i*4+3].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4+3].y ++ = rects[i].y + rects[i].height - extra + pDrawable->y; ++ regRects[i*4+3].width = rects[i].width + 1 + 2 * extra; ++ regRects[i*4+3].height = 1 + 2 * extra; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects*4, ++ regRects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)regRects); ++ } ++ ++ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); ++ ++ if (nrects) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyArc - take the union of bounding boxes around each arc (and clip). ++ * Bounding boxes assume each is a full circle / ellipse. ++ */ ++ ++static void ++rfbPolyArc(pDrawable, pGC, narcs, arcs) ++ DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int narcs; ++ xArc *arcs; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyArc called\n")); ++ ++ if (narcs) { ++ rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolyArc: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < narcs; i++) ++ { ++ rects[i].x = arcs[i].x - extra + pDrawable->x; ++ rects[i].y = arcs[i].y - extra + pDrawable->y; ++ rects[i].width = arcs[i].width + lw; ++ rects[i].height = arcs[i].height + lw; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); ++ ++ if (narcs) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * FillPolygon - take bounding box around polygon (and clip). ++ */ ++ ++static void ++rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts) ++ register DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int shape, mode; ++ int count; ++ DDXPointPtr pts; ++{ ++ int i; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbFillPolygon called\n")); ++ ++ if (count) { ++ int minX = pts[0].x, maxX = pts[0].x; ++ int minY = pts[0].y, maxY = pts[0].y; ++ ++ if (mode == CoordModePrevious) ++ { ++ int x = pts[0].x, y = pts[0].y; ++ ++ for (i = 1; i < count; i++) { ++ x += pts[i].x; ++ y += pts[i].y; ++ if (x < minX) minX = x; ++ if (x > maxX) maxX = x; ++ if (y < minY) minY = y; ++ if (y > maxY) maxY = y; ++ } ++ } ++ else ++ { ++ for (i = 1; i < count; i++) { ++ if (pts[i].x < minX) minX = pts[i].x; ++ if (pts[i].x > maxX) maxX = pts[i].x; ++ if (pts[i].y < minY) minY = pts[i].y; ++ if (pts[i].y > maxY) maxY = pts[i].y; ++ } ++ } ++ ++ box.x1 = minX + pDrawable->x; ++ box.y1 = minY + pDrawable->y; ++ box.x2 = maxX + 1 + pDrawable->x; ++ box.y2 = maxY + 1 + pDrawable->y; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyFillRect - take the union of the given rectangles (and clip). ++ */ ++ ++static void ++rfbPolyFillRect(pDrawable, pGC, nrects, rects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *rects; ++{ ++ RegionPtr tmpRegion; ++ xRectangle *regRects; ++ int i; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyFillRect called\n")); ++ ++ if (nrects) { ++ regRects = (xRectangle *)xalloc(nrects*sizeof(xRectangle)); ++ if (!regRects) { ++ FatalError("rfbPolyFillRect: xalloc failed\n"); ++ } ++ ++ for (i = 0; i < nrects; i++) { ++ regRects[i].x = rects[i].x + pDrawable->x; ++ regRects[i].y = rects[i].y + pDrawable->y; ++ regRects[i].width = rects[i].width; ++ regRects[i].height = rects[i].height; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects, regRects, ++ CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)regRects); ++ } ++ ++ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); ++ ++ if (nrects) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyFillArc - take the union of bounding boxes around each arc (and clip). ++ * Bounding boxes assume each is a full circle / ellipse. ++ */ ++ ++static void ++rfbPolyFillArc(pDrawable, pGC, narcs, arcs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int narcs; ++ xArc *arcs; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyFillArc called\n")); ++ ++ if (narcs) { ++ rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolyFillArc: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < narcs; i++) ++ { ++ rects[i].x = arcs[i].x - extra + pDrawable->x; ++ rects[i].y = arcs[i].y - extra + pDrawable->y; ++ rects[i].width = arcs[i].width + lw; ++ rects[i].height = arcs[i].height + lw; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); ++ ++ if (narcs) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * Get a rough bounding box around n characters of the given font. ++ */ ++ ++static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox) ++ DrawablePtr pDrawable; ++ FontPtr font; ++ int x, y, n; ++ BoxPtr pbox; ++{ ++ int maxAscent, maxDescent, maxCharWidth; ++ ++ if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent)) ++ maxAscent = FONTASCENT(font); ++ else ++ maxAscent = FONTMAXBOUNDS(font,ascent); ++ ++ if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent)) ++ maxDescent = FONTDESCENT(font); ++ else ++ maxDescent = FONTMAXBOUNDS(font,descent); ++ ++ if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth)) ++ maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing); ++ else ++ maxCharWidth = FONTMAXBOUNDS(font,characterWidth); ++ ++ pbox->x1 = pDrawable->x + x; ++ pbox->y1 = pDrawable->y + y - maxAscent; ++ pbox->x2 = pbox->x1 + maxCharWidth * n; ++ pbox->y2 = pbox->y1 + maxAscent + maxDescent; ++ ++ if (FONTMINBOUNDS(font,leftSideBearing) < 0) { ++ pbox->x1 += FONTMINBOUNDS(font,leftSideBearing); ++ } ++} ++ ++ ++/* ++ * PolyText8 - use rough bounding box. ++ */ ++ ++static int ++rfbPolyText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ int ret; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyText8 called '%.*s'\n",count,chars)); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++ return ret; ++} ++ ++/* ++ * PolyText16 - use rough bounding box. ++ */ ++ ++static int ++rfbPolyText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ int ret; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyText16 called\n")); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++ return ret; ++} ++ ++/* ++ * ImageText8 - use rough bounding box. ++ */ ++ ++static void ++rfbImageText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageText8 called '%.*s'\n",count,chars)); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * ImageText16 - use rough bounding box. ++ */ ++ ++static void ++rfbImageText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageText16 called\n")); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * ImageGlyphBlt - use rough bounding box. ++ */ ++ ++static void ++rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageGlyphBlt called\n")); ++ ++ if (nglyph) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); ++ ++ if (nglyph) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyGlyphBlt - use rough bounding box. ++ */ ++ ++static void ++rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyGlyphBlt called\n")); ++ ++ if (nglyph) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ if (nglyph) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PushPixels - be fairly safe - region modified is intersection of the given ++ * rectangle with the window clip region. ++ */ ++ ++static void ++rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y) ++ GCPtr pGC; ++ PixmapPtr pBitMap; ++ DrawablePtr pDrawable; ++ int w, h, x, y; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPushPixels called\n")); ++ ++ box.x1 = x + pDrawable->x; ++ box.y1 = y + pDrawable->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ ++ (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++#ifdef RENDER ++void ++rfbComposite( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height ++){ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ RegionRec tmpRegion; ++ BoxRec box; ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ ++ box.x1 = pDst->pDrawable->x + xDst; ++ box.y1 = pDst->pDrawable->y + yDst; ++ box.x2 = box.x1 + width; ++ box.y2 = box.y1 + height; ++ ++ REGION_INIT(pScreen, &tmpRegion, &box, 0); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion); ++ ++ ps->Composite = pVNC->Composite; ++ (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, ++ xMask, yMask, xDst, yDst, width, height); ++ ps->Composite = rfbComposite; ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ REGION_UNINIT(pScreen, &tmpRegion); ++} ++#endif /* RENDER */ ++ ++/****************************************************************************/ ++/* ++ * Other functions ++ */ ++/****************************************************************************/ ++ ++/* ++ * rfbCopyRegion. Args are src and dst regions plus a translation (dx,dy). ++ * Takes these args together with the existing modified region and possibly an ++ * existing copy region and translation. Produces a combined modified region ++ * plus copy region and translation. Note that the copy region is the ++ * destination of the copy. ++ * ++ * First we trim parts of src which are invalid (ie in the modified region). ++ * Then we see if there is any overlap between the src and the existing copy ++ * region. If not then the two copies cannot be combined, so we choose ++ * whichever is bigger to form the basis of a new copy, while the other copy is ++ * just done the hard way by being added to the modified region. So if the ++ * existing copy is bigger then we simply add the destination of the new copy ++ * to the modified region and we're done. If the new copy is bigger, we add ++ * the old copy region to the modified region and behave as though there is no ++ * existing copy region. ++ * ++ * At this stage we now know that either the two copies can be combined, or ++ * that there is no existing copy. We temporarily add both the existing copy ++ * region and dst to the modified region (this is the entire area of the screen ++ * affected in any way). Finally we calculate the new copy region, and remove ++ * it from the modified region. ++ * ++ * Note: ++ * 1. The src region is modified by this routine. ++ * 2. When the copy region is empty, copyDX and copyDY MUST be set to zero. ++ */ ++ ++static void ++rfbCopyRegion(pScreen, cl, src, dst, dx, dy) ++ ScreenPtr pScreen; ++ rfbClientPtr cl; ++ RegionPtr src; ++ RegionPtr dst; ++ int dx, dy; ++{ ++ RegionRec tmp; ++ ++ /* src = src - modifiedRegion */ ++ ++ REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion); ++ ++ if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ ++ REGION_NULL(pScreen, &tmp); ++ REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion); ++ ++ if (REGION_NOTEMPTY(pScreen, &tmp)) { ++ ++ /* if src and copyRegion overlap: ++ src = src intersect copyRegion */ ++ ++ REGION_COPY(pScreen, src, &tmp); ++ ++ } else { ++ ++ /* if no overlap, find bigger region */ ++ ++ int newArea = (((REGION_EXTENTS(pScreen,src))->x2 ++ - (REGION_EXTENTS(pScreen,src))->x1) ++ * ((REGION_EXTENTS(pScreen,src))->y2 ++ - (REGION_EXTENTS(pScreen,src))->y1)); ++ ++ int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2 ++ - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1) ++ * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2 ++ - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1)); ++ ++ if (oldArea > newArea) { ++ ++ /* existing copy is bigger: ++ modifiedRegion = modifiedRegion union dst ++ copyRegion = copyRegion - dst ++ return */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ dst); ++ REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion, ++ dst); ++ if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ } ++ return; ++ } ++ ++ /* new copy is bigger: ++ modifiedRegion = modifiedRegion union copyRegion ++ copyRegion = empty */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ REGION_EMPTY(pScreen, &cl->copyRegion); ++ cl->copyDX = cl->copyDY = 0; ++ } ++ } ++ ++ ++ /* modifiedRegion = modifiedRegion union dst union copyRegion */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst); ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ ++ /* copyRegion = T(src) intersect dst */ ++ ++ REGION_TRANSLATE(pScreen, src, dx, dy); ++ REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst); ++ ++ /* modifiedRegion = modifiedRegion - copyRegion */ ++ ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ ++ /* combine new translation T with existing translation */ ++ ++ if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ cl->copyDX += dx; ++ cl->copyDY += dy; ++ } else { ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ } ++} ++ ++ ++/* ++ * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer ++ * goes off. ++ */ ++ ++static CARD32 ++rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) ++{ ++ rfbClientPtr cl = (rfbClientPtr)arg; ++ ++ rfbSendFramebufferUpdate(cl->pScreen, cl); ++ ++ cl->deferredUpdateScheduled = FALSE; ++ return 0; ++} ++ ++ ++/* ++ * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro ++ * to schedule an update. ++ */ ++ ++static void ++rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl) ++{ ++ if (rfbDeferUpdateTime != 0) { ++ cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0, ++ rfbDeferUpdateTime, ++ rfbDeferredUpdateCallback, cl); ++ cl->deferredUpdateScheduled = TRUE; ++ } else { ++ rfbSendFramebufferUpdate(pScreen, cl); ++ } ++} ++ ++ ++/* ++ * PrintRegion is useful for debugging. ++ */ ++ ++#ifdef DEBUG ++static void ++PrintRegion(ScreenPtr pScreen, RegionPtr reg) ++{ ++ int nrects = REGION_NUM_RECTS(reg); ++ int i; ++ ++ ErrorF("Region num rects %d extents %d,%d %d,%d\n",nrects, ++ (REGION_EXTENTS(pScreen,reg))->x1, ++ (REGION_EXTENTS(pScreen,reg))->y1, ++ (REGION_EXTENTS(pScreen,reg))->x2, ++ (REGION_EXTENTS(pScreen,reg))->y2); ++ ++ for (i = 0; i < nrects; i++) { ++ ErrorF(" rect %d,%d %dx%d\n", ++ REGION_RECTS(reg)[i].x1, ++ REGION_RECTS(reg)[i].y1, ++ REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1, ++ REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1); ++ } ++} ++#endif +diff --git a/hw/dmx/vnc/hextile.c b/hw/dmx/vnc/hextile.c +new file mode 100644 +index 0000000..6017489 +--- /dev/null ++++ b/hw/dmx/vnc/hextile.c +@@ -0,0 +1,352 @@ ++/* ++ * hextile.c ++ * ++ * Routines to implement Hextile Encoding ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include "rfb.h" ++ ++static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h); ++static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h); ++static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h); ++ ++ ++/* ++ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingHextile(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingHextile); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingHextile]++; ++ cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader; ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ return sendHextiles8(cl, x, y, w, h); ++ case 16: ++ return sendHextiles16(cl, x, y, w, h); ++ case 32: ++ return sendHextiles32(cl, x, y, w, h); ++ } ++ ++ rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel); ++ return FALSE; ++} ++ ++ ++#define PUT_PIXEL8(pix) (pVNC->updateBuf[pVNC->ublen++] = (pix)) ++ ++#define PUT_PIXEL16(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1]) ++ ++#define PUT_PIXEL32(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[2], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[3]) ++ ++ ++#define DEFINE_SEND_HEXTILES(bpp) \ ++ \ ++ \ ++static Bool subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, \ ++ int h, CARD##bpp bg, \ ++ CARD##bpp fg, Bool mono); \ ++static void testColours##bpp(CARD##bpp *data, int size, Bool *mono, \ ++ Bool *solid, CARD##bpp *bg, CARD##bpp *fg); \ ++ \ ++ \ ++/* \ ++ * rfbSendHextiles \ ++ */ \ ++ \ ++static Bool \ ++sendHextiles##bpp(cl, rx, ry, rw, rh) \ ++ rfbClientPtr cl; \ ++ int rx, ry, rw, rh; \ ++{ \ ++ VNCSCREENPTR(cl->pScreen); \ ++ int x, y, w, h; \ ++ int startUblen; \ ++ unsigned char *fbptr; \ ++ CARD##bpp bg = 0, fg = 0, newBg, newFg; \ ++ Bool mono, solid; \ ++ Bool validBg = FALSE; \ ++ Bool validFg = FALSE; \ ++ CARD##bpp clientPixelData[16*16*(bpp/8)]; \ ++ \ ++ for (y = ry; y < ry+rh; y += 16) { \ ++ for (x = rx; x < rx+rw; x += 16) { \ ++ w = h = 16; \ ++ if (rx+rw - x < 16) \ ++ w = rx+rw - x; \ ++ if (ry+rh - y < 16) \ ++ h = ry+rh - y; \ ++ \ ++ if ((pVNC->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \ ++ if (!rfbSendUpdateBuf(cl)) \ ++ return FALSE; \ ++ } \ ++ \ ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) \ ++ + (x * (pVNC->bitsPerPixel / 8))); \ ++ \ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \ ++ &pVNC->rfbServerFormat, \ ++ &cl->format, fbptr, (char *)clientPixelData, \ ++ pVNC->paddedWidthInBytes, w, h, x, y); \ ++ \ ++ startUblen = pVNC->ublen; \ ++ pVNC->updateBuf[startUblen] = 0; \ ++ pVNC->ublen++; \ ++ \ ++ testColours##bpp(clientPixelData, w * h, \ ++ &mono, &solid, &newBg, &newFg); \ ++ \ ++ if (!validBg || (newBg != bg)) { \ ++ validBg = TRUE; \ ++ bg = newBg; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \ ++ PUT_PIXEL##bpp(bg); \ ++ } \ ++ \ ++ if (solid) { \ ++ cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \ ++ continue; \ ++ } \ ++ \ ++ pVNC->updateBuf[startUblen] |= rfbHextileAnySubrects; \ ++ \ ++ if (mono) { \ ++ if (!validFg || (newFg != fg)) { \ ++ validFg = TRUE; \ ++ fg = newFg; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \ ++ PUT_PIXEL##bpp(fg); \ ++ } \ ++ } else { \ ++ validFg = FALSE; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileSubrectsColoured; \ ++ } \ ++ \ ++ if (!subrectEncode##bpp(cl->pScreen, clientPixelData, w, h, bg, fg, mono)) { \ ++ /* encoding was too large, use raw */ \ ++ validBg = FALSE; \ ++ validFg = FALSE; \ ++ pVNC->ublen = startUblen; \ ++ pVNC->updateBuf[pVNC->ublen++] = rfbHextileRaw; \ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \ ++ &pVNC->rfbServerFormat, &cl->format, fbptr,\ ++ (char *)clientPixelData, \ ++ pVNC->paddedWidthInBytes, w, h, x, y); \ ++ \ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)clientPixelData,\ ++ w * h * (bpp/8)); \ ++ \ ++ pVNC->ublen += w * h * (bpp/8); \ ++ } \ ++ \ ++ cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \ ++ } \ ++ } \ ++ \ ++ return TRUE; \ ++} \ ++ \ ++ \ ++static Bool \ ++subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, int h, \ ++ CARD##bpp bg, CARD##bpp fg, Bool mono) \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp clientdata; \ ++ int x,y; \ ++ int i,j; \ ++ int hx=0,hy,vx=0,vy; \ ++ int hyflag; \ ++ CARD##bpp *seg; \ ++ CARD##bpp *line; \ ++ int hw,hh,vw,vh; \ ++ int thex,they,thew,theh; \ ++ int numsubs = 0; \ ++ int newLen; \ ++ int nSubrectsUblen; \ ++ \ ++ nSubrectsUblen = pVNC->ublen; \ ++ pVNC->ublen++; \ ++ \ ++ for (y=0; y 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/dmx/vnc/httpd.c b/hw/dmx/vnc/httpd.c +new file mode 100644 +index 0000000..863543a +--- /dev/null ++++ b/hw/dmx/vnc/httpd.c +@@ -0,0 +1,520 @@ ++/* ++ * httpd.c - a simple HTTP server ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef USE_LIBWRAP ++#define USE_LIBWRAP 0 ++#endif ++#if USE_LIBWRAP ++#include ++#endif ++ ++#include "rfb.h" ++ ++#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \ ++ "File Not Found\n" \ ++ "

File Not Found

\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 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(¶m_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, ++ "\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/dmx/vnc/kbdptr.c b/hw/dmx/vnc/kbdptr.c +new file mode 100644 +index 0000000..2610dbe +--- /dev/null ++++ b/hw/dmx/vnc/kbdptr.c +@@ -0,0 +1,446 @@ ++/* ++ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ * ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "rfb.h" ++#include "X11/X.h" ++#define NEED_EVENTS ++#include "X11/Xproto.h" ++#include "inputstr.h" ++#define XK_CYRILLIC ++#include ++#include ++#include "mi.h" ++#include "mipointer.h" ++ ++#if DMXVNC ++#include "../dmx.h" ++#include "../dmxinput.h" ++#endif ++ ++#if XFREE86VNC ++#if defined(XINPUT) ++# include "xf86Xinput.h" ++# define Enqueue(ev) xf86eqEnqueue(ev) ++#else ++# define Enqueue(ev) mieqEnqueue(ev) ++#endif ++#else /*XFREE86VNC*/ ++#if DMXVNC ++# define Enqueue(ev) dmxeqEnqueue(ev) ++#else ++# define Enqueue(ev) mieqEnqueue(ev) ++#endif ++#endif /*XFREE86VNC*/ ++ ++ ++#define KEY_IS_PRESSED(keycode) \ ++ (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7))) ++ ++static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper); ++ ++DeviceIntPtr kbdDevice = NULL; ++ ++#include "keyboard.h" ++ ++void ++vncSetKeyboardDevice(DeviceIntPtr kbd) ++{ ++ kbdDevice = kbd; ++} ++ ++/* ++ * Called when the rfbserver receives a rfbKeyEvent event from a client. ++ * Put an X keyboard event into the event queue. ++ */ ++void ++KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl) ++{ ++ xEvent ev, fake; ++ KeySymsPtr keySyms; ++ int i; ++ int keyCode = 0; ++ int freeIndex = -1; ++ unsigned long time; ++ Bool fakeShiftPress = FALSE; ++ Bool fakeShiftLRelease = FALSE; ++ Bool fakeShiftRRelease = FALSE; ++ Bool shiftMustBeReleased = FALSE; ++ Bool shiftMustBePressed = FALSE; ++ ++ if (!kbdDevice) return; ++ ++ keySyms = &kbdDevice->key->curKeySyms; ++ ++#ifdef CORBA ++ if (cl) { ++ CARD32 clientId = cl->sock; ++ ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, ++ 32, PropModeReplace, 1, (pointer)&clientId, TRUE); ++ } ++#endif ++ ++ if (down) { ++ ev.u.u.type = KeyPress; ++ } else { ++ ev.u.u.type = KeyRelease; ++ } ++ ++ /* NOTE: This is where it gets hairy for XFree86 servers. ++ * I think the best way to deal with this is invent a new protocol ++ * to send over the wire the remote keyboard type and correctly ++ * handle that as XINPUT extension device (we're part of the way ++ * there for that. ++ * ++ * Alan. ++ */ ++#if !XFREE86VNC ++ /* First check if it's one of our predefined keys. If so then we can make ++ some attempt at allowing an xmodmap inside a VNC desktop behave ++ something like you'd expect - e.g. if keys A & B are swapped over and ++ the VNC client sends an A, then map it to a B when generating the X ++ event. We don't attempt to do this for keycodes which we make up on the ++ fly because it's too hard... */ ++ ++ for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { ++ if (keySym == map[i]) { ++ keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY; ++ ++ if (map[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) { ++ ++ /* this keycode has more than one symbol associated with it, ++ so shift state is important */ ++ ++ if ((i % GLYPHS_PER_KEY) == 0) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ break; ++ } ++ } ++#endif ++ ++ if (!keyCode) { ++ ++ /* not one of our predefined keys - see if it's in the current keyboard ++ mapping (i.e. we've already allocated an extra keycode for it) */ ++ ++ if (keySyms->mapWidth < 2) { ++ ErrorF("KbdAddEvent: Sanity check failed - Keyboard mapping has " ++ "less than 2 keysyms per keycode (KeySym 0x%x)\n", ++ (unsigned) keySym); ++ return; ++ } ++ ++ for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) { ++ if (keySym == keySyms->map[i]) { ++ keyCode = MIN_KEY_CODE + i / keySyms->mapWidth; ++ ++ if (keySyms->map[(i / keySyms->mapWidth) ++ * keySyms->mapWidth + 1] != NoSymbol) { ++ ++ /* this keycode has more than one symbol associated with ++ it, so shift state is important */ ++ ++ if ((i % keySyms->mapWidth) == 0) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ break; ++ } ++ if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol) ++ && (i % keySyms->mapWidth) == 0) ++ { ++ freeIndex = i; ++ } ++ } ++ } ++ ++ if (!keyCode) { ++ KeySym lower, upper; ++ ++ /* we don't have an existing keycode - make one up on the fly and add ++ it to the keyboard mapping. Thanks to Vlad Harchev for pointing ++ out problems with non-ascii capitalisation. */ ++ ++ if (freeIndex == -1) { ++ ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n", ++ (unsigned) keySym); ++ return; ++ } ++ ++ keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth; ++ ++ vncXConvertCase(keySym, &lower, &upper); ++ ++ if (lower == upper) { ++ keySyms->map[freeIndex] = keySym; ++ ++ } else { ++ keySyms->map[freeIndex] = lower; ++ keySyms->map[freeIndex+1] = upper; ++ ++ if (keySym == lower) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ ++ SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient); ++ ++ ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n", ++ (unsigned) keySym, keyCode); ++ } ++ ++ time = GetTimeInMillis(); ++ ++ if (down) { ++ if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) { ++ fakeShiftPress = TRUE; ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) { ++ if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) { ++ fakeShiftLRelease = TRUE; ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) { ++ fakeShiftRRelease = TRUE; ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_R_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ } ++ } ++ ++ ev.u.u.detail = keyCode; ++ ev.u.keyButtonPointer.time = time; ++ Enqueue(&ev); ++ ++ if (fakeShiftPress) { ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (fakeShiftLRelease) { ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (fakeShiftRRelease) { ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_R_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++} ++ ++/* ++ * Called when the rfbserver receives a rfbPointerEvent event from a client. ++ * Put an X mouse event into the event queue. ++ */ ++void ++PtrAddEvent(buttonMask, x, y, cl) ++ int buttonMask; ++ int x; ++ int y; ++ rfbClientPtr cl; ++{ ++ xEvent ev; ++ int i; ++ unsigned long time; ++ static int oldButtonMask = 0; ++ ++#ifdef CORBA ++ if (cl) { ++ CARD32 clientId = cl->sock; ++ ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, ++ 32, PropModeReplace, 1, (pointer)&clientId, TRUE); ++ } ++#endif ++ ++ time = GetTimeInMillis(); ++ ++#if DMXVNC ++ dmxCoreMotion(x, y, 0, DMX_NO_BLOCK); ++#else ++ miPointerAbsoluteCursor(x, y, time); ++#endif ++ ++ for (i = 0; i < 5; i++) { ++ if ((buttonMask ^ oldButtonMask) & (1<key->down[i] != 0) { ++ for (j = 0; j < 8; j++) { ++ if (kbdDevice->key->down[i] & (1 << j)) { ++ ev.u.u.type = KeyRelease; ++ ev.u.u.detail = (i << 3) | j; ++ ev.u.keyButtonPointer.time = time; ++ Enqueue(&ev); ++ } ++ } ++ } ++ } ++} ++ ++ ++/* copied from Xlib source */ ++ ++static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper) ++{ ++ *lower = sym; ++ *upper = sym; ++ switch(sym >> 8) { ++ case 0: /* Latin 1 */ ++ if ((sym >= XK_A) && (sym <= XK_Z)) ++ *lower += (XK_a - XK_A); ++ else if ((sym >= XK_a) && (sym <= XK_z)) ++ *upper -= (XK_a - XK_A); ++ else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) ++ *lower += (XK_agrave - XK_Agrave); ++ else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) ++ *upper -= (XK_agrave - XK_Agrave); ++ else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) ++ *lower += (XK_oslash - XK_Ooblique); ++ else if ((sym >= XK_oslash) && (sym <= XK_thorn)) ++ *upper -= (XK_oslash - XK_Ooblique); ++ break; ++ case 1: /* Latin 2 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym == XK_Aogonek) ++ *lower = XK_aogonek; ++ else if (sym >= XK_Lstroke && sym <= XK_Sacute) ++ *lower += (XK_lstroke - XK_Lstroke); ++ else if (sym >= XK_Scaron && sym <= XK_Zacute) ++ *lower += (XK_scaron - XK_Scaron); ++ else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) ++ *lower += (XK_zcaron - XK_Zcaron); ++ else if (sym == XK_aogonek) ++ *upper = XK_Aogonek; ++ else if (sym >= XK_lstroke && sym <= XK_sacute) ++ *upper -= (XK_lstroke - XK_Lstroke); ++ else if (sym >= XK_scaron && sym <= XK_zacute) ++ *upper -= (XK_scaron - XK_Scaron); ++ else if (sym >= XK_zcaron && sym <= XK_zabovedot) ++ *upper -= (XK_zcaron - XK_Zcaron); ++ else if (sym >= XK_Racute && sym <= XK_Tcedilla) ++ *lower += (XK_racute - XK_Racute); ++ else if (sym >= XK_racute && sym <= XK_tcedilla) ++ *upper -= (XK_racute - XK_Racute); ++ break; ++ case 2: /* Latin 3 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) ++ *lower += (XK_hstroke - XK_Hstroke); ++ else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) ++ *lower += (XK_gbreve - XK_Gbreve); ++ else if (sym >= XK_hstroke && sym <= XK_hcircumflex) ++ *upper -= (XK_hstroke - XK_Hstroke); ++ else if (sym >= XK_gbreve && sym <= XK_jcircumflex) ++ *upper -= (XK_gbreve - XK_Gbreve); ++ else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) ++ *lower += (XK_cabovedot - XK_Cabovedot); ++ else if (sym >= XK_cabovedot && sym <= XK_scircumflex) ++ *upper -= (XK_cabovedot - XK_Cabovedot); ++ break; ++ case 3: /* Latin 4 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Rcedilla && sym <= XK_Tslash) ++ *lower += (XK_rcedilla - XK_Rcedilla); ++ else if (sym >= XK_rcedilla && sym <= XK_tslash) ++ *upper -= (XK_rcedilla - XK_Rcedilla); ++ else if (sym == XK_ENG) ++ *lower = XK_eng; ++ else if (sym == XK_eng) ++ *upper = XK_ENG; ++ else if (sym >= XK_Amacron && sym <= XK_Umacron) ++ *lower += (XK_amacron - XK_Amacron); ++ else if (sym >= XK_amacron && sym <= XK_umacron) ++ *upper -= (XK_amacron - XK_Amacron); ++ break; ++ case 6: /* Cyrillic */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) ++ *lower -= (XK_Serbian_DJE - XK_Serbian_dje); ++ else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) ++ *upper += (XK_Serbian_DJE - XK_Serbian_dje); ++ else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) ++ *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); ++ else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) ++ *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); ++ break; ++ case 7: /* Greek */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) ++ *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); ++ else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && ++ sym != XK_Greek_iotaaccentdieresis && ++ sym != XK_Greek_upsilonaccentdieresis) ++ *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); ++ else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) ++ *lower += (XK_Greek_alpha - XK_Greek_ALPHA); ++ else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && ++ sym != XK_Greek_finalsmallsigma) ++ *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); ++ break; ++ } ++} +diff --git a/hw/dmx/vnc/keyboard.h b/hw/dmx/vnc/keyboard.h +new file mode 100644 +index 0000000..ab5b1b3 +--- /dev/null ++++ b/hw/dmx/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 ++ */ ++ ++#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/dmx/vnc/loginauth.c b/hw/dmx/vnc/loginauth.c +new file mode 100644 +index 0000000..0106737 +--- /dev/null ++++ b/hw/dmx/vnc/loginauth.c +@@ -0,0 +1,142 @@ ++/* ++ * loginauth.c - deal with login-style Unix authentication. ++ * ++ * This file implements the UnixLogin authentication protocol when setting up ++ * an RFB connection. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef HAVE_DMX_CONFIG_H ++#include ++#endif ++ ++#ifdef linux ++#include /* XXX xserver has a shadow.h file too */ ++#endif ++#include ++#include ++#include ++#include ++#include ++#include "rfb.h" ++ ++void rfbLoginAuthProcessClientMessage(rfbClientPtr cl) ++{ ++ int n1 = 0, n2 = 0; ++ CARD32 loginLen, passwdLen, authResult; ++ char *loginBuf, *passwdBuf; ++ struct passwd *ps; ++ char *encPasswd1, *encPasswd2; ++ Bool ok; ++ ++ if ((n1 = ReadExact(cl->sock, (char *)&loginLen, ++ sizeof(loginLen))) <= 0 || ++ (n2 = ReadExact(cl->sock, (char *)&passwdLen, ++ sizeof(passwdLen))) <= 0) { ++ if (n1 != 0 || n2 != 0) ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ loginLen = Swap32IfLE(loginLen); ++ passwdLen = Swap32IfLE(passwdLen); ++ loginBuf = (char *)xalloc(loginLen + 1); ++ passwdBuf = (char *)xalloc(passwdLen + 1); ++ ++ n1 = n2 = 0; ++ if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 || ++ (n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) { ++ if (n1 != 0 || n2 != 0) ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ loginBuf[loginLen] = '\0'; ++ passwdBuf[passwdLen] = '\0'; ++ ++ encPasswd1 = encPasswd2 = NULL; ++ ++ ps = getpwnam(loginBuf); ++ if (ps == NULL) { ++ rfbLog("rfbLoginAuthProcessClientMessage: " ++ "Cannot get password file entry for \"%s\"\n", loginBuf); ++ } else { ++ encPasswd1 = ps->pw_passwd; ++#ifdef linux ++ if (strlen(ps->pw_passwd) == 1) { ++ struct spwd *sps; ++ ++ sps = getspnam(loginBuf); ++ if (sps == NULL) { ++ rfbLog("rfbLoginAuthProcessClientMessage:" ++ " getspnam() failed for user \"%s\"\n", loginBuf); ++ } else { ++ encPasswd1 = sps->sp_pwdp; ++ } ++ } ++#endif ++ encPasswd2 = crypt(passwdBuf, encPasswd1); ++ memset(passwdBuf, 0, strlen(passwdBuf)); ++ } ++ ++ ok = FALSE; ++ if (encPasswd1 != NULL && encPasswd2 != NULL) { ++ if (strcmp(encPasswd1, encPasswd2) == 0) ++ ok = TRUE; ++ } ++ ++ if (!ok) { ++ rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n", ++ cl->host); ++ ++ if (rfbAuthConsiderBlocking(cl)) { ++ authResult = Swap32IfLE(rfbVncAuthTooMany); ++ } else { ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ } ++ ++ if (WriteExact(cl->sock, (char *)&authResult, ++ sizeof(authResult)) < 0) { ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ rfbAuthUnblock(cl); ++ ++ cl->login = strdup(loginBuf); ++ rfbLog("Login-style authentication passed for user %s at %s\n", ++ cl->login, cl->host); ++ ++ authResult = Swap32IfLE(rfbVncAuthOK); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) { ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ cl->state = RFB_INITIALISATION; ++} ++ +diff --git a/hw/dmx/vnc/rdp.c b/hw/dmx/vnc/rdp.c +new file mode 100644 +index 0000000..c7d4f98 +--- /dev/null ++++ b/hw/dmx/vnc/rdp.c +@@ -0,0 +1,145 @@ ++/* ++ * Copyright (C) 2004 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rfb.h" ++ ++typedef struct rdpClientRec { ++ ScreenPtr pScreen; ++} rdpClientRec, *rdpClientPtr; ++ ++typedef struct rdpInRec { ++ char version; ++ char pad; ++ short length; ++ char hdrlen; ++ unsigned char pdu; ++} rdpInRec, *rdpInPtr; ++ ++static void ++rdpCloseSock(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ close(pVNC->rdpListenSock); ++ RemoveEnabledDevice(pVNC->rdpListenSock); ++ pVNC->rdpListenSock = -1; ++} ++ ++/* ++ * rdpNewClient is called when a new connection has been made by whatever ++ * means. ++ */ ++ ++static rdpClientPtr ++rdpNewClient(ScreenPtr pScreen, int sock) ++{ ++ rdpInRec in; ++ rdpClientPtr cl; ++ BoxRec box; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(struct sockaddr_in); ++ VNCSCREENPTR(pScreen); ++ int i; ++ ++ cl = (rdpClientPtr)xalloc(sizeof(rdpClientRec)); ++ ++ cl->pScreen = pScreen; ++ ++ in.version = 3; ++ in.pad = 0; ++ in.length = 0x600; /* big endian */ ++ in.hdrlen = 0x00; ++ in.pdu = 0xCC; ++ ++ if (WriteExact(sock, (char *)&in, sizeof(rdpInRec)) < 0) { ++ rfbLogPerror("rfbNewClient: write"); ++ rdpCloseSock(pScreen); ++ return NULL; ++ } ++ ++ return cl; ++} ++/* ++ * rdpCheckFds is called from ProcessInputEvents to check for input on the ++ * HTTP socket(s). If there is input to process, rdpProcessInput is called. ++ */ ++ ++static void ++rdpCheckFds(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ int nfds; ++ fd_set fds; ++ struct timeval tv; ++ struct sockaddr_in addr; ++ int sock; ++ const int one =1; ++ SOCKLEN_T addrlen = sizeof(addr); ++ ++ FD_ZERO(&fds); ++ FD_SET(pVNC->rdpListenSock, &fds); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ nfds = select(pVNC->rdpListenSock + 1, &fds, NULL, NULL, &tv); ++ if (nfds == 0) { ++ return; ++ } ++ if (nfds < 0) { ++ if (errno != EINTR) ++ rfbLogPerror("httpCheckFds: select"); ++ return; ++ } ++ ++ if (pVNC->rdpListenSock != -1 && FD_ISSET(pVNC->rdpListenSock, &fds)) { ++ ++ if ((sock = accept(pVNC->rdpListenSock, ++ (struct sockaddr *)&addr, &addrlen)) < 0) { ++ rfbLogPerror("rdpCheckFds: accept"); ++ return; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("rdpCheckFds: fcntl"); ++ close(sock); ++ return; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("rdpCheckFds: setsockopt"); ++ close(sock); ++ return; ++ } ++ ++ rfbLog("\n"); ++ ++ rfbLog("Got RDP connection from client %s\n", inet_ntoa(addr.sin_addr)); ++ ++ AddEnabledDevice(sock); ++ ++ rdpNewClient(pScreen, sock); ++ } ++} +diff --git a/hw/dmx/vnc/rfb.h b/hw/dmx/vnc/rfb.h +new file mode 100644 +index 0000000..6e86abb +--- /dev/null ++++ b/hw/dmx/vnc/rfb.h +@@ -0,0 +1,697 @@ ++/* ++ * rfb.h - header file for RFB DDX implementation. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000-2004 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if HAVE_DMX_CONFIG_H ++#include "dmx-config.h" ++#endif ++ ++#include ++#include "scrnintstr.h" ++#include "colormapst.h" ++#include "dixstruct.h" ++#include "gcstruct.h" ++#include "regionstr.h" ++#include "windowstr.h" ++#include "dixfontstr.h" ++#include "picture.h" ++#include "glyphstr.h" ++#if 0 /* && !XFREE86VNC */ ++#include "osdep.h" ++#endif ++#include ++#include ++/* ++ * HTTP_BUF_SIZE for http transfers ++ */ ++#define HTTP_BUF_SIZE 32768 ++/* ++ * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the ++ * framebuffer. So for a max screen width of say 2K with 32-bit pixels this ++ * means 8K minimum. ++ */ ++#define UPDATE_BUF_SIZE 30000 ++#ifdef RENDER ++#include "picturestr.h" ++#endif ++#define _VNC_SERVER ++#include "vncint.h" ++ ++#if defined(sun) || defined(hpux) ++#define SOCKLEN_T int ++#else ++#define SOCKLEN_T socklen_t ++#endif ++ ++/* It's a good idea to keep these values a bit greater than required. */ ++#define MAX_ENCODINGS 10 ++#define MAX_SECURITY_TYPES 4 ++#define MAX_TUNNELING_CAPS 16 ++#define MAX_AUTH_CAPS 16 ++ ++#define VNCSCREENPTR(ptr) \ ++ vncScreenPtr pVNC = VNCPTR(ptr) ++ ++/* ++ * Per-screen (framebuffer) structure. There is only one of these, since we ++ * don't allow the X server to have multiple screens. ++ */ ++ ++typedef struct ++{ ++ int rfbPort; ++ int rdpPort; ++ int udpPort; ++ int rfbListenSock; ++ int rdpListenSock; ++ int udpSock; ++ int httpPort; ++ int httpListenSock; ++ int httpSock; ++ char * httpDir; ++ char buf[HTTP_BUF_SIZE]; ++ Bool udpSockConnected; ++ char * rfbAuthPasswdFile; ++ size_t buf_filled; ++ int maxFd; ++ fd_set allFds; ++ Bool useGetImage; ++ Bool noCursor; ++ Bool rfbAlwaysShared; ++ Bool rfbNeverShared; ++ Bool rfbDontDisconnect; ++ Bool rfbUserAccept; ++ Bool rfbViewOnly; ++ ColormapPtr savedColormap; ++ ColormapPtr rfbInstalledColormap; ++ rfbPixelFormat rfbServerFormat; ++ Bool rfbAuthTooManyTries; ++ int rfbAuthTries; ++ Bool loginAuthEnabled; ++ struct in_addr interface; ++ OsTimerPtr timer; ++ char updateBuf[UPDATE_BUF_SIZE]; ++ int ublen; ++ int width; ++ int paddedWidthInBytes; ++ int height; ++ int depth; ++ int bitsPerPixel; ++ int sizeInBytes; ++ unsigned char *pfbMemory; ++ Pixel blackPixel; ++ Pixel whitePixel; ++ ++ /* The following two members are used to minimise the amount of unnecessary ++ drawing caused by cursor movement. Whenever any drawing affects the ++ part of the screen where the cursor is, the cursor is removed first and ++ then the drawing is done (this is what the sprite routines test for). ++ Afterwards, however, we do not replace the cursor, even when the cursor ++ is logically being moved across the screen. We only draw the cursor ++ again just as we are about to send the client a framebuffer update. ++ ++ We need to be careful when removing and drawing the cursor because of ++ their relationship with the normal drawing routines. The drawing ++ routines can invoke the cursor routines, but also the cursor routines ++ themselves end up invoking drawing routines. ++ ++ Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by ++ doing a CopyArea from a pixmap to the screen, where the pixmap contains ++ the saved contents of the screen under the cursor. Before doing this, ++ however, we set cursorIsDrawn to FALSE. Then, when CopyArea is called, ++ it sees that cursorIsDrawn is FALSE and so doesn't feel the need to ++ (recursively!) remove the cursor before doing it. ++ ++ Putting up the cursor (rfbSpriteRestoreCursor) involves a call to ++ PushPixels. While this is happening, cursorIsDrawn must be FALSE so ++ that PushPixels doesn't think it has to remove the cursor first. ++ Obviously cursorIsDrawn is set to TRUE afterwards. ++ ++ Another problem we face is that drawing routines sometimes cause a ++ framebuffer update to be sent to the RFB client. When the RFB client is ++ already waiting for a framebuffer update and some drawing to the ++ framebuffer then happens, the drawing routine sees that the client is ++ ready, so it calls rfbSendFramebufferUpdate. If the cursor is not drawn ++ at this stage, it must be put up, and so rfbSpriteRestoreCursor is ++ called. However, if the original drawing routine was actually called ++ from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't ++ want this to happen. So both the cursor routines set ++ dontSendFramebufferUpdate to TRUE, and all the drawing routines check ++ this before calling rfbSendFramebufferUpdate. */ ++ ++ Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ ++ Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the ++ cursor */ ++ ++ /* wrapped screen functions */ ++ ++ CloseScreenProcPtr CloseScreen; ++ CreateGCProcPtr CreateGC; ++ PaintWindowBackgroundProcPtr PaintWindowBackground; ++ PaintWindowBorderProcPtr PaintWindowBorder; ++ CopyWindowProcPtr CopyWindow; ++ ClearToBackgroundProcPtr ClearToBackground; ++ RestoreAreasProcPtr RestoreAreas; ++ ScreenWakeupHandlerProcPtr WakeupHandler; ++#ifdef CHROMIUM ++ RealizeWindowProcPtr RealizeWindow; ++ UnrealizeWindowProcPtr UnrealizeWindow; ++ DestroyWindowProcPtr DestroyWindow; ++ ResizeWindowProcPtr ResizeWindow; ++ PositionWindowProcPtr PositionWindow; ++ ClipNotifyProcPtr ClipNotify; ++#endif ++#ifdef RENDER ++ CompositeProcPtr Composite; ++#endif ++ ++} rfbScreenInfo, *rfbScreenInfoPtr; ++ ++ ++/* ++ * rfbTranslateFnType is the type of translation functions. ++ */ ++ ++struct rfbClientRec; ++typedef void (*rfbTranslateFnType)(ScreenPtr pScreen, ++ char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y); ++ ++ ++/* ++ * Per-client structure. ++ */ ++ ++typedef struct rfbClientRec { ++ int sock; ++ char *host; ++ char *login; ++ ++ int protocol_minor_ver; /* RFB protocol minor version in use. */ ++ Bool protocol_tightvnc; /* TightVNC protocol extensions enabled */ ++ ++ /* Possible client states: */ ++ ++ enum { ++ RFB_PROTOCOL_VERSION, /* establishing protocol version */ ++ RFB_SECURITY_TYPE, /* negotiating security (RFB v.3.7) */ ++ RFB_TUNNELING_TYPE, /* establishing tunneling (RFB v.3.7t) */ ++ RFB_AUTH_TYPE, /* negotiating authentication (RFB v.3.7t) */ ++ RFB_AUTHENTICATION, /* authenticating (VNC authentication) */ ++ RFB_INITIALISATION, /* sending initialisation messages */ ++ RFB_NORMAL /* normal protocol messages */ ++ } state; ++ ++ Bool viewOnly; /* Do not accept input from this client. */ ++ ++ Bool reverseConnection; ++ ++ Bool readyForSetColourMapEntries; ++ ++ Bool useCopyRect; ++ int preferredEncoding; ++ int correMaxWidth, correMaxHeight; ++ ++ /* The list of security types sent to this client (protocol 3.7). ++ Note that the first entry is the number of list items following. */ ++ ++ CARD8 securityTypes[MAX_SECURITY_TYPES + 1]; ++ ++ /* Lists of capability codes sent to clients. We remember these ++ lists to restrict clients from choosing those tunneling and ++ authentication types that were not advertised. */ ++ ++ int nAuthCaps; ++ CARD32 authCaps[MAX_AUTH_CAPS]; ++ ++ /* This is not useful while we don't support tunneling: ++ int nTunnelingCaps; ++ CARD32 tunnelingCaps[MAX_TUNNELING_CAPS]; */ ++ ++ /* The following member is only used during VNC authentication */ ++ ++ CARD8 authChallenge[CHALLENGESIZE]; ++ ++ /* The following members represent the update needed to get the client's ++ framebuffer from its present state to the current state of our ++ framebuffer. ++ ++ If the client does not accept CopyRect encoding then the update is ++ simply represented as the region of the screen which has been modified ++ (modifiedRegion). ++ ++ If the client does accept CopyRect encoding, then the update consists of ++ two parts. First we have a single copy from one region of the screen to ++ another (the destination of the copy is copyRegion), and second we have ++ the region of the screen which has been modified in some other way ++ (modifiedRegion). ++ ++ Although the copy is of a single region, this region may have many ++ rectangles. When sending an update, the copyRegion is always sent ++ before the modifiedRegion. This is because the modifiedRegion may ++ overlap parts of the screen which are in the source of the copy. ++ ++ In fact during normal processing, the modifiedRegion may even overlap ++ the destination copyRegion. Just before an update is sent we remove ++ from the copyRegion anything in the modifiedRegion. */ ++ ++ RegionRec copyRegion; /* the destination region of the copy */ ++ int copyDX, copyDY; /* the translation by which the copy happens */ ++ ++ RegionRec modifiedRegion; /* the region of the screen modified in any ++ other way */ ++ ++ /* As part of the FramebufferUpdateRequest, a client can express interest ++ in a subrectangle of the whole framebuffer. This is stored in the ++ requestedRegion member. In the normal case this is the whole ++ framebuffer if the client is ready, empty if it's not. */ ++ ++ RegionRec requestedRegion; ++ ++ /* The following members represent the state of the "deferred update" timer ++ - when the framebuffer is modified and the client is ready, in most ++ cases it is more efficient to defer sending the update by a few ++ milliseconds so that several changes to the framebuffer can be combined ++ into a single update. */ ++ ++ Bool deferredUpdateScheduled; ++ OsTimerPtr deferredUpdateTimer; ++ ++ /* translateFn points to the translation function which is used to copy ++ and translate a rectangle from the framebuffer to an output buffer. */ ++ ++ rfbTranslateFnType translateFn; ++ ++ char *translateLookupTable; ++ ++ rfbPixelFormat format; ++ ++ /* statistics */ ++ ++ int rfbBytesSent[MAX_ENCODINGS]; ++ int rfbRectanglesSent[MAX_ENCODINGS]; ++ int rfbLastRectMarkersSent; ++ int rfbLastRectBytesSent; ++ int rfbCursorShapeBytesSent; ++ int rfbCursorShapeUpdatesSent; ++ int rfbCursorPosBytesSent; ++ int rfbCursorPosUpdatesSent; ++ int rfbFramebufferUpdateMessagesSent; ++ int rfbRawBytesEquivalent; ++ int rfbKeyEventsRcvd; ++ int rfbPointerEventsRcvd; ++ ++ /* zlib encoding -- necessary compression state info per client */ ++ ++ struct z_stream_s compStream; ++ Bool compStreamInited; ++ ++ CARD32 zlibCompressLevel; ++ ++ /* tight encoding -- preserve zlib streams' state for each client */ ++ ++ z_stream zsStruct[4]; ++ Bool zsActive[4]; ++ int zsLevel[4]; ++ int tightCompressLevel; ++ int tightQualityLevel; ++ ++ Bool enableLastRectEncoding; /* client supports LastRect encoding */ ++ Bool enableCursorShapeUpdates; /* client supports cursor shape updates */ ++ Bool enableCursorPosUpdates; /* client supports PointerPos updates */ ++#ifdef CHROMIUM ++ Bool enableChromiumEncoding; /* client supports Chromium encoding */ ++#endif ++ Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */ ++ Bool cursorWasChanged; /* cursor shape update should be sent */ ++ Bool cursorWasMoved; /* cursor position update should be sent */ ++ ++ int cursorX, cursorY; /* client's cursor position */ ++ ++ struct rfbClientRec *next; ++ ++ ScreenPtr pScreen; ++ int userAccepted; ++ ++#ifdef CHROMIUM ++ unsigned int chromium_port; ++#endif ++} rfbClientRec, *rfbClientPtr; ++ ++#ifdef CHROMIUM ++typedef struct CRWindowTable { ++ unsigned long CRwinId; ++ unsigned long XwinId; ++ BoxPtr clipRects; ++ int numRects; ++ struct CRWindowTable *next; ++} CRWindowTable, *CRWindowTablePtr; ++ ++extern struct CRWindowTable *windowTable; ++#endif ++ ++/* ++ * This macro is used to test whether there is a framebuffer update needing to ++ * be sent to the client. ++ */ ++ ++#define FB_UPDATE_PENDING(cl) \ ++ ((!(cl)->enableCursorShapeUpdates && !pVNC->cursorIsDrawn) || \ ++ ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \ ++ ((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) || \ ++ REGION_NOTEMPTY(((cl)->pScreen),&(cl)->copyRegion) || \ ++ REGION_NOTEMPTY(((cl)->pScreen),&(cl)->modifiedRegion)) ++ ++/* ++ * This macro creates an empty region (ie. a region with no areas) if it is ++ * given a rectangle with a width or height of zero. It appears that ++ * REGION_INTERSECT does not quite do the right thing with zero-width ++ * rectangles, but it should with completely empty regions. ++ */ ++ ++#define SAFE_REGION_INIT(pscreen, preg, rect, size) \ ++{ \ ++ if ( ( (rect) ) && \ ++ ( ( (rect)->x2 == (rect)->x1 ) || \ ++ ( (rect)->y2 == (rect)->y1 ) ) ) { \ ++ REGION_NULL( (pscreen), (preg) ); \ ++ } else { \ ++ REGION_INIT( (pscreen), (preg), (rect), (size) ); \ ++ } \ ++} ++ ++/* ++ * An rfbGCRec is where we store the pointers to the original GC funcs and ops ++ * which we wrap (NULL means not wrapped). ++ */ ++ ++typedef struct { ++ GCFuncs *wrapFuncs; ++ GCOps *wrapOps; ++} rfbGCRec, *rfbGCPtr; ++ ++ ++ ++/* ++ * Macros for endian swapping. ++ */ ++ ++#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) ++ ++#define Swap32(l) (((l) >> 24) | \ ++ (((l) & 0x00ff0000) >> 8) | \ ++ (((l) & 0x0000ff00) << 8) | \ ++ ((l) << 24)) ++ ++static const int rfbEndianTest = 1; ++ ++#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s)) ++ ++#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l)) ++ ++ ++/* ++ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.130). ++ * Normally, using macros is no good, but this macro saves us from ++ * writing constants twice -- it constructs signature names from codes. ++ * Note that "code_sym" argument should be a single symbol, not an expression. ++ */ ++ ++#define SetCapInfo(cap_ptr, code_sym, vendor) \ ++{ \ ++ rfbCapabilityInfo *pcap; \ ++ pcap = (cap_ptr); \ ++ pcap->code = Swap32IfLE(code_sym); \ ++ memcpy(pcap->vendorSignature, (vendor), \ ++ sz_rfbCapabilityInfoVendor); \ ++ memcpy(pcap->nameSignature, sig_##code_sym, \ ++ sz_rfbCapabilityInfoName); \ ++} ++ ++ ++/* init.c */ ++ ++extern char *desktopName; ++extern char rfbThisHost[]; ++extern Atom VNC_LAST_CLIENT_ID; ++ ++extern rfbScreenInfo rfbScreen; ++extern int rfbGCIndex; ++ ++extern int inetdSock; ++ ++extern int rfbBitsPerPixel(int depth); ++extern void rfbLog(char *format, ...); ++extern void rfbLogPerror(char *str); ++ ++ ++/* sockets.c */ ++ ++extern int rfbMaxClientWait; ++ ++extern Bool rfbInitSockets(ScreenPtr pScreen); ++extern void rfbDisconnectUDPSock(ScreenPtr pScreen); ++extern void rfbCloseSock(ScreenPtr pScreen, int sock); ++extern void rfbCheckFds(ScreenPtr pScreen); ++extern void rfbWaitForClient(int sock); ++extern int rfbConnect(ScreenPtr pScreen, char *host, int port); ++ ++extern int ReadExact(int sock, char *buf, int len); ++extern int WriteExact(int sock, char *buf, int len); ++extern int ListenOnTCPPort(ScreenPtr pScreen, int port); ++extern int ListenOnUDPPort(ScreenPtr pScreen, int port); ++extern int ConnectToTcpAddr(char *host, int port); ++ ++ ++/* cmap.c */ ++ ++ ++extern int rfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps); ++extern void rfbInstallColormap(ColormapPtr pmap); ++extern void rfbUninstallColormap(ColormapPtr pmap); ++extern void rfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs); ++ ++ ++/* draw.c */ ++ ++extern int rfbDeferUpdateTime; ++ ++extern void ++rfbComposite( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height ++); ++ ++extern void rfbGlyphs( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlistInit, ++ GlyphListPtr listInit, ++ GlyphPtr *glyphsInit ++); ++extern Bool rfbCloseScreen(int,ScreenPtr); ++extern Bool rfbCreateGC(GCPtr); ++extern void rfbPaintWindowBackground(WindowPtr, RegionPtr, int what); ++extern void rfbPaintWindowBorder(WindowPtr, RegionPtr, int what); ++extern void rfbCopyWindow(WindowPtr, DDXPointRec, RegionPtr); ++#ifdef CHROMIUM ++extern Bool rfbRealizeWindow(WindowPtr); ++extern Bool rfbUnrealizeWindow(WindowPtr); ++extern Bool rfbDestroyWindow(WindowPtr); ++extern void rfbResizeWindow(WindowPtr, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib); ++extern Bool rfbPositionWindow(WindowPtr, int x, int y); ++extern void rfbClipNotify(WindowPtr, int x, int y); ++#endif ++extern void rfbClearToBackground(WindowPtr, int x, int y, int w, ++ int h, Bool generateExposures); ++extern RegionPtr rfbRestoreAreas(WindowPtr, RegionPtr); ++ ++ ++/* cutpaste.c */ ++ ++extern void rfbSetXCutText(char *str, int len); ++extern void rfbGotXCutText(char *str, int len); ++ ++ ++/* kbdptr.c */ ++ ++extern Bool compatibleKbd; ++extern unsigned char ptrAcceleration; ++ ++extern void PtrDeviceInit(void); ++extern void PtrDeviceOn(DeviceIntPtr pDev); ++extern void PtrDeviceOff(void); ++extern void PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl); ++extern void PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl); ++ ++extern void KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap); ++extern void KbdDeviceOn(void); ++extern void KbdDeviceOff(void); ++extern void KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl); ++extern void KbdReleaseAllKeys(void); ++ ++ ++/* rfbserver.c */ ++ ++ ++extern rfbClientPtr rfbClientHead; ++extern rfbClientPtr pointerClient; ++ ++extern void rfbUserAllow(int sock, int accept); ++ ++extern void rfbNewClientConnection(ScreenPtr pScreen, int sock); ++extern rfbClientPtr rfbReverseConnection(ScreenPtr pScreen, char *host, int port); ++extern void rfbRootPropertyChange(ScreenPtr pScreen); ++extern void rfbClientConnectionGone(int sock); ++extern void rfbProcessClientMessage(ScreenPtr pScreen, int sock); ++extern void rfbClientConnFailed(rfbClientPtr cl, char *reason); ++extern void rfbNewUDPConnection(int sock); ++extern void rfbProcessUDPInput(ScreenPtr pScreen, int sock); ++extern Bool rfbSendFramebufferUpdate(ScreenPtr pScreen, rfbClientPtr cl); ++extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h); ++extern Bool rfbSendUpdateBuf(rfbClientPtr cl); ++extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, ++ int nColours); ++extern void rfbSendBell(void); ++extern void rfbSendServerCutText(char *str, int len); ++#ifdef CHROMIUM ++extern void rfbSendChromiumWindowShow(unsigned int winid, unsigned int show); ++extern void rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h); ++extern void rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects); ++#endif ++ ++/* translate.c */ ++ ++extern Bool rfbEconomicTranslate; ++ ++extern void rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y); ++extern Bool rfbSetTranslateFunction(rfbClientPtr cl); ++extern void rfbSetClientColourMaps(int firstColour, int nColours); ++extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour, ++ int nColours); ++ ++ ++/* httpd.c */ ++ ++extern Bool httpInitSockets(ScreenPtr pScreen); ++extern void httpCheckFds(ScreenPtr pScreen); ++ ++ ++ ++/* auth.c */ ++ ++extern void rfbAuthNewClient(rfbClientPtr cl); ++extern void rfbProcessClientSecurityType(rfbClientPtr cl); ++extern void rfbProcessClientTunnelingType(rfbClientPtr cl); ++extern void rfbProcessClientAuthType(rfbClientPtr cl); ++extern void rfbVncAuthProcessResponse(rfbClientPtr cl); ++ ++/* Functions to prevent too many successive authentication failures */ ++extern Bool rfbAuthConsiderBlocking(rfbClientPtr cl); ++extern void rfbAuthUnblock(rfbClientPtr cl); ++extern Bool rfbAuthIsBlocked(rfbClientPtr cl); ++ ++/* loginauth.c */ ++ ++extern void rfbLoginAuthProcessClientMessage(rfbClientPtr cl); ++ ++/* rre.c */ ++ ++extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* corre.c */ ++ ++extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* hextile.c */ ++ ++extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w, ++ int h); ++ ++ ++/* zlib.c */ ++ ++/* Minimum zlib rectangle size in bytes. Anything smaller will ++ * not compress well due to overhead. ++ */ ++#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17) ++ ++/* Set maximum zlib rectangle size in pixels. Always allow at least ++ * two scan lines. ++ */ ++#define ZLIB_MAX_RECT_SIZE (128*256) ++#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \ ++ ( min * 2 ) : ZLIB_MAX_RECT_SIZE ) ++ ++extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, ++ int h); ++ ++ ++/* tight.c */ ++ ++#define TIGHT_DEFAULT_COMPRESSION 6 ++ ++extern Bool rfbTightDisableGradient; ++ ++extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h); ++extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* cursor.c */ ++ ++extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen); ++extern Bool rfbSendCursorPos(rfbClientPtr cl, ScreenPtr pScreen); ++ ++ ++/* stats.c */ ++ ++extern void rfbResetStats(rfbClientPtr cl); ++extern void rfbPrintStats(rfbClientPtr cl); +diff --git a/hw/dmx/vnc/rfbkeyb.c b/hw/dmx/vnc/rfbkeyb.c +new file mode 100644 +index 0000000..df5b999 +--- /dev/null ++++ b/hw/dmx/vnc/rfbkeyb.c +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include ++ ++#if XFREE86VNC ++#ifndef XFree86LOADER ++#include ++#include ++#endif ++ ++#include ++#include ++#define NEED_XF86_TYPES ++#if !defined(DGUX) ++#include ++#include ++#endif ++#include ++#include ++#include /* Needed for InitValuator/Proximity stuff */ ++#include ++#include ++ ++#ifdef XFree86LOADER ++#include ++#endif ++#else ++#include ++#include ++#include ++#endif ++ ++#include "rfb.h" ++ ++extern Bool noXkbExtension; ++extern void rfbSendBell(void); ++extern DeviceIntPtr kbdDevice; ++ ++static const char *DEFAULTS[] = { ++ NULL ++}; ++ ++#include "keyboard.h" ++ ++#ifdef XKB ++#include ++#include ++#include ++ ++#if XFREE86VNC ++ /* ++ * would like to use an XkbComponentNamesRec here but can't without ++ * pulling in a bunch of header files. :-( ++ */ ++static char * xkbkeymap; ++static char * xkbkeycodes; ++static char * xkbtypes; ++static char * xkbcompat; ++static char * xkbsymbols; ++static char * xkbgeometry; ++static Bool xkbcomponents_specified; ++static char * xkbrules; ++static char * xkbmodel; ++static char * xkblayout; ++static char * xkbvariant; ++static char * xkboptions; ++#endif ++#endif ++ ++void ++KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap) ++{ ++ int i; ++ ++ kbdDevice = pDevice; ++ ++ for (i = 0; i < MAP_LENGTH; i++) ++ pModMap[i] = NoSymbol; ++ ++ pModMap[CONTROL_L_KEY_CODE] = ControlMask; ++ pModMap[CONTROL_R_KEY_CODE] = ControlMask; ++ pModMap[SHIFT_L_KEY_CODE] = ShiftMask; ++ pModMap[SHIFT_R_KEY_CODE] = ShiftMask; ++ pModMap[META_L_KEY_CODE] = Mod1Mask; ++ pModMap[META_R_KEY_CODE] = Mod1Mask; ++ pModMap[ALT_L_KEY_CODE] = Mod1Mask; ++ pModMap[ALT_R_KEY_CODE] = Mod1Mask; ++ ++ pKeySyms->minKeyCode = MIN_KEY_CODE; ++ pKeySyms->maxKeyCode = MAX_KEY_CODE; ++ pKeySyms->mapWidth = GLYPHS_PER_KEY; ++ ++ pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym) ++ * MAP_LENGTH * GLYPHS_PER_KEY); ++ ++ if (!pKeySyms->map) { ++ ErrorF("xalloc failed in KbdDeviceInit\n"); ++ exit(1); ++ } ++ ++ for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++) ++ pKeySyms->map[i] = NoSymbol; ++ ++ for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { ++ pKeySyms->map[i] = map[i]; ++ } ++} ++ ++void ++KbdDeviceOn(void) ++{ ++} ++ ++ ++void ++KbdDeviceOff(void) ++{ ++} ++ ++#if XFREE86VNC ++static int ++xf86rfbKeybControlProc(DeviceIntPtr device, int onoff) ++{ ++ KeySymsRec keySyms; ++ CARD8 modMap[MAP_LENGTH]; ++ DevicePtr pDev = (DevicePtr)device; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ KbdDeviceInit(device, &keySyms, modMap); ++#ifdef XKB ++ if (noXkbExtension) { ++#endif ++ InitKeyboardDeviceStruct(pDev, &keySyms, modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++#ifdef XKB ++ } else { ++ XkbComponentNamesRec names; ++ if (XkbInitialMap) { ++ if ((xkbkeymap = strchr(XkbInitialMap, '/')) != NULL) ++ xkbkeymap++; ++ else ++ xkbkeymap = XkbInitialMap; ++ } ++ if (xkbkeymap) { ++ names.keymap = xkbkeymap; ++ names.keycodes = NULL; ++ names.types = NULL; ++ names.compat = NULL; ++ names.symbols = NULL; ++ names.geometry = NULL; ++ } else { ++ names.keymap = NULL; ++ names.keycodes = xkbkeycodes; ++ names.types = xkbtypes; ++ names.compat = xkbcompat; ++ names.symbols = xkbsymbols; ++ names.geometry = xkbgeometry; ++ } ++ if ((xkbkeymap || xkbcomponents_specified) ++ && (xkbmodel == NULL || xkblayout == NULL)) { ++ xkbrules = NULL; ++ } ++#if 0 ++ XkbSetRulesDflts(xkbrules, xkbmodel, ++ xkblayout, xkbvariant, ++ xkboptions); ++#endif ++ XkbInitKeyboardDeviceStruct(device, ++ &names, ++ &keySyms, ++ modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++ } ++#endif /* XKB */ ++ break; ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ KbdDeviceOn(); ++ break; ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ KbdDeviceOff(); ++ break; ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ KbdDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static void ++xf86rfbKeybUninit(InputDriverPtr drv, ++ InputInfoPtr pInfo, ++ int flags) ++{ ++ xf86rfbKeybControlProc(pInfo->dev, DEVICE_OFF); ++} ++ ++static InputInfoPtr ++xf86rfbKeybInit(InputDriverPtr drv, ++ IDevPtr dev, ++ int flags) ++{ ++ InputInfoPtr pInfo; ++ char *s; ++ Bool from; ++ ++ if (!(pInfo = xf86AllocateInput(drv, 0))) ++ return NULL; ++ ++ /* Initialise the InputInfoRec. */ ++ pInfo->name = dev->identifier; ++ pInfo->type_name = "rfbKeyb"; ++ pInfo->flags = XI86_KEYBOARD_CAPABLE; ++ pInfo->device_control = xf86rfbKeybControlProc; ++ pInfo->read_input = NULL; ++ pInfo->motion_history_proc = NULL; ++ pInfo->history_size = 0; ++ pInfo->control_proc = NULL; ++ pInfo->close_proc = NULL; ++ pInfo->switch_mode = NULL; ++ pInfo->conversion_proc = NULL; ++ pInfo->reverse_conversion_proc = NULL; ++ pInfo->fd = -1; ++ pInfo->dev = NULL; ++ pInfo->private_flags = 0; ++ pInfo->always_core_feedback = 0; ++ pInfo->conf_idev = dev; ++ ++ /* Collect the options, and process the common options. */ ++ xf86CollectInputOptions(pInfo, DEFAULTS, NULL); ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ /* Mark the device configured */ ++ pInfo->flags |= XI86_CONFIGURED; ++ ++#ifdef XKB ++ from = X_DEFAULT; ++ if (noXkbExtension) ++ from = X_CMDLINE; ++ else if (xf86FindOption(dev->commonOptions, "XkbDisable")) { ++ noXkbExtension = ++ xf86SetBoolOption(dev->commonOptions, "XkbDisable", FALSE); ++ from = X_CONFIG; ++ } ++ if (noXkbExtension) ++ xf86Msg(from, "XKB: disabled\n"); ++ ++#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL)) ++ ++ if (!noXkbExtension && !XkbInitialMap) { ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeymap", NULL))) { ++ xkbkeymap = NULL_IF_EMPTY(s); ++ xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" " ++ "(overrides other XKB settings)\n", xkbkeymap); ++ } else { ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbCompat", NULL))) { ++ xkbcompat = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbTypes", NULL))) { ++ xkbtypes = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeycodes", NULL))) { ++ xkbkeycodes = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbGeometry", NULL))) { ++ xkbgeometry = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbSymbols", NULL))) { ++ xkbsymbols = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbRules", NULL))) { ++ xkbrules = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbModel", NULL))) { ++ xkbmodel = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbLayout", NULL))) { ++ xkblayout = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbVariant", NULL))) { ++ xkbvariant = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbOptions", NULL))) { ++ xkboptions = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s); ++ } ++ } ++ } ++#undef NULL_IF_EMPTY ++#endif /* XKB */ ++ ++ /* Return the configured device */ ++ return (pInfo); ++} ++ ++#ifdef XFree86LOADER ++static ++#endif ++InputDriverRec RFBKEYB = { ++ 1, /* driver version */ ++ "rfbkeyb", /* driver name */ ++ NULL, /* identify */ ++ xf86rfbKeybInit, /* pre-init */ ++ xf86rfbKeybUninit, /* un-init */ ++ NULL, /* module */ ++ 0 /* ref count */ ++}; ++ ++/* ++ *************************************************************************** ++ * ++ * Dynamic loading functions ++ * ++ *************************************************************************** ++ */ ++#ifdef XFree86LOADER ++static void ++xf86rfbKeybUnplug(pointer p) ++{ ++} ++ ++static pointer ++xf86rfbKeybPlug(pointer module, ++ pointer options, ++ int *errmaj, ++ int *errmin) ++{ ++ xf86AddInputDriver(&RFBKEYB, module, 0); ++ ++ return module; ++} ++ ++void ++vncInitKeyb(void) ++{ ++ xf86AddInputDriver(&RFBKEYB, NULL, 0); ++} ++ ++static XF86ModuleVersionInfo xf86rfbKeybVersionRec = ++{ ++ "rfbkeyb", ++ "xf4vnc Project, see http://xf4vnc.sf.net", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XF86_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_XINPUT, ++ ABI_XINPUT_VERSION, ++ MOD_CLASS_XINPUT, ++ {0, 0, 0, 0} /* signature, to be patched into the file by */ ++ /* a tool */ ++}; ++ ++XF86ModuleData rfbkeybModuleData = {&xf86rfbKeybVersionRec, ++ xf86rfbKeybPlug, ++ xf86rfbKeybUnplug}; ++ ++#endif /* XFree86LOADER */ ++#endif /* XFREE86VNC */ +diff --git a/hw/dmx/vnc/rfbmouse.c b/hw/dmx/vnc/rfbmouse.c +new file mode 100644 +index 0000000..c92c8ca +--- /dev/null ++++ b/hw/dmx/vnc/rfbmouse.c +@@ -0,0 +1,243 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#if XFREE86VNC ++#ifndef XFree86LOADER ++#include ++#include ++#endif ++ ++#include ++#include ++#define NEED_XF86_TYPES ++#if !defined(DGUX) ++#include ++#include ++#endif ++#include ++#include ++#include /* Needed for InitValuator/Proximity stuff */ ++#include ++#include ++ ++#ifdef XFree86LOADER ++#include ++#endif ++ ++static const char *DEFAULTS[] = { ++ NULL ++}; ++#else ++#include ++#include ++#include ++#endif ++ ++#include "rfb.h" ++ ++ ++unsigned char ptrAcceleration = 50; ++ ++void ++PtrDeviceOn(DeviceIntPtr pDev) ++{ ++#if 0 ++ ptrAcceleration = (unsigned char)pDev->ptrfeed->ctrl.num; ++#endif ++} ++ ++void ++PtrDeviceInit(void) ++{ ++} ++ ++void ++PtrDeviceOff(void) ++{ ++} ++ ++ ++void ++PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl) ++{ ++#if 0 ++ ptrAcceleration = (char)ctrl->num; ++ ++ if (udpSockConnected) { ++ if (write(udpSock, &ptrAcceleration, 1) <= 0) { ++ ErrorF("PtrDeviceControl: UDP input: write"); ++ rfbDisconnectUDPSock(); ++ } ++ } ++#endif ++} ++ ++#if XFREE86VNC ++static int ++xf86rfbMouseControlProc(DeviceIntPtr device, int onoff) ++{ ++ BYTE map[6]; ++ DevicePtr pDev = (DevicePtr)device; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ PtrDeviceInit(); ++ map[1] = 1; ++ map[2] = 2; ++ map[3] = 3; ++ map[4] = 4; ++ map[5] = 5; ++ InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents, ++ PtrDeviceControl, ++ miPointerGetMotionBufferSize()); ++ break; ++ ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ PtrDeviceOn(device); ++ break; ++ ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ PtrDeviceOff(); ++ break; ++ ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ PtrDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static void ++xf86rfbMouseUninit(InputDriverPtr drv, ++ InputInfoPtr pInfo, ++ int flags) ++{ ++ xf86rfbMouseControlProc(pInfo->dev, DEVICE_OFF); ++} ++ ++static InputInfoPtr ++xf86rfbMouseInit(InputDriverPtr drv, ++ IDevPtr dev, ++ int flags) ++{ ++ InputInfoPtr pInfo; ++ ++ if (!(pInfo = xf86AllocateInput(drv, 0))) ++ return NULL; ++ ++ /* Initialise the InputInfoRec. */ ++ pInfo->name = dev->identifier; ++ pInfo->type_name = "rfbMouse"; ++ pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; ++ pInfo->device_control = xf86rfbMouseControlProc; ++ pInfo->read_input = NULL; ++ pInfo->motion_history_proc = xf86GetMotionEvents; ++ pInfo->history_size = 0; ++ pInfo->control_proc = NULL; ++ pInfo->close_proc = NULL; ++ pInfo->switch_mode = NULL; ++ pInfo->conversion_proc = NULL; ++ pInfo->reverse_conversion_proc = NULL; ++ pInfo->fd = -1; ++ pInfo->dev = NULL; ++ pInfo->private_flags = 0; ++ pInfo->always_core_feedback = 0; ++ pInfo->conf_idev = dev; ++ ++ /* Collect the options, and process the common options. */ ++ xf86CollectInputOptions(pInfo, DEFAULTS, NULL); ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ /* Mark the device configured */ ++ pInfo->flags |= XI86_CONFIGURED; ++ ++ /* Return the configured device */ ++ return (pInfo); ++} ++ ++#ifdef XFree86LOADER ++static ++#endif ++InputDriverRec RFBMOUSE = { ++ 1, /* driver version */ ++ "rfbmouse", /* driver name */ ++ NULL, /* identify */ ++ xf86rfbMouseInit, /* pre-init */ ++ xf86rfbMouseUninit, /* un-init */ ++ NULL, /* module */ ++ 0 /* ref count */ ++}; ++ ++/* ++ *************************************************************************** ++ * ++ * Dynamic loading functions ++ * ++ *************************************************************************** ++ */ ++#ifdef XFree86LOADER ++static void ++xf86rfbMouseUnplug(pointer p) ++{ ++} ++ ++static pointer ++xf86rfbMousePlug(pointer module, ++ pointer options, ++ int *errmaj, ++ int *errmin) ++{ ++ xf86AddInputDriver(&RFBMOUSE, module, 0); ++ ++ return module; ++} ++ ++void ++vncInitMouse(void) ++{ ++ xf86AddInputDriver(&RFBMOUSE, NULL, 0); ++} ++ ++static XF86ModuleVersionInfo xf86rfbMouseVersionRec = ++{ ++ "rfbmouse", ++ "xf4vnc Project, see http://xf4vnc.sf.net", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XF86_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_XINPUT, ++ ABI_XINPUT_VERSION, ++ MOD_CLASS_XINPUT, ++ {0, 0, 0, 0} /* signature, to be patched into the file by */ ++ /* a tool */ ++}; ++ ++XF86ModuleData rfbmouseModuleData = {&xf86rfbMouseVersionRec, ++ xf86rfbMousePlug, ++ xf86rfbMouseUnplug}; ++ ++#endif /* XFree86LOADER */ ++#endif +diff --git a/hw/dmx/vnc/rfbproto.h b/hw/dmx/vnc/rfbproto.h +new file mode 100644 +index 0000000..bbef703 +--- /dev/null ++++ b/hw/dmx/vnc/rfbproto.h +@@ -0,0 +1,1347 @@ ++/* ++ * Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ * rfbproto.h - header file for the RFB protocol, versions 3.3, 3.7 and 3.7t ++ * (protocol 3.7t is effectively 3.7 with TightVNC extensions enabled) ++ * ++ * Uses types CARD for an n-bit unsigned integer, INT for an n-bit signed ++ * integer (for n = 8, 16 and 32). ++ * ++ * All multiple byte integers are in big endian (network) order (most ++ * significant byte first). Unless noted otherwise there is no special ++ * alignment of protocol structures. ++ * ++ * ++ * Once the initial handshaking is done, all messages start with a type byte, ++ * (usually) followed by message-specific data. The order of definitions in ++ * this file is as follows: ++ * ++ * (1) Structures used in several types of message. ++ * (2) Structures used in the initial handshaking. ++ * (3) Message types. ++ * (4) Encoding types. ++ * (5) For each message type, the form of the data following the type byte. ++ * Sometimes this is defined by a single structure but the more complex ++ * messages have to be explained by comments. ++ */ ++ ++ ++/***************************************************************************** ++ * ++ * Structures used in several messages ++ * ++ *****************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to specify a rectangle. This structure is a multiple of 4 ++ * bytes so that it can be interspersed with 32-bit pixel data without ++ * affecting alignment. ++ */ ++ ++typedef struct _rfbRectangle { ++ CARD16 x; ++ CARD16 y; ++ CARD16 w; ++ CARD16 h; ++} rfbRectangle; ++ ++#define sz_rfbRectangle 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to specify pixel format. ++ */ ++ ++typedef struct _rfbPixelFormat { ++ ++ CARD8 bitsPerPixel; /* 8,16,32 only */ ++ ++ CARD8 depth; /* 8 to 32 */ ++ ++ CARD8 bigEndian; /* True if multi-byte pixels are interpreted ++ as big endian, or if single-bit-per-pixel ++ has most significant bit of the byte ++ corresponding to first (leftmost) pixel. Of ++ course this is meaningless for 8 bits/pix */ ++ ++ CARD8 trueColour; /* If false then we need a "colour map" to ++ convert pixels to RGB. If true, xxxMax and ++ xxxShift specify bits used for red, green ++ and blue */ ++ ++ /* the following fields are only meaningful if trueColour is true */ ++ ++ CARD16 redMax; /* maximum red value (= 2^n - 1 where n is the ++ number of bits used for red). Note this ++ value is always in big endian order. */ ++ ++ CARD16 greenMax; /* similar for green */ ++ ++ CARD16 blueMax; /* and blue */ ++ ++ CARD8 redShift; /* number of shifts needed to get the red ++ value in a pixel to the least significant ++ bit. To find the red value from a given ++ pixel, do the following: ++ 1) Swap pixel value according to bigEndian ++ (e.g. if bigEndian is false and host byte ++ order is big endian, then swap). ++ 2) Shift right by redShift. ++ 3) AND with redMax (in host byte order). ++ 4) You now have the red value between 0 and ++ redMax. */ ++ ++ CARD8 greenShift; /* similar for green */ ++ ++ CARD8 blueShift; /* and blue */ ++ ++ CARD8 pad1; ++ CARD16 pad2; ++ ++} rfbPixelFormat; ++ ++#define sz_rfbPixelFormat 16 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to describe protocol options such as tunneling methods, ++ * authentication schemes and message types (protocol version 3.7t). ++ */ ++ ++typedef struct _rfbCapabilityInfo { ++ ++ CARD32 code; /* numeric identifier */ ++ CARD8 vendorSignature[4]; /* vendor identification */ ++ CARD8 nameSignature[8]; /* abbreviated option name */ ++ ++} rfbCapabilityInfo; ++ ++#define sz_rfbCapabilityInfoVendor 4 ++#define sz_rfbCapabilityInfoName 8 ++#define sz_rfbCapabilityInfo 16 ++ ++/* ++ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC. ++ */ ++ ++#define rfbStandardVendor "STDV" ++#define rfbTridiaVncVendor "TRDV" ++#define rfbTightVncVendor "TGHT" ++#define rfbTungstenGraphicsVendor "TGIV" ++ ++ ++/***************************************************************************** ++ * ++ * Initial handshaking messages ++ * ++ *****************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * Protocol Version ++ * ++ * The server always sends 12 bytes to start which identifies the latest RFB ++ * protocol version number which it supports. These bytes are interpreted ++ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where ++ * xxx and yyy are the major and minor version numbers (for version 3.7 ++ * this is "RFB 003.007\n"). ++ * ++ * The client then replies with a similar 12-byte message giving the version ++ * number of the protocol which should actually be used (which may be different ++ * to that quoted by the server). ++ * ++ * It is intended that both clients and servers may provide some level of ++ * backwards compatibility by this mechanism. Servers in particular should ++ * attempt to provide backwards compatibility, and even forwards compatibility ++ * to some extent. For example if a client demands version 3.1 of the ++ * protocol, a 3.0 server can probably assume that by ignoring requests for ++ * encoding types it doesn't understand, everything will still work OK. This ++ * will probably not be the case for changes in the major version number. ++ * ++ * The format string below can be used in sprintf or sscanf to generate or ++ * decode the version string respectively. ++ */ ++ ++#define rfbProtocolVersionFormat "RFB %03d.%03d\n" ++#define rfbProtocolMajorVersion 3 ++#define rfbProtocolMinorVersion 7 ++#define rfbProtocolFallbackMinorVersion 3 ++ ++typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */ ++ ++#define sz_rfbProtocolVersionMsg 12 ++ ++ ++/* ++ * Negotiation of the security type (protocol version 3.7) ++ * ++ * Once the protocol version has been decided, the server either sends a list ++ * of supported security types, or informs the client about an error (when the ++ * number of security types is 0). Security type rfbSecTypeTight is used to ++ * enable TightVNC-specific protocol extensions. The value rfbSecTypeVncAuth ++ * stands for classic VNC authentication. ++ * ++ * The client selects a particular security type from the list provided by the ++ * server. ++ */ ++ ++#define rfbSecTypeInvalid 0 ++#define rfbSecTypeNone 1 ++#define rfbSecTypeVncAuth 2 ++#define rfbSecTypeTight 16 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Negotiation of Tunneling Capabilities (protocol version 3.7t) ++ * ++ * If the chosen security type is rfbSecTypeTight, the server sends a list of ++ * supported tunneling methods ("tunneling" refers to any additional layer of ++ * data transformation, such as encryption or external compression.) ++ * ++ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures ++ * that list all supported tunneling methods in the order of preference. ++ * ++ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be ++ * used, and the client should not send a response requesting a tunneling ++ * method. ++ */ ++ ++typedef struct _rfbTunnelingCapsMsg { ++ CARD32 nTunnelTypes; ++ /* followed by nTunnelTypes * rfbCapabilityInfo structures */ ++} rfbTunnelingCapsMsg; ++ ++#define sz_rfbTunnelingCapsMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Tunneling Method Request (protocol version 3.7t) ++ * ++ * If the list of tunneling capabilities sent by the server was not empty, the ++ * client should reply with a 32-bit code specifying a particular tunneling ++ * method. The following code should be used for no tunneling. ++ */ ++ ++#define rfbNoTunneling 0 ++#define sig_rfbNoTunneling "NOTUNNEL" ++ ++ ++/*----------------------------------------------------------------------------- ++ * Negotiation of Authentication Capabilities (protocol version 3.7t) ++ * ++ * After setting up tunneling, the server sends a list of supported ++ * authentication schemes. ++ * ++ * nAuthTypes specifies the number of following rfbCapabilityInfo structures ++ * that list all supported authentication schemes in the order of preference. ++ * ++ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is ++ * necessary, and the client should not send a response requesting an ++ * authentication scheme. ++ */ ++ ++typedef struct _rfbAuthenticationCapsMsg { ++ CARD32 nAuthTypes; ++ /* followed by nAuthTypes * rfbCapabilityInfo structures */ ++} rfbAuthenticationCapsMsg; ++ ++#define sz_rfbAuthenticationCapsMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Authentication Scheme Request (protocol version 3.7t) ++ * ++ * If the list of authentication capabilities sent by the server was not empty, ++ * the client should reply with a 32-bit code specifying a particular ++ * authentication scheme. The following codes are supported. ++ */ ++ ++#define rfbAuthNone 1 ++#define rfbAuthVNC 2 ++#define rfbAuthUnixLogin 129 ++#define rfbAuthExternal 130 ++ ++#define sig_rfbAuthNone "NOAUTH__" ++#define sig_rfbAuthVNC "VNCAUTH_" ++#define sig_rfbAuthUnixLogin "ULGNAUTH" ++#define sig_rfbAuthExternal "XTRNAUTH" ++ ++ ++/*----------------------------------------------------------------------------- ++ * Standard VNC Authentication (all protocol versions) ++ * ++ * Standard authentication result codes are defined below. ++ */ ++ ++#define rfbVncAuthOK 0 ++#define rfbVncAuthFailed 1 ++#define rfbVncAuthTooMany 2 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Client Initialisation Message ++ * ++ * Once the client and server are sure that they're happy to talk to one ++ * another, the client sends an initialisation message. At present this ++ * message only consists of a boolean indicating whether the server should try ++ * to share the desktop by leaving other clients connected, or give exclusive ++ * access to this client by disconnecting all other clients. ++ */ ++ ++typedef struct _rfbClientInitMsg { ++ CARD8 shared; ++} rfbClientInitMsg; ++ ++#define sz_rfbClientInitMsg 1 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Server Initialisation Message ++ * ++ * After the client initialisation message, the server sends one of its own. ++ * This tells the client the width and height of the server's framebuffer, ++ * its pixel format and the name associated with the desktop. ++ */ ++ ++typedef struct _rfbServerInitMsg { ++ CARD16 framebufferWidth; ++ CARD16 framebufferHeight; ++ rfbPixelFormat format; /* the server's preferred pixel format */ ++ CARD32 nameLength; ++ /* followed by char name[nameLength] */ ++} rfbServerInitMsg; ++ ++#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat) ++ ++ ++/*----------------------------------------------------------------------------- ++ * Server Interaction Capabilities Message (protocol version 3.7t) ++ * ++ * In the protocol version 3.7t, the server informs the client what message ++ * types it supports in addition to ones defined in the protocol version 3.7. ++ * Also, the server sends the list of all supported encodings (note that it's ++ * not necessary to advertise the "raw" encoding sinse it MUST be supported in ++ * RFB 3.x protocols). ++ * ++ * This data immediately follows the server initialisation message. ++ */ ++ ++typedef struct _rfbInteractionCapsMsg { ++ CARD16 nServerMessageTypes; ++ CARD16 nClientMessageTypes; ++ CARD16 nEncodingTypes; ++ CARD16 pad; /* reserved, must be 0 */ ++ /* followed by nServerMessageTypes * rfbCapabilityInfo structures */ ++ /* followed by nClientMessageTypes * rfbCapabilityInfo structures */ ++} rfbInteractionCapsMsg; ++ ++#define sz_rfbInteractionCapsMsg 8 ++ ++ ++/* ++ * Following the server initialisation message it's up to the client to send ++ * whichever protocol messages it wants. Typically it will send a ++ * SetPixelFormat message and a SetEncodings message, followed by a ++ * FramebufferUpdateRequest. From then on the server will send ++ * FramebufferUpdate messages in response to the client's ++ * FramebufferUpdateRequest messages. The client should send ++ * FramebufferUpdateRequest messages with incremental set to true when it has ++ * finished processing one FramebufferUpdate and is ready to process another. ++ * With a fast client, the rate at which FramebufferUpdateRequests are sent ++ * should be regulated to avoid hogging the network. ++ */ ++ ++ ++ ++/***************************************************************************** ++ * ++ * Message types ++ * ++ *****************************************************************************/ ++ ++/* server -> client */ ++ ++#define rfbFramebufferUpdate 0 ++#define rfbSetColourMapEntries 1 ++#define rfbBell 2 ++#define rfbServerCutText 3 ++/* Chromium extensions, use higher values */ ++#define rfbChromiumStart 50 ++#define rfbChromiumMoveResizeWindow 51 ++#define rfbChromiumClipList 52 ++#define rfbChromiumWindowShow 53 ++ ++#define rfbFileListData 130 ++#define rfbFileDownloadData 131 ++#define rfbFileUploadCancel 132 ++#define rfbFileDownloadFailed 133 ++ ++/* signatures for non-standard messages */ ++#define sig_rfbFileListData "FTS_LSDT" ++#define sig_rfbFileDownloadData "FTS_DNDT" ++#define sig_rfbFileUploadCancel "FTS_UPCN" ++#define sig_rfbFileDownloadFailed "FTS_DNFL" ++ ++ ++/* client -> server */ ++ ++#define rfbSetPixelFormat 0 ++#define rfbFixColourMapEntries 1 /* not currently supported */ ++#define rfbSetEncodings 2 ++#define rfbFramebufferUpdateRequest 3 ++#define rfbKeyEvent 4 ++#define rfbPointerEvent 5 ++#define rfbClientCutText 6 ++/* Chromium extensions, use higher values */ ++#define rfbChromiumStop 50 ++#define rfbChromiumExpose 51 ++ ++#define rfbFileListRequest 130 ++#define rfbFileDownloadRequest 131 ++#define rfbFileUploadRequest 132 ++#define rfbFileUploadData 133 ++#define rfbFileDownloadCancel 134 ++#define rfbFileUploadFailed 135 ++#define rfbFileCreateDirRequest 136 ++ ++/* signatures for non-standard messages */ ++#define sig_rfbFileListRequest "FTC_LSRQ" ++#define sig_rfbFileDownloadRequest "FTC_DNRQ" ++#define sig_rfbFileUploadRequest "FTC_UPRQ" ++#define sig_rfbFileUploadData "FTC_UPDT" ++#define sig_rfbFileDownloadCancel "FTC_DNCN" ++#define sig_rfbFileUploadFailed "FTC_UPFL" ++#define sig_rfbFileCreateDirRequest "FTC_FCDR" ++ ++/***************************************************************************** ++ * ++ * Encoding types ++ * ++ *****************************************************************************/ ++ ++#define rfbEncodingRaw 0 ++#define rfbEncodingCopyRect 1 ++#define rfbEncodingRRE 2 ++#define rfbEncodingCoRRE 4 ++#define rfbEncodingHextile 5 ++#define rfbEncodingZlib 6 ++#define rfbEncodingTight 7 ++#define rfbEncodingZlibHex 8 ++ ++/* signatures for basic encoding types */ ++#define sig_rfbEncodingRaw "RAW_____" ++#define sig_rfbEncodingCopyRect "COPYRECT" ++#define sig_rfbEncodingRRE "RRE_____" ++#define sig_rfbEncodingCoRRE "CORRE___" ++#define sig_rfbEncodingHextile "HEXTILE_" ++#define sig_rfbEncodingZlib "ZLIB____" ++#define sig_rfbEncodingTight "TIGHT___" ++#define sig_rfbEncodingZlibHex "ZLIBHEX_" ++#define sig_rfbEncodingChromium "CHROMIUM" ++ ++/* ++ * Special encoding numbers: ++ * 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels; ++ * 0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data; ++ * 0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions; ++ * 0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet; ++ * 0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor; ++ * 0xFFFFFFF0 .. 0xFFFFFFFF -- not allocated yet. ++ */ ++ ++#define rfbEncodingCompressLevel0 0xFFFFFF00 ++#define rfbEncodingCompressLevel1 0xFFFFFF01 ++#define rfbEncodingCompressLevel2 0xFFFFFF02 ++#define rfbEncodingCompressLevel3 0xFFFFFF03 ++#define rfbEncodingCompressLevel4 0xFFFFFF04 ++#define rfbEncodingCompressLevel5 0xFFFFFF05 ++#define rfbEncodingCompressLevel6 0xFFFFFF06 ++#define rfbEncodingCompressLevel7 0xFFFFFF07 ++#define rfbEncodingCompressLevel8 0xFFFFFF08 ++#define rfbEncodingCompressLevel9 0xFFFFFF09 ++ ++#define rfbEncodingXCursor 0xFFFFFF10 ++#define rfbEncodingRichCursor 0xFFFFFF11 ++#define rfbEncodingPointerPos 0xFFFFFF18 ++ ++#define rfbEncodingLastRect 0xFFFFFF20 ++#define rfbEncodingNewFBSize 0xFFFFFF21 ++#define rfbEncodingChromium 0xFFFFFF2F ++#define rfbEncodingChromium2 0xFFFFFF30 ++ ++#define rfbEncodingQualityLevel0 0xFFFFFFE0 ++#define rfbEncodingQualityLevel1 0xFFFFFFE1 ++#define rfbEncodingQualityLevel2 0xFFFFFFE2 ++#define rfbEncodingQualityLevel3 0xFFFFFFE3 ++#define rfbEncodingQualityLevel4 0xFFFFFFE4 ++#define rfbEncodingQualityLevel5 0xFFFFFFE5 ++#define rfbEncodingQualityLevel6 0xFFFFFFE6 ++#define rfbEncodingQualityLevel7 0xFFFFFFE7 ++#define rfbEncodingQualityLevel8 0xFFFFFFE8 ++#define rfbEncodingQualityLevel9 0xFFFFFFE9 ++ ++/* signatures for "fake" encoding types */ ++#define sig_rfbEncodingCompressLevel0 "COMPRLVL" ++#define sig_rfbEncodingXCursor "X11CURSR" ++#define sig_rfbEncodingRichCursor "RCHCURSR" ++#define sig_rfbEncodingPointerPos "POINTPOS" ++#define sig_rfbEncodingLastRect "LASTRECT" ++#define sig_rfbEncodingNewFBSize "NEWFBSIZ" ++#define sig_rfbEncodingQualityLevel0 "JPEGQLVL" ++ ++ ++/***************************************************************************** ++ * ++ * Server -> client message definitions ++ * ++ *****************************************************************************/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer. ++ * ++ * This message consists of a header giving the number of rectangles of pixel ++ * data followed by the rectangles themselves. The header is padded so that ++ * together with the type byte it is an exact multiple of 4 bytes (to help ++ * with alignment of 32-bit pixels): ++ */ ++ ++typedef struct _rfbFramebufferUpdateMsg { ++ CARD8 type; /* always rfbFramebufferUpdate */ ++ CARD8 pad; ++ CARD16 nRects; ++ /* followed by nRects rectangles */ ++} rfbFramebufferUpdateMsg; ++ ++#define sz_rfbFramebufferUpdateMsg 4 ++ ++/* ++ * Each rectangle of pixel data consists of a header describing the position ++ * and size of the rectangle and a type word describing the encoding of the ++ * pixel data, followed finally by the pixel data. Note that if the client has ++ * not sent a SetEncodings message then it will only receive raw pixel data. ++ * Also note again that this structure is a multiple of 4 bytes. ++ */ ++ ++typedef struct _rfbFramebufferUpdateRectHeader { ++ rfbRectangle r; ++ CARD32 encoding; /* one of the encoding types rfbEncoding... */ ++} rfbFramebufferUpdateRectHeader; ++ ++#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Raw Encoding. Pixels are sent in top-to-bottom scanline order, ++ * left-to-right within a scanline with no padding in between. ++ */ ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * CopyRect Encoding. The pixels are specified simply by the x and y position ++ * of the source rectangle. ++ */ ++ ++typedef struct _rfbCopyRect { ++ CARD16 srcX; ++ CARD16 srcY; ++} rfbCopyRect; ++ ++#define sz_rfbCopyRect 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * RRE - Rise-and-Run-length Encoding. We have an rfbRREHeader structure ++ * giving the number of subrectangles following. Finally the data follows in ++ * the form [...] where each is ++ * []. ++ */ ++ ++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 ++ * [...] where each is ++ * []. This means that ++ * the whole rectangle must be at most 255x255 pixels. ++ */ ++ ++typedef struct _rfbCoRRERectangle { ++ CARD8 x; ++ CARD8 y; ++ CARD8 w; ++ CARD8 h; ++} rfbCoRRERectangle; ++ ++#define sz_rfbCoRRERectangle 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Hextile Encoding. The rectangle is divided up into "tiles" of 16x16 pixels, ++ * starting at the top left going in left-to-right, top-to-bottom order. If ++ * the width of the rectangle is not an exact multiple of 16 then the width of ++ * the last tile in each row will be correspondingly smaller. Similarly if the ++ * height is not an exact multiple of 16 then the height of each tile in the ++ * final row will also be smaller. Each tile begins with a "subencoding" type ++ * byte, which is a mask made up of a number of bits. If the Raw bit is set ++ * then the other bits are irrelevant; w*h pixel values follow (where w and h ++ * are the width and height of the tile). Otherwise the tile is encoded in a ++ * similar way to RRE, except that the position and size of each subrectangle ++ * can be specified in just two bytes. The other bits in the mask are as ++ * follows: ++ * ++ * BackgroundSpecified - if set, a pixel value follows which specifies ++ * the background colour for this tile. The first non-raw tile in a ++ * rectangle must have this bit set. If this bit isn't set then the ++ * background is the same as the last tile. ++ * ++ * ForegroundSpecified - if set, a pixel value follows which specifies ++ * the foreground colour to be used for all subrectangles in this tile. ++ * If this bit is set then the SubrectsColoured bit must be zero. ++ * ++ * AnySubrects - if set, a single byte follows giving the number of ++ * subrectangles following. If not set, there are no subrectangles (i.e. ++ * the whole tile is just solid background colour). ++ * ++ * SubrectsColoured - if set then each subrectangle is preceded by a pixel ++ * value giving the colour of that subrectangle. If not set, all ++ * subrectangles are the same colour, the foreground colour; if the ++ * ForegroundSpecified bit wasn't set then the foreground is the same as ++ * the last tile. ++ * ++ * The position and size of each subrectangle is specified in two bytes. The ++ * Pack macros below can be used to generate the two bytes from x, y, w, h, ++ * and the Extract macros can be used to extract the x, y, w, h values from ++ * the two bytes. ++ */ ++ ++#define rfbHextileRaw (1 << 0) ++#define rfbHextileBackgroundSpecified (1 << 1) ++#define rfbHextileForegroundSpecified (1 << 2) ++#define rfbHextileAnySubrects (1 << 3) ++#define rfbHextileSubrectsColoured (1 << 4) ++ ++#define rfbHextilePackXY(x,y) (((x) << 4) | (y)) ++#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1)) ++#define rfbHextileExtractX(byte) ((byte) >> 4) ++#define rfbHextileExtractY(byte) ((byte) & 0xf) ++#define rfbHextileExtractW(byte) (((byte) >> 4) + 1) ++#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1) ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ZLIB - zlib compression Encoding. We have an rfbZlibHeader structure ++ * giving the number of bytes to follow. Finally the data follows in ++ * zlib compressed format. ++ */ ++ ++typedef struct _rfbZlibHeader { ++ CARD32 nBytes; ++} rfbZlibHeader; ++ ++#define sz_rfbZlibHeader 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Tight Encoding. ++ * ++ *-- The first byte of each Tight-encoded rectangle is a "compression control ++ * byte". Its format is as follows (bit 0 is the least significant one): ++ * ++ * bit 0: if 1, then compression stream 0 should be reset; ++ * bit 1: if 1, then compression stream 1 should be reset; ++ * bit 2: if 1, then compression stream 2 should be reset; ++ * bit 3: if 1, then compression stream 3 should be reset; ++ * bits 7-4: if 1000 (0x08), then the compression type is "fill", ++ * if 1001 (0x09), then the compression type is "jpeg", ++ * if 0xxx, then the compression type is "basic", ++ * values greater than 1001 are not valid. ++ * ++ * If the compression type is "basic", then bits 6..4 of the ++ * compression control byte (those xxx in 0xxx) specify the following: ++ * ++ * bits 5-4: decimal representation is the index of a particular zlib ++ * stream which should be used for decompressing the data; ++ * bit 6: if 1, then a "filter id" byte is following this byte. ++ * ++ *-- The data that follows after the compression control byte described ++ * above depends on the compression type ("fill", "jpeg" or "basic"). ++ * ++ *-- If the compression type is "fill", then the only pixel value follows, in ++ * client pixel format (see NOTE 1). This value applies to all pixels of the ++ * rectangle. ++ * ++ *-- If the compression type is "jpeg", the following data stream looks like ++ * this: ++ * ++ * 1..3 bytes: data size (N) in compact representation; ++ * N bytes: JPEG image. ++ * ++ * Data size is compactly represented in one, two or three bytes, according ++ * to the following scheme: ++ * ++ * 0xxxxxxx (for values 0..127) ++ * 1xxxxxxx 0yyyyyyy (for values 128..16383) ++ * 1xxxxxxx 1yyyyyyy zzzzzzzz (for values 16384..4194303) ++ * ++ * Here each character denotes one bit, xxxxxxx are the least significant 7 ++ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the ++ * most significant 8 bits (bits 14-21). For example, decimal value 10000 ++ * should be represented as two bytes: binary 10010000 01001110, or ++ * hexadecimal 90 4E. ++ * ++ *-- If the compression type is "basic" and bit 6 of the compression control ++ * byte was set to 1, then the next (second) byte specifies "filter id" which ++ * tells the decoder what filter type was used by the encoder to pre-process ++ * pixel data before the compression. The "filter id" byte can be one of the ++ * following: ++ * ++ * 0: no filter ("copy" filter); ++ * 1: "palette" filter; ++ * 2: "gradient" filter. ++ * ++ *-- If bit 6 of the compression control byte is set to 0 (no "filter id" ++ * byte), or if the filter id is 0, then raw pixel values in the client ++ * format (see NOTE 1) will be compressed. See below details on the ++ * compression. ++ * ++ *-- The "gradient" filter pre-processes pixel data with a simple algorithm ++ * which converts each color component to a difference between a "predicted" ++ * intensity and the actual intensity. Such a technique does not affect ++ * uncompressed data size, but helps to compress photo-like images better. ++ * Pseudo-code for converting intensities to differences is the following: ++ * ++ * P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1]; ++ * if (P[i,j] < 0) then P[i,j] := 0; ++ * if (P[i,j] > MAX) then P[i,j] := MAX; ++ * D[i,j] := V[i,j] - P[i,j]; ++ * ++ * Here V[i,j] is the intensity of a color component for a pixel at ++ * coordinates (i,j). MAX is the maximum value of intensity for a color ++ * component. ++ * ++ *-- The "palette" filter converts true-color pixel data to indexed colors ++ * and a palette which can consist of 2..256 colors. If the number of colors ++ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to ++ * encode one pixel. 1-bit encoding is performed such way that the most ++ * significant bits correspond to the leftmost pixels, and each raw of pixels ++ * is aligned to the byte boundary. When "palette" filter is used, the ++ * palette is sent before the pixel data. The palette begins with an unsigned ++ * byte which value is the number of colors in the palette minus 1 (i.e. 1 ++ * means 2 colors, 255 means 256 colors in the palette). Then follows the ++ * palette itself which consist of pixel values in client pixel format (see ++ * NOTE 1). ++ * ++ *-- The pixel data is compressed using the zlib library. But if the data ++ * size after applying the filter but before the compression is less then 12, ++ * then the data is sent as is, uncompressed. Four separate zlib streams ++ * (0..3) can be used and the decoder should read the actual stream id from ++ * the compression control byte (see NOTE 2). ++ * ++ * If the compression is not used, then the pixel data is sent as is, ++ * otherwise the data stream looks like this: ++ * ++ * 1..3 bytes: data size (N) in compact representation; ++ * N bytes: zlib-compressed data. ++ * ++ * Data size is compactly represented in one, two or three bytes, just like ++ * in the "jpeg" compression method (see above). ++ * ++ *-- NOTE 1. If the color depth is 24, and all three color components are ++ * 8-bit wide, then one pixel in Tight encoding is always represented by ++ * three bytes, where the first byte is red component, the second byte is ++ * green component, and the third byte is blue component of the pixel color ++ * value. This applies to colors in palettes as well. ++ * ++ *-- NOTE 2. The decoder must reset compression streams' states before ++ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control ++ * byte are set to 1. Note that the decoder must reset zlib streams even if ++ * the compression type is "fill" or "jpeg". ++ * ++ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only ++ * when bits-per-pixel value is either 16 or 32, not 8. ++ * ++ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048 ++ * pixels. If a rectangle is wider, it must be split into several rectangles ++ * and each one should be encoded separately. ++ * ++ */ ++ ++#define rfbTightExplicitFilter 0x04 ++#define rfbTightFill 0x08 ++#define rfbTightJpeg 0x09 ++#define rfbTightMaxSubencoding 0x09 ++ ++/* Filters to improve compression efficiency */ ++#define rfbTightFilterCopy 0x00 ++#define rfbTightFilterPalette 0x01 ++#define rfbTightFilterGradient 0x02 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ZLIBHEX - zlib compressed Hextile Encoding. Essentially, this is the ++ * hextile encoding with zlib compression on the tiles that can not be ++ * efficiently encoded with one of the other hextile subencodings. The ++ * new zlib subencoding uses two bytes to specify the length of the ++ * compressed tile and then the compressed data follows. As with the ++ * raw sub-encoding, the zlib subencoding invalidates the other ++ * values, if they are also set. ++ */ ++ ++#define rfbHextileZlibRaw (1 << 5) ++#define rfbHextileZlibHex (1 << 6) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * XCursor encoding. This is a special encoding used to transmit X-style ++ * cursor shapes from server to clients. Note that for this encoding, ++ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot ++ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB ++ * samples are sent after header in the rfbXCursorColors structure. They ++ * denote foreground and background colors of the cursor. If a client ++ * supports only black-and-white cursors, it should ignore these colors and ++ * assume that foreground is black and background is white. Next, two bitmaps ++ * (1 bits per pixel) follow: first one with actual data (value 0 denotes ++ * background color, value 1 denotes foreground color), second one with ++ * transparency data (bits with zero value mean that these pixels are ++ * transparent). Both bitmaps represent cursor data in a byte stream, from ++ * left to right, from top to bottom, and each row is byte-aligned. Most ++ * significant bits correspond to leftmost pixels. The number of bytes in ++ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor ++ * should be hidden (or default local cursor should be set by the client). ++ */ ++ ++typedef struct _rfbXCursorColors { ++ CARD8 foreRed; ++ CARD8 foreGreen; ++ CARD8 foreBlue; ++ CARD8 backRed; ++ CARD8 backGreen; ++ CARD8 backBlue; ++} rfbXCursorColors; ++ ++#define sz_rfbXCursorColors 6 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * RichCursor encoding. This is a special encoding used to transmit cursor ++ * shapes from server to clients. It is similar to the XCursor encoding but ++ * uses client pixel format instead of two RGB colors to represent cursor ++ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader ++ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h). ++ * After header, two pixmaps follow: first one with cursor image in current ++ * client pixel format (like in raw encoding), second with transparency data ++ * (1 bit per pixel, exactly the same format as used for transparency bitmap ++ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or ++ * default local cursor should be set by the client). ++ */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetColourMapEntries - these messages are only sent if the pixel ++ * format uses a "colour map" (i.e. trueColour false) and the client has not ++ * fixed the entire colour map using FixColourMapEntries. In addition they ++ * will only start being sent after the client has sent its first ++ * FramebufferUpdateRequest. So if the client always tells the server to use ++ * trueColour then it never needs to process this type of message. ++ */ ++ ++typedef struct _rfbSetColourMapEntriesMsg { ++ CARD8 type; /* always rfbSetColourMapEntries */ ++ CARD8 redIndex; /* used to be pad, but used for DirectColor */ ++ CARD16 firstColour; ++ CARD16 nColours; ++ ++ /* Followed by nColours * 3 * CARD16 ++ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */ ++ ++} rfbSetColourMapEntriesMsg; ++ ++#define sz_rfbSetColourMapEntriesMsg 6 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Bell - ring a bell on the client if it has one. ++ */ ++ ++typedef struct _rfbBellMsg { ++ CARD8 type; /* always rfbBell */ ++} rfbBellMsg; ++ ++#define sz_rfbBellMsg 1 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * ServerCutText - the server has new text in its cut buffer. ++ */ ++ ++typedef struct _rfbServerCutTextMsg { ++ CARD8 type; /* always rfbServerCutText */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 length; ++ /* followed by char text[length] */ ++} rfbServerCutTextMsg; ++ ++#define sz_rfbServerCutTextMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumStart - a port number for the crserver ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumStart */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 crServerPort; ++ CARD32 mothershipPort; ++} rfbChromiumStartMsg; ++ ++#define sz_rfbChromiumStartMsg 12 ++ ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumMoveResizeWindow - move a chromium window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumMoveResizeWindow */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 x; ++ CARD32 y; ++ CARD32 w; ++ CARD32 h; ++} rfbChromiumMoveResizeWindowMsg; ++ ++#define sz_rfbChromiumMoveResizeWindowMsg 24 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumClipList - send clip list ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumClipList */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 length; ++} rfbChromiumClipListMsg; ++ ++#define sz_rfbChromiumClipListMsg 12 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumWindowShow - map or unmap a window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumWindowShow */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 show; ++} rfbChromiumWindowShowMsg; ++ ++#define sz_rfbChromiumWindowShowMsg 12 ++ ++/*----------------------------------------------------------------------------- ++ * FileListData ++ */ ++ ++typedef struct _rfbFileListDataMsg { ++ CARD8 type; ++ CARD8 flags; ++ CARD16 numFiles; ++ CARD16 dataSize; ++ CARD16 compressedSize; ++ /* Followed by SizeData[numFiles] */ ++ /* Followed by Filenames[compressedSize] */ ++} rfbFileListDataMsg; ++ ++#define sz_rfbFileListDataMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadData ++ */ ++ ++typedef struct _rfbFileDownloadDataMsg { ++ CARD8 type; ++ CARD8 compressLevel; ++ CARD16 realSize; ++ CARD16 compressedSize; ++ /* Followed by File[copressedSize] */ ++} rfbFileDownloadDataMsg; ++ ++#define sz_rfbFileDownloadDataMsg 6 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadCancel ++ */ ++ ++typedef struct _rfbFileUploadCancelMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileUploadCancelMsg; ++ ++#define sz_rfbFileUploadCancelMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadFailed ++ */ ++ ++typedef struct _rfbFileDownloadFailedMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileDownloadFailedMsg; ++ ++#define sz_rfbFileDownloadFailedMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Union of all server->client messages. ++ */ ++ ++typedef union _rfbServerToClientMsg { ++ CARD8 type; ++ rfbFramebufferUpdateMsg fu; ++ rfbSetColourMapEntriesMsg scme; ++ rfbBellMsg b; ++ rfbServerCutTextMsg sct; ++ rfbFileListDataMsg fld; ++ rfbFileDownloadDataMsg fdd; ++ rfbFileUploadCancelMsg fuc; ++ rfbFileDownloadFailedMsg fdf; ++ rfbChromiumStartMsg scd; ++ rfbChromiumMoveResizeWindowMsg scm; ++ rfbChromiumClipListMsg sccl; ++ rfbChromiumWindowShowMsg scws; ++} rfbServerToClientMsg; ++ ++ ++ ++/***************************************************************************** ++ * ++ * Message definitions (client -> server) ++ * ++ *****************************************************************************/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetPixelFormat - tell the RFB server the format in which the client wants ++ * pixels sent. ++ */ ++ ++typedef struct _rfbSetPixelFormatMsg { ++ CARD8 type; /* always rfbSetPixelFormat */ ++ CARD8 pad1; ++ CARD16 pad2; ++ rfbPixelFormat format; ++} rfbSetPixelFormatMsg; ++ ++#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4) ++ ++ ++/*----------------------------------------------------------------------------- ++ * FixColourMapEntries - when the pixel format uses a "colour map", fix ++ * read-only colour map entries. ++ * ++ * ***************** NOT CURRENTLY SUPPORTED ***************** ++ */ ++ ++typedef struct _rfbFixColourMapEntriesMsg { ++ CARD8 type; /* always rfbFixColourMapEntries */ ++ CARD8 pad; ++ CARD16 firstColour; ++ CARD16 nColours; ++ ++ /* Followed by nColours * 3 * CARD16 ++ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */ ++ ++} rfbFixColourMapEntriesMsg; ++ ++#define sz_rfbFixColourMapEntriesMsg 6 ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetEncodings - tell the RFB server which encoding types we accept. Put them ++ * in order of preference, if we have any. We may always receive raw ++ * encoding, even if we don't specify it here. ++ */ ++ ++typedef struct _rfbSetEncodingsMsg { ++ CARD8 type; /* always rfbSetEncodings */ ++ CARD8 pad; ++ CARD16 nEncodings; ++ /* followed by nEncodings * CARD32 encoding types */ ++} rfbSetEncodingsMsg; ++ ++#define sz_rfbSetEncodingsMsg 4 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FramebufferUpdateRequest - request for a framebuffer update. If incremental ++ * is true then the client just wants the changes since the last update. If ++ * false then it wants the whole of the specified rectangle. ++ */ ++ ++typedef struct _rfbFramebufferUpdateRequestMsg { ++ CARD8 type; /* always rfbFramebufferUpdateRequest */ ++ CARD8 incremental; ++ CARD16 x; ++ CARD16 y; ++ CARD16 w; ++ CARD16 h; ++} rfbFramebufferUpdateRequestMsg; ++ ++#define sz_rfbFramebufferUpdateRequestMsg 10 ++ ++ ++/*----------------------------------------------------------------------------- ++ * KeyEvent - key press or release ++ * ++ * Keys are specified using the "keysym" values defined by the X Window System. ++ * For most ordinary keys, the keysym is the same as the corresponding ASCII ++ * value. Other common keys are: ++ * ++ * BackSpace 0xff08 ++ * Tab 0xff09 ++ * Return or Enter 0xff0d ++ * Escape 0xff1b ++ * Insert 0xff63 ++ * Delete 0xffff ++ * Home 0xff50 ++ * End 0xff57 ++ * Page Up 0xff55 ++ * Page Down 0xff56 ++ * Left 0xff51 ++ * Up 0xff52 ++ * Right 0xff53 ++ * Down 0xff54 ++ * F1 0xffbe ++ * F2 0xffbf ++ * ... ... ++ * F12 0xffc9 ++ * Shift 0xffe1 ++ * Control 0xffe3 ++ * Meta 0xffe7 ++ * Alt 0xffe9 ++ */ ++ ++typedef struct _rfbKeyEventMsg { ++ CARD8 type; /* always rfbKeyEvent */ ++ CARD8 down; /* true if down (press), false if up */ ++ CARD16 pad; ++ CARD32 key; /* key is specified as an X keysym */ ++} rfbKeyEventMsg; ++ ++#define sz_rfbKeyEventMsg 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * PointerEvent - mouse/pen move and/or button press. ++ */ ++ ++typedef struct _rfbPointerEventMsg { ++ CARD8 type; /* always rfbPointerEvent */ ++ CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */ ++ CARD16 x; ++ CARD16 y; ++} rfbPointerEventMsg; ++ ++#define rfbButton1Mask 1 ++#define rfbButton2Mask 2 ++#define rfbButton3Mask 4 ++#define rfbButton4Mask 8 ++#define rfbButton5Mask 16 ++ ++#define sz_rfbPointerEventMsg 6 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * ClientCutText - the client has new text in its cut buffer. ++ */ ++ ++typedef struct _rfbClientCutTextMsg { ++ CARD8 type; /* always rfbClientCutText */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 length; ++ /* followed by char text[length] */ ++} rfbClientCutTextMsg; ++ ++#define sz_rfbClientCutTextMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileListRequest ++ */ ++ ++typedef struct _rfbFileListRequestMsg { ++ CARD8 type; ++ CARD8 flags; ++ CARD16 dirNameSize; ++ /* Followed by char Dirname[dirNameSize] */ ++} rfbFileListRequestMsg; ++ ++#define sz_rfbFileListRequestMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadRequest ++ */ ++ ++typedef struct _rfbFileDownloadRequestMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 fNameSize; ++ CARD32 position; ++ /* Followed by char Filename[fNameSize] */ ++} rfbFileDownloadRequestMsg; ++ ++#define sz_rfbFileDownloadRequestMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadRequest ++ */ ++ ++typedef struct _rfbFileUploadRequestMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 fNameSize; ++ CARD32 position; ++ /* Followed by char Filename[fNameSize] */ ++} rfbFileUploadRequestMsg; ++ ++#define sz_rfbFileUploadRequestMsg 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadData ++ */ ++ ++typedef struct _rfbFileUploadDataMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 realSize; ++ CARD16 compressedSize; ++ /* Followed by File[compressedSize] */ ++} rfbFileUploadDataMsg; ++ ++#define sz_rfbFileUploadDataMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadCancel ++ */ ++ ++typedef struct _rfbFileDownloadCancelMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileDownloadCancelMsg; ++ ++#define sz_rfbFileDownloadCancelMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadFailed ++ */ ++ ++typedef struct _rfbFileUploadFailedMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileUploadFailedMsg; ++ ++#define sz_rfbFileUploadFailedMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileCreateDirRequest ++ */ ++ ++typedef struct _rfbFileCreateDirRequestMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 dNameLen; ++ CARD32 dModTime; ++ /* Followed by dName[dNameLen] */ ++} rfbFileCreateDirRequestMsg; ++ ++#define sz_rfbFileCreateDirRequestMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumStop - the client has stopped the GL app. ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumStop */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 port; ++} rfbChromiumStopMsg; ++ ++#define sz_rfbChromiumStopMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumExpose - redraw the window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumExpose */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++} rfbChromiumExposeMsg; ++ ++#define sz_rfbChromiumExposeMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * Union of all client->server messages. ++ */ ++ ++typedef union _rfbClientToServerMsg { ++ CARD8 type; ++ rfbSetPixelFormatMsg spf; ++ rfbFixColourMapEntriesMsg fcme; ++ rfbSetEncodingsMsg se; ++ rfbFramebufferUpdateRequestMsg fur; ++ rfbKeyEventMsg ke; ++ rfbPointerEventMsg pe; ++ rfbClientCutTextMsg cct; ++ rfbFileListRequestMsg flr; ++ rfbFileDownloadRequestMsg fdr; ++ rfbFileUploadRequestMsg fupr; ++ rfbFileUploadDataMsg fud; ++ rfbFileDownloadCancelMsg fdc; ++ rfbFileUploadFailedMsg fuf; ++ rfbFileCreateDirRequestMsg fcdr; ++ rfbChromiumStopMsg csd; ++ rfbChromiumExposeMsg cse; ++} rfbClientToServerMsg; +diff --git a/hw/dmx/vnc/rfbserver.c b/hw/dmx/vnc/rfbserver.c +new file mode 100644 +index 0000000..e48facc +--- /dev/null ++++ b/hw/dmx/vnc/rfbserver.c +@@ -0,0 +1,2265 @@ ++/* ++ * rfbserver.c - deal with server-side of the RFB protocol. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* Use ``#define CORBA'' to enable CORBA control interface */ ++ ++#include "rfb.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "windowstr.h" ++#include "input.h" ++#include "mipointer.h" ++#if XFREE86VNC ++#include ++#endif ++#ifdef CHROMIUM ++#include "mivalidate.h" ++#endif ++#include "sprite.h" ++#include "propertyst.h" ++#include ++#include ++ ++#ifdef CORBA ++#include ++#endif ++ ++#if 0 ++extern int GenerateVncConnectedEvent(int sock); ++extern int GenerateVncDisconnectedEvent(int sock); ++#endif ++#ifdef CHROMIUM ++extern int GenerateVncChromiumConnectedEvent(int sock); ++struct CRWindowTable *windowTable = NULL; ++#endif ++ ++extern Atom VNC_CONNECT; ++ ++rfbClientPtr rfbClientHead = NULL; ++rfbClientPtr pointerClient = NULL; /* Mutex for pointer events */ ++ ++static rfbClientPtr rfbNewClient(ScreenPtr pScreen, int sock); ++static void rfbProcessClientProtocolVersion(rfbClientPtr cl); ++static void rfbProcessClientInitMessage(rfbClientPtr cl); ++static void rfbSendInteractionCaps(rfbClientPtr cl); ++static void rfbProcessClientNormalMessage(rfbClientPtr cl); ++static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy); ++static Bool rfbSendLastRectMarker(rfbClientPtr cl); ++ ++static char *text = NULL; ++ ++void ++rfbRootPropertyChange(ScreenPtr pScreen) ++{ ++ PropertyPtr pProp; ++ WindowPtr pWin = WindowTable[pScreen->myNum]; ++ ++ pProp = wUserProps (pWin); ++ ++ while (pProp) { ++ if ((pProp->propertyName == XA_CUT_BUFFER0) && ++ (pProp->type == XA_STRING) && ++ (pProp->format == 8)) ++ { ++ /* Ensure we don't keep re-sending cut buffer */ ++ ++ if ( (text && pProp->data && strncmp(text, pProp->data, pProp->size)) || !text) ++ rfbGotXCutText(pProp->data, pProp->size); ++ ++ if (text) xfree(text); ++ text = xalloc(1 + pProp->size); ++ if (! text) return; ++ if (pProp->data) memcpy(text, pProp->data, pProp->size); ++ text[pProp->size] = '\0'; ++ ++ return; ++ } ++ if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING) ++ && (pProp->format == 8) && (pProp->size > 0)) ++ { ++ int i; ++ rfbClientPtr cl; ++ int port = 5500; ++ char *host = (char *)Xalloc(pProp->size+1); ++ memcpy(host, pProp->data, pProp->size); ++ host[pProp->size] = 0; ++ for (i = 0; i < pProp->size; i++) { ++ if (host[i] == ':') { ++ port = atoi(&host[i+1]); ++ host[i] = 0; ++ } ++ } ++ ++ cl = rfbReverseConnection(pScreen, host, port); ++ ++#ifdef CORBA ++ if (cl != NULL) ++ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1); ++#endif ++ ++ ChangeWindowProperty(pWin, ++ pProp->propertyName, pProp->type, ++ pProp->format, PropModeReplace, ++ 0, NULL, ++ FALSE ++ ); ++ ++ free(host); ++ } ++ pProp = pProp->next; ++ } ++} ++ ++int ++rfbBitsPerPixel(depth) ++ int depth; ++{ ++ if (depth == 1) return 1; ++ else if (depth <= 8) return 8; ++ else if (depth <= 16) return 16; ++ else return 32; ++} ++ ++void ++rfbUserAllow(int sock, int accept) ++{ ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->sock == sock) { ++ cl->userAccepted = accept; ++ } ++ } ++} ++ ++/* ++ * rfbNewClientConnection is called from sockets.c when a new connection ++ * comes in. ++ */ ++ ++void ++rfbNewClientConnection(ScreenPtr pScreen, int sock) ++{ ++ rfbClientPtr cl; ++ ++ cl = rfbNewClient(pScreen, sock); ++ ++#if 0 ++ GenerateVncConnectedEvent(sock); ++#endif ++ ++#if XFREE86VNC ++ /* Someone is connected - disable VT switching */ ++ xf86EnableVTSwitch(FALSE); ++#endif ++ ++#ifdef CORBA ++ if (cl != NULL) ++ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1); ++#endif ++} ++ ++ ++/* ++ * rfbReverseConnection is called by the CORBA stuff to make an outward ++ * connection to a "listening" RFB client. ++ */ ++ ++rfbClientPtr ++rfbReverseConnection(ScreenPtr pScreen, char *host, int port) ++{ ++ int sock; ++ rfbClientPtr cl; ++ ++ if ((sock = rfbConnect(pScreen, host, port)) < 0) ++ return (rfbClientPtr)NULL; ++ ++ cl = rfbNewClient(pScreen, sock); ++ ++ if (cl) { ++ cl->reverseConnection = TRUE; ++ } ++ ++ return cl; ++} ++ ++ ++#ifdef CHROMIUM ++/* ++ * rfbSetClip -- ++ * Generate expose event. ++ * This function is overkill and should be cleaned up, but it ++ * works for now. ++ */ ++ ++static void ++rfbSetClip(WindowPtr pWin, BOOL enable) ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ WindowPtr pChild; ++ Bool WasViewable = (Bool)(pWin->viewable); ++ Bool anyMarked = FALSE; ++ RegionPtr pOldClip = NULL, bsExposed; ++#ifdef DO_SAVE_UNDERS ++ Bool dosave = FALSE; ++#endif ++ WindowPtr pLayerWin; ++ BoxRec box; ++ ++ if (WasViewable) ++ { ++ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) ++ { ++ (void) (*pScreen->MarkOverlappedWindows)(pChild, ++ pChild, ++ &pLayerWin); ++ } ++ (*pScreen->MarkWindow) (pWin); ++ anyMarked = TRUE; ++ if (pWin->valdata) ++ { ++ if (HasBorder (pWin)) ++ { ++ RegionPtr borderVisible; ++ ++ borderVisible = REGION_CREATE(pScreen, NullBox, 1); ++ REGION_SUBTRACT(pScreen, borderVisible, ++ &pWin->borderClip, &pWin->winSize); ++ pWin->valdata->before.borderVisible = borderVisible; ++ } ++ pWin->valdata->before.resized = TRUE; ++ } ++ } ++ ++ /* ++ * Use REGION_BREAK to avoid optimizations in ValidateTree ++ * that assume the root borderClip can't change well, normally ++ * it doesn't...) ++ */ ++ if (enable) ++ { ++ box.x1 = 0; ++ box.y1 = 0; ++ box.x2 = pScreen->width; ++ box.y2 = pScreen->height; ++ REGION_INIT (pScreen, &pWin->winSize, &box, 1); ++ REGION_INIT (pScreen, &pWin->borderSize, &box, 1); ++ if (WasViewable) ++ REGION_RESET(pScreen, &pWin->borderClip, &box); ++ pWin->drawable.width = pScreen->width; ++ pWin->drawable.height = pScreen->height; ++ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); ++ } ++ else ++ { ++ REGION_EMPTY(pScreen, &pWin->borderClip); ++ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); ++ } ++ ++ ResizeChildrenWinSize (pWin, 0, 0, 0, 0); ++ ++ if (WasViewable) ++ { ++ if (pWin->backStorage) ++ { ++ pOldClip = REGION_CREATE(pScreen, NullBox, 1); ++ REGION_COPY(pScreen, pOldClip, &pWin->clipList); ++ } ++ ++ if (pWin->firstChild) ++ { ++ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, ++ pWin->firstChild, ++ (WindowPtr *)NULL); ++ } ++ else ++ { ++ (*pScreen->MarkWindow) (pWin); ++ anyMarked = TRUE; ++ } ++ ++#ifdef DO_SAVE_UNDERS ++ if (DO_SAVE_UNDERS(pWin)) ++ { ++ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin); ++ } ++#endif /* DO_SAVE_UNDERS */ ++ ++ if (anyMarked) ++ (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); ++ } ++ ++ if (pWin->backStorage && ++ ((pWin->backingStore == Always) || WasViewable)) ++ { ++ if (!WasViewable) ++ pOldClip = &pWin->clipList; /* a convenient empty region */ ++ bsExposed = (*pScreen->TranslateBackingStore) ++ (pWin, 0, 0, pOldClip, ++ pWin->drawable.x, pWin->drawable.y); ++ if (WasViewable) ++ REGION_DESTROY(pScreen, pOldClip); ++ if (bsExposed) ++ { ++ RegionPtr valExposed = NullRegion; ++ ++ if (pWin->valdata) ++ valExposed = &pWin->valdata->after.exposed; ++ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); ++ if (valExposed) ++ REGION_EMPTY(pScreen, valExposed); ++ REGION_DESTROY(pScreen, bsExposed); ++ } ++ } ++ if (WasViewable) ++ { ++ if (anyMarked) ++ (*pScreen->HandleExposures)(pWin); ++#ifdef DO_SAVE_UNDERS ++ if (dosave) ++ (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin); ++#endif /* DO_SAVE_UNDERS */ ++ if (anyMarked && pScreen->PostValidateTree) ++ (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); ++ } ++ if (pWin->realized) ++ WindowsRestructured (); ++ FlushAllOutput (); ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * rfbNewClient is called when a new connection has been made by whatever ++ * means. ++ */ ++ ++static rfbClientPtr ++rfbNewClient(ScreenPtr pScreen, int sock) ++{ ++ rfbProtocolVersionMsg pv; ++ rfbClientPtr cl; ++ BoxRec box; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(struct sockaddr_in); ++ VNCSCREENPTR(pScreen); ++ int i; ++ ++ if (rfbClientHead == NULL) { ++ /* no other clients - make sure we don't think any keys are pressed */ ++ KbdReleaseAllKeys(); ++ } else { ++ rfbLog(" (other clients"); ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ rfbLog(" %s",cl->host); ++ } ++ rfbLog(")\n"); ++ } ++ ++ cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec)); ++ ++#ifdef CHROMIUM ++ cl->chromium_port = 0; /* no GL application on this port, yet */ ++#endif ++ cl->userAccepted = 0; /* user hasn't even approached this yet .... */ ++ cl->sock = sock; ++ getpeername(sock, (struct sockaddr *)&addr, &addrlen); ++ cl->host = strdup(inet_ntoa(addr.sin_addr)); ++ cl->login = NULL; ++ ++ /* Dispatch client input to rfbProcessClientProtocolVersion(). */ ++ cl->state = RFB_PROTOCOL_VERSION; ++ ++ cl->viewOnly = FALSE; ++ cl->reverseConnection = FALSE; ++ cl->readyForSetColourMapEntries = FALSE; ++ cl->useCopyRect = FALSE; ++ cl->preferredEncoding = rfbEncodingRaw; ++ cl->correMaxWidth = 48; ++ cl->correMaxHeight = 48; ++ cl->pScreen = pScreen; ++ ++ REGION_NULL(pScreen,&cl->copyRegion); ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ ++ box.x1 = box.y1 = 0; ++ box.x2 = pVNC->width; ++ box.y2 = pVNC->height; ++ REGION_INIT(pScreen,&cl->modifiedRegion,&box,0); ++ ++ REGION_NULL(pScreen,&cl->requestedRegion); ++ ++ cl->deferredUpdateScheduled = FALSE; ++ cl->deferredUpdateTimer = NULL; ++ ++ cl->format = pVNC->rfbServerFormat; ++ cl->translateFn = rfbTranslateNone; ++ cl->translateLookupTable = NULL; ++ ++ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; ++ cl->tightQualityLevel = -1; ++ for (i = 0; i < 4; i++) ++ cl->zsActive[i] = FALSE; ++ ++ cl->enableCursorShapeUpdates = FALSE; ++ cl->enableCursorPosUpdates = FALSE; ++ cl->enableLastRectEncoding = FALSE; ++#ifdef CHROMIUM ++ cl->enableChromiumEncoding = FALSE; ++#endif ++ ++ cl->next = rfbClientHead; ++ rfbClientHead = cl; ++ ++ rfbResetStats(cl); ++ ++ cl->compStreamInited = FALSE; ++ cl->compStream.total_in = 0; ++ cl->compStream.total_out = 0; ++ cl->compStream.zalloc = Z_NULL; ++ cl->compStream.zfree = Z_NULL; ++ cl->compStream.opaque = Z_NULL; ++ ++ cl->zlibCompressLevel = 5; ++ ++ sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion, ++ rfbProtocolMinorVersion); ++ ++ if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) { ++ rfbLogPerror("rfbNewClient: write"); ++ rfbCloseSock(pScreen, sock); ++ return NULL; ++ } ++ ++ return cl; ++} ++ ++ ++/* ++ * rfbClientConnectionGone is called from sockets.c just after a connection ++ * has gone away. ++ */ ++ ++void ++rfbClientConnectionGone(sock) ++ int sock; ++{ ++ rfbClientPtr cl, prev; ++ int i; ++#if XFREE86VNC ++ int allowvt = TRUE; ++#endif ++ ++ for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) { ++ if (sock == cl->sock) ++ break; ++ } ++ ++ if (!cl) { ++ rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock); ++ return; ++ } ++ ++ if (cl->login != NULL) { ++ rfbLog("Client %s (%s) gone\n", cl->login, cl->host); ++ free(cl->login); ++ } else { ++ rfbLog("Client %s gone\n", cl->host); ++ } ++ free(cl->host); ++ ++ /* Release the compression state structures if any. */ ++ if ( cl->compStreamInited == TRUE ) { ++ deflateEnd( &(cl->compStream) ); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ if (cl->zsActive[i]) ++ deflateEnd(&cl->zsStruct[i]); ++ } ++ ++ if (pointerClient == cl) ++ pointerClient = NULL; ++ ++#ifdef CORBA ++ destroyConnection(cl); ++#endif ++ ++ if (prev) ++ prev->next = cl->next; ++ else ++ rfbClientHead = cl->next; ++ ++ REGION_UNINIT(cl->pScreen,&cl->copyRegion); ++ REGION_UNINIT(cl->pScreen,&cl->modifiedRegion); ++ TimerFree(cl->deferredUpdateTimer); ++ ++ rfbPrintStats(cl); ++ ++ if (cl->translateLookupTable) free(cl->translateLookupTable); ++ ++ xfree(cl); ++ ++#if 0 ++ GenerateVncDisconnectedEvent(sock); ++#endif ++ ++#if XFREE86VNC ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ /* still someone connected */ ++ allowvt = FALSE; ++ } ++ ++ xf86EnableVTSwitch(allowvt); ++#endif ++} ++ ++ ++/* ++ * rfbProcessClientMessage is called when there is data to read from a client. ++ */ ++ ++void ++rfbProcessClientMessage(ScreenPtr pScreen, int sock) ++{ ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (sock == cl->sock) ++ break; ++ } ++ ++ if (!cl) { ++ rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock); ++ rfbCloseSock(pScreen, sock); ++ return; ++ } ++ ++#ifdef CORBA ++ if (isClosePending(cl)) { ++ rfbLog("Closing connection to client %s\n", cl->host); ++ rfbCloseSock(pScreen, sock); ++ return; ++ } ++#endif ++ ++ switch (cl->state) { ++ case RFB_PROTOCOL_VERSION: ++ rfbProcessClientProtocolVersion(cl); ++ break; ++ case RFB_SECURITY_TYPE: /* protocol 3.7 */ ++ rfbProcessClientSecurityType(cl); ++ break; ++ case RFB_TUNNELING_TYPE: /* protocol 3.7t */ ++ rfbProcessClientTunnelingType(cl); ++ break; ++ case RFB_AUTH_TYPE: /* protocol 3.7t */ ++ rfbProcessClientAuthType(cl); ++ break; ++ case RFB_AUTHENTICATION: ++ rfbVncAuthProcessResponse(cl); ++ break; ++ case RFB_INITIALISATION: ++ rfbProcessClientInitMessage(cl); ++ break; ++ default: ++ rfbProcessClientNormalMessage(cl); ++ } ++} ++ ++ ++/* ++ * rfbProcessClientProtocolVersion is called when the client sends its ++ * protocol version. ++ */ ++ ++static void ++rfbProcessClientProtocolVersion(cl) ++ rfbClientPtr cl; ++{ ++ rfbProtocolVersionMsg pv; ++ int n, major, minor; ++ ++ if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientProtocolVersion: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientProtocolVersion: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ pv[sz_rfbProtocolVersionMsg] = 0; ++ if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) { ++ rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ rfbLog("Using protocol version %d.%d\n", major, minor); ++ ++ if (major != rfbProtocolMajorVersion) { ++ rfbLog("RFB protocol version mismatch - server %d.%d, client %d.%d\n", ++ rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Always use one of the two standard versions of the RFB protocol. */ ++ cl->protocol_minor_ver = minor; ++ if (minor > rfbProtocolMinorVersion) { ++ cl->protocol_minor_ver = rfbProtocolMinorVersion; ++ } else if (minor < rfbProtocolMinorVersion) { ++ cl->protocol_minor_ver = rfbProtocolFallbackMinorVersion; ++ } ++ if (minor != rfbProtocolMinorVersion && ++ minor != rfbProtocolFallbackMinorVersion) { ++ rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n", ++ major, minor, rfbProtocolMajorVersion, cl->protocol_minor_ver); ++ } ++ ++ /* TightVNC protocol extensions are not enabled yet. */ ++ cl->protocol_tightvnc = FALSE; ++ ++ rfbAuthNewClient(cl); ++} ++ ++/* ++ * rfbClientConnFailed is called when a client connection has failed ++ * before the authentication stage. ++ */ ++ ++void ++rfbClientConnFailed(cl, reason) ++ rfbClientPtr cl; ++ char *reason; ++{ ++ int headerLen, reasonLen; ++ char buf[8]; ++ ++ headerLen = (cl->protocol_minor_ver >= 7) ? 1 : 4; ++ reasonLen = strlen(reason); ++ ((CARD32 *)buf)[0] = 0; ++ ((CARD32 *)buf)[1] = Swap32IfLE(reasonLen); ++ ++ if ( WriteExact(cl->sock, buf, headerLen) < 0 || ++ WriteExact(cl->sock, buf + 4, 4) < 0 || ++ WriteExact(cl->sock, reason, reasonLen) < 0 ) { ++ rfbLogPerror("rfbClientConnFailed: write"); ++ } ++ ++ rfbCloseSock(cl->pScreen, cl->sock); ++} ++ ++ ++/* ++ * rfbProcessClientInitMessage is called when the client sends its ++ * initialisation message. ++ */ ++ ++static void ++rfbProcessClientInitMessage(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbClientInitMsg ci; ++ char buf[256]; ++ rfbServerInitMsg *si = (rfbServerInitMsg *)buf; ++ struct passwd *user; ++ int len, n; ++ rfbClientPtr otherCl, nextCl; ++ ++ if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientInitMessage: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientInitMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ si->framebufferWidth = Swap16IfLE(pVNC->width); ++ si->framebufferHeight = Swap16IfLE(pVNC->height); ++ si->format = pVNC->rfbServerFormat; ++ si->format.redMax = Swap16IfLE(si->format.redMax); ++ si->format.greenMax = Swap16IfLE(si->format.greenMax); ++ si->format.blueMax = Swap16IfLE(si->format.blueMax); ++ ++ user = getpwuid(getuid()); ++ ++ if (strlen(desktopName) > 128) /* sanity check on desktop name len */ ++ desktopName[128] = 0; ++ ++ if (user) { ++ sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)", ++ user->pw_name, desktopName, rfbThisHost, display); ++ } else { ++ sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)", ++ desktopName, rfbThisHost, display); ++ } ++ len = strlen(buf + sz_rfbServerInitMsg); ++ si->nameLength = Swap32IfLE(len); ++ ++ if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) { ++ rfbLogPerror("rfbProcessClientInitMessage: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (cl->protocol_tightvnc) ++ rfbSendInteractionCaps(cl); /* protocol 3.7t */ ++ ++ /* Dispatch client input to rfbProcessClientNormalMessage(). */ ++ cl->state = RFB_NORMAL; ++ ++ if (!cl->reverseConnection && ++ (pVNC->rfbNeverShared || (!pVNC->rfbAlwaysShared && !ci.shared))) { ++ ++ if (pVNC->rfbDontDisconnect) { ++ for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) { ++ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { ++ rfbLog("-dontdisconnect: Not shared & existing client\n"); ++ rfbLog(" refusing new client %s\n", cl->host); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ } else { ++ for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) { ++ nextCl = otherCl->next; ++ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { ++ rfbLog("Not shared - closing connection to client %s\n", ++ otherCl->host); ++ rfbCloseSock(otherCl->pScreen, otherCl->sock); ++ } ++ } ++ } ++ } ++} ++ ++ ++/* ++ * rfbSendInteractionCaps is called after sending the server ++ * initialisation message, only if the protocol version is 3.130. ++ * In this function, we send the lists of supported protocol messages ++ * and encodings. ++ */ ++ ++/* Update these constants on changing capability lists below! */ ++#define N_SMSG_CAPS 0 ++#define N_CMSG_CAPS 0 ++#define N_ENC_CAPS 12 ++ ++void ++rfbSendInteractionCaps(cl) ++ rfbClientPtr cl; ++{ ++ rfbInteractionCapsMsg intr_caps; ++ rfbCapabilityInfo enc_list[N_ENC_CAPS]; ++ int i; ++ ++ /* Fill in the header structure sent prior to capability lists. */ ++ intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS); ++ intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS); ++ intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS); ++ intr_caps.pad = 0; ++ ++ /* Supported server->client message types. */ ++ /* For future file transfer support: ++ i = 0; ++ SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor); ++ if (i != N_SMSG_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ */ ++ ++ /* Supported client->server message types. */ ++ /* For future file transfer support: ++ i = 0; ++ SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor); ++ if (i != N_CMSG_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ */ ++ ++ /* Encoding types. */ ++ i = 0; ++ SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor); ++ if (i != N_ENC_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Send header and capability lists */ ++ if (WriteExact(cl->sock, (char *)&intr_caps, ++ sz_rfbInteractionCapsMsg) < 0 || ++ WriteExact(cl->sock, (char *)&enc_list[0], ++ sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) { ++ rfbLogPerror("rfbSendInteractionCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientNormalMessage(). */ ++ cl->state = RFB_NORMAL; ++} ++ ++ ++/* ++ * rfbProcessClientNormalMessage is called when the client has sent a normal ++ * protocol message. ++ */ ++ ++static void ++rfbProcessClientNormalMessage(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int n; ++ rfbClientToServerMsg msg; ++ char *str; ++ ++#if 0 ++ if (pVNC->rfbUserAccept) { ++ /* ++ * We've asked for another level of user authentication ++ * If the user has not validated this connected, don't ++ * process it. ++ */ ++ /* ++ * NOTE: we do it here, so the vncviewer knows it's ++ * connected, but waiting for the first screen update ++ */ ++ if (cl->userAccepted == VNC_USER_UNDEFINED) ++ return; ++ if (cl->userAccepted == VNC_USER_DISCONNECT) { ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++#endif ++ ++ if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ switch (msg.type) { ++ ++ case rfbSetPixelFormat: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbSetPixelFormatMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel; ++ cl->format.depth = msg.spf.format.depth; ++ cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0); ++ cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0); ++ cl->format.redMax = Swap16IfLE(msg.spf.format.redMax); ++ cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax); ++ cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax); ++ cl->format.redShift = msg.spf.format.redShift; ++ cl->format.greenShift = msg.spf.format.greenShift; ++ cl->format.blueShift = msg.spf.format.blueShift; ++ ++ cl->readyForSetColourMapEntries = TRUE; ++ ++ rfbSetTranslateFunction(cl); ++ return; ++ ++ ++ case rfbFixColourMapEntries: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbFixColourMapEntriesMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ rfbLog("rfbProcessClientNormalMessage: %s", ++ "FixColourMapEntries unsupported\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ ++ ++ case rfbSetEncodings: ++ { ++ int i; ++ CARD32 enc; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbSetEncodingsMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings); ++ ++ cl->preferredEncoding = -1; ++ cl->useCopyRect = FALSE; ++ cl->enableCursorShapeUpdates = FALSE; ++ cl->enableCursorPosUpdates = FALSE; ++ cl->enableLastRectEncoding = FALSE; ++#ifdef CHROMIUM ++ cl->enableChromiumEncoding = FALSE; ++#endif ++ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; ++ cl->tightQualityLevel = -1; ++ ++ for (i = 0; i < msg.se.nEncodings; i++) { ++ if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ enc = Swap32IfLE(enc); ++ ++ switch (enc) { ++ ++ case rfbEncodingCopyRect: ++ cl->useCopyRect = TRUE; ++ rfbLog("Using copyrect encoding for client %s\n", ++ cl->host); ++ break; ++ case rfbEncodingRaw: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using raw encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingRRE: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using rre encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingCoRRE: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using CoRRE encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingHextile: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using hextile encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingZlib: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using zlib encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingTight: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using tight encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingXCursor: ++ rfbLog("Enabling X-style cursor updates for client %s\n", ++ cl->host); ++ cl->enableCursorShapeUpdates = TRUE; ++ cl->useRichCursorEncoding = FALSE; ++ cl->cursorWasChanged = TRUE; ++ break; ++ case rfbEncodingRichCursor: ++ if (!cl->enableCursorShapeUpdates) { ++ rfbLog("Enabling full-color cursor updates for client " ++ "%s\n", cl->host); ++ cl->enableCursorShapeUpdates = TRUE; ++ cl->useRichCursorEncoding = TRUE; ++ cl->cursorWasChanged = TRUE; ++ } ++ break; ++ case rfbEncodingPointerPos: ++ if (!cl->enableCursorPosUpdates) { ++ rfbLog("Enabling cursor position updates for client %s\n", ++ cl->host); ++ cl->enableCursorPosUpdates = TRUE; ++ cl->cursorWasMoved = TRUE; ++ cl->cursorX = -1; ++ cl->cursorY = -1; ++ } ++ break; ++ case rfbEncodingLastRect: ++ if (!cl->enableLastRectEncoding) { ++ rfbLog("Enabling LastRect protocol extension for client " ++ "%s\n", cl->host); ++ cl->enableLastRectEncoding = TRUE; ++ } ++ break; ++#ifdef CHROMIUM ++ case rfbEncodingChromium: ++ if (!cl->enableChromiumEncoding) { ++ WindowPtr pWin = WindowTable[cl->pScreen->myNum]; ++ rfbLog("Enabling Chromium protocol extension for client " ++ "%s\n", cl->host); ++ cl->enableChromiumEncoding = TRUE; ++ /* Now generate an event, so we can start our GL app */ ++ GenerateVncChromiumConnectedEvent(cl->sock); ++ /* Generate exposures for all windows */ ++ rfbSetClip(pWin, 1); ++ } ++ break; ++#endif ++ default: ++ if ( enc >= (CARD32)rfbEncodingCompressLevel0 && ++ enc <= (CARD32)rfbEncodingCompressLevel9 ) { ++ cl->zlibCompressLevel = enc & 0x0F; ++ cl->tightCompressLevel = enc & 0x0F; ++ rfbLog("Using compression level %d for client %s\n", ++ cl->tightCompressLevel, cl->host); ++ } else if ( enc >= (CARD32)rfbEncodingQualityLevel0 && ++ enc <= (CARD32)rfbEncodingQualityLevel9 ) { ++ cl->tightQualityLevel = enc & 0x0F; ++ rfbLog("Using image quality level %d for client %s\n", ++ cl->tightQualityLevel, cl->host); ++ } else { ++ rfbLog("rfbProcessClientNormalMessage: ignoring unknown " ++ "encoding 0x%x\n", (int)enc); ++ } ++ } ++ } ++ ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = rfbEncodingRaw; ++ rfbLog("No encoding specified - using raw encoding for client %s\n", ++ cl->host); ++ } ++ ++ if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) { ++ rfbLog("Disabling cursor position updates for client %s\n", ++ cl->host); ++ cl->enableCursorPosUpdates = FALSE; ++ } ++ ++#if XFREE86VNC ++ /* ++ * With XFree86 and the hardware cursor's we need to put up the ++ * cursor again, and if we've detected a cursor shapeless client ++ * we need to disable hardware cursors. ++ */ ++ if (!cl->enableCursorShapeUpdates) ++ pVNC->SWCursor = (Bool *)TRUE; ++ else ++ pVNC->SWCursor = (Bool *)FALSE; ++ ++ { ++ int x, y; ++ miPointerPosition(&x, &y); ++ (*pVNC->spriteFuncs->SetCursor)(cl->pScreen, pVNC->pCurs, x, y); ++ } ++#endif ++ ++ return; ++ } ++ ++ ++ case rfbFramebufferUpdateRequest: ++ { ++ RegionRec tmpRegion; ++ BoxRec box; ++ ++#ifdef CORBA ++ addCapability(cl, DISPLAY_DEVICE); ++#endif ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ box.x1 = Swap16IfLE(msg.fur.x); ++ box.y1 = Swap16IfLE(msg.fur.y); ++ box.x2 = box.x1 + Swap16IfLE(msg.fur.w); ++ box.y2 = box.y1 + Swap16IfLE(msg.fur.h); ++ SAFE_REGION_INIT(cl->pScreen,&tmpRegion,&box,0); ++ ++ REGION_UNION(cl->pScreen, &cl->requestedRegion, &cl->requestedRegion, ++ &tmpRegion); ++ ++ if (!cl->readyForSetColourMapEntries) { ++ /* client hasn't sent a SetPixelFormat so is using server's */ ++ cl->readyForSetColourMapEntries = TRUE; ++ if (!cl->format.trueColour) { ++ if (!rfbSetClientColourMap(cl, 0, 0)) { ++ REGION_UNINIT(cl->pScreen,&tmpRegion); ++ return; ++ } ++ } ++ } ++ ++ if (!msg.fur.incremental) { ++ REGION_UNION(cl->pScreen,&cl->modifiedRegion,&cl->modifiedRegion, ++ &tmpRegion); ++ REGION_SUBTRACT(cl->pScreen,&cl->copyRegion,&cl->copyRegion, ++ &tmpRegion); ++ } ++ ++ if (FB_UPDATE_PENDING(cl)) { ++ rfbSendFramebufferUpdate(cl->pScreen, cl); ++ } ++ ++ REGION_UNINIT(cl->pScreen,&tmpRegion); ++ return; ++ } ++ ++ case rfbKeyEvent: ++ ++ cl->rfbKeyEventsRcvd++; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbKeyEventMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++#ifdef CORBA ++ addCapability(cl, KEYBOARD_DEVICE); ++ ++ if (!isKeyboardEnabled(cl)) ++ return; ++#endif ++ if (!pVNC->rfbViewOnly && !cl->viewOnly) { ++ KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl); ++ } ++ return; ++ ++ ++ case rfbPointerEvent: ++ ++ cl->rfbPointerEventsRcvd++; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbPointerEventMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++#ifdef CORBA ++ addCapability(cl, POINTER_DEVICE); ++ ++ if (!isPointerEnabled(cl)) ++ return; ++#endif ++ ++ if (pointerClient && (pointerClient != cl)) ++ return; ++ ++ if (msg.pe.buttonMask == 0) ++ pointerClient = NULL; ++ else ++ pointerClient = cl; ++ ++ if (!pVNC->rfbViewOnly && !cl->viewOnly) { ++ cl->cursorX = (int)Swap16IfLE(msg.pe.x); ++ cl->cursorY = (int)Swap16IfLE(msg.pe.y); ++ PtrAddEvent(msg.pe.buttonMask, cl->cursorX, cl->cursorY, cl); ++ } ++ return; ++ ++ ++ case rfbClientCutText: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbClientCutTextMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ msg.cct.length = Swap32IfLE(msg.cct.length); ++ ++ str = (char *)xalloc(msg.cct.length); ++ ++ if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ xfree(str); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* NOTE: We do not accept cut text from a view-only client */ ++ if (!cl->viewOnly) ++ rfbSetXCutText(str, msg.cct.length); ++ ++ xfree(str); ++ return; ++ ++#ifdef CHROMIUM ++ case rfbChromiumStop: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbChromiumStopMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* would we use msg.csd.port ??? */ ++ ++ cl->chromium_port = 0; ++ ++ /* tear down window information */ ++ { ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ xfree(wt); ++ } ++ ++ windowTable = NULL; ++ } ++ ++ return; ++ ++ case rfbChromiumExpose: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbChromiumExposeMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* find the window and re-expose it */ ++ { ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->CRwinId == msg.cse.winid) { ++ WindowPtr pWin; ++ pWin = LookupIDByType(wt->XwinId, RT_WINDOW); ++ if (pWin) { ++ miSendExposures(pWin, &pWin->clipList, ++ pWin->drawable.x, ++ pWin->drawable.y); ++ FlushAllOutput(); ++ } ++ } ++ } ++ } ++ ++ return; ++#endif ++ ++ default: ++ ++ rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n", ++ msg.type); ++ rfbLog(" ... closing connection\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++} ++ ++ ++ ++/* ++ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to ++ * the RFB client. ++ */ ++ ++Bool ++rfbSendFramebufferUpdate(pScreen, cl) ++ ScreenPtr pScreen; ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(pScreen); ++ int i; ++ int nUpdateRegionRects; ++ rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)pVNC->updateBuf; ++ RegionRec updateRegion, updateCopyRegion; ++ int dx, dy; ++ Bool sendCursorShape = FALSE; ++ Bool sendCursorPos = FALSE; ++ ++ /* ++ * If this client understands cursor shape updates, cursor should be ++ * removed from the framebuffer. Otherwise, make sure it's put up. ++ */ ++ ++#if XFREE86VNC ++ if (cl->enableCursorShapeUpdates) { ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor(pScreen); ++ if (!pVNC->cursorIsDrawn && cl->cursorWasChanged) ++ sendCursorShape = TRUE; ++ } else { ++ if (!pVNC->cursorIsDrawn) ++ rfbSpriteRestoreCursor(pScreen); ++ } ++#else ++ if (cl->enableCursorShapeUpdates) ++ if (cl->cursorWasChanged) ++ sendCursorShape = TRUE; ++#endif ++ ++ /* ++ * Do we plan to send cursor position update? ++ */ ++ ++ if (cl->enableCursorPosUpdates && cl->cursorWasMoved) ++ sendCursorPos = TRUE; ++ ++ /* ++ * The modifiedRegion may overlap the destination copyRegion. We remove ++ * any overlapping bits from the copyRegion (since they'd only be ++ * overwritten anyway). ++ */ ++ ++ REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion, ++ &cl->modifiedRegion); ++ ++ /* ++ * The client is interested in the region requestedRegion. The region ++ * which should be updated now is the intersection of requestedRegion ++ * and the union of modifiedRegion and copyRegion. If it's empty then ++ * no update is needed. ++ */ ++ ++ REGION_NULL(pScreen,&updateRegion); ++ REGION_UNION(pScreen, &updateRegion, &cl->copyRegion, ++ &cl->modifiedRegion); ++ REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion, ++ &updateRegion); ++ ++ if ( !REGION_NOTEMPTY(pScreen,&updateRegion) && ++ !sendCursorShape && !sendCursorPos ) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return TRUE; ++ } ++ ++ /* ++ * We assume that the client doesn't have any pixel data outside the ++ * requestedRegion. In other words, both the source and destination of a ++ * copy must lie within requestedRegion. So the region we can send as a ++ * copy is the intersection of the copyRegion with both the requestedRegion ++ * and the requestedRegion translated by the amount of the copy. We set ++ * updateCopyRegion to this. ++ */ ++ ++ REGION_NULL(pScreen,&updateCopyRegion); ++ REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion, ++ &cl->requestedRegion); ++ REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY); ++ REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion, ++ &cl->requestedRegion); ++ dx = cl->copyDX; ++ dy = cl->copyDY; ++ ++ /* ++ * Next we remove updateCopyRegion from updateRegion so that updateRegion ++ * is the part of this update which is sent as ordinary pixel data (i.e not ++ * a copy). ++ */ ++ ++ REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion); ++ ++ /* ++ * Finally we leave modifiedRegion to be the remainder (if any) of parts of ++ * the screen which are modified but outside the requestedRegion. We also ++ * empty both the requestedRegion and the copyRegion - note that we never ++ * carry over a copyRegion for a future update. ++ */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &updateRegion); ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &updateCopyRegion); ++ ++ REGION_EMPTY(pScreen, &cl->requestedRegion); ++ REGION_EMPTY(pScreen, &cl->copyRegion); ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ ++ /* ++ * Now send the update. ++ */ ++ ++ cl->rfbFramebufferUpdateMessagesSent++; ++ ++ if (cl->preferredEncoding == rfbEncodingCoRRE) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1) ++ * ((h-1) / cl->correMaxHeight + 1)); ++ } ++ } else if (cl->preferredEncoding == rfbEncodingZlib) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1); ++ } ++ } else if (cl->preferredEncoding == rfbEncodingTight) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ int n = rfbNumCodedRectsTight(cl, x, y, w, h); ++ if (n == 0) { ++ nUpdateRegionRects = 0xFFFF; ++ break; ++ } ++ nUpdateRegionRects += n; ++ } ++ } else { ++ nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion); ++ } ++ ++ fu->type = rfbFramebufferUpdate; ++ if (nUpdateRegionRects != 0xFFFF) { ++ fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) + ++ nUpdateRegionRects + ++ !!sendCursorShape + !!sendCursorPos); ++ } else { ++ fu->nRects = 0xFFFF; ++ } ++ pVNC->ublen = sz_rfbFramebufferUpdateMsg; ++ ++ if (sendCursorShape) { ++ cl->cursorWasChanged = FALSE; ++ if (!rfbSendCursorShape(cl, pScreen)) ++ return FALSE; ++ } ++ ++ if (sendCursorPos) { ++ cl->cursorWasMoved = FALSE; ++ if (!rfbSendCursorPos(cl, pScreen)) ++ return FALSE; ++ } ++ ++ if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) { ++ if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ REGION_UNINIT(pScreen,&updateCopyRegion); ++ return FALSE; ++ } ++ } ++ ++ REGION_UNINIT(pScreen,&updateCopyRegion); ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ ++ cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader ++ + w * (cl->format.bitsPerPixel / 8) * h); ++ ++ switch (cl->preferredEncoding) { ++ case rfbEncodingRaw: ++ if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingRRE: ++ if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingCoRRE: ++ if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingHextile: ++ if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingZlib: ++ if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingTight: ++ if (!rfbSendRectEncodingTight(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ } ++ } ++ ++ REGION_UNINIT(pScreen,&updateRegion); ++ ++ if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl)) ++ return FALSE; ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * Send the copy region as a string of CopyRect encoded rectangles. ++ * The only slightly tricky thing is that we should send the messages in ++ * the correct order so that an earlier CopyRect will not corrupt the source ++ * of a later one. ++ */ ++ ++static Bool ++rfbSendCopyRegion(cl, reg, dx, dy) ++ rfbClientPtr cl; ++ RegionPtr reg; ++ int dx, dy; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand; ++ int x, y, w, h; ++ rfbFramebufferUpdateRectHeader rect; ++ rfbCopyRect cr; ++ ++ nrects = REGION_NUM_RECTS(reg); ++ ++ if (dx <= 0) { ++ x_inc = 1; ++ } else { ++ x_inc = -1; ++ } ++ ++ if (dy <= 0) { ++ thisRect = 0; ++ y_inc = 1; ++ } else { ++ thisRect = nrects - 1; ++ y_inc = -1; ++ } ++ ++ while (nrects > 0) { ++ ++ firstInNextBand = thisRect; ++ nrectsInBand = 0; ++ ++ while ((nrects > 0) && ++ (REGION_RECTS(reg)[firstInNextBand].y1 ++ == REGION_RECTS(reg)[thisRect].y1)) ++ { ++ firstInNextBand += y_inc; ++ nrects--; ++ nrectsInBand++; ++ } ++ ++ if (x_inc != y_inc) { ++ thisRect = firstInNextBand - y_inc; ++ } ++ ++ while (nrectsInBand > 0) { ++ if ((pVNC->ublen + sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbCopyRect) > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ x = REGION_RECTS(reg)[thisRect].x1; ++ y = REGION_RECTS(reg)[thisRect].y1; ++ w = REGION_RECTS(reg)[thisRect].x2 - x; ++ h = REGION_RECTS(reg)[thisRect].y2 - y; ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingCopyRect); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cr.srcX = Swap16IfLE(x - dx); ++ cr.srcY = Swap16IfLE(y - dy); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&cr, sz_rfbCopyRect); ++ pVNC->ublen += sz_rfbCopyRect; ++ ++ cl->rfbRectanglesSent[rfbEncodingCopyRect]++; ++ cl->rfbBytesSent[rfbEncodingCopyRect] ++ += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect; ++ ++ thisRect += x_inc; ++ nrectsInBand--; ++ } ++ ++ thisRect = firstInNextBand; ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Send a given rectangle in raw encoding (rfbEncodingRaw). ++ */ ++ ++Bool ++rfbSendRectEncodingRaw(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ int nlines; ++ int bytesPerLine = w * (cl->format.bitsPerPixel / 8); ++ unsigned char *fbptr = NULL; ++ int newy = 0; ++ ++ if (pVNC->useGetImage) { ++ newy = y; ++ } else { ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ } ++ ++ /* Flush the buffer to guarantee correct alignment for translateFn(). */ ++ if (pVNC->ublen > 0) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingRaw); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingRaw]++; ++ cl->rfbBytesSent[rfbEncodingRaw] ++ += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h; ++ ++ nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine; ++ ++ while (TRUE) { ++ if (nlines > h) ++ nlines = h; ++ ++ if (pVNC->useGetImage) { ++ (*cl->pScreen->GetImage)((DrawablePtr)WindowTable[cl->pScreen->myNum], x, newy, w, nlines, ZPixmap, ~0, &pVNC->updateBuf[pVNC->ublen]); ++ newy += nlines; ++ } else { ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat, ++ &cl->format, fbptr, &pVNC->updateBuf[pVNC->ublen], ++ pVNC->paddedWidthInBytes, w, nlines, x, y); ++ } ++ ++ pVNC->ublen += nlines * bytesPerLine; ++ h -= nlines; ++ ++ if (h == 0) /* rect fitted in buffer, do next one */ ++ return TRUE; ++ ++ /* buffer full - flush partial rect and do another nlines */ ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ if (!pVNC->useGetImage) ++ fbptr += (pVNC->paddedWidthInBytes * nlines); ++ ++ nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine; ++ if (nlines == 0) { ++ rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d " ++ "bytes per line\n", bytesPerLine); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ } ++} ++ ++ ++/* ++ * Send an empty rectangle with encoding field set to value of ++ * rfbEncodingLastRect to notify client that this is the last ++ * rectangle in framebuffer update ("LastRect" extension of RFB ++ * protocol). ++ */ ++ ++static Bool ++rfbSendLastRectMarker(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.encoding = Swap32IfLE(rfbEncodingLastRect); ++ rect.r.x = 0; ++ rect.r.y = 0; ++ rect.r.w = 0; ++ rect.r.h = 0; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbLastRectMarkersSent++; ++ cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Send the contents of pVNC->updateBuf. Returns 1 if successful, -1 if ++ * not (errno should be set). ++ */ ++ ++Bool ++rfbSendUpdateBuf(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ ++ /* ++ int i; ++ for (i = 0; i < pVNC->ublen; i++) { ++ rfbLog("%02x ",((unsigned char *)pVNC->updateBuf)[i]); ++ } ++ rfbLog("\n"); ++ */ ++ ++ if (pVNC->ublen > 0 && WriteExact(cl->sock, pVNC->updateBuf, pVNC->ublen) < 0) { ++ rfbLogPerror("rfbSendUpdateBuf: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ pVNC->ublen = 0; ++ return TRUE; ++} ++ ++ ++ ++/* ++ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the ++ * client, using values from the currently installed colormap. ++ */ ++ ++Bool ++rfbSendSetColourMapEntries(cl, firstColour, nColours) ++ rfbClientPtr cl; ++ int firstColour; ++ int nColours; ++{ ++#if !XFREE86VNC ++ VNCSCREENPTR(cl->pScreen); ++#endif ++ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; ++ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; ++ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); ++ EntryPtr pent; ++ EntryPtr redEntry, greenEntry, blueEntry; ++ unsigned short redPart, greenPart, bluePart; ++ int i, len; ++ ++ scme->type = rfbSetColourMapEntries; ++ scme->nColours = Swap16IfLE(nColours); ++ ++ len = sz_rfbSetColourMapEntriesMsg; ++ ++ /* PseudoColor */ ++#if XFREE86VNC ++ if (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor) { ++#else ++ if (pVNC->rfbInstalledColormap->class == PseudoColor) { ++#endif ++ scme->firstColour = Swap16IfLE(firstColour); ++#if XFREE86VNC ++ pent = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[firstColour]; ++#else ++ pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[firstColour]; ++#endif ++ for (i = 0; i < nColours; i++) { ++ if (pent->fShared) { ++ rgb[i*3] = Swap16IfLE(pent->co.shco.red->color); ++ rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color); ++ rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color); ++ } else { ++ rgb[i*3] = Swap16IfLE(pent->co.local.red); ++ rgb[i*3+1] = Swap16IfLE(pent->co.local.green); ++ rgb[i*3+2] = Swap16IfLE(pent->co.local.blue); ++ } ++ pent++; ++ } ++ } ++ ++ else { ++ ++ /* Break the DirectColor pixel into its r/g/b components */ ++#if XFREE86VNC ++ redPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->redMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetRed; ++ greenPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->greenMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetGreen; ++ bluePart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->blueMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetBlue; ++#else ++ redPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->redMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetRed; ++ greenPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->greenMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetGreen; ++ bluePart = (firstColour & pVNC->rfbInstalledColormap->pVisual->blueMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetBlue; ++#endif ++ ++ /* ++ * The firstColour field is only 16 bits. To support 24-bit pixels we ++ * sneak the red component in the 8-bit padding field which we renamed ++ * to redIndex. Green and blue are in firstColour (MSB, LSB respectively). ++ */ ++ scme->redIndex = Swap16IfLE(redPart); ++ scme->firstColour = Swap16IfLE((greenPart << 8) | bluePart); ++ ++#if XFREE86VNC ++ redEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[redPart]; ++ greenEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->green[greenPart]; ++ blueEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->blue[bluePart]; ++#else ++ redEntry = (EntryPtr)&pVNC->rfbInstalledColormap->red[redPart]; ++ greenEntry = (EntryPtr)&pVNC->rfbInstalledColormap->green[greenPart]; ++ blueEntry = (EntryPtr)&pVNC->rfbInstalledColormap->blue[bluePart]; ++#endif ++ for (i = 0; i < nColours; i++) { ++ if (redEntry->fShared) ++ rgb[i*3] = Swap16IfLE(redEntry->co.shco.red->color); ++ else ++ rgb[i*3] = Swap16IfLE(redEntry->co.local.red); ++ ++ if (greenEntry->fShared) ++ rgb[i*3+1] = Swap16IfLE(greenEntry->co.shco.green->color); ++ else ++ rgb[i*3+1] = Swap16IfLE(greenEntry->co.local.green); ++ ++ if (blueEntry->fShared) ++ rgb[i*3+2] = Swap16IfLE(blueEntry->co.shco.blue->color); ++ else ++ rgb[i*3+2] = Swap16IfLE(blueEntry->co.local.blue); ++ ++ redEntry++; ++ greenEntry++; ++ blueEntry++; ++ } ++ } ++ ++ len += nColours * 3 * 2; ++ ++ if (WriteExact(cl->sock, buf, len) < 0) { ++ rfbLogPerror("rfbSendSetColourMapEntries: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* ++ * rfbSendBell sends a Bell message to all the clients. ++ */ ++ ++void ++rfbSendBell() ++{ ++ rfbClientPtr cl, nextCl; ++ rfbBellMsg b; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ b.type = rfbBell; ++ if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) { ++ rfbLogPerror("rfbSendBell: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ } ++} ++ ++#ifdef CHROMIUM ++#ifdef sun ++extern int inet_aton(const char *cp, struct in_addr *inp); ++#endif ++ ++/** ++ * Tell the VNC viewers to start a new crserver process. ++ */ ++void ++rfbSendChromiumStart(unsigned int ipaddress, unsigned int port) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumStartMsg scd; ++ struct in_addr ip; ++ unsigned int vncipaddress; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ inet_aton(cl->host, &ip); ++ memcpy(&vncipaddress, &ip, sizeof(unsigned int)); ++ if (ipaddress == vncipaddress && !cl->chromium_port) { ++ cl->chromium_port = port; ++ scd.type = rfbChromiumStart; ++ scd.port = port; ++ if (WriteExact(cl->sock, (char *)&scd, ++ sz_rfbChromiumStartMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumStart: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ /* We only start one client at at time, so break now! */ ++ break; ++ } ++ } ++} ++ ++/** ++ * Begin tracking the size, position, visibility and cliprect info for the ++ * given Chromium/X window. ++ */ ++void ++rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid) ++{ ++ CRWindowTable *nextRec; ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ /* See if we're already managing this window */ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ /* and if so, update it's window ID */ ++ if (wt->CRwinId == cr_windowid) { ++ wt->XwinId = windowid; ++ return; ++ } ++ } ++ ++ /* o.k, new window so create new slot information */ ++ nextRec = (CRWindowTable *)xalloc(sizeof(CRWindowTable)); ++ ++ if (!nextRec) ++ { ++ rfbLog("OUCH, Chromium can't monitor window ID\n"); ++ return; ++ } ++ ++ nextRec->next = NULL; ++ nextRec->CRwinId = cr_windowid; ++ nextRec->XwinId = windowid; ++ nextRec->clipRects = NULL; ++ nextRec->numRects = 0; ++ ++ if (!windowTable) ++ windowTable = nextRec; ++ else ++ { ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (!wt->next) /* found the next slot */ ++ wt->next = nextRec; ++ } ++ } ++} ++ ++/** ++ * Send new window position/size info to all VNC clients who want this info. ++ */ ++void ++rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumMoveResizeWindowMsg scm; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ scm.type = rfbChromiumMoveResizeWindow; ++ scm.winid = winid; ++ scm.x = x; ++ scm.y = y; ++ scm.w = w; ++ scm.h = h; ++ if (WriteExact(cl->sock, (char *)&scm, ++ sz_rfbChromiumMoveResizeWindowMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumMoveResizeWindow: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++ ++/** ++ * Send the new cliprect info for the given window to all VNC clients who ++ * want this info. ++ */ ++void ++rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumClipListMsg sccl; ++ int len = sizeof(BoxRec) * numClipRects; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ sccl.type = rfbChromiumClipList; ++ sccl.winid = winid; ++ sccl.length = Swap32IfLE(len); ++ if (WriteExact(cl->sock, (char *)&sccl, ++ sz_rfbChromiumClipListMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumClipList: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ if (WriteExact(cl->sock, (char *)pClipRects, len) < 0) { ++ rfbLogPerror("rfbSendChromiumClipList: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++ ++/** ++ * Tell VNC clients about the visibility status of given window. ++ */ ++void ++rfbSendChromiumWindowShow(unsigned int winid, unsigned int show) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumWindowShowMsg scws; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ scws.type = rfbChromiumWindowShow; ++ scws.winid = winid; ++ scws.show = show; ++ if (WriteExact(cl->sock, (char *)&scws, ++ sz_rfbChromiumWindowShowMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumWindowShow: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * rfbSendServerCutText sends a ServerCutText message to all the clients. ++ */ ++ ++void ++rfbSendServerCutText(char *str, int len) ++{ ++ rfbClientPtr cl, nextCl = NULL; ++ rfbServerCutTextMsg sct; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ if (cl->state != RFB_NORMAL) continue; ++ nextCl = cl->next; ++ sct.type = rfbServerCutText; ++ sct.length = Swap32IfLE(len); ++ if (WriteExact(cl->sock, (char *)&sct, ++ sz_rfbServerCutTextMsg) < 0) { ++ rfbLogPerror("rfbSendServerCutText: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ if (WriteExact(cl->sock, str, len) < 0) { ++ rfbLogPerror("rfbSendServerCutText: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ } ++} ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * UDP can be used for keyboard and pointer events when the underlying ++ * network is highly reliable. This is really here to support ORL's ++ * videotile, whose TCP implementation doesn't like sending lots of small ++ * packets (such as 100s of pen readings per second!). ++ */ ++ ++void ++rfbNewUDPConnection(sock) ++ int sock; ++{ ++ if (write(sock, &ptrAcceleration, 1) < 0) { ++ rfbLogPerror("rfbNewUDPConnection: write"); ++ } ++} ++ ++/* ++ * Because UDP is a message based service, we can't read the first byte and ++ * then the rest of the packet separately like we do with TCP. We will always ++ * get a whole packet delivered in one go, so we ask read() for the maximum ++ * number of bytes we can possibly get. ++ */ ++ ++void ++rfbProcessUDPInput(ScreenPtr pScreen, int sock) ++{ ++ VNCSCREENPTR(pScreen); ++ int n; ++ rfbClientToServerMsg msg; ++ ++ if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) { ++ if (n < 0) { ++ rfbLogPerror("rfbProcessUDPInput: read"); ++ } ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ ++ switch (msg.type) { ++ ++ case rfbKeyEvent: ++ if (n != sz_rfbKeyEventMsg) { ++ rfbLog("rfbProcessUDPInput: key event incorrect length\n"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ if (!pVNC->rfbViewOnly) { ++ KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), 0); ++ } ++ break; ++ ++ case rfbPointerEvent: ++ if (n != sz_rfbPointerEventMsg) { ++ rfbLog("rfbProcessUDPInput: ptr event incorrect length\n"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ if (!pVNC->rfbViewOnly) { ++ PtrAddEvent(msg.pe.buttonMask, ++ Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), 0); ++ } ++ break; ++ ++ default: ++ rfbLog("rfbProcessUDPInput: unknown message type %d\n", ++ msg.type); ++ rfbDisconnectUDPSock(pScreen); ++ } ++} +diff --git a/hw/dmx/vnc/rre.c b/hw/dmx/vnc/rre.c +new file mode 100644 +index 0000000..9e63ed7 +--- /dev/null ++++ b/hw/dmx/vnc/rre.c +@@ -0,0 +1,325 @@ ++/* ++ * rre.c ++ * ++ * Routines to implement Rise-and-Run-length Encoding (RRE). This ++ * code is based on krw's original javatel rfbserver. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include "rfb.h" ++ ++/* ++ * rreBeforeBuf contains pixel data in the client's format. ++ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is ++ * larger than the raw data or if it exceeds rreAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int rreBeforeBufSize = 0; ++static char *rreBeforeBuf = NULL; ++ ++static int rreAfterBufSize = 0; ++static char *rreAfterBuf = NULL; ++static int rreAfterBufLen; ++ ++static int subrectEncode8(CARD8 *data, int w, int h); ++static int subrectEncode16(CARD16 *data, int w, int h); ++static int subrectEncode32(CARD32 *data, int w, int h); ++static CARD32 getBgColour(char *data, int size, int bpp); ++ ++ ++/* ++ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbRREHeader hdr; ++ int nSubrects; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (rreBeforeBufSize < maxRawSize) { ++ rreBeforeBufSize = maxRawSize; ++ if (rreBeforeBuf == NULL) ++ rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); ++ else ++ rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); ++ } ++ ++ if (rreAfterBufSize < maxRawSize) { ++ rreAfterBufSize = maxRawSize; ++ if (rreAfterBuf == NULL) ++ rreAfterBuf = (char *)xalloc(rreAfterBufSize); ++ else ++ rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); ++ } ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, rreBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); ++ break; ++ case 16: ++ nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); ++ break; ++ case 32: ++ nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); ++ break; ++ default: ++ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); ++ exit(1); ++ } ++ ++ if (nSubrects < 0) { ++ ++ /* RRE encoding was too large, use raw */ ++ ++ return rfbSendRectEncodingRaw(cl, x, y, w, h); ++ } ++ ++ cl->rfbRectanglesSent[rfbEncodingRRE]++; ++ cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbRREHeader + rreAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingRRE); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nSubrects = Swap32IfLE(nSubrects); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader); ++ pVNC->ublen += sz_rfbRREHeader; ++ ++ for (i = 0; i < rreAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > rreAfterBufLen) { ++ bytesToCopy = rreAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * subrectEncode() encodes the given multicoloured rectangle as a background ++ * colour overwritten by single-coloured rectangles. It returns the number ++ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't ++ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The ++ * single-colour rectangle partition is not optimal, but does find the biggest ++ * horizontal or vertical rectangle top-left anchored to each consecutive ++ * coordinate position. ++ * ++ * The coding scheme is simply [...] where each ++ * is []. ++ */ ++ ++#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 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) { ++ 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/dmx/vnc/sockets.c b/hw/dmx/vnc/sockets.c +new file mode 100644 +index 0000000..6d33435 +--- /dev/null ++++ b/hw/dmx/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 ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if HAVE_DMX_CONFIG_H ++#include "dmx-config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "windowstr.h" ++ ++#ifndef USE_LIBWRAP ++#define USE_LIBWRAP 0 ++#endif ++#if USE_LIBWRAP ++#include ++#include ++int allow_severity = LOG_INFO; ++int deny_severity = LOG_WARNING; ++#endif ++ ++#include "rfb.h" ++ ++int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has ++ gone away - needed to stop us hanging */ ++ ++static struct sockaddr_in udpRemoteAddr; ++ ++/* ++ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB ++ * connections. It does nothing if called again. ++ */ ++ ++Bool ++rfbInitSockets(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if (inetdSock != -1) { ++ const int one = 1; ++ ++ if (fcntl(inetdSock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("fcntl"); ++ return FALSE; ++ } ++ ++ if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("setsockopt"); ++ return FALSE; ++ } ++ ++ AddEnabledDevice(inetdSock); ++ FD_ZERO(&pVNC->allFds); ++ FD_SET(inetdSock, &pVNC->allFds); ++ pVNC->maxFd = inetdSock; ++ return TRUE; ++ } ++ ++ if (pVNC->rfbPort == 0) { ++ pVNC->rfbPort = 5900 + atoi(display) + pScreen->myNum; ++ } ++ ++ if ((pVNC->rfbListenSock = ListenOnTCPPort(pScreen, pVNC->rfbPort)) < 0) { ++ rfbLogPerror("ListenOnTCPPort"); ++ pVNC->rfbPort = 0; ++ return FALSE; ++ } ++ ++ rfbLog("Listening for VNC connections on TCP port %d\n", pVNC->rfbPort); ++ ++ AddEnabledDevice(pVNC->rfbListenSock); ++ ++ FD_ZERO(&pVNC->allFds); ++ FD_SET(pVNC->rfbListenSock, &pVNC->allFds); ++ pVNC->maxFd = pVNC->rfbListenSock; ++ ++ if (pVNC->udpPort != 0) { ++ rfbLog("rfbInitSockets: listening for input on UDP port %d\n",pVNC->udpPort); ++ ++ if ((pVNC->udpSock = ListenOnUDPPort(pScreen, pVNC->udpPort)) < 0) { ++ rfbLogPerror("ListenOnUDPPort"); ++ return FALSE; ++ } ++ AddEnabledDevice(pVNC->udpSock); ++ FD_SET(pVNC->udpSock, &pVNC->allFds); ++ pVNC->maxFd = max(pVNC->udpSock,pVNC->maxFd); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB ++ * socket(s). If there is input to process, the appropriate function in the ++ * RFB server code will be called (rfbNewClientConnection, ++ * rfbProcessClientMessage, etc). ++ */ ++ ++void ++rfbCheckFds(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++#if XFREE86VNC ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++#endif ++ int nfds; ++ fd_set fds; ++ struct timeval tv; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(addr); ++ char buf[6]; ++ const int one = 1; ++ int sock; ++ static Bool inetdInitDone = FALSE; ++ ++ if (!inetdInitDone && inetdSock != -1) { ++ rfbNewClientConnection(pScreen, inetdSock); ++ inetdInitDone = TRUE; ++ } ++ ++ memcpy((char *)&fds, (char *)&pVNC->allFds, sizeof(fd_set)); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ nfds = select(pVNC->maxFd + 1, &fds, NULL, NULL, &tv); ++ if (nfds == 0) { ++ return; ++ } ++ if (nfds < 0) { ++ if (errno != EINTR) ++ rfbLogPerror("rfbCheckFds: select"); ++ return; ++ } ++ ++ if (pVNC->rfbListenSock != -1 && FD_ISSET(pVNC->rfbListenSock, &fds)) { ++ ++ if ((sock = accept(pVNC->rfbListenSock, ++ (struct sockaddr *)&addr, &addrlen)) < 0) { ++ rfbLogPerror("rfbCheckFds: accept"); ++ return; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("rfbCheckFds: fcntl"); ++ close(sock); ++ return; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("rfbCheckFds: setsockopt"); ++ close(sock); ++ return; ++ } ++ ++ rfbLog("\n"); ++ ++#if USE_LIBWRAP ++ if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), ++ STRING_UNKNOWN)) { ++ rfbLog("Rejected connection from client %s\n", ++ inet_ntoa(addr.sin_addr)); ++ close(sock); ++ return; ++ } ++#endif ++ ++ rfbLog("Got VNC connection from client %s\n", inet_ntoa(addr.sin_addr)); ++ ++ AddEnabledDevice(sock); ++ FD_SET(sock, &pVNC->allFds); ++ pVNC->maxFd = max(sock,pVNC->maxFd); ++ ++ rfbNewClientConnection(pScreen, sock); ++ ++ FD_CLR(pVNC->rfbListenSock, &fds); ++ if (--nfds == 0) ++ return; ++ } ++ ++ if ((pVNC->udpSock != -1) && FD_ISSET(pVNC->udpSock, &fds)) { ++ ++ if (recvfrom(pVNC->udpSock, buf, 1, MSG_PEEK, ++ (struct sockaddr *)&addr, &addrlen) < 0) { ++ ++ rfbLogPerror("rfbCheckFds: UDP: recvfrom"); ++ rfbDisconnectUDPSock(pScreen); ++ ++ } else { ++ ++ if (!pVNC->udpSockConnected || ++ (memcmp(&addr, &udpRemoteAddr, addrlen) != 0)) ++ { ++ /* new remote end */ ++ rfbLog("rfbCheckFds: UDP: got connection\n"); ++ ++ memcpy(&udpRemoteAddr, &addr, addrlen); ++ pVNC->udpSockConnected = TRUE; ++ ++ if (connect(pVNC->udpSock, ++ (struct sockaddr *)&addr, addrlen) < 0) { ++ rfbLogPerror("rfbCheckFds: UDP: connect"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ ++ rfbNewUDPConnection(pVNC->udpSock); ++ } ++ ++ rfbProcessUDPInput(pScreen, pVNC->udpSock); ++ } ++ ++ FD_CLR(pVNC->udpSock, &fds); ++ if (--nfds == 0) ++ return; ++ } ++ ++ for (sock = 0; sock <= pVNC->maxFd; sock++) { ++ if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &pVNC->allFds)) { ++#if XFREE86VNC ++ if (!pScrn->vtSema) ++ rfbCloseSock(pScreen, sock); ++ else ++#endif ++ rfbProcessClientMessage(pScreen, sock); ++ } ++ } ++} ++ ++ ++void ++rfbDisconnectUDPSock(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ pVNC->udpSockConnected = FALSE; ++} ++ ++ ++void ++rfbCloseSock(ScreenPtr pScreen, int sock) ++{ ++ VNCSCREENPTR(pScreen); ++ close(sock); ++ RemoveEnabledDevice(sock); ++ FD_CLR(sock, &pVNC->allFds); ++ rfbClientConnectionGone(sock); ++ if (sock == inetdSock) ++ GiveUp(0); ++} ++ ++#if 0 ++/* ++ * rfbWaitForClient can be called to wait for the RFB client to send us a ++ * message. When one is received it is processed by calling ++ * rfbProcessClientMessage(). ++ */ ++ ++void ++rfbWaitForClient(sock) ++ int sock; ++{ ++ int n; ++ fd_set fds; ++ struct timeval tv; ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = rfbMaxClientWait / 1000; ++ tv.tv_usec = (rfbMaxClientWait % 1000) * 1000; ++ n = select(sock+1, &fds, NULL, NULL, &tv); ++ if (n < 0) { ++ rfbLogPerror("rfbWaitForClient: select"); ++ exit(1); ++ } ++ if (n == 0) { ++ rfbCloseSock(sock); ++ return; ++ } ++ ++ rfbProcessClientMessage(sock); ++} ++#endif ++ ++/* ++ * rfbConnect is called to make a connection out to a given TCP address. ++ */ ++ ++int ++rfbConnect(ScreenPtr pScreen, char *host, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ int sock; ++ int one = 1; ++ ++ rfbLog("\n"); ++ rfbLog("Making connection to client on host %s port %d\n", ++ host,port); ++ ++ if ((sock = ConnectToTcpAddr(host, port)) < 0) { ++ rfbLogPerror("connection failed"); ++ return -1; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("fcntl failed"); ++ close(sock); ++ return -1; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("setsockopt failed"); ++ close(sock); ++ return -1; ++ } ++ ++ AddEnabledDevice(sock); ++ FD_SET(sock, &pVNC->allFds); ++ pVNC->maxFd = max(sock,pVNC->maxFd); ++ ++ return sock; ++} ++ ++ ++ ++ ++/* ++ * ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if ++ * those bytes have been read, 0 if the other end has closed, or -1 if an error ++ * occurred (errno is set to ETIMEDOUT if it timed out). ++ */ ++ ++int ++ReadExact(sock, buf, len) ++ int sock; ++ char *buf; ++ int len; ++{ ++ int n; ++ fd_set fds; ++ int tries = 5; ++ struct timeval tv; ++ ++ while (len > 0) { ++ n = read(sock, buf, len); ++ ++ if (n > 0) { ++ ++ buf += n; ++ len -= n; ++ ++ } else if (n == 0) { ++ ++ return 0; ++ ++ } else { ++ if (errno != EWOULDBLOCK && errno != EAGAIN) { ++ return n; ++ } ++ ++ do { ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = rfbMaxClientWait / 1000; ++ tv.tv_usec = (rfbMaxClientWait % 1000) * 1000; ++ n = select(sock+1, &fds, NULL, NULL, &tv); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((n < 0 && errno == EINTR) && tries > 0); ++ ++ if (n < 0) { ++ rfbLogPerror("ReadExact: select"); ++ return n; ++ } ++ if (n == 0) { ++ errno = ETIMEDOUT; ++ return -1; ++ } ++ } ++ } ++ return 1; ++} ++ ++ ++ ++/* ++ * WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if ++ * those bytes have been written, or -1 if an error occurred (errno is set to ++ * ETIMEDOUT if it timed out). ++ */ ++ ++int ++WriteExact(sock, buf, len) ++ int sock; ++ char *buf; ++ int len; ++{ ++ int n; ++ fd_set fds; ++ struct timeval tv; ++ int totalTimeWaited = 0; ++ ++ while (len > 0) { ++ n = write(sock, buf, len); ++ ++ if (n > 0) { ++ ++ buf += n; ++ len -= n; ++ ++ } else if (n == 0) { ++ ++ rfbLog("WriteExact: write returned 0?\n"); ++ return -1; ++ ++ } else { ++ if (errno != EWOULDBLOCK && errno != EAGAIN) { ++ return n; ++ } ++ ++#if 0 ++ /* Retry every 5 seconds until we exceed rfbMaxClientWait. We ++ need to do this because select doesn't necessarily return ++ immediately when the other end has gone away */ ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = 5; ++ tv.tv_usec = 0; ++#else ++ /* We're in the WakeupHandler now, so don't wait */ ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++#endif ++ n = select(sock+1, NULL, &fds, NULL, &tv); ++#if 0 ++ if (n < 0) { ++ rfbLogPerror("WriteExact: select"); ++ return n; ++ } ++ if (n == 0) { ++ totalTimeWaited += 5000; ++ if (totalTimeWaited >= rfbMaxClientWait) { ++ errno = ETIMEDOUT; ++ return -1; ++ } ++ } else { ++ totalTimeWaited = 0; ++ } ++#endif ++ } ++ } ++ return 1; ++} ++ ++ ++int ++ListenOnTCPPort(ScreenPtr pScreen, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ struct sockaddr_in addr; ++ int sock; ++ int one = 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = pVNC->interface.s_addr; ++ ++ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ return -1; ++ } ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { ++ close(sock); ++ return -1; ++ } ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ close(sock); ++ return -1; ++ } ++ if (listen(sock, 5) < 0) { ++ close(sock); ++ return -1; ++ } ++ ++ return sock; ++} ++ ++ ++int ++ConnectToTcpAddr(host, port) ++ char *host; ++ int port; ++{ ++ struct hostent *hp; ++ int sock, n; ++ struct sockaddr_in addr; ++ int tries = 5; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ ++ if ((addr.sin_addr.s_addr = inet_addr(host)) == -1) ++ { ++ if (!(hp = gethostbyname(host))) { ++ errno = EINVAL; ++ return -1; ++ } ++ addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr; ++ } ++ ++ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ return -1; ++ } ++ ++ do { ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((sock < 0 && errno == EINTR) && tries > 0); ++ ++ if (sock < 0) { ++ return -1; ++ } ++ ++ tries = 5; ++ ++ do { ++ n = connect(sock, (struct sockaddr *)&addr, (sizeof(addr))); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((n < 0 && errno == EINTR) && tries > 0); ++ ++ if (n < 0) { ++ close(sock); ++ return -1; ++ } ++ ++ return sock; ++} ++ ++ ++int ++ListenOnUDPPort(ScreenPtr pScreen, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ struct sockaddr_in addr; ++ int sock; ++ int one = 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = pVNC->interface.s_addr; ++ ++ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ++ return -1; ++ } ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { ++ return -1; ++ } ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ return -1; ++ } ++ ++ return sock; ++} ++ ++#if 0 ++/* ++ * rdpInitSockets sets up the TCP for RDP ++ * connections. It does nothing if called again. ++ */ ++ ++Bool ++rdpInitSockets(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if ((pVNC->rdpListenSock = ListenOnTCPPort(pScreen, pVNC->rdpPort)) < 0) { ++ rfbLogPerror("ListenOnTCPPort"); ++ pVNC->rdpPort = 0; ++ return FALSE; ++ } ++ ++ rfbLog("Listening for RDP connections on TCP port %d\n", pVNC->rdpPort); ++ ++ AddEnabledDevice(pVNC->rdpListenSock); ++ ++ return TRUE; ++} ++#endif +diff --git a/hw/dmx/vnc/sprite.c b/hw/dmx/vnc/sprite.c +new file mode 100644 +index 0000000..6be60b6 +--- /dev/null ++++ b/hw/dmx/vnc/sprite.c +@@ -0,0 +1,2491 @@ ++/* ++ * sprite.c ++ * ++ * software sprite routines - based on misprite ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* $XConsortium: misprite.c,v 5.47 94/04/17 20:27:53 dpw Exp $ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#include "rfb.h" ++# include "X11/X.h" ++# include "X11/Xproto.h" ++# include "misc.h" ++# include "pixmapstr.h" ++# include "input.h" ++# include "mi.h" ++# include "cursorstr.h" ++/*# include "font.h"*/ ++# include "scrnintstr.h" ++# include "colormapst.h" ++# include "windowstr.h" ++# include "gcstruct.h" ++# include "mipointer.h" ++# include "spritest.h" ++# include "dixfontstr.h" ++/*# include "fontstruct.h"*/ ++#ifdef RENDER ++# include "mipict.h" ++#endif ++ ++/* ++ * screen wrappers ++ */ ++ ++static int rfbSpriteScreenIndex; ++static unsigned long rfbSpriteGeneration = 0; ++ ++static Bool rfbSpriteCloseScreen(int i, ScreenPtr pScreen); ++static void rfbSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, ++ int w, int h, unsigned int format, ++ unsigned long planemask, char *pdstLine); ++static void rfbSpriteGetSpans(DrawablePtr pDrawable, int wMax, ++ DDXPointPtr ppt, int *pwidth, int nspans, ++ char *pdstStart); ++static void rfbSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, ++ int width, int height); ++static Bool rfbSpriteCreateGC(GCPtr pGC); ++static void rfbSpriteBlockHandler(int i, pointer blockData, ++ pointer pTimeout, ++ pointer pReadMask); ++static void rfbSpriteInstallColormap(ColormapPtr pMap); ++static void rfbSpriteStoreColors(ColormapPtr pMap, int ndef, ++ xColorItem *pdef); ++ ++static void rfbSpritePaintWindowBackground(WindowPtr pWin, ++ RegionPtr pRegion, int what); ++static void rfbSpritePaintWindowBorder(WindowPtr pWin, ++ RegionPtr pRegion, int what); ++static void rfbSpriteCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, ++ RegionPtr pRegion); ++static void rfbSpriteClearToBackground(WindowPtr pWin, int x, int y, ++ int w, int h, ++ Bool generateExposures); ++ ++#ifdef RENDER ++static void rfbSpriteComposite(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height); ++ ++static void rfbSpriteGlyphs(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlist, ++ GlyphListPtr list, ++ GlyphPtr *glyphs); ++#endif ++ ++static void rfbSpriteSaveDoomedAreas(WindowPtr pWin, ++ RegionPtr pObscured, int dx, ++ int dy); ++static RegionPtr rfbSpriteRestoreAreas(WindowPtr pWin, RegionPtr pRgnExposed); ++static void rfbSpriteComputeSaved(ScreenPtr pScreen); ++ ++#define SCREEN_PROLOGUE(pScreen, field)\ ++ ((pScreen)->field = \ ++ ((rfbSpriteScreenPtr) (pScreen)->devPrivates[rfbSpriteScreenIndex].ptr)->field) ++ ++#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ ++ ((pScreen)->field = wrapper) ++ ++/* ++ * GC func wrappers ++ */ ++ ++static int rfbSpriteGCIndex; ++ ++static void rfbSpriteValidateGC(GCPtr pGC, unsigned long stateChanges, ++ DrawablePtr pDrawable); ++static void rfbSpriteCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); ++static void rfbSpriteDestroyGC(GCPtr pGC); ++static void rfbSpriteChangeGC(GCPtr pGC, unsigned long mask); ++static void rfbSpriteChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); ++static void rfbSpriteDestroyClip(GCPtr pGC); ++static void rfbSpriteCopyClip(GCPtr pgcDst, GCPtr pgcSrc); ++ ++static GCFuncs rfbSpriteGCFuncs = { ++ rfbSpriteValidateGC, ++ rfbSpriteChangeGC, ++ rfbSpriteCopyGC, ++ rfbSpriteDestroyGC, ++ rfbSpriteChangeClip, ++ rfbSpriteDestroyClip, ++ rfbSpriteCopyClip, ++}; ++ ++#define GC_FUNC_PROLOGUE(pGC) \ ++ rfbSpriteGCPtr pGCPriv = \ ++ (rfbSpriteGCPtr) (pGC)->devPrivates[rfbSpriteGCIndex].ptr;\ ++ (pGC)->funcs = pGCPriv->wrapFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ (pGC)->ops = pGCPriv->wrapOps; ++ ++#define GC_FUNC_EPILOGUE(pGC) \ ++ pGCPriv->wrapFuncs = (pGC)->funcs; \ ++ (pGC)->funcs = &rfbSpriteGCFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ { \ ++ pGCPriv->wrapOps = (pGC)->ops; \ ++ (pGC)->ops = &rfbSpriteGCOps; \ ++ } ++ ++/* ++ * GC op wrappers ++ */ ++ ++static void rfbSpriteFillSpans(DrawablePtr pDrawable, GCPtr pGC, ++ int nInit, DDXPointPtr pptInit, ++ int *pwidthInit, int fSorted); ++static void rfbSpriteSetSpans(DrawablePtr pDrawable, GCPtr pGC, ++ char *psrc, DDXPointPtr ppt, int *pwidth, ++ int nspans, int fSorted); ++static void rfbSpritePutImage(DrawablePtr pDrawable, GCPtr pGC, ++ int depth, int x, int y, int w, int h, ++ int leftPad, int format, char *pBits); ++static RegionPtr rfbSpriteCopyArea(DrawablePtr pSrc, DrawablePtr pDst, ++ GCPtr pGC, int srcx, int srcy, int w, ++ int h, int dstx, int dsty); ++static RegionPtr rfbSpriteCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, ++ GCPtr pGC, int srcx, int srcy, int w, ++ int h, int dstx, int dsty, ++ unsigned long plane); ++static void rfbSpritePolyPoint(DrawablePtr pDrawable, GCPtr pGC, ++ int mode, int npt, xPoint *pptInit); ++static void rfbSpritePolylines(DrawablePtr pDrawable, GCPtr pGC, ++ int mode, int npt, DDXPointPtr pptInit); ++static void rfbSpritePolySegment(DrawablePtr pDrawable, GCPtr pGC, ++ int nseg, xSegment *pSegs); ++static void rfbSpritePolyRectangle(DrawablePtr pDrawable, GCPtr pGC, ++ int nrects, xRectangle *pRects); ++static void rfbSpritePolyArc(DrawablePtr pDrawable, GCPtr pGC, ++ int narcs, xArc *parcs); ++static void rfbSpriteFillPolygon(DrawablePtr pDrawable, GCPtr pGC, ++ int shape, int mode, int count, ++ DDXPointPtr pPts); ++static void rfbSpritePolyFillRect(DrawablePtr pDrawable, GCPtr pGC, ++ int nrectFill, xRectangle *prectInit); ++static void rfbSpritePolyFillArc(DrawablePtr pDrawable, GCPtr pGC, ++ int narcs, xArc *parcs); ++static int rfbSpritePolyText8(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, char *chars); ++static int rfbSpritePolyText16(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, ++ unsigned short *chars); ++static void rfbSpriteImageText8(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, char *chars); ++static void rfbSpriteImageText16(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, ++ unsigned short *chars); ++static void rfbSpriteImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, unsigned int nglyph, ++ CharInfoPtr *ppci, ++ pointer pglyphBase); ++static void rfbSpritePolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, unsigned int nglyph, ++ CharInfoPtr *ppci, ++ pointer pglyphBase); ++static void rfbSpritePushPixels(GCPtr pGC, PixmapPtr pBitMap, ++ DrawablePtr pDst, int w, int h, ++ int x, int y); ++#ifdef NEED_LINEHELPER ++static void rfbSpriteLineHelper(); ++#endif ++ ++static GCOps rfbSpriteGCOps = { ++ rfbSpriteFillSpans, rfbSpriteSetSpans, rfbSpritePutImage, ++ rfbSpriteCopyArea, rfbSpriteCopyPlane, rfbSpritePolyPoint, ++ rfbSpritePolylines, rfbSpritePolySegment, rfbSpritePolyRectangle, ++ rfbSpritePolyArc, rfbSpriteFillPolygon, rfbSpritePolyFillRect, ++ rfbSpritePolyFillArc, rfbSpritePolyText8, rfbSpritePolyText16, ++ rfbSpriteImageText8, rfbSpriteImageText16, rfbSpriteImageGlyphBlt, ++ rfbSpritePolyGlyphBlt, rfbSpritePushPixels ++#ifdef NEED_LINEHELPER ++ , rfbSpriteLineHelper ++#endif ++}; ++ ++/* ++ * testing only -- remove cursor for every draw. Eventually, ++ * each draw operation will perform a bounding box check against ++ * the saved cursor area ++ */ ++ ++#define GC_SETUP_CHEAP(pDrawable) \ ++ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr) \ ++ (pDrawable)->pScreen->devPrivates[rfbSpriteScreenIndex].ptr; \ ++ ++#define GC_SETUP(pDrawable, pGC) \ ++ GC_SETUP_CHEAP(pDrawable) \ ++ rfbSpriteGCPtr pGCPrivate = (rfbSpriteGCPtr) \ ++ (pGC)->devPrivates[rfbSpriteGCIndex].ptr; \ ++ GCFuncs *oldFuncs = pGC->funcs; ++ ++#define GC_SETUP_AND_CHECK(pDrawable, pGC) \ ++ GC_SETUP(pDrawable, pGC); \ ++ if (GC_CHECK((WindowPtr)pDrawable)) \ ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ ++#define GC_CHECK(pWin) \ ++ (pVNC->cursorIsDrawn && \ ++ (pScreenPriv->pCacheWin == pWin ? \ ++ pScreenPriv->isInCacheWin : ( \ ++ (pScreenPriv->pCacheWin = (pWin)) , \ ++ (pScreenPriv->isInCacheWin = \ ++ (pWin)->drawable.x < pScreenPriv->saved.x2 && \ ++ pScreenPriv->saved.x1 < (pWin)->drawable.x + \ ++ (int) (pWin)->drawable.width && \ ++ (pWin)->drawable.y < pScreenPriv->saved.y2 && \ ++ pScreenPriv->saved.y1 < (pWin)->drawable.y + \ ++ (int) (pWin)->drawable.height &&\ ++ RECT_IN_REGION((pWin)->drawable.pScreen, &(pWin)->borderClip, \ ++ &pScreenPriv->saved) != rgnOUT)))) ++ ++#define GC_OP_PROLOGUE(pGC) { \ ++ (pGC)->funcs = pGCPrivate->wrapFuncs; \ ++ (pGC)->ops = pGCPrivate->wrapOps; \ ++ } ++ ++#define GC_OP_EPILOGUE(pGC) { \ ++ pGCPrivate->wrapOps = (pGC)->ops; \ ++ (pGC)->funcs = oldFuncs; \ ++ (pGC)->ops = &rfbSpriteGCOps; \ ++ } ++ ++/* ++ * pointer-sprite method table ++ */ ++ ++static Bool rfbSpriteRealizeCursor (), rfbSpriteUnrealizeCursor (); ++static void rfbSpriteSetCursor (), rfbSpriteMoveCursor (); ++ ++miPointerSpriteFuncRec rfbSpritePointerFuncs = { ++ rfbSpriteRealizeCursor, ++ rfbSpriteUnrealizeCursor, ++ rfbSpriteSetCursor, ++ rfbSpriteMoveCursor, ++}; ++ ++/* ++ * other misc functions ++ */ ++ ++static Bool rfbDisplayCursor (ScreenPtr pScreen, CursorPtr pCursor); ++ ++ ++/* ++ * rfbSpriteInitialize -- called from device-dependent screen ++ * initialization proc after all of the function pointers have ++ * been stored in the screen structure. ++ */ ++ ++Bool ++rfbSpriteInitialize (pScreen, cursorFuncs, screenFuncs) ++ ScreenPtr pScreen; ++ rfbSpriteCursorFuncPtr cursorFuncs; ++ miPointerScreenFuncPtr screenFuncs; ++{ ++ rfbSpriteScreenPtr pPriv; ++ VisualPtr pVisual; ++#ifdef RENDER ++ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); ++#endif ++ ++ if (rfbSpriteGeneration != serverGeneration) ++ { ++ rfbSpriteScreenIndex = AllocateScreenPrivateIndex (); ++ if (rfbSpriteScreenIndex < 0) ++ return FALSE; ++ rfbSpriteGeneration = serverGeneration; ++ rfbSpriteGCIndex = AllocateGCPrivateIndex (); ++ } ++ if (!AllocateGCPrivate(pScreen, rfbSpriteGCIndex, sizeof(rfbSpriteGCRec))) ++ return FALSE; ++ pPriv = (rfbSpriteScreenPtr) xalloc (sizeof (rfbSpriteScreenRec)); ++ if (!pPriv) ++ return FALSE; ++ if (!miPointerInitialize (pScreen, &rfbSpritePointerFuncs, screenFuncs,TRUE)) ++ { ++ xfree ((pointer) pPriv); ++ return FALSE; ++ } ++ for (pVisual = pScreen->visuals; ++ pVisual->vid != pScreen->rootVisual; ++ pVisual++) ++ ; ++ pPriv->pVisual = pVisual; ++ pPriv->CloseScreen = pScreen->CloseScreen; ++ pPriv->GetImage = pScreen->GetImage; ++ pPriv->GetSpans = pScreen->GetSpans; ++ pPriv->SourceValidate = pScreen->SourceValidate; ++ pPriv->CreateGC = pScreen->CreateGC; ++#if 0 ++ pPriv->BlockHandler = pScreen->BlockHandler; ++#endif ++ pPriv->InstallColormap = pScreen->InstallColormap; ++ pPriv->StoreColors = pScreen->StoreColors; ++ pPriv->DisplayCursor = pScreen->DisplayCursor; ++ ++ pPriv->PaintWindowBackground = pScreen->PaintWindowBackground; ++ pPriv->PaintWindowBorder = pScreen->PaintWindowBorder; ++ pPriv->CopyWindow = pScreen->CopyWindow; ++ pPriv->ClearToBackground = pScreen->ClearToBackground; ++ ++ pPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas; ++ pPriv->RestoreAreas = pScreen->RestoreAreas; ++#ifdef RENDER ++ if (ps) ++ { ++ pPriv->Composite = ps->Composite; ++ pPriv->Glyphs = ps->Glyphs; ++ } ++#endif ++ ++ pPriv->pCursor = NULL; ++ pPriv->x = 0; ++ pPriv->y = 0; ++ pPriv->shouldBeUp = FALSE; ++ pPriv->pCacheWin = NullWindow; ++ pPriv->isInCacheWin = FALSE; ++ pPriv->checkPixels = TRUE; ++ pPriv->pInstalledMap = NULL; ++ pPriv->pColormap = NULL; ++ pPriv->funcs = cursorFuncs; ++ pPriv->colors[SOURCE_COLOR].red = 0; ++ pPriv->colors[SOURCE_COLOR].green = 0; ++ pPriv->colors[SOURCE_COLOR].blue = 0; ++ pPriv->colors[MASK_COLOR].red = 0; ++ pPriv->colors[MASK_COLOR].green = 0; ++ pPriv->colors[MASK_COLOR].blue = 0; ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr = (pointer) pPriv; ++ pScreen->CloseScreen = rfbSpriteCloseScreen; ++ pScreen->GetImage = rfbSpriteGetImage; ++ pScreen->GetSpans = rfbSpriteGetSpans; ++ pScreen->SourceValidate = rfbSpriteSourceValidate; ++ pScreen->CreateGC = rfbSpriteCreateGC; ++#if 0 ++ pScreen->BlockHandler = rfbSpriteBlockHandler; ++#endif ++ pScreen->InstallColormap = rfbSpriteInstallColormap; ++ pScreen->StoreColors = rfbSpriteStoreColors; ++ ++ pScreen->PaintWindowBackground = rfbSpritePaintWindowBackground; ++ pScreen->PaintWindowBorder = rfbSpritePaintWindowBorder; ++ pScreen->CopyWindow = rfbSpriteCopyWindow; ++ pScreen->ClearToBackground = rfbSpriteClearToBackground; ++ ++ pScreen->SaveDoomedAreas = rfbSpriteSaveDoomedAreas; ++ pScreen->RestoreAreas = rfbSpriteRestoreAreas; ++ ++ pScreen->DisplayCursor = rfbDisplayCursor; ++#ifdef RENDER ++ if (ps) ++ { ++ ps->Composite = rfbSpriteComposite; ++ ps->Glyphs = rfbSpriteGlyphs; ++ } ++#endif ++ ++ return TRUE; ++} ++ ++/* ++ * Screen wrappers ++ */ ++ ++/* ++ * CloseScreen wrapper -- unwrap everything, free the private data ++ * and call the wrapped function ++ */ ++ ++static Bool ++rfbSpriteCloseScreen (i, pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++#ifdef RENDER ++ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); ++#endif ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ pScreen->CloseScreen = pScreenPriv->CloseScreen; ++ pScreen->GetImage = pScreenPriv->GetImage; ++ pScreen->GetSpans = pScreenPriv->GetSpans; ++ pScreen->SourceValidate = pScreenPriv->SourceValidate; ++ pScreen->CreateGC = pScreenPriv->CreateGC; ++#if 0 ++ pScreen->BlockHandler = pScreenPriv->BlockHandler; ++#endif ++ pScreen->InstallColormap = pScreenPriv->InstallColormap; ++ pScreen->StoreColors = pScreenPriv->StoreColors; ++ ++ pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground; ++ pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder; ++ pScreen->CopyWindow = pScreenPriv->CopyWindow; ++ pScreen->ClearToBackground = pScreenPriv->ClearToBackground; ++ ++ pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas; ++ pScreen->RestoreAreas = pScreenPriv->RestoreAreas; ++#ifdef RENDER ++ if (ps) ++ { ++ ps->Composite = pScreenPriv->Composite; ++ ps->Glyphs = pScreenPriv->Glyphs; ++ } ++#endif ++ ++ xfree ((pointer) pScreenPriv); ++ ++ return (*pScreen->CloseScreen) (i, pScreen); ++} ++ ++static void ++rfbSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine) ++ DrawablePtr pDrawable; ++ int sx, sy, w, h; ++ unsigned int format; ++ unsigned long planemask; ++ char *pdstLine; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, GetImage); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ if (pDrawable->type == DRAWABLE_WINDOW && ++ pVNC->cursorIsDrawn && ++ ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->GetImage) (pDrawable, sx, sy, w, h, ++ format, planemask, pdstLine); ++ ++ SCREEN_EPILOGUE (pScreen, GetImage, rfbSpriteGetImage); ++} ++ ++static void ++rfbSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart) ++ DrawablePtr pDrawable; ++ int wMax; ++ DDXPointPtr ppt; ++ int *pwidth; ++ int nspans; ++ char *pdstStart; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, GetSpans); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn) ++ { ++ register DDXPointPtr pts; ++ register int *widths; ++ register int nPts; ++ register int xorg, ++ yorg; ++ ++ xorg = pDrawable->x; ++ yorg = pDrawable->y; ++ ++ for (pts = ppt, widths = pwidth, nPts = nspans; ++ nPts--; ++ pts++, widths++) ++ { ++ if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg, ++ pts->x+xorg,*widths)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ break; ++ } ++ } ++ } ++ ++ (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); ++ ++ SCREEN_EPILOGUE (pScreen, GetSpans, rfbSpriteGetSpans); ++} ++ ++static void ++rfbSpriteSourceValidate (pDrawable, x, y, width, height) ++ DrawablePtr pDrawable; ++ int x, y, width, height; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, SourceValidate); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn && ++ ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y, ++ x, y, width, height)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ if (pScreen->SourceValidate) ++ (*pScreen->SourceValidate) (pDrawable, x, y, width, height); ++ ++ SCREEN_EPILOGUE (pScreen, SourceValidate, rfbSpriteSourceValidate); ++} ++ ++static Bool ++rfbSpriteCreateGC (pGC) ++ GCPtr pGC; ++{ ++ ScreenPtr pScreen = pGC->pScreen; ++ Bool ret; ++ rfbSpriteGCPtr pPriv; ++ ++ SCREEN_PROLOGUE (pScreen, CreateGC); ++ ++ pPriv = (rfbSpriteGCPtr)pGC->devPrivates[rfbSpriteGCIndex].ptr; ++ ++ ret = (*pScreen->CreateGC) (pGC); ++ ++ pPriv->wrapOps = NULL; ++ pPriv->wrapFuncs = pGC->funcs; ++ pGC->funcs = &rfbSpriteGCFuncs; ++ ++ SCREEN_EPILOGUE (pScreen, CreateGC, rfbSpriteCreateGC); ++ ++ return ret; ++} ++ ++static void ++rfbSpriteBlockHandler (i, blockData, pTimeout, pReadmask) ++ int i; ++ pointer blockData; ++ pointer pTimeout; ++ pointer pReadmask; ++{ ++ ScreenPtr pScreen = screenInfo.screens[i]; ++ rfbSpriteScreenPtr pPriv; ++ VNCSCREENPTR(pScreen); ++ ++ pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ SCREEN_PROLOGUE(pScreen, BlockHandler); ++ ++ (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); ++ ++ SCREEN_EPILOGUE(pScreen, BlockHandler, rfbSpriteBlockHandler); ++ ++ if (!pVNC->cursorIsDrawn && pPriv->shouldBeUp) ++ rfbSpriteRestoreCursor (pScreen); ++} ++ ++static void ++rfbSpriteInstallColormap (pMap) ++ ColormapPtr pMap; ++{ ++ ScreenPtr pScreen = pMap->pScreen; ++ rfbSpriteScreenPtr pPriv; ++ VNCSCREENPTR(pScreen); ++ ++ pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ SCREEN_PROLOGUE(pScreen, InstallColormap); ++ ++ (*pScreen->InstallColormap) (pMap); ++ ++ SCREEN_EPILOGUE(pScreen, InstallColormap, rfbSpriteInstallColormap); ++ ++ pPriv->pInstalledMap = pMap; ++ if (pPriv->pColormap != pMap) ++ { ++ pPriv->checkPixels = TRUE; ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++} ++ ++static void ++rfbSpriteStoreColors (pMap, ndef, pdef) ++ ColormapPtr pMap; ++ int ndef; ++ xColorItem *pdef; ++{ ++ ScreenPtr pScreen = pMap->pScreen; ++ rfbSpriteScreenPtr pPriv; ++ int i; ++ int updated; ++ VisualPtr pVisual; ++ VNCSCREENPTR(pScreen); ++ ++ pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ SCREEN_PROLOGUE(pScreen, StoreColors); ++ ++ (*pScreen->StoreColors) (pMap, ndef, pdef); ++ ++ SCREEN_EPILOGUE(pScreen, StoreColors, rfbSpriteStoreColors); ++ ++ if (pPriv->pColormap == pMap) ++ { ++ updated = 0; ++ pVisual = pMap->pVisual; ++ if (pVisual->class == DirectColor) ++ { ++ /* Direct color - match on any of the subfields */ ++ ++#define MaskMatch(a,b,mask) ((a) & ((pVisual->mask) == (b)) & (pVisual->mask)) ++ ++#define UpdateDAC(plane,dac,mask) {\ ++ if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\ ++ pPriv->colors[plane].dac = pdef[i].dac; \ ++ updated = 1; \ ++ } \ ++} ++ ++#define CheckDirect(plane) \ ++ UpdateDAC(plane,red,redMask) \ ++ UpdateDAC(plane,green,greenMask) \ ++ UpdateDAC(plane,blue,blueMask) ++ ++ for (i = 0; i < ndef; i++) ++ { ++ CheckDirect (SOURCE_COLOR) ++ CheckDirect (MASK_COLOR) ++ } ++ } ++ else ++ { ++ /* PseudoColor/GrayScale - match on exact pixel */ ++ for (i = 0; i < ndef; i++) ++ { ++ if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) ++ { ++ pPriv->colors[SOURCE_COLOR] = pdef[i]; ++ if (++updated == 2) ++ break; ++ } ++ if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) ++ { ++ pPriv->colors[MASK_COLOR] = pdef[i]; ++ if (++updated == 2) ++ break; ++ } ++ } ++ } ++ if (updated) ++ { ++ pPriv->checkPixels = TRUE; ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++} ++ ++static void ++rfbSpriteFindColors (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr) ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ CursorPtr pCursor; ++ xColorItem *sourceColor, *maskColor; ++ ++ pCursor = pScreenPriv->pCursor; ++ sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; ++ maskColor = &pScreenPriv->colors[MASK_COLOR]; ++ if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || ++ !(pCursor->foreRed == sourceColor->red && ++ pCursor->foreGreen == sourceColor->green && ++ pCursor->foreBlue == sourceColor->blue && ++ pCursor->backRed == maskColor->red && ++ pCursor->backGreen == maskColor->green && ++ pCursor->backBlue == maskColor->blue)) ++ { ++ pScreenPriv->pColormap = pScreenPriv->pInstalledMap; ++ sourceColor->red = pCursor->foreRed; ++ sourceColor->green = pCursor->foreGreen; ++ sourceColor->blue = pCursor->foreBlue; ++ FakeAllocColor (pScreenPriv->pColormap, sourceColor); ++ maskColor->red = pCursor->backRed; ++ maskColor->green = pCursor->backGreen; ++ maskColor->blue = pCursor->backBlue; ++ FakeAllocColor (pScreenPriv->pColormap, maskColor); ++ /* "free" the pixels right away, don't let this confuse you */ ++ FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); ++ FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); ++ } ++ pScreenPriv->checkPixels = FALSE; ++} ++ ++/* ++ * BackingStore wrappers ++ */ ++ ++static void ++rfbSpriteSaveDoomedAreas (pWin, pObscured, dx, dy) ++ WindowPtr pWin; ++ RegionPtr pObscured; ++ int dx, dy; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ BoxRec cursorBox; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, SaveDoomedAreas); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ cursorBox = pScreenPriv->saved; ++ ++ if (dx || dy) ++ { ++ cursorBox.x1 += dx; ++ cursorBox.y1 += dy; ++ cursorBox.x2 += dx; ++ cursorBox.y2 += dy; ++ } ++ if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy); ++ ++ SCREEN_EPILOGUE (pScreen, SaveDoomedAreas, rfbSpriteSaveDoomedAreas); ++} ++ ++static RegionPtr ++rfbSpriteRestoreAreas (pWin, prgnExposed) ++ WindowPtr pWin; ++ RegionPtr prgnExposed; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ RegionPtr result; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, RestoreAreas); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ if (RECT_IN_REGION( pScreen, prgnExposed, &pScreenPriv->saved) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ result = (*pScreen->RestoreAreas) (pWin, prgnExposed); ++ ++ SCREEN_EPILOGUE (pScreen, RestoreAreas, rfbSpriteRestoreAreas); ++ ++ return result; ++} ++ ++/* ++ * Window wrappers ++ */ ++ ++static void ++rfbSpritePaintWindowBackground (pWin, pRegion, what) ++ WindowPtr pWin; ++ RegionPtr pRegion; ++ int what; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, PaintWindowBackground); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ /* ++ * If the cursor is on the same screen as the window, check the ++ * region to paint for the cursor and remove it as necessary ++ */ ++ if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->PaintWindowBackground) (pWin, pRegion, what); ++ ++ SCREEN_EPILOGUE (pScreen, PaintWindowBackground, rfbSpritePaintWindowBackground); ++} ++ ++static void ++rfbSpritePaintWindowBorder (pWin, pRegion, what) ++ WindowPtr pWin; ++ RegionPtr pRegion; ++ int what; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, PaintWindowBorder); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ /* ++ * If the cursor is on the same screen as the window, check the ++ * region to paint for the cursor and remove it as necessary ++ */ ++ if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->PaintWindowBorder) (pWin, pRegion, what); ++ ++ SCREEN_EPILOGUE (pScreen, PaintWindowBorder, rfbSpritePaintWindowBorder); ++} ++ ++static void ++rfbSpriteCopyWindow (pWin, ptOldOrg, pRegion) ++ WindowPtr pWin; ++ DDXPointRec ptOldOrg; ++ RegionPtr pRegion; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ BoxRec cursorBox; ++ int dx, dy; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, CopyWindow); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ /* ++ * check both the source and the destination areas. The given ++ * region is source relative, so offset the cursor box by ++ * the delta position ++ */ ++ cursorBox = pScreenPriv->saved; ++ dx = pWin->drawable.x - ptOldOrg.x; ++ dy = pWin->drawable.y - ptOldOrg.y; ++ cursorBox.x1 -= dx; ++ cursorBox.x2 -= dx; ++ cursorBox.y1 -= dy; ++ cursorBox.y2 -= dy; ++ if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT || ++ RECT_IN_REGION( pScreen, pRegion, &cursorBox) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->CopyWindow) (pWin, ptOldOrg, pRegion); ++ ++ SCREEN_EPILOGUE (pScreen, CopyWindow, rfbSpriteCopyWindow); ++} ++ ++static void ++rfbSpriteClearToBackground (pWin, x, y, w, h, generateExposures) ++ WindowPtr pWin; ++ short x,y; ++ unsigned short w,h; ++ Bool generateExposures; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ int realw, realh; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, ClearToBackground); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (GC_CHECK(pWin)) ++ { ++ if (!(realw = w)) ++ realw = (int) pWin->drawable.width - x; ++ if (!(realh = h)) ++ realh = (int) pWin->drawable.height - y; ++ if (ORG_OVERLAP(&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y, ++ x, y, realw, realh)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++ ++ (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); ++ ++ SCREEN_EPILOGUE (pScreen, ClearToBackground, rfbSpriteClearToBackground); ++} ++ ++/* ++ * GC Func wrappers ++ */ ++ ++static void ++rfbSpriteValidateGC (pGC, changes, pDrawable) ++ GCPtr pGC; ++ unsigned long changes; ++ DrawablePtr pDrawable; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); ++ ++ pGCPriv->wrapOps = NULL; ++ if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDrawable)->viewable) ++ { ++ WindowPtr pWin; ++ RegionPtr pRegion; ++ ++ pWin = (WindowPtr) pDrawable; ++ pRegion = &pWin->clipList; ++ if (pGC->subWindowMode == IncludeInferiors) ++ pRegion = &pWin->borderClip; ++ if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) ++ pGCPriv->wrapOps = pGC->ops; ++ } ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteChangeGC (pGC, mask) ++ GCPtr pGC; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->ChangeGC) (pGC, mask); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteCopyGC (pGCSrc, mask, pGCDst) ++ GCPtr pGCSrc, pGCDst; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE (pGCDst); ++ ++ (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); ++ ++ GC_FUNC_EPILOGUE (pGCDst); ++} ++ ++static void ++rfbSpriteDestroyGC (pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->DestroyGC) (pGC); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteChangeClip (pGC, type, pvalue, nrects) ++ GCPtr pGC; ++ int type; ++ pointer pvalue; ++ int nrects; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteCopyClip(pgcDst, pgcSrc) ++ GCPtr pgcDst, pgcSrc; ++{ ++ GC_FUNC_PROLOGUE (pgcDst); ++ ++ (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); ++ ++ GC_FUNC_EPILOGUE (pgcDst); ++} ++ ++static void ++rfbSpriteDestroyClip(pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (* pGC->funcs->DestroyClip)(pGC); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++/* ++ * GC Op wrappers ++ */ ++ ++static void ++rfbSpriteFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nInit; /* number of spans to fill */ ++ DDXPointPtr pptInit; /* pointer to list of start points */ ++ int *pwidthInit; /* pointer to list of n widths */ ++ int fSorted; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register DDXPointPtr pts; ++ register int *widths; ++ register int nPts; ++ ++ for (pts = pptInit, widths = pwidthInit, nPts = nInit; ++ nPts--; ++ pts++, widths++) ++ { ++ if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ char *psrc; ++ register DDXPointPtr ppt; ++ int *pwidth; ++ int nspans; ++ int fSorted; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register DDXPointPtr pts; ++ register int *widths; ++ register int nPts; ++ ++ for (pts = ppt, widths = pwidth, nPts = nspans; ++ nPts--; ++ pts++, widths++) ++ { ++ if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths)) ++ { ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int depth; ++ int x; ++ int y; ++ int w; ++ int h; ++ int format; ++ char *pBits; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ if (ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, ++ x,y,w,h)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static RegionPtr ++rfbSpriteCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ GCPtr pGC; ++ int srcx; ++ int srcy; ++ int w; ++ int h; ++ int dstx; ++ int dsty; ++{ ++ RegionPtr rgn; ++ ScreenPtr pScreen = pGC->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDst, pGC); ++ ++ /* check destination/source overlap. */ ++ if (GC_CHECK((WindowPtr) pDst) && ++ (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) || ++ ((pDst == pSrc) && ++ ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h)))) ++ { ++ rfbSpriteRemoveCursor (pDst->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty); ++ ++ GC_OP_EPILOGUE (pGC); ++ ++ return rgn; ++} ++ ++static RegionPtr ++rfbSpriteCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ register GCPtr pGC; ++ int srcx, ++ srcy; ++ int w, ++ h; ++ int dstx, ++ dsty; ++ unsigned long plane; ++{ ++ RegionPtr rgn; ++ ScreenPtr pScreen = pGC->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDst, pGC); ++ ++ /* ++ * check destination/source for overlap. ++ */ ++ if (GC_CHECK((WindowPtr) pDst) && ++ (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) || ++ ((pDst == pSrc) && ++ ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h)))) ++ { ++ rfbSpriteRemoveCursor (pDst->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty, plane); ++ ++ GC_OP_EPILOGUE (pGC); ++ ++ return rgn; ++} ++ ++static void ++rfbSpritePolyPoint (pDrawable, pGC, mode, npt, pptInit) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; /* Origin or Previous */ ++ int npt; ++ xPoint *pptInit; ++{ ++ xPoint t; ++ int n; ++ BoxRec cursor; ++ register xPoint *pts; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (npt && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ cursor.x1 = pScreenPriv->saved.x1 - pDrawable->x; ++ cursor.y1 = pScreenPriv->saved.y1 - pDrawable->y; ++ cursor.x2 = pScreenPriv->saved.x2 - pDrawable->x; ++ cursor.y2 = pScreenPriv->saved.y2 - pDrawable->y; ++ ++ if (mode == CoordModePrevious) ++ { ++ t.x = 0; ++ t.y = 0; ++ for (pts = pptInit, n = npt; n--; pts++) ++ { ++ t.x += pts->x; ++ t.y += pts->y; ++ if (cursor.x1 <= t.x && t.x <= cursor.x2 && ++ cursor.y1 <= t.y && t.y <= cursor.y2) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ else ++ { ++ for (pts = pptInit, n = npt; n--; pts++) ++ { ++ if (cursor.x1 <= pts->x && pts->x <= cursor.x2 && ++ cursor.y1 <= pts->y && pts->y <= cursor.y2) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolylines (pDrawable, pGC, mode, npt, pptInit) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; ++ int npt; ++ DDXPointPtr pptInit; ++{ ++ BoxPtr cursor; ++ register DDXPointPtr pts; ++ int n; ++ int x, y, x1, y1, x2, y2; ++ int lw; ++ int extra; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (npt && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ cursor = &pScreenPriv->saved; ++ lw = pGC->lineWidth; ++ x = pptInit->x + pDrawable->x; ++ y = pptInit->y + pDrawable->y; ++ ++ if (npt == 1) ++ { ++ extra = lw >> 1; ++ if (LINE_OVERLAP(cursor, x, y, x, y, extra)) ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ else ++ { ++ extra = lw >> 1; ++ /* ++ * mitered joins can project quite a way from ++ * the line end; the 11 degree miter limit limits ++ * this extension to 10.43 * lw / 2, rounded up ++ * and converted to int yields 6 * lw ++ */ ++ if (pGC->joinStyle == JoinMiter) ++ extra = 6 * lw; ++ else if (pGC->capStyle == CapProjecting) ++ extra = lw; ++ for (pts = pptInit + 1, n = npt - 1; n--; pts++) ++ { ++ x1 = x; ++ y1 = y; ++ if (mode == CoordModeOrigin) ++ { ++ x2 = pDrawable->x + pts->x; ++ y2 = pDrawable->y + pts->y; ++ } ++ else ++ { ++ x2 = x + pts->x; ++ y2 = y + pts->y; ++ } ++ x = x2; ++ y = y2; ++ LINE_SORT(x1, y1, x2, y2); ++ if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ } ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, pptInit); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolySegment(pDrawable, pGC, nseg, pSegs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nseg; ++ xSegment *pSegs; ++{ ++ int n; ++ register xSegment *segs; ++ BoxPtr cursor; ++ int x1, y1, x2, y2; ++ int extra; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (nseg && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ cursor = &pScreenPriv->saved; ++ extra = pGC->lineWidth >> 1; ++ if (pGC->capStyle == CapProjecting) ++ extra = pGC->lineWidth; ++ for (segs = pSegs, n = nseg; n--; segs++) ++ { ++ x1 = segs->x1 + pDrawable->x; ++ y1 = segs->y1 + pDrawable->y; ++ x2 = segs->x2 + pDrawable->x; ++ y2 = segs->y2 + pDrawable->y; ++ LINE_SORT(x1, y1, x2, y2); ++ if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, pSegs); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyRectangle(pDrawable, pGC, nrects, pRects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *pRects; ++{ ++ register xRectangle *rects; ++ BoxPtr cursor; ++ int lw; ++ int n; ++ int x1, y1, x2, y2; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ lw = pGC->lineWidth >> 1; ++ cursor = &pScreenPriv->saved; ++ for (rects = pRects, n = nrects; n--; rects++) ++ { ++ x1 = rects->x + pDrawable->x; ++ y1 = rects->y + pDrawable->y; ++ x2 = x1 + (int)rects->width; ++ y2 = y1 + (int)rects->height; ++ if (LINE_OVERLAP(cursor, x1, y1, x2, y1, lw) || ++ LINE_OVERLAP(cursor, x2, y1, x2, y2, lw) || ++ LINE_OVERLAP(cursor, x1, y2, x2, y2, lw) || ++ LINE_OVERLAP(cursor, x1, y1, x1, y2, lw)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, pRects); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyArc(pDrawable, pGC, narcs, parcs) ++ DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int narcs; ++ xArc *parcs; ++{ ++ BoxPtr cursor; ++ int lw; ++ int n; ++ register xArc *arcs; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ lw = pGC->lineWidth >> 1; ++ cursor = &pScreenPriv->saved; ++ for (arcs = parcs, n = narcs; n--; arcs++) ++ { ++ if (ORG_OVERLAP (cursor, pDrawable->x, pDrawable->y, ++ arcs->x - lw, arcs->y - lw, ++ (int) arcs->width + pGC->lineWidth, ++ (int) arcs->height + pGC->lineWidth)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, parcs); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteFillPolygon(pDrawable, pGC, shape, mode, count, pPts) ++ register DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int shape, mode; ++ int count; ++ DDXPointPtr pPts; ++{ ++ int x, y, minx, miny, maxx, maxy; ++ register DDXPointPtr pts; ++ int n; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (count && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ x = pDrawable->x; ++ y = pDrawable->y; ++ pts = pPts; ++ minx = maxx = pts->x; ++ miny = maxy = pts->y; ++ pts++; ++ n = count - 1; ++ ++ if (mode == CoordModeOrigin) ++ { ++ for (; n--; pts++) ++ { ++ if (pts->x < minx) ++ minx = pts->x; ++ else if (pts->x > maxx) ++ maxx = pts->x; ++ if (pts->y < miny) ++ miny = pts->y; ++ else if (pts->y > maxy) ++ maxy = pts->y; ++ } ++ minx += x; ++ miny += y; ++ maxx += x; ++ maxy += y; ++ } ++ else ++ { ++ x += minx; ++ y += miny; ++ minx = maxx = x; ++ miny = maxy = y; ++ for (; n--; pts++) ++ { ++ x += pts->x; ++ y += pts->y; ++ if (x < minx) ++ minx = x; ++ else if (x > maxx) ++ maxx = x; ++ if (y < miny) ++ miny = y; ++ else if (y > maxy) ++ maxy = y; ++ } ++ } ++ if (BOX_OVERLAP(&pScreenPriv->saved,minx,miny,maxx,maxy)) ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pPts); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyFillRect(pDrawable, pGC, nrectFill, prectInit) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrectFill; /* number of rectangles to fill */ ++ xRectangle *prectInit; /* Pointer to first rectangle to fill */ ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register int nRect; ++ register xRectangle *pRect; ++ register int xorg, yorg; ++ ++ xorg = pDrawable->x; ++ yorg = pDrawable->y; ++ ++ for (nRect = nrectFill, pRect = prectInit; nRect--; pRect++) { ++ if (ORGRECT_OVERLAP(&pScreenPriv->saved,xorg,yorg,pRect)){ ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrectFill, prectInit); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyFillArc(pDrawable, pGC, narcs, parcs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int narcs; ++ xArc *parcs; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register int n; ++ BoxPtr cursor; ++ register xArc *arcs; ++ ++ cursor = &pScreenPriv->saved; ++ ++ for (arcs = parcs, n = narcs; n--; arcs++) ++ { ++ if (ORG_OVERLAP(cursor, pDrawable->x, pDrawable->y, ++ arcs->x, arcs->y, ++ (int) arcs->width, (int) arcs->height)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, parcs); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++/* ++ * general Poly/Image text function. Extract glyph information, ++ * compute bounding box and remove cursor if it is overlapped. ++ */ ++ ++static Bool ++rfbSpriteTextOverlap (pDraw, font, x, y, n, charinfo, imageblt, w, cursorBox) ++ DrawablePtr pDraw; ++ FontPtr font; ++ int x, y; ++ unsigned int n; ++ CharInfoPtr *charinfo; ++ Bool imageblt; ++ unsigned int w; ++ BoxPtr cursorBox; ++{ ++ ExtentInfoRec extents; ++ ++ x += pDraw->x; ++ y += pDraw->y; ++ ++ if (FONTMINBOUNDS(font,characterWidth) >= 0) ++ { ++ /* compute an approximate (but covering) bounding box */ ++ if (!imageblt || (charinfo[0]->metrics.leftSideBearing < 0)) ++ extents.overallLeft = charinfo[0]->metrics.leftSideBearing; ++ else ++ extents.overallLeft = 0; ++ if (w) ++ extents.overallRight = w - charinfo[n-1]->metrics.characterWidth; ++ else ++ extents.overallRight = FONTMAXBOUNDS(font,characterWidth) ++ * (n - 1); ++ if (imageblt && (charinfo[n-1]->metrics.characterWidth > ++ charinfo[n-1]->metrics.rightSideBearing)) ++ extents.overallRight += charinfo[n-1]->metrics.characterWidth; ++ else ++ extents.overallRight += charinfo[n-1]->metrics.rightSideBearing; ++ if (imageblt && FONTASCENT(font) > FONTMAXBOUNDS(font,ascent)) ++ extents.overallAscent = FONTASCENT(font); ++ else ++ extents.overallAscent = FONTMAXBOUNDS(font, ascent); ++ if (imageblt && FONTDESCENT(font) > FONTMAXBOUNDS(font,descent)) ++ extents.overallDescent = FONTDESCENT(font); ++ else ++ extents.overallDescent = FONTMAXBOUNDS(font,descent); ++ if (!BOX_OVERLAP(cursorBox, ++ x + extents.overallLeft, ++ y - extents.overallAscent, ++ x + extents.overallRight, ++ y + extents.overallDescent)) ++ return FALSE; ++ else if (imageblt && w) ++ return TRUE; ++ /* if it does overlap, fall through and compute exactly, because ++ * taking down the cursor is expensive enough to make this worth it ++ */ ++ } ++ QueryGlyphExtents(font, charinfo, n, &extents); ++ if (imageblt) ++ { ++ if (extents.overallWidth > extents.overallRight) ++ extents.overallRight = extents.overallWidth; ++ if (extents.overallWidth < extents.overallLeft) ++ extents.overallLeft = extents.overallWidth; ++ if (extents.overallLeft > 0) ++ extents.overallLeft = 0; ++ if (extents.fontAscent > extents.overallAscent) ++ extents.overallAscent = extents.fontAscent; ++ if (extents.fontDescent > extents.overallDescent) ++ extents.overallDescent = extents.fontDescent; ++ } ++ return (BOX_OVERLAP(cursorBox, ++ x + extents.overallLeft, ++ y - extents.overallAscent, ++ x + extents.overallRight, ++ y + extents.overallDescent)); ++} ++ ++/* ++ * values for textType: ++ */ ++#define TT_POLY8 0 ++#define TT_IMAGE8 1 ++#define TT_POLY16 2 ++#define TT_IMAGE16 3 ++ ++static int ++rfbSpriteText (pDraw, pGC, x, y, count, chars, fontEncoding, textType, cursorBox) ++ DrawablePtr pDraw; ++ GCPtr pGC; ++ int x, ++ y; ++ unsigned long count; ++ char *chars; ++ FontEncoding fontEncoding; ++ Bool textType; ++ BoxPtr cursorBox; ++{ ++ CharInfoPtr *charinfo; ++ register CharInfoPtr *info; ++ unsigned long i; ++ unsigned int n; ++ int w; ++ void (*drawFunc)() = NULL; ++ ++ Bool imageblt; ++ ++ imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); ++ ++ charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr)); ++ if (!charinfo) ++ return x; ++ ++ GetGlyphs(pGC->font, count, (unsigned char *)chars, ++ fontEncoding, &i, charinfo); ++ n = (unsigned int)i; ++ w = 0; ++ if (!imageblt) ++ for (info = charinfo; i--; info++) ++ w += (*info)->metrics.characterWidth; ++ ++ if (n != 0) { ++ if (rfbSpriteTextOverlap(pDraw, pGC->font, x, y, n, charinfo, imageblt, w, cursorBox)) ++ rfbSpriteRemoveCursor(pDraw->pScreen); ++ ++#ifdef AVOID_GLYPHBLT ++ /* ++ * On displays like Apollos, which do not optimize the GlyphBlt functions because they ++ * convert fonts to their internal form in RealizeFont and optimize text directly, we ++ * want to invoke the text functions here, not the GlyphBlt functions. ++ */ ++ switch (textType) ++ { ++ case TT_POLY8: ++ drawFunc = (void (*)())pGC->ops->PolyText8; ++ break; ++ case TT_IMAGE8: ++ drawFunc = pGC->ops->ImageText8; ++ break; ++ case TT_POLY16: ++ drawFunc = (void (*)())pGC->ops->PolyText16; ++ break; ++ case TT_IMAGE16: ++ drawFunc = pGC->ops->ImageText16; ++ break; ++ } ++ (*drawFunc) (pDraw, pGC, x, y, (int) count, chars); ++#else /* don't AVOID_GLYPHBLT */ ++ /* ++ * On the other hand, if the device does use GlyphBlt ultimately to do text, we ++ * don't want to slow it down by invoking the text functions and having them call ++ * GetGlyphs all over again, so we go directly to the GlyphBlt functions here. ++ */ ++ drawFunc = imageblt ? pGC->ops->ImageGlyphBlt : pGC->ops->PolyGlyphBlt; ++ (*drawFunc) (pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); ++#endif /* AVOID_GLYPHBLT */ ++ } ++ DEALLOCATE_LOCAL(charinfo); ++ return x + w; ++} ++ ++static int ++rfbSpritePolyText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ int ret; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, chars, ++ Linear8Bit, TT_POLY8, &pScreenPriv->saved); ++ else ++ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++ return ret; ++} ++ ++static int ++rfbSpritePolyText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ int ret; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, ++ (char *)chars, ++ FONTLASTROW(pGC->font) == 0 ? ++ Linear16Bit : TwoD16Bit, TT_POLY16, &pScreenPriv->saved); ++ else ++ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++ return ret; ++} ++ ++static void ++rfbSpriteImageText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ (void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, ++ chars, Linear8Bit, TT_IMAGE8, &pScreenPriv->saved); ++ else ++ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteImageText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ (void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, ++ (char *)chars, ++ FONTLASTROW(pGC->font) == 0 ? ++ Linear16Bit : TwoD16Bit, TT_IMAGE16, &pScreenPriv->saved); ++ else ++ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable) && ++ rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, TRUE, 0, &pScreenPriv->saved)) ++ { ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ } ++ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable) && ++ rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, FALSE, 0, &pScreenPriv->saved)) ++ { ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ } ++ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePushPixels(pGC, pBitMap, pDrawable, w, h, x, y) ++ GCPtr pGC; ++ PixmapPtr pBitMap; ++ DrawablePtr pDrawable; ++ int w, h, x, y; ++{ ++ VNCSCREENPTR(pGC->pScreen); ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable) && ++ ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,x,y,w,h)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++#ifdef NEED_LINEHELPER ++/* ++ * I don't expect this routine will ever be called, as the GC ++ * will have been unwrapped for the line drawing ++ */ ++ ++static void ++rfbSpriteLineHelper() ++{ ++ FatalError("rfbSpriteLineHelper called\n"); ++} ++#endif ++ ++#ifdef RENDER ++ ++# define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) ++ ++static void ++rfbSpritePictureOverlap (PicturePtr pPict, ++ INT16 x, ++ INT16 y, ++ CARD16 w, ++ CARD16 h) ++{ ++ VNCSCREENPTR(pPict->pDrawable->pScreen); ++ ++ if (pPict->pDrawable->type == DRAWABLE_WINDOW) ++ { ++ WindowPtr pWin = (WindowPtr) (pPict->pDrawable); ++ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr) ++ pPict->pDrawable->pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (GC_CHECK(pWin)) ++ { ++ if (pPict->repeat) ++ { ++ x = mod(x,pWin->drawable.width); ++ y = mod(y,pWin->drawable.height); ++ } ++ if (ORG_OVERLAP (&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y, ++ x, y, w, h)) ++ rfbSpriteRemoveCursor (pWin->drawable.pScreen); ++ } ++ } ++} ++ ++#define PICTURE_PROLOGUE(ps, pScreenPriv, field) \ ++ ps->field = pScreenPriv->field ++ ++#define PICTURE_EPILOGUE(ps, field, wrap) \ ++ ps->field = wrap ++ ++static void ++rfbSpriteComposite(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height) ++{ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ PICTURE_PROLOGUE(ps, pScreenPriv, Composite); ++ rfbSpritePictureOverlap (pSrc, xSrc, ySrc, width, height); ++ if (pMask) ++ rfbSpritePictureOverlap (pMask, xMask, yMask, width, height); ++ rfbSpritePictureOverlap (pDst, xDst, yDst, width, height); ++ ++ (*ps->Composite) (op, ++ pSrc, ++ pMask, ++ pDst, ++ xSrc, ++ ySrc, ++ xMask, ++ yMask, ++ xDst, ++ yDst, ++ width, ++ height); ++ ++ PICTURE_EPILOGUE(ps, Composite, rfbSpriteComposite); ++} ++ ++static void ++rfbSpriteGlyphs(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlist, ++ GlyphListPtr list, ++ GlyphPtr *glyphs) ++{ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ PICTURE_PROLOGUE(ps, pScreenPriv, Glyphs); ++ if (pSrc->pDrawable->type == DRAWABLE_WINDOW) ++ { ++ WindowPtr pSrcWin = (WindowPtr) (pSrc->pDrawable); ++ ++ if (GC_CHECK(pSrcWin)) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ if (pDst->pDrawable->type == DRAWABLE_WINDOW) ++ { ++ WindowPtr pDstWin = (WindowPtr) (pDst->pDrawable); ++ ++ if (GC_CHECK(pDstWin)) ++ { ++ BoxRec extents; ++ ++ miGlyphExtents (nlist, list, glyphs, &extents); ++ if (BOX_OVERLAP(&pScreenPriv->saved, ++ extents.x1 + pDstWin->drawable.x, ++ extents.y1 + pDstWin->drawable.y, ++ extents.x2 + pDstWin->drawable.x, ++ extents.y2 + pDstWin->drawable.y)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++ } ++ ++ (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); ++ ++ PICTURE_EPILOGUE (ps, Glyphs, rfbSpriteGlyphs); ++} ++#endif ++ ++/* ++ * miPointer interface routines ++ */ ++ ++#define SPRITE_PAD 8 ++ ++static Bool ++rfbSpriteRealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pCursor == pScreenPriv->pCursor) ++ pScreenPriv->checkPixels = TRUE; ++ return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor); ++} ++ ++static Bool ++rfbSpriteUnrealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor); ++} ++ ++static void ++rfbSpriteSetCursor (pScreen, pCursor, x, y) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ rfbClientPtr cl, nextCl; ++ VNCSCREENPTR(pScreen); ++ ++ pScreenPriv ++ = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (!pCursor) ++ { ++ pScreenPriv->shouldBeUp = FALSE; ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ pScreenPriv->pCursor = 0; ++ return; ++ } ++ pScreenPriv->shouldBeUp = TRUE; ++ if (pScreenPriv->x == x && ++ pScreenPriv->y == y && ++ pScreenPriv->pCursor == pCursor && ++ !pScreenPriv->checkPixels) ++ { ++ return; ++ } ++ pScreenPriv->x = x; ++ pScreenPriv->y = y; ++ pScreenPriv->pCacheWin = NullWindow; ++ if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor) ++ { ++ pScreenPriv->pCursor = pCursor; ++ rfbSpriteFindColors (pScreen); ++ } ++ if (pVNC->cursorIsDrawn) { ++ int sx, sy; ++ /* ++ * check to see if the old saved region ++ * encloses the new sprite, in which case we use ++ * the flicker-free MoveCursor primitive. ++ */ ++ sx = pScreenPriv->x - (int)pCursor->bits->xhot; ++ sy = pScreenPriv->y - (int)pCursor->bits->yhot; ++ if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 && ++ sx < pScreenPriv->saved.x2 && ++ sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 && ++ sy < pScreenPriv->saved.y2 && ++ (int) pCursor->bits->width + (2 * SPRITE_PAD) == ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1 && ++ (int) pCursor->bits->height + (2 * SPRITE_PAD) == ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1 ++ ) ++ { ++ pVNC->cursorIsDrawn = FALSE; ++ if (!(sx >= pScreenPriv->saved.x1 && ++ sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 && ++ sy >= pScreenPriv->saved.y1 && ++ sy + (int)pCursor->bits->height < pScreenPriv->saved.y2)) ++ { ++ int oldx1, oldy1, dx, dy; ++ ++ oldx1 = pScreenPriv->saved.x1; ++ oldy1 = pScreenPriv->saved.y1; ++ dx = oldx1 - (sx - SPRITE_PAD); ++ dy = oldy1 - (sy - SPRITE_PAD); ++ pScreenPriv->saved.x1 -= dx; ++ pScreenPriv->saved.y1 -= dy; ++ pScreenPriv->saved.x2 -= dx; ++ pScreenPriv->saved.y2 -= dy; ++ (void) (*pScreenPriv->funcs->ChangeSave) (pScreen, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1, ++ dx, dy); ++ } ++ (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1, ++ sx - pScreenPriv->saved.x1, ++ sy - pScreenPriv->saved.y1, ++ pScreenPriv->colors[SOURCE_COLOR].pixel, ++ pScreenPriv->colors[MASK_COLOR].pixel); ++ pVNC->cursorIsDrawn = TRUE; ++ } ++ else ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++#if 0 ++ if (!pVNC->cursorIsDrawn && pScreenPriv->pCursor) ++ rfbSpriteRestoreCursor (pScreen); ++#endif ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (cl->enableCursorPosUpdates) { ++ if (x == cl->cursorX && y == cl->cursorY) { ++ cl->cursorWasMoved = FALSE; ++ continue; ++ } ++ cl->cursorWasMoved = TRUE; ++ } ++ if (REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) { ++ /* cursorIsDrawn is guaranteed to be FALSE here, so we definitely ++ want to send a screen update to the client, even if that's only ++ putting up the cursor */ ++ rfbSendFramebufferUpdate(pScreen, cl); ++ } ++ } ++} ++ ++static void ++rfbSpriteMoveCursor (pScreen, x, y) ++ ScreenPtr pScreen; ++ int x, y; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ rfbSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y); ++} ++ ++/* ++ * undraw/draw cursor ++ */ ++ ++void ++rfbSpriteRemoveCursor (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ if (!pVNC->cursorIsDrawn) ++ return; ++ ++ pScreenPriv ++ = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ pVNC->dontSendFramebufferUpdate = TRUE; ++ pVNC->cursorIsDrawn = FALSE; ++ pScreenPriv->pCacheWin = NullWindow; ++ if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) ++ { ++ pVNC->cursorIsDrawn = TRUE; ++ } ++ pVNC->dontSendFramebufferUpdate = FALSE; ++} ++ ++ ++void ++rfbSpriteRestoreCursor (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ int x, y; ++ CursorPtr pCursor; ++ VNCSCREENPTR(pScreen); ++ ++ pScreenPriv ++ = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ pCursor = pScreenPriv->pCursor; ++ ++ if (pVNC->cursorIsDrawn || !pCursor) ++ return; ++ ++ pVNC->dontSendFramebufferUpdate = TRUE; ++ ++ rfbSpriteComputeSaved (pScreen); ++ ++ x = pScreenPriv->x - (int)pCursor->bits->xhot; ++ y = pScreenPriv->y - (int)pCursor->bits->yhot; ++ if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) ++ { ++ if (pScreenPriv->checkPixels) ++ rfbSpriteFindColors (pScreen); ++ if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y, ++ pScreenPriv->colors[SOURCE_COLOR].pixel, ++ pScreenPriv->colors[MASK_COLOR].pixel)) ++ pVNC->cursorIsDrawn = TRUE; ++ } ++ ++ pVNC->dontSendFramebufferUpdate = FALSE; ++} ++ ++/* ++ * compute the desired area of the screen to save ++ */ ++ ++static void ++rfbSpriteComputeSaved (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ int x, y, w, h; ++ int wpad, hpad; ++ CursorPtr pCursor; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ pCursor = pScreenPriv->pCursor; ++ x = pScreenPriv->x - (int)pCursor->bits->xhot; ++ y = pScreenPriv->y - (int)pCursor->bits->yhot; ++ w = pCursor->bits->width; ++ h = pCursor->bits->height; ++ wpad = SPRITE_PAD; ++ hpad = SPRITE_PAD; ++ pScreenPriv->saved.x1 = x - wpad; ++ pScreenPriv->saved.y1 = y - hpad; ++ pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2; ++ pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2; ++} ++ ++ ++/* ++ * this function is called when the cursor shape is being changed ++ */ ++ ++static Bool ++rfbDisplayCursor(pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbClientPtr cl; ++ rfbSpriteScreenPtr pPriv; ++ ++ for (cl = rfbClientHead; cl ; cl = cl->next) { ++ if (cl->enableCursorShapeUpdates) ++ cl->cursorWasChanged = TRUE; ++ } ++ ++ pPriv = (rfbSpriteScreenPtr)pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ return (*pPriv->DisplayCursor)(pScreen, pCursor); ++} ++ ++ ++/* ++ * obtain current cursor pointer ++ */ ++ ++CursorPtr ++rfbSpriteGetCursorPtr (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ return pScreenPriv->pCursor; ++} ++ ++/* ++ * obtain current cursor position ++ */ ++ ++void ++rfbSpriteGetCursorPos (pScreen, px, py) ++ ScreenPtr pScreen; ++ int *px, *py; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ *px = pScreenPriv->x; ++ *py = pScreenPriv->y; ++} ++ +diff --git a/hw/dmx/vnc/sprite.h b/hw/dmx/vnc/sprite.h +new file mode 100644 +index 0000000..ed34726 +--- /dev/null ++++ b/hw/dmx/vnc/sprite.h +@@ -0,0 +1,141 @@ ++/* ++ * sprite.h ++ * ++ * software-sprite/sprite drawing - based on misprite ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * 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/dmx/vnc/spritest.h b/hw/dmx/vnc/spritest.h +new file mode 100644 +index 0000000..8593ee0 +--- /dev/null ++++ b/hw/dmx/vnc/spritest.h +@@ -0,0 +1,138 @@ ++/* ++ * spritest.h ++ * ++ * sprite structures - based on misprite ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * 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/dmx/vnc/stats.c b/hw/dmx/vnc/stats.c +new file mode 100644 +index 0000000..53017ee +--- /dev/null ++++ b/hw/dmx/vnc/stats.c +@@ -0,0 +1,113 @@ ++/* ++ * stats.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#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/dmx/vnc/tableinitcmtemplate.c b/hw/dmx/vnc/tableinitcmtemplate.c +new file mode 100644 +index 0000000..8a757e5 +--- /dev/null ++++ b/hw/dmx/vnc/tableinitcmtemplate.c +@@ -0,0 +1,89 @@ ++/* ++ * tableinitcmtemplate.c - template for initialising lookup tables for ++ * translation from a colour map to true colour. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with a different definition of the macro OUT. ++ * For each value of OUT, this file defines a function which allocates an ++ * appropriately sized lookup table and initialises it. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define OUT_T CONCAT2E(CARD,OUT) ++#define SwapOUT(x) CONCAT2E(Swap,OUT(x)) ++#define rfbInitColourMapSingleTableOUT \ ++ CONCAT2E(rfbInitColourMapSingleTable,OUT) ++ ++static void ++rfbInitColourMapSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ VNCSCREENPTR(pScreen); ++ int i, r, g, b; ++ OUT_T *t; ++ EntryPtr pent; ++ int nEntries = 1 << in->bitsPerPixel; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc(nEntries * sizeof(OUT_T)); ++ t = (OUT_T *)*table; ++ ++#if XFREE86VNC ++ pent = (EntryPtr)&miInstalledMaps[pScreen->myNum]->red[0]; ++#else ++ pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[0]; ++#endif ++ ++ for (i = 0; i < nEntries; i++) { ++ if (pent->fShared) { ++ r = pent->co.shco.red->color; ++ g = pent->co.shco.green->color; ++ b = pent->co.shco.blue->color; ++ } else { ++ r = pent->co.local.red; ++ g = pent->co.local.green; ++ b = pent->co.local.blue; ++ } ++ t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) | ++ (((g * out->greenMax + 32767) / 65535) << out->greenShift) | ++ (((b * out->blueMax + 32767) / 65535) << out->blueShift)); ++#if (OUT != 8) ++ if (out->bigEndian != in->bigEndian) { ++ t[i] = SwapOUT(t[i]); ++ } ++#endif ++ pent++; ++ } ++} ++ ++#undef OUT_T ++#undef SwapOUT ++#undef rfbInitColourMapSingleTableOUT +diff --git a/hw/dmx/vnc/tableinittctemplate.c b/hw/dmx/vnc/tableinittctemplate.c +new file mode 100644 +index 0000000..da8ae01 +--- /dev/null ++++ b/hw/dmx/vnc/tableinittctemplate.c +@@ -0,0 +1,142 @@ ++/* ++ * tableinittctemplate.c - template for initialising lookup tables for ++ * truecolour to truecolour translation. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with a different definition of the macro OUT. ++ * For each value of OUT, this file defines two functions for initialising ++ * lookup tables. One is for truecolour translation using a single lookup ++ * table, the other is for truecolour translation using three separate ++ * lookup tables for the red, green and blue values. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define OUT_T CONCAT2E(CARD,OUT) ++#define SwapOUT(x) CONCAT2E(Swap,OUT(x)) ++#define rfbInitTrueColourSingleTableOUT \ ++ CONCAT2E(rfbInitTrueColourSingleTable,OUT) ++#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT) ++#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT) ++ ++static void ++rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift, ++ int swap); ++ ++ ++/* ++ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour ++ * translation. ++ */ ++ ++static void ++rfbInitTrueColourSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ int i; ++ int inRed, inGreen, inBlue, outRed, outGreen, outBlue; ++ OUT_T *t; ++ int nEntries = 1 << in->bitsPerPixel; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc(nEntries * sizeof(OUT_T)); ++ t = (OUT_T *)*table; ++ ++ for (i = 0; i < nEntries; i++) { ++ inRed = (i >> in->redShift) & in->redMax; ++ inGreen = (i >> in->greenShift) & in->greenMax; ++ inBlue = (i >> in->blueShift) & in->blueMax; ++ ++ outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax; ++ outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax; ++ outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax; ++ ++ t[i] = ((outRed << out->redShift) | ++ (outGreen << out->greenShift) | ++ (outBlue << out->blueShift)); ++#if (OUT != 8) ++ if (out->bigEndian != in->bigEndian) { ++ t[i] = SwapOUT(t[i]); ++ } ++#endif ++ } ++} ++ ++ ++/* ++ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the ++ * red, green and blue values. ++ */ ++ ++static void ++rfbInitTrueColourRGBTablesOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ OUT_T *redTable; ++ OUT_T *greenTable; ++ OUT_T *blueTable; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3) ++ * sizeof(OUT_T)); ++ redTable = (OUT_T *)*table; ++ greenTable = redTable + in->redMax + 1; ++ blueTable = greenTable + in->greenMax + 1; ++ ++ rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax, ++ out->redShift, (out->bigEndian != in->bigEndian)); ++ rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax, ++ out->greenShift, (out->bigEndian != in->bigEndian)); ++ rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax, ++ out->blueShift, (out->bigEndian != in->bigEndian)); ++} ++ ++static void ++rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift, ++ int swap) ++{ ++ int i; ++ int nEntries = inMax + 1; ++ ++ for (i = 0; i < nEntries; i++) { ++ table[i] = ((i * outMax + inMax / 2) / inMax) << outShift; ++#if (OUT != 8) ++ if (swap) { ++ table[i] = SwapOUT(table[i]); ++ } ++#endif ++ } ++} ++ ++#undef OUT_T ++#undef SwapOUT ++#undef rfbInitTrueColourSingleTableOUT ++#undef rfbInitTrueColourRGBTablesOUT ++#undef rfbInitOneRGBTableOUT +diff --git a/hw/dmx/vnc/tabletranstemplate.c b/hw/dmx/vnc/tabletranstemplate.c +new file mode 100644 +index 0000000..87cfcba +--- /dev/null ++++ b/hw/dmx/vnc/tabletranstemplate.c +@@ -0,0 +1,119 @@ ++/* ++ * tabletranstemplate.c - template for translation using lookup tables. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with different definitions of the macros IN and OUT. ++ * ++ * For each pair of values IN and OUT, this file defines two functions for ++ * translating a given rectangle of pixel data. One uses a single lookup ++ * table, and the other uses three separate lookup tables for the red, green ++ * and blue values. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(IN) || !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define IN_T CONCAT2E(CARD,IN) ++#define OUT_T CONCAT2E(CARD,OUT) ++#define rfbTranslateWithSingleTableINtoOUT \ ++ CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT) ++#define rfbTranslateWithRGBTablesINtoOUT \ ++ CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT) ++ ++/* ++ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data ++ * using a single lookup table. ++ */ ++ ++static void ++rfbTranslateWithSingleTableINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y) ++{ ++ IN_T *ip = (IN_T *)iptr; ++ OUT_T *op = (OUT_T *)optr; ++ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width; ++ OUT_T *opLineEnd; ++ OUT_T *t = (OUT_T *)table; ++ ++ while (height > 0) { ++ opLineEnd = op + width; ++ ++ while (op < opLineEnd) { ++ *(op++) = t[*(ip++)]; ++ } ++ ++ ip += ipextra; ++ height--; ++ } ++} ++ ++ ++/* ++ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data ++ * using three separate lookup tables for the red, green and blue values. ++ */ ++ ++static void ++rfbTranslateWithRGBTablesINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y) ++{ ++ IN_T *ip = (IN_T *)iptr; ++ OUT_T *op = (OUT_T *)optr; ++ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width; ++ OUT_T *opLineEnd; ++ OUT_T *redTable = (OUT_T *)table; ++ OUT_T *greenTable = redTable + in->redMax + 1; ++ OUT_T *blueTable = greenTable + in->greenMax + 1; ++ ++ while (height > 0) { ++ opLineEnd = op + width; ++ ++ while (op < opLineEnd) { ++ *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] | ++ greenTable[(*ip >> in->greenShift) & in->greenMax] | ++ blueTable[(*ip >> in->blueShift) & in->blueMax]); ++ ip++; ++ } ++ ip += ipextra; ++ height--; ++ } ++} ++ ++#undef IN_T ++#undef OUT_T ++#undef rfbTranslateWithSingleTableINtoOUT ++#undef rfbTranslateWithRGBTablesINtoOUT +diff --git a/hw/dmx/vnc/tight.c b/hw/dmx/vnc/tight.c +new file mode 100644 +index 0000000..3dfd8a1 +--- /dev/null ++++ b/hw/dmx/vnc/tight.c +@@ -0,0 +1,1827 @@ ++/* ++ * tight.c ++ * ++ * Routines to implement Tight Encoding ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "rfb.h" ++#include ++ ++ ++/* Note: The following constant should not be changed. */ ++#define TIGHT_MIN_TO_COMPRESS 12 ++ ++/* The parameters below may be adjusted. */ ++#define MIN_SPLIT_RECT_SIZE 4096 ++#define MIN_SOLID_SUBRECT_SIZE 2048 ++#define MAX_SPLIT_TILE_SIZE 16 ++ ++/* May be set to TRUE with "-lazytight" Xvnc option. */ ++Bool rfbTightDisableGradient = FALSE; ++ ++/* This variable is set on every rfbSendRectEncodingTight() call. */ ++static Bool usePixelFormat24; ++ ++ ++/* Compression level stuff. The following array contains various ++ encoder parameters for each of 10 compression levels (0..9). ++ Last three parameters correspond to JPEG quality levels (0..9). */ ++ ++typedef struct TIGHT_CONF_s { ++ int maxRectSize, maxRectWidth; ++ int monoMinRectSize, gradientMinRectSize; ++ int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel; ++ int gradientThreshold, gradientThreshold24; ++ int idxMaxColorsDivisor; ++ int jpegQuality, jpegThreshold, jpegThreshold24; ++} TIGHT_CONF; ++ ++static TIGHT_CONF tightConf[10] = { ++ { 512, 32, 6, 65536, 0, 0, 0, 0, 0, 0, 4, 5, 10000, 23000 }, ++ { 2048, 128, 6, 65536, 1, 1, 1, 0, 0, 0, 8, 10, 8000, 18000 }, ++ { 6144, 256, 8, 65536, 3, 3, 2, 0, 0, 0, 24, 15, 6500, 15000 }, ++ { 10240, 1024, 12, 65536, 5, 5, 3, 0, 0, 0, 32, 25, 5000, 12000 }, ++ { 16384, 2048, 12, 65536, 6, 6, 4, 0, 0, 0, 32, 37, 4000, 10000 }, ++ { 32768, 2048, 12, 4096, 7, 7, 5, 4, 150, 380, 32, 50, 3000, 8000 }, ++ { 65536, 2048, 16, 4096, 7, 7, 6, 4, 170, 420, 48, 60, 2000, 5000 }, ++ { 65536, 2048, 16, 4096, 8, 8, 7, 5, 180, 450, 64, 70, 1000, 2500 }, ++ { 65536, 2048, 32, 8192, 9, 9, 8, 6, 190, 475, 64, 75, 500, 1200 }, ++ { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } ++}; ++ ++/* Stuff dealing with palettes. */ ++ ++typedef struct COLOR_LIST_s { ++ struct COLOR_LIST_s *next; ++ int idx; ++ CARD32 rgb; ++} COLOR_LIST; ++ ++typedef struct PALETTE_ENTRY_s { ++ COLOR_LIST *listNode; ++ int numPixels; ++} PALETTE_ENTRY; ++ ++typedef struct PALETTE_s { ++ PALETTE_ENTRY entry[256]; ++ COLOR_LIST *hash[256]; ++ COLOR_LIST list[256]; ++} PALETTE; ++ ++static int paletteNumColors, paletteMaxColors; ++static CARD32 monoBackground, monoForeground; ++static PALETTE palette; ++ ++/* Pointers to dynamically-allocated buffers. */ ++ ++static int tightBeforeBufSize = 0; ++static char *tightBeforeBuf = NULL; ++ ++static int tightAfterBufSize = 0; ++static char *tightAfterBuf = NULL; ++ ++static int *prevRowBuf = NULL; ++ ++ ++/* Prototypes for static functions. */ ++ ++static void FindBestSolidArea (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 colorValue, int *w_ptr, int *h_ptr); ++static void ExtendSolidArea (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 colorValue, ++ int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr); ++static Bool CheckSolidTile (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile8 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile16 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile32 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++ ++static Bool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h); ++static Bool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h); ++static Bool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h); ++ ++static Bool SendSolidRect (rfbClientPtr cl); ++static Bool SendMonoRect (rfbClientPtr cl, int w, int h); ++static Bool SendIndexedRect (rfbClientPtr cl, int w, int h); ++static Bool SendFullColorRect (rfbClientPtr cl, int w, int h); ++static Bool SendGradientRect (rfbClientPtr cl, int w, int h); ++ ++static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen, ++ int zlibLevel, int zlibStrategy); ++static Bool SendCompressedData(rfbClientPtr cl, int compressedLen); ++ ++static void FillPalette8(int count); ++static void FillPalette16(int count); ++static void FillPalette32(int count); ++ ++static void PaletteReset(void); ++static int PaletteInsert(CARD32 rgb, int numPixels, int bpp); ++ ++static void Pack24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int count); ++ ++static void EncodeIndexedRect16(CARD8 *buf, int count); ++static void EncodeIndexedRect32(CARD8 *buf, int count); ++ ++static void EncodeMonoRect8(CARD8 *buf, int w, int h); ++static void EncodeMonoRect16(CARD8 *buf, int w, int h); ++static void EncodeMonoRect32(CARD8 *buf, int w, int h); ++ ++static void FilterGradient24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int w, int h); ++static void FilterGradient16(ScreenPtr pScreen, CARD16 *buf, rfbPixelFormat *fmt, int w, int h); ++static void FilterGradient32(ScreenPtr pScreen, CARD32 *buf, rfbPixelFormat *fmt, int w, int h); ++ ++static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++ ++static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, ++ int quality); ++static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++ ++static void JpegInitDestination(j_compress_ptr cinfo); ++static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo); ++static void JpegTermDestination(j_compress_ptr cinfo); ++static void JpegSetDstManager(j_compress_ptr cinfo); ++ ++ ++/* ++ * Tight encoding implementation. ++ */ ++ ++int ++rfbNumCodedRectsTight(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ int maxRectSize, maxRectWidth; ++ int subrectMaxWidth, subrectMaxHeight; ++ ++ /* No matter how many rectangles we will send if LastRect markers ++ are used to terminate rectangle stream. */ ++ if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE) ++ return 0; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ ++ if (w > maxRectWidth || w * h > maxRectSize) { ++ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ subrectMaxHeight = maxRectSize / subrectMaxWidth; ++ return (((w - 1) / maxRectWidth + 1) * ++ ((h - 1) / subrectMaxHeight + 1)); ++ } else { ++ return 1; ++ } ++} ++ ++Bool ++rfbSendRectEncodingTight(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int nMaxRows; ++ CARD32 colorValue; ++ int dx, dy, dw, dh; ++ int x_best, y_best, w_best, h_best; ++ unsigned char *fbptr; ++ ++ if ( cl->format.depth == 24 && cl->format.redMax == 0xFF && ++ cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) { ++ usePixelFormat24 = TRUE; ++ } else { ++ usePixelFormat24 = FALSE; ++ } ++ ++ if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE) ++ return SendRectSimple(cl, x, y, w, h); ++ ++ /* Make sure we can write at least one pixel into tightBeforeBuf. */ ++ ++ if (tightBeforeBufSize < 4) { ++ tightBeforeBufSize = 4; ++ if (tightBeforeBuf == NULL) ++ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); ++ else ++ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, ++ tightBeforeBufSize); ++ } ++ ++ /* Calculate maximum number of rows in one non-solid rectangle. */ ++ ++ { ++ int maxRectSize, maxRectWidth, nMaxWidth; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ nMaxRows = maxRectSize / nMaxWidth; ++ } ++ ++ /* Try to find large solid-color areas and send them separately. */ ++ ++ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { ++ ++ /* If a rectangle becomes too large, send its upper part now. */ ++ ++ if (dy - y >= nMaxRows) { ++ if (!SendRectSimple(cl, x, y, w, nMaxRows)) ++ return 0; ++ y += nMaxRows; ++ h -= nMaxRows; ++ } ++ ++ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? ++ MAX_SPLIT_TILE_SIZE : (y + h - dy); ++ ++ for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) { ++ ++ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ? ++ MAX_SPLIT_TILE_SIZE : (x + w - dx); ++ ++ if (CheckSolidTile(cl->pScreen, dx, dy, dw, dh, &colorValue, FALSE)) { ++ ++ /* Get dimensions of solid-color area. */ ++ ++ FindBestSolidArea(cl->pScreen, dx, dy, w - (dx - x), h - (dy - y), ++ colorValue, &w_best, &h_best); ++ ++ /* Make sure a solid rectangle is large enough ++ (or the whole rectangle is of the same color). */ ++ ++ if ( w_best * h_best != w * h && ++ w_best * h_best < MIN_SOLID_SUBRECT_SIZE ) ++ continue; ++ ++ /* Try to extend solid rectangle to maximum size. */ ++ ++ x_best = dx; y_best = dy; ++ ExtendSolidArea(cl->pScreen, x, y, w, h, colorValue, ++ &x_best, &y_best, &w_best, &h_best); ++ ++ /* Send rectangles at top and left to solid-color area. */ ++ ++ if ( y_best != y && ++ !SendRectSimple(cl, x, y, w, y_best-y) ) ++ return FALSE; ++ if ( x_best != x && ++ !rfbSendRectEncodingTight(cl, x, y_best, ++ x_best-x, h_best) ) ++ return FALSE; ++ ++ /* Send solid-color rectangle. */ ++ ++ if (!SendTightHeader(cl, x_best, y_best, w_best, h_best)) ++ return FALSE; ++ ++ fbptr = (pVNC->pfbMemory + ++ (pVNC->paddedWidthInBytes * y_best) + ++ (x_best * (pVNC->bitsPerPixel / 8))); ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, tightBeforeBuf, ++ pVNC->paddedWidthInBytes, 1, 1, ++ x_best, y_best); ++ ++ if (!SendSolidRect(cl)) ++ return FALSE; ++ ++ /* Send remaining rectangles (at right and bottom). */ ++ ++ if ( x_best + w_best != x + w && ++ !rfbSendRectEncodingTight(cl, x_best+w_best, y_best, ++ w-(x_best-x)-w_best, h_best) ) ++ return FALSE; ++ if ( y_best + h_best != y + h && ++ !rfbSendRectEncodingTight(cl, x, y_best+h_best, ++ w, h-(y_best-y)-h_best) ) ++ return FALSE; ++ ++ /* Return after all recursive calls are done. */ ++ ++ return TRUE; ++ } ++ ++ } ++ ++ } ++ ++ /* No suitable solid-color rectangles found. */ ++ ++ return SendRectSimple(cl, x, y, w, h); ++} ++ ++static void ++FindBestSolidArea(pScreen, x, y, w, h, colorValue, w_ptr, h_ptr) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 colorValue; ++ int *w_ptr, *h_ptr; ++{ ++ int dx, dy, dw, dh; ++ int w_prev; ++ int w_best = 0, h_best = 0; ++ ++ w_prev = w; ++ ++ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { ++ ++ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? ++ MAX_SPLIT_TILE_SIZE : (y + h - dy); ++ dw = (w_prev > MAX_SPLIT_TILE_SIZE) ? ++ MAX_SPLIT_TILE_SIZE : w_prev; ++ ++ if (!CheckSolidTile(pScreen, x, dy, dw, dh, &colorValue, TRUE)) ++ break; ++ ++ for (dx = x + dw; dx < x + w_prev;) { ++ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ? ++ MAX_SPLIT_TILE_SIZE : (x + w_prev - dx); ++ if (!CheckSolidTile(pScreen, dx, dy, dw, dh, &colorValue, TRUE)) ++ break; ++ dx += dw; ++ } ++ ++ w_prev = dx - x; ++ if (w_prev * (dy + dh - y) > w_best * h_best) { ++ w_best = w_prev; ++ h_best = dy + dh - y; ++ } ++ } ++ ++ *w_ptr = w_best; ++ *h_ptr = h_best; ++} ++ ++static void ++ExtendSolidArea(pScreen, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 colorValue; ++ int *x_ptr, *y_ptr, *w_ptr, *h_ptr; ++{ ++ int cx, cy; ++ ++ /* Try to extend the area upwards. */ ++ for ( cy = *y_ptr - 1; ++ cy >= y && CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); ++ cy-- ); ++ *h_ptr += *y_ptr - (cy + 1); ++ *y_ptr = cy + 1; ++ ++ /* ... downwards. */ ++ for ( cy = *y_ptr + *h_ptr; ++ cy < y + h && ++ CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); ++ cy++ ); ++ *h_ptr += cy - (*y_ptr + *h_ptr); ++ ++ /* ... to the left. */ ++ for ( cx = *x_ptr - 1; ++ cx >= x && CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); ++ cx-- ); ++ *w_ptr += *x_ptr - (cx + 1); ++ *x_ptr = cx + 1; ++ ++ /* ... to the right. */ ++ for ( cx = *x_ptr + *w_ptr; ++ cx < x + w && ++ CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); ++ cx++ ); ++ *w_ptr += cx - (*x_ptr + *w_ptr); ++} ++ ++/* ++ * Check if a rectangle is all of the same color. If needSameColor is ++ * set to non-zero, then also check that its color equals to the ++ * *colorPtr value. The result is 1 if the test is successfull, and in ++ * that case new color will be stored in *colorPtr. ++ */ ++ ++static Bool ++CheckSolidTile(pScreen, x, y, w, h, colorPtr, needSameColor) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 *colorPtr; ++ Bool needSameColor; ++{ ++ VNCSCREENPTR(pScreen); ++ switch(pVNC->rfbServerFormat.bitsPerPixel) { ++ case 32: ++ return CheckSolidTile32(pScreen, x, y, w, h, colorPtr, needSameColor); ++ case 16: ++ return CheckSolidTile16(pScreen, x, y, w, h, colorPtr, needSameColor); ++ default: ++ return CheckSolidTile8(pScreen, x, y, w, h, colorPtr, needSameColor); ++ } ++} ++ ++#define DEFINE_CHECK_SOLID_FUNCTION(bpp) \ ++ \ ++static Bool \ ++CheckSolidTile##bpp(pScreen, x, y, w, h, colorPtr, needSameColor) \ ++ ScreenPtr pScreen; \ ++ int x, y; \ ++ CARD32 *colorPtr; \ ++ Bool needSameColor; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp *fbptr; \ ++ CARD##bpp colorValue; \ ++ int dx, dy; \ ++ \ ++ fbptr = (CARD##bpp *) \ ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * (bpp/8)]; \ ++ \ ++ colorValue = *fbptr; \ ++ if (needSameColor && (CARD32)colorValue != *colorPtr) \ ++ return FALSE; \ ++ \ ++ for (dy = 0; dy < h; dy++) { \ ++ for (dx = 0; dx < w; dx++) { \ ++ if (colorValue != fbptr[dx]) \ ++ return FALSE; \ ++ } \ ++ fbptr = (CARD##bpp *)((CARD8 *)fbptr + pVNC->paddedWidthInBytes); \ ++ } \ ++ \ ++ *colorPtr = (CARD32)colorValue; \ ++ return TRUE; \ ++} ++ ++DEFINE_CHECK_SOLID_FUNCTION(8) ++DEFINE_CHECK_SOLID_FUNCTION(16) ++DEFINE_CHECK_SOLID_FUNCTION(32) ++ ++static Bool ++SendRectSimple(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ int maxBeforeSize, maxAfterSize; ++ int maxRectSize, maxRectWidth; ++ int subrectMaxWidth, subrectMaxHeight; ++ int dx, dy; ++ int rw, rh; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ ++ maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8); ++ maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; ++ ++ if (tightBeforeBufSize < maxBeforeSize) { ++ tightBeforeBufSize = maxBeforeSize; ++ if (tightBeforeBuf == NULL) ++ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); ++ else ++ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, ++ tightBeforeBufSize); ++ } ++ ++ if (tightAfterBufSize < maxAfterSize) { ++ tightAfterBufSize = maxAfterSize; ++ if (tightAfterBuf == NULL) ++ tightAfterBuf = (char *)xalloc(tightAfterBufSize); ++ else ++ tightAfterBuf = (char *)xrealloc(tightAfterBuf, ++ tightAfterBufSize); ++ } ++ ++ if (w > maxRectWidth || w * h > maxRectSize) { ++ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ subrectMaxHeight = maxRectSize / subrectMaxWidth; ++ ++ for (dy = 0; dy < h; dy += subrectMaxHeight) { ++ for (dx = 0; dx < w; dx += maxRectWidth) { ++ rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx; ++ rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy; ++ if (!SendSubrect(cl, x+dx, y+dy, rw, rh)) ++ return FALSE; ++ } ++ } ++ } else { ++ if (!SendSubrect(cl, x, y, w, h)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static Bool ++SendSubrect(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ unsigned char *fbptr; ++ Bool success = FALSE; ++ ++ /* Send pending data if there is more than 128 bytes. */ ++ if (pVNC->ublen > 128) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if (!SendTightHeader(cl, x, y, w, h)) ++ return FALSE; ++ ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat, ++ &cl->format, fbptr, tightBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ paletteMaxColors = w * h / tightConf[cl->tightCompressLevel].idxMaxColorsDivisor; ++ if ( paletteMaxColors < 2 && ++ w * h >= tightConf[cl->tightCompressLevel].monoMinRectSize ) { ++ paletteMaxColors = 2; ++ } ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ FillPalette8(w * h); ++ break; ++ case 16: ++ FillPalette16(w * h); ++ break; ++ default: ++ FillPalette32(w * h); ++ } ++ ++ switch (paletteNumColors) { ++ case 0: ++ /* Truecolor image */ ++ if (DetectSmoothImage(cl, &cl->format, w, h)) { ++ if (cl->tightQualityLevel != -1) { ++ success = SendJpegRect(cl, x, y, w, h, ++ tightConf[cl->tightQualityLevel].jpegQuality); ++ } else { ++ success = SendGradientRect(cl, w, h); ++ } ++ } else { ++ success = SendFullColorRect(cl, w, h); ++ } ++ break; ++ case 1: ++ /* Solid rectangle */ ++ success = SendSolidRect(cl); ++ break; ++ case 2: ++ /* Two-color rectangle */ ++ success = SendMonoRect(cl, w, h); ++ break; ++ default: ++ /* Up to 256 different colors */ ++ if ( paletteNumColors > 96 && ++ cl->tightQualityLevel != -1 && cl->tightQualityLevel <= 3 && ++ DetectSmoothImage(cl, &cl->format, w, h) ) { ++ success = SendJpegRect(cl, x, y, w, h, ++ tightConf[cl->tightQualityLevel].jpegQuality); ++ } else { ++ success = SendIndexedRect(cl, w, h); ++ } ++ } ++ return success; ++} ++ ++static Bool ++SendTightHeader(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingTight); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingTight]++; ++ cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader; ++ ++ return TRUE; ++} ++ ++/* ++ * Subencoding implementations. ++ */ ++ ++static Bool ++SendSolidRect(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int len; ++ ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightBeforeBuf, &cl->format, 1); ++ len = 3; ++ } else ++ len = cl->format.bitsPerPixel / 8; ++ ++ if (pVNC->ublen + 1 + len > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightFill << 4); ++ memcpy (&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, len); ++ pVNC->ublen += len; ++ ++ cl->rfbBytesSent[rfbEncodingTight] += len + 1; ++ ++ return TRUE; ++} ++ ++static Bool ++SendMonoRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 1; ++ int paletteLen, dataLen; ++ ++ if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 + ++ 2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ /* Prepare tight encoding header. */ ++ dataLen = (w + 7) / 8; ++ dataLen *= h; ++ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette; ++ pVNC->updateBuf[pVNC->ublen++] = 1; ++ ++ /* Prepare palette, convert image. */ ++ switch (cl->format.bitsPerPixel) { ++ ++ case 32: ++ EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h); ++ ++ ((CARD32 *)tightAfterBuf)[0] = monoBackground; ++ ((CARD32 *)tightAfterBuf)[1] = monoForeground; ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightAfterBuf, &cl->format, 2); ++ paletteLen = 6; ++ } else ++ paletteLen = 8; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteLen); ++ pVNC->ublen += paletteLen; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen; ++ break; ++ ++ case 16: ++ EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h); ++ ++ ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground; ++ ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, 4); ++ pVNC->ublen += 4; ++ cl->rfbBytesSent[rfbEncodingTight] += 7; ++ break; ++ ++ default: ++ EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h); ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)monoBackground; ++ pVNC->updateBuf[pVNC->ublen++] = (char)monoForeground; ++ cl->rfbBytesSent[rfbEncodingTight] += 5; ++ } ++ ++ return CompressData(cl, streamId, dataLen, ++ tightConf[cl->tightCompressLevel].monoZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendIndexedRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 2; ++ int i, entryLen; ++ ++ if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 + ++ paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ /* Prepare tight encoding header. */ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette; ++ pVNC->updateBuf[pVNC->ublen++] = (char)(paletteNumColors - 1); ++ ++ /* Prepare palette, convert image. */ ++ switch (cl->format.bitsPerPixel) { ++ ++ case 32: ++ EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h); ++ ++ for (i = 0; i < paletteNumColors; i++) { ++ ((CARD32 *)tightAfterBuf)[i] = ++ palette.entry[i].listNode->rgb; ++ } ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightAfterBuf, &cl->format, paletteNumColors); ++ entryLen = 3; ++ } else ++ entryLen = 4; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * entryLen); ++ pVNC->ublen += paletteNumColors * entryLen; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen; ++ break; ++ ++ case 16: ++ EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h); ++ ++ for (i = 0; i < paletteNumColors; i++) { ++ ((CARD16 *)tightAfterBuf)[i] = ++ (CARD16)palette.entry[i].listNode->rgb; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * 2); ++ pVNC->ublen += paletteNumColors * 2; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2; ++ break; ++ ++ default: ++ return FALSE; /* Should never happen. */ ++ } ++ ++ return CompressData(cl, streamId, w * h, ++ tightConf[cl->tightCompressLevel].idxZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendFullColorRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 0; ++ int len; ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */ ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightBeforeBuf, &cl->format, w * h); ++ len = 3; ++ } else ++ len = cl->format.bitsPerPixel / 8; ++ ++ return CompressData(cl, streamId, w * h * len, ++ tightConf[cl->tightCompressLevel].rawZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendGradientRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 3; ++ int len; ++ ++ if (cl->format.bitsPerPixel == 8) ++ return SendFullColorRect(cl, w, h); ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if (prevRowBuf == NULL) ++ prevRowBuf = (int *)xalloc(2048 * 3 * sizeof(int)); ++ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterGradient; ++ cl->rfbBytesSent[rfbEncodingTight] += 2; ++ ++ if (usePixelFormat24) { ++ FilterGradient24(cl->pScreen, tightBeforeBuf, &cl->format, w, h); ++ len = 3; ++ } else if (cl->format.bitsPerPixel == 32) { ++ FilterGradient32(cl->pScreen, (CARD32 *)tightBeforeBuf, &cl->format, w, h); ++ len = 4; ++ } else { ++ FilterGradient16(cl->pScreen, (CARD16 *)tightBeforeBuf, &cl->format, w, h); ++ len = 2; ++ } ++ ++ return CompressData(cl, streamId, w * h * len, ++ tightConf[cl->tightCompressLevel].gradientZlibLevel, ++ Z_FILTERED); ++} ++ ++static Bool ++CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy) ++ rfbClientPtr cl; ++ int streamId, dataLen, zlibLevel, zlibStrategy; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ z_streamp pz; ++ int err; ++ ++ if (dataLen < TIGHT_MIN_TO_COMPRESS) { ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, dataLen); ++ pVNC->ublen += dataLen; ++ cl->rfbBytesSent[rfbEncodingTight] += dataLen; ++ return TRUE; ++ } ++ ++ pz = &cl->zsStruct[streamId]; ++ ++ /* Initialize compression stream if needed. */ ++ if (!cl->zsActive[streamId]) { ++ pz->zalloc = Z_NULL; ++ pz->zfree = Z_NULL; ++ pz->opaque = Z_NULL; ++ ++ err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS, ++ MAX_MEM_LEVEL, zlibStrategy); ++ if (err != Z_OK) ++ return FALSE; ++ ++ cl->zsActive[streamId] = TRUE; ++ cl->zsLevel[streamId] = zlibLevel; ++ } ++ ++ /* Prepare buffer pointers. */ ++ pz->next_in = (Bytef *)tightBeforeBuf; ++ pz->avail_in = dataLen; ++ pz->next_out = (Bytef *)tightAfterBuf; ++ pz->avail_out = tightAfterBufSize; ++ ++ /* Change compression parameters if needed. */ ++ if (zlibLevel != cl->zsLevel[streamId]) { ++ if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) { ++ return FALSE; ++ } ++ cl->zsLevel[streamId] = zlibLevel; ++ } ++ ++ /* Actual compression. */ ++ if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK || ++ pz->avail_in != 0 || pz->avail_out == 0 ) { ++ return FALSE; ++ } ++ ++ return SendCompressedData(cl, tightAfterBufSize - pz->avail_out); ++} ++ ++static Bool SendCompressedData(cl, compressedLen) ++ rfbClientPtr cl; ++ int compressedLen; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int i, portionLen; ++ ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen & 0x7F; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ if (compressedLen > 0x7F) { ++ pVNC->updateBuf[pVNC->ublen-1] |= 0x80; ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 7 & 0x7F; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ if (compressedLen > 0x3FFF) { ++ pVNC->updateBuf[pVNC->ublen-1] |= 0x80; ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 14 & 0xFF; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ } ++ } ++ ++ portionLen = UPDATE_BUF_SIZE; ++ for (i = 0; i < compressedLen; i += portionLen) { ++ if (i + portionLen > compressedLen) { ++ portionLen = compressedLen - i; ++ } ++ if (pVNC->ublen + portionLen > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &tightAfterBuf[i], portionLen); ++ pVNC->ublen += portionLen; ++ } ++ cl->rfbBytesSent[rfbEncodingTight] += compressedLen; ++ return TRUE; ++} ++ ++/* ++ * Code to determine how many different colors used in rectangle. ++ */ ++ ++static void ++FillPalette8(count) ++ int count; ++{ ++ CARD8 *data = (CARD8 *)tightBeforeBuf; ++ CARD8 c0, c1; ++ int i, n0, n1; ++ ++ paletteNumColors = 0; ++ ++ c0 = data[0]; ++ for (i = 1; i < count && data[i] == c0; i++); ++ if (i == count) { ++ paletteNumColors = 1; ++ return; /* Solid rectangle */ ++ } ++ ++ if (paletteMaxColors < 2) ++ return; ++ ++ n0 = i; ++ c1 = data[i]; ++ n1 = 0; ++ for (i++; i < count; i++) { ++ if (data[i] == c0) { ++ n0++; ++ } else if (data[i] == c1) { ++ n1++; ++ } else ++ break; ++ } ++ if (i == count) { ++ if (n0 > n1) { ++ monoBackground = (CARD32)c0; ++ monoForeground = (CARD32)c1; ++ } else { ++ monoBackground = (CARD32)c1; ++ monoForeground = (CARD32)c0; ++ } ++ paletteNumColors = 2; /* Two colors */ ++ } ++} ++ ++#define DEFINE_FILL_PALETTE_FUNCTION(bpp) \ ++ \ ++static void \ ++FillPalette##bpp(count) \ ++ int count; \ ++{ \ ++ CARD##bpp *data = (CARD##bpp *)tightBeforeBuf; \ ++ CARD##bpp c0, c1, ci = 0; \ ++ int i, n0, n1, ni; \ ++ \ ++ c0 = data[0]; \ ++ for (i = 1; i < count && data[i] == c0; i++); \ ++ if (i >= count) { \ ++ paletteNumColors = 1; /* Solid rectangle */ \ ++ return; \ ++ } \ ++ \ ++ if (paletteMaxColors < 2) { \ ++ paletteNumColors = 0; /* Full-color encoding preferred */ \ ++ return; \ ++ } \ ++ \ ++ n0 = i; \ ++ c1 = data[i]; \ ++ n1 = 0; \ ++ for (i++; i < count; i++) { \ ++ ci = data[i]; \ ++ if (ci == c0) { \ ++ n0++; \ ++ } else if (ci == c1) { \ ++ n1++; \ ++ } else \ ++ break; \ ++ } \ ++ if (i >= count) { \ ++ if (n0 > n1) { \ ++ monoBackground = (CARD32)c0; \ ++ monoForeground = (CARD32)c1; \ ++ } else { \ ++ monoBackground = (CARD32)c1; \ ++ monoForeground = (CARD32)c0; \ ++ } \ ++ paletteNumColors = 2; /* Two colors */ \ ++ return; \ ++ } \ ++ \ ++ PaletteReset(); \ ++ PaletteInsert (c0, (CARD32)n0, bpp); \ ++ PaletteInsert (c1, (CARD32)n1, bpp); \ ++ \ ++ ni = 1; \ ++ for (i++; i < count; i++) { \ ++ if (data[i] == ci) { \ ++ ni++; \ ++ } else { \ ++ if (!PaletteInsert (ci, (CARD32)ni, bpp)) \ ++ return; \ ++ ci = data[i]; \ ++ ni = 1; \ ++ } \ ++ } \ ++ PaletteInsert (ci, (CARD32)ni, bpp); \ ++} ++ ++DEFINE_FILL_PALETTE_FUNCTION(16) ++DEFINE_FILL_PALETTE_FUNCTION(32) ++ ++ ++/* ++ * Functions to operate with palette structures. ++ */ ++ ++#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF)) ++#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF)) ++ ++static void ++PaletteReset(void) ++{ ++ paletteNumColors = 0; ++ memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *)); ++} ++ ++static int ++PaletteInsert(CARD32 rgb, int numPixels, int bpp) ++{ ++ COLOR_LIST *pnode; ++ COLOR_LIST *prev_pnode = NULL; ++ int hash_key, idx, new_idx, count; ++ ++ hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb); ++ ++ pnode = palette.hash[hash_key]; ++ ++ while (pnode != NULL) { ++ if (pnode->rgb == rgb) { ++ /* Such palette entry already exists. */ ++ new_idx = idx = pnode->idx; ++ count = palette.entry[idx].numPixels + numPixels; ++ if (new_idx && palette.entry[new_idx-1].numPixels < count) { ++ do { ++ palette.entry[new_idx] = palette.entry[new_idx-1]; ++ palette.entry[new_idx].listNode->idx = new_idx; ++ new_idx--; ++ } ++ while (new_idx && palette.entry[new_idx-1].numPixels < count); ++ palette.entry[new_idx].listNode = pnode; ++ pnode->idx = new_idx; ++ } ++ palette.entry[new_idx].numPixels = count; ++ return paletteNumColors; ++ } ++ prev_pnode = pnode; ++ pnode = pnode->next; ++ } ++ ++ /* Check if palette is full. */ ++ if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) { ++ paletteNumColors = 0; ++ return 0; ++ } ++ ++ /* Move palette entries with lesser pixel counts. */ ++ for ( idx = paletteNumColors; ++ idx > 0 && palette.entry[idx-1].numPixels < numPixels; ++ idx-- ) { ++ palette.entry[idx] = palette.entry[idx-1]; ++ palette.entry[idx].listNode->idx = idx; ++ } ++ ++ /* Add new palette entry into the freed slot. */ ++ pnode = &palette.list[paletteNumColors]; ++ if (prev_pnode != NULL) { ++ prev_pnode->next = pnode; ++ } else { ++ palette.hash[hash_key] = pnode; ++ } ++ pnode->next = NULL; ++ pnode->idx = idx; ++ pnode->rgb = rgb; ++ palette.entry[idx].listNode = pnode; ++ palette.entry[idx].numPixels = numPixels; ++ ++ return (++paletteNumColors); ++} ++ ++ ++/* ++ * Converting 32-bit color samples into 24-bit colors. ++ * Should be called only when redMax, greenMax and blueMax are 255. ++ * Color components assumed to be byte-aligned. ++ */ ++ ++static void Pack24(pScreen, buf, fmt, count) ++ ScreenPtr pScreen; ++ char *buf; ++ rfbPixelFormat *fmt; ++ int count; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *buf32; ++ CARD32 pix; ++ int r_shift, g_shift, b_shift; ++ ++ buf32 = (CARD32 *)buf; ++ ++ if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) { ++ r_shift = fmt->redShift; ++ g_shift = fmt->greenShift; ++ b_shift = fmt->blueShift; ++ } else { ++ r_shift = 24 - fmt->redShift; ++ g_shift = 24 - fmt->greenShift; ++ b_shift = 24 - fmt->blueShift; ++ } ++ ++ while (count--) { ++ pix = *buf32++; ++ *buf++ = (char)(pix >> r_shift); ++ *buf++ = (char)(pix >> g_shift); ++ *buf++ = (char)(pix >> b_shift); ++ } ++} ++ ++ ++/* ++ * Converting truecolor samples into palette indices. ++ */ ++ ++#define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ ++ \ ++static void \ ++EncodeIndexedRect##bpp(buf, count) \ ++ CARD8 *buf; \ ++ int count; \ ++{ \ ++ COLOR_LIST *pnode; \ ++ CARD##bpp *src; \ ++ CARD##bpp rgb; \ ++ int rep = 0; \ ++ \ ++ src = (CARD##bpp *) buf; \ ++ \ ++ while (count--) { \ ++ rgb = *src++; \ ++ while (count && *src == rgb) { \ ++ rep++, src++, count--; \ ++ } \ ++ pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \ ++ while (pnode != NULL) { \ ++ if ((CARD##bpp)pnode->rgb == rgb) { \ ++ *buf++ = (CARD8)pnode->idx; \ ++ while (rep) { \ ++ *buf++ = (CARD8)pnode->idx; \ ++ rep--; \ ++ } \ ++ break; \ ++ } \ ++ pnode = pnode->next; \ ++ } \ ++ } \ ++} ++ ++DEFINE_IDX_ENCODE_FUNCTION(16) ++DEFINE_IDX_ENCODE_FUNCTION(32) ++ ++#define DEFINE_MONO_ENCODE_FUNCTION(bpp) \ ++ \ ++static void \ ++EncodeMonoRect##bpp(buf, w, h) \ ++ CARD8 *buf; \ ++ int w, h; \ ++{ \ ++ CARD##bpp *ptr; \ ++ CARD##bpp bg; \ ++ unsigned int value, mask; \ ++ int aligned_width; \ ++ int x, y, bg_bits; \ ++ \ ++ ptr = (CARD##bpp *) buf; \ ++ bg = (CARD##bpp) monoBackground; \ ++ aligned_width = w - w % 8; \ ++ \ ++ for (y = 0; y < h; y++) { \ ++ for (x = 0; x < aligned_width; x += 8) { \ ++ for (bg_bits = 0; bg_bits < 8; bg_bits++) { \ ++ if (*ptr++ != bg) \ ++ break; \ ++ } \ ++ if (bg_bits == 8) { \ ++ *buf++ = 0; \ ++ continue; \ ++ } \ ++ mask = 0x80 >> bg_bits; \ ++ value = mask; \ ++ for (bg_bits++; bg_bits < 8; bg_bits++) { \ ++ mask >>= 1; \ ++ if (*ptr++ != bg) { \ ++ value |= mask; \ ++ } \ ++ } \ ++ *buf++ = (CARD8)value; \ ++ } \ ++ \ ++ mask = 0x80; \ ++ value = 0; \ ++ if (x >= w) \ ++ continue; \ ++ \ ++ for (; x < w; x++) { \ ++ if (*ptr++ != bg) { \ ++ value |= mask; \ ++ } \ ++ mask >>= 1; \ ++ } \ ++ *buf++ = (CARD8)value; \ ++ } \ ++} ++ ++DEFINE_MONO_ENCODE_FUNCTION(8) ++DEFINE_MONO_ENCODE_FUNCTION(16) ++DEFINE_MONO_ENCODE_FUNCTION(32) ++ ++ ++/* ++ * ``Gradient'' filter for 24-bit color samples. ++ * Should be called only when redMax, greenMax and blueMax are 255. ++ * Color components assumed to be byte-aligned. ++ */ ++ ++static void ++FilterGradient24(pScreen, buf, fmt, w, h) ++ ScreenPtr pScreen; ++ char *buf; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *buf32; ++ CARD32 pix32; ++ int *prevRowPtr; ++ int shiftBits[3]; ++ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; ++ int prediction; ++ int x, y, c; ++ ++ buf32 = (CARD32 *)buf; ++ memset (prevRowBuf, 0, w * 3 * sizeof(int)); ++ ++ if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) { ++ shiftBits[0] = fmt->redShift; ++ shiftBits[1] = fmt->greenShift; ++ shiftBits[2] = fmt->blueShift; ++ } else { ++ shiftBits[0] = 24 - fmt->redShift; ++ shiftBits[1] = 24 - fmt->greenShift; ++ shiftBits[2] = 24 - fmt->blueShift; ++ } ++ ++ for (y = 0; y < h; y++) { ++ for (c = 0; c < 3; c++) { ++ pixUpper[c] = 0; ++ pixHere[c] = 0; ++ } ++ prevRowPtr = prevRowBuf; ++ for (x = 0; x < w; x++) { ++ pix32 = *buf32++; ++ for (c = 0; c < 3; c++) { ++ pixUpperLeft[c] = pixUpper[c]; ++ pixLeft[c] = pixHere[c]; ++ pixUpper[c] = *prevRowPtr; ++ pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF); ++ *prevRowPtr++ = pixHere[c]; ++ ++ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; ++ if (prediction < 0) { ++ prediction = 0; ++ } else if (prediction > 0xFF) { ++ prediction = 0xFF; ++ } ++ *buf++ = (char)(pixHere[c] - prediction); ++ } ++ } ++ } ++} ++ ++ ++/* ++ * ``Gradient'' filter for other color depths. ++ */ ++ ++#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \ ++ \ ++static void \ ++FilterGradient##bpp(pScreen, buf, fmt, w, h) \ ++ ScreenPtr pScreen; \ ++ CARD##bpp *buf; \ ++ rfbPixelFormat *fmt; \ ++ int w, h; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp pix, diff; \ ++ Bool endianMismatch; \ ++ int *prevRowPtr; \ ++ int maxColor[3], shiftBits[3]; \ ++ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; \ ++ int prediction; \ ++ int x, y, c; \ ++ \ ++ memset (prevRowBuf, 0, w * 3 * sizeof(int)); \ ++ \ ++ endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian); \ ++ \ ++ maxColor[0] = fmt->redMax; \ ++ maxColor[1] = fmt->greenMax; \ ++ maxColor[2] = fmt->blueMax; \ ++ shiftBits[0] = fmt->redShift; \ ++ shiftBits[1] = fmt->greenShift; \ ++ shiftBits[2] = fmt->blueShift; \ ++ \ ++ for (y = 0; y < h; y++) { \ ++ for (c = 0; c < 3; c++) { \ ++ pixUpper[c] = 0; \ ++ pixHere[c] = 0; \ ++ } \ ++ prevRowPtr = prevRowBuf; \ ++ for (x = 0; x < w; x++) { \ ++ pix = *buf; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ diff = 0; \ ++ for (c = 0; c < 3; c++) { \ ++ pixUpperLeft[c] = pixUpper[c]; \ ++ pixLeft[c] = pixHere[c]; \ ++ pixUpper[c] = *prevRowPtr; \ ++ pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ *prevRowPtr++ = pixHere[c]; \ ++ \ ++ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \ ++ if (prediction < 0) { \ ++ prediction = 0; \ ++ } else if (prediction > maxColor[c]) { \ ++ prediction = maxColor[c]; \ ++ } \ ++ diff |= ((pixHere[c] - prediction) & maxColor[c]) \ ++ << shiftBits[c]; \ ++ } \ ++ if (endianMismatch) { \ ++ diff = Swap##bpp(diff); \ ++ } \ ++ *buf++ = diff; \ ++ } \ ++ } \ ++} ++ ++DEFINE_GRADIENT_FILTER_FUNCTION(16) ++DEFINE_GRADIENT_FILTER_FUNCTION(32) ++ ++ ++/* ++ * Code to guess if given rectangle is suitable for smooth image ++ * compression (by applying "gradient" filter or JPEG coder). ++ */ ++ ++#define JPEG_MIN_RECT_SIZE 4096 ++ ++#define DETECT_SUBROW_WIDTH 7 ++#define DETECT_MIN_WIDTH 8 ++#define DETECT_MIN_HEIGHT 8 ++ ++static int ++DetectSmoothImage (cl, fmt, w, h) ++ rfbClientPtr cl; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ unsigned long avgError; ++ ++ if ( pVNC->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 || ++ w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) { ++ return 0; ++ } ++ ++ if (cl->tightQualityLevel != -1) { ++ if (w * h < JPEG_MIN_RECT_SIZE) { ++ return 0; ++ } ++ } else { ++ if ( rfbTightDisableGradient || ++ w * h < tightConf[cl->tightCompressLevel].gradientMinRectSize ) { ++ return 0; ++ } ++ } ++ ++ if (fmt->bitsPerPixel == 32) { ++ if (usePixelFormat24) { ++ avgError = DetectSmoothImage24(cl, fmt, w, h); ++ if (cl->tightQualityLevel != -1) { ++ return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold24); ++ } ++ return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold24); ++ } else { ++ avgError = DetectSmoothImage32(cl, fmt, w, h); ++ } ++ } else { ++ avgError = DetectSmoothImage16(cl, fmt, w, h); ++ } ++ if (cl->tightQualityLevel != -1) { ++ return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold); ++ } ++ return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold); ++} ++ ++static unsigned long ++DetectSmoothImage24 (cl, fmt, w, h) ++ rfbClientPtr cl; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ int off; ++ int x, y, d, dx, c; ++ int diffStat[256]; ++ int pixelCount = 0; ++ int pix, left[3]; ++ unsigned long avgError; ++ ++ /* If client is big-endian, color samples begin from the second ++ byte (offset 1) of a 32-bit pixel value. */ ++ off = (fmt->bigEndian != 0); ++ ++ memset(diffStat, 0, 256*sizeof(int)); ++ ++ y = 0, x = 0; ++ while (y < h && x < w) { ++ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { ++ for (c = 0; c < 3; c++) { ++ left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF; ++ } ++ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { ++ for (c = 0; c < 3; c++) { ++ pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF; ++ diffStat[abs(pix - left[c])]++; ++ left[c] = pix; ++ } ++ pixelCount++; ++ } ++ } ++ if (w > h) { ++ x += h; ++ y = 0; ++ } else { ++ x = 0; ++ y += w; ++ } ++ } ++ ++ if (diffStat[0] * 33 / pixelCount >= 95) ++ return 0; ++ ++ avgError = 0; ++ for (c = 1; c < 8; c++) { ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); ++ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) ++ return 0; ++ } ++ for (; c < 256; c++) { ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); ++ } ++ avgError /= (pixelCount * 3 - diffStat[0]); ++ ++ return avgError; ++} ++ ++#define DEFINE_DETECT_FUNCTION(bpp) \ ++ \ ++static unsigned long \ ++DetectSmoothImage##bpp (cl, fmt, w, h) \ ++ rfbClientPtr cl; \ ++ rfbPixelFormat *fmt; \ ++ int w, h; \ ++{ \ ++ VNCSCREENPTR(cl->pScreen); \ ++ Bool endianMismatch; \ ++ CARD##bpp pix; \ ++ int maxColor[3], shiftBits[3]; \ ++ int x, y, d, dx, c; \ ++ int diffStat[256]; \ ++ int pixelCount = 0; \ ++ int sample, sum, left[3]; \ ++ unsigned long avgError; \ ++ \ ++ endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian); \ ++ \ ++ maxColor[0] = fmt->redMax; \ ++ maxColor[1] = fmt->greenMax; \ ++ maxColor[2] = fmt->blueMax; \ ++ shiftBits[0] = fmt->redShift; \ ++ shiftBits[1] = fmt->greenShift; \ ++ shiftBits[2] = fmt->blueShift; \ ++ \ ++ memset(diffStat, 0, 256*sizeof(int)); \ ++ \ ++ y = 0, x = 0; \ ++ while (y < h && x < w) { \ ++ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { \ ++ pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d]; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ for (c = 0; c < 3; c++) { \ ++ left[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ } \ ++ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { \ ++ pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d+dx]; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ sum = 0; \ ++ for (c = 0; c < 3; c++) { \ ++ sample = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ sum += abs(sample - left[c]); \ ++ left[c] = sample; \ ++ } \ ++ if (sum > 255) \ ++ sum = 255; \ ++ diffStat[sum]++; \ ++ pixelCount++; \ ++ } \ ++ } \ ++ if (w > h) { \ ++ x += h; \ ++ y = 0; \ ++ } else { \ ++ x = 0; \ ++ y += w; \ ++ } \ ++ } \ ++ \ ++ if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90) \ ++ return 0; \ ++ \ ++ avgError = 0; \ ++ for (c = 1; c < 8; c++) { \ ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \ ++ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) \ ++ return 0; \ ++ } \ ++ for (; c < 256; c++) { \ ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \ ++ } \ ++ avgError /= (pixelCount - diffStat[0]); \ ++ \ ++ return avgError; \ ++} ++ ++DEFINE_DETECT_FUNCTION(16) ++DEFINE_DETECT_FUNCTION(32) ++ ++ ++/* ++ * JPEG compression stuff. ++ */ ++ ++static struct jpeg_destination_mgr jpegDstManager; ++static Bool jpegError; ++static int jpegDstDataLen; ++ ++static Bool ++SendJpegRect(cl, x, y, w, h, quality) ++ rfbClientPtr cl; ++ int x, y, w, h; ++ int quality; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ struct jpeg_compress_struct cinfo; ++ struct jpeg_error_mgr jerr; ++ CARD8 *srcBuf; ++ JSAMPROW rowPointer[1]; ++ int dy; ++ ++ if (pVNC->rfbServerFormat.bitsPerPixel == 8) ++ return SendFullColorRect(cl, w, h); ++ ++ srcBuf = (CARD8 *)xalloc(w * 3); ++ if (srcBuf == NULL) { ++ return SendFullColorRect(cl, w, h); ++ } ++ rowPointer[0] = srcBuf; ++ ++ cinfo.err = jpeg_std_error(&jerr); ++ jpeg_create_compress(&cinfo); ++ ++ cinfo.image_width = w; ++ cinfo.image_height = h; ++ cinfo.input_components = 3; ++ cinfo.in_color_space = JCS_RGB; ++ ++ jpeg_set_defaults(&cinfo); ++ jpeg_set_quality(&cinfo, quality, TRUE); ++ ++ JpegSetDstManager (&cinfo); ++ ++ jpeg_start_compress(&cinfo, TRUE); ++ ++ for (dy = 0; dy < h; dy++) { ++ PrepareRowForJpeg(cl->pScreen, srcBuf, x, y + dy, w); ++ jpeg_write_scanlines(&cinfo, rowPointer, 1); ++ if (jpegError) ++ break; ++ } ++ ++ if (!jpegError) ++ jpeg_finish_compress(&cinfo); ++ ++ jpeg_destroy_compress(&cinfo); ++ xfree((char *)srcBuf); ++ ++ if (jpegError) ++ return SendFullColorRect(cl, w, h); ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightJpeg << 4); ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ ++ return SendCompressedData(cl, jpegDstDataLen); ++} ++ ++static void ++PrepareRowForJpeg(pScreen, dst, x, y, count) ++ ScreenPtr pScreen; ++ CARD8 *dst; ++ int x, y, count; ++{ ++ VNCSCREENPTR(pScreen); ++ if (pVNC->rfbServerFormat.bitsPerPixel == 32) { ++ if ( pVNC->rfbServerFormat.redMax == 0xFF && ++ pVNC->rfbServerFormat.greenMax == 0xFF && ++ pVNC->rfbServerFormat.blueMax == 0xFF ) { ++ PrepareRowForJpeg24(pScreen, dst, x, y, count); ++ } else { ++ PrepareRowForJpeg32(pScreen, dst, x, y, count); ++ } ++ } else { ++ /* 16 bpp assumed. */ ++ PrepareRowForJpeg16(pScreen, dst, x, y, count); ++ } ++} ++ ++static void ++PrepareRowForJpeg24(pScreen, dst, x, y, count) ++ ScreenPtr pScreen; ++ CARD8 *dst; ++ int x, y, count; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *fbptr; ++ CARD32 pix; ++ ++ fbptr = (CARD32 *) ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * 4]; ++ ++ while (count--) { ++ pix = *fbptr++; ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift); ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift); ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift); ++ } ++} ++ ++#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \ ++ \ ++static void \ ++PrepareRowForJpeg##bpp(pScreen, dst, x, y, count) \ ++ ScreenPtr pScreen; \ ++ CARD8 *dst; \ ++ int x, y, count; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp *fbptr; \ ++ CARD##bpp pix; \ ++ int inRed, inGreen, inBlue; \ ++ \ ++ fbptr = (CARD##bpp *) \ ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + \ ++ x * (bpp / 8)]; \ ++ \ ++ while (count--) { \ ++ pix = *fbptr++; \ ++ \ ++ inRed = (int) \ ++ (pix >> pVNC->rfbServerFormat.redShift & pVNC->rfbServerFormat.redMax); \ ++ inGreen = (int) \ ++ (pix >> pVNC->rfbServerFormat.greenShift & pVNC->rfbServerFormat.greenMax); \ ++ inBlue = (int) \ ++ (pix >> pVNC->rfbServerFormat.blueShift & pVNC->rfbServerFormat.blueMax); \ ++ \ ++ *dst++ = (CARD8)((inRed * 255 + pVNC->rfbServerFormat.redMax / 2) / \ ++ pVNC->rfbServerFormat.redMax); \ ++ *dst++ = (CARD8)((inGreen * 255 + pVNC->rfbServerFormat.greenMax / 2) / \ ++ pVNC->rfbServerFormat.greenMax); \ ++ *dst++ = (CARD8)((inBlue * 255 + pVNC->rfbServerFormat.blueMax / 2) / \ ++ pVNC->rfbServerFormat.blueMax); \ ++ } \ ++} ++ ++DEFINE_JPEG_GET_ROW_FUNCTION(16) ++DEFINE_JPEG_GET_ROW_FUNCTION(32) ++ ++/* ++ * Destination manager implementation for JPEG library. ++ */ ++ ++static void ++JpegInitDestination(j_compress_ptr cinfo) ++{ ++ jpegError = FALSE; ++ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf; ++ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize; ++} ++ ++static boolean ++JpegEmptyOutputBuffer(j_compress_ptr cinfo) ++{ ++ jpegError = TRUE; ++ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf; ++ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize; ++ ++ return TRUE; ++} ++ ++static void ++JpegTermDestination(j_compress_ptr cinfo) ++{ ++ jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer; ++} ++ ++static void ++JpegSetDstManager(j_compress_ptr cinfo) ++{ ++ jpegDstManager.init_destination = JpegInitDestination; ++ jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer; ++ jpegDstManager.term_destination = JpegTermDestination; ++ cinfo->dest = &jpegDstManager; ++} ++ +diff --git a/hw/dmx/vnc/translate.c b/hw/dmx/vnc/translate.c +new file mode 100644 +index 0000000..eb9bcb0 +--- /dev/null ++++ b/hw/dmx/vnc/translate.c +@@ -0,0 +1,496 @@ ++/* ++ * translate.c - translate between different pixel formats ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++#if XFREE86VNC ++#include ++#endif ++ ++static void PrintPixelFormat(rfbPixelFormat *pf); ++static Bool rfbSetClientColourMapBGR233(); ++ ++Bool rfbEconomicTranslate = FALSE; ++ ++/* ++ * Some standard pixel formats. ++ */ ++ ++static const rfbPixelFormat BGR233Format = { ++ 8, 8, 0, 1, 7, 7, 3, 0, 3, 6 ++}; ++ ++ ++/* ++ * Macro to compare pixel formats. ++ */ ++ ++#define PF_EQ(x,y) \ ++ ((x.bitsPerPixel == y.bitsPerPixel) && \ ++ (x.depth == y.depth) && \ ++ ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \ ++ (x.trueColour == y.trueColour) && \ ++ (!x.trueColour || ((x.redMax == y.redMax) && \ ++ (x.greenMax == y.greenMax) && \ ++ (x.blueMax == y.blueMax) && \ ++ (x.redShift == y.redShift) && \ ++ (x.greenShift == y.greenShift) && \ ++ (x.blueShift == y.blueShift)))) ++ ++#define CONCAT2(a,b) a##b ++#define CONCAT2E(a,b) CONCAT2(a,b) ++#define CONCAT4(a,b,c,d) a##b##c##d ++#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d) ++ ++#define OUT 8 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++#define OUT 16 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++#define OUT 32 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++typedef void (*rfbInitTableFnType)(ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out); ++ ++rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = { ++ rfbInitTrueColourSingleTable8, ++ rfbInitTrueColourSingleTable16, ++ rfbInitTrueColourSingleTable32 ++}; ++ ++rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = { ++ rfbInitColourMapSingleTable8, ++ rfbInitColourMapSingleTable16, ++ rfbInitColourMapSingleTable32 ++}; ++ ++rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = { ++ rfbInitTrueColourRGBTables8, ++ rfbInitTrueColourRGBTables16, ++ rfbInitTrueColourRGBTables32 ++}; ++ ++rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = { ++ { rfbTranslateWithSingleTable8to8, ++ rfbTranslateWithSingleTable8to16, ++ rfbTranslateWithSingleTable8to32 }, ++ { rfbTranslateWithSingleTable16to8, ++ rfbTranslateWithSingleTable16to16, ++ rfbTranslateWithSingleTable16to32 }, ++ { rfbTranslateWithSingleTable32to8, ++ rfbTranslateWithSingleTable32to16, ++ rfbTranslateWithSingleTable32to32 } ++}; ++ ++rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = { ++ { rfbTranslateWithRGBTables8to8, ++ rfbTranslateWithRGBTables8to16, ++ rfbTranslateWithRGBTables8to32 }, ++ { rfbTranslateWithRGBTables16to8, ++ rfbTranslateWithRGBTables16to16, ++ rfbTranslateWithRGBTables16to32 }, ++ { rfbTranslateWithRGBTables32to8, ++ rfbTranslateWithRGBTables32to16, ++ rfbTranslateWithRGBTables32to32 } ++}; ++ ++ ++ ++/* ++ * rfbTranslateNone is used when no translation is required. ++ */ ++ ++void ++rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, int bytesBetweenInputLines, ++ int width, int height, int x, int y) ++{ ++ VNCSCREENPTR(pScreen); ++ int bytesPerOutputLine = width * (out->bitsPerPixel / 8); ++ ++ if (pVNC->useGetImage) { ++ DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum]; ++ ++ /* catch all for other TranslateNone cases - hextile, corre, rre, etc.*/ ++ (*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, optr); ++ } else { ++ while (height > 0) { ++ memcpy(optr, iptr, bytesPerOutputLine); ++ iptr += bytesBetweenInputLines; ++ optr += bytesPerOutputLine; ++ height--; ++ } ++ } ++} ++ ++ ++/* ++ * rfbSetTranslateFunction sets the translation function. ++ */ ++ ++Bool ++rfbSetTranslateFunction(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbLog("Pixel format for client %s:\n",cl->host); ++ PrintPixelFormat(&cl->format); ++ ++ /* ++ * Check that bits per pixel values are valid ++ */ ++ ++ if ((pVNC->rfbServerFormat.bitsPerPixel != 8) && ++ (pVNC->rfbServerFormat.bitsPerPixel != 16) && ++ (pVNC->rfbServerFormat.bitsPerPixel != 32)) ++ { ++ rfbLog("%s: server bits per pixel not 8, 16 or 32\n", ++ "rfbSetTranslateFunction"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if ((cl->format.bitsPerPixel != 8) && ++ (cl->format.bitsPerPixel != 16) && ++ (cl->format.bitsPerPixel != 32)) ++ { ++ rfbLog("%s: client bits per pixel not 8, 16 or 32\n", ++ "rfbSetTranslateFunction"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if (!pVNC->rfbServerFormat.trueColour && ++ (pVNC->rfbServerFormat.bitsPerPixel != 8) && ++#if XFREE86VNC ++ (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) { ++#else ++ (pVNC->rfbInstalledColormap->class == PseudoColor)) { ++#endif ++ rfbLog("rfbSetTranslateFunction: server has colour map " ++ "but %d-bit - can only cope with 8-bit colour maps\n", ++ pVNC->rfbServerFormat.bitsPerPixel); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if (!cl->format.trueColour && ++ (cl->format.bitsPerPixel != 8) && ++#if XFREE86VNC ++ (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) { ++#else ++ (pVNC->rfbInstalledColormap->class == PseudoColor) ) { ++#endif ++ rfbLog("rfbSetTranslateFunction: client has colour map " ++ "but %d-bit - can only cope with 8-bit colour maps\n", ++ cl->format.bitsPerPixel); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ /* ++ * bpp is valid, now work out how to translate ++ */ ++ ++ if (!cl->format.trueColour) { ++ ++ /* ? -> colour map */ ++ ++ if (!pVNC->rfbServerFormat.trueColour) { ++ ++ /* colour map -> colour map */ ++ ++#if XFREE86VNC ++ if (miInstalledMaps[cl->pScreen->myNum]->class == DirectColor) { ++#else ++ if (pVNC->rfbInstalledColormap->class == DirectColor) { ++#endif ++ rfbLog("rfbSetTranslateFunction: client is %d-bit DirectColor," ++ " client has colour map\n",cl->format.bitsPerPixel); ++ ++ cl->translateFn = rfbTranslateWithRGBTablesFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16]) ++ (cl->pScreen, &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ return rfbSetClientColourMap(cl, 0, 0); ++ ++ /* PseudoColor colormap */ ++ ++ } else { ++ rfbLog("rfbSetTranslateFunction: both 8-bit colour map: " ++ "no translation needed\n"); ++ cl->translateFn = rfbTranslateNone; ++ return rfbSetClientColourMap(cl, 0, 0); ++ } ++ } ++ ++ /* ++ * truecolour -> colour map ++ * ++ * Set client's colour map to BGR233, then effectively it's ++ * truecolour as well ++ */ ++ ++ if (!rfbSetClientColourMapBGR233(cl)) ++ return FALSE; ++ ++ cl->format = BGR233Format; ++ } ++ ++ /* ? -> truecolour */ ++ ++ if (!pVNC->rfbServerFormat.trueColour) { ++ ++ /* colour map -> truecolour */ ++ ++ rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour," ++ " server has colour map\n",cl->format.bitsPerPixel); ++ ++ cl->translateFn = rfbTranslateWithSingleTableFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ return rfbSetClientColourMap(cl, 0, 0); ++ } ++ ++ /* truecolour -> truecolour */ ++ ++ if (PF_EQ(cl->format,pVNC->rfbServerFormat)) { ++ ++ /* client & server the same */ ++ ++ rfbLog(" no translation needed\n"); ++ cl->translateFn = rfbTranslateNone; ++ return TRUE; ++ } ++ ++ if ((pVNC->rfbServerFormat.bitsPerPixel < 16) || ++ (!rfbEconomicTranslate && (pVNC->rfbServerFormat.bitsPerPixel == 16))) { ++ ++ /* we can use a single lookup table for <= 16 bpp */ ++ ++ cl->translateFn = rfbTranslateWithSingleTableFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourSingleTableFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ } else { ++ ++ /* otherwise we use three separate tables for red, green and blue */ ++ ++ cl->translateFn = rfbTranslateWithRGBTablesFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourRGBTablesFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's ++ * just like an 8-bit BGR233 true colour client. ++ */ ++ ++static Bool ++rfbSetClientColourMapBGR233(cl) ++ rfbClientPtr cl; ++{ ++ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; ++ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; ++ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); ++ int i, len; ++ int r, g, b; ++ ++ if (cl->format.bitsPerPixel != 8) { ++ rfbLog("%s: client not 8 bits per pixel\n", ++ "rfbSetClientColourMapBGR233"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ scme->type = rfbSetColourMapEntries; ++ ++ scme->firstColour = Swap16IfLE(0); ++ scme->nColours = Swap16IfLE(256); ++ ++ len = sz_rfbSetColourMapEntriesMsg; ++ ++ i = 0; ++ ++ for (b = 0; b < 4; b++) { ++ for (g = 0; g < 8; g++) { ++ for (r = 0; r < 8; r++) { ++ rgb[i++] = Swap16IfLE(r * 65535 / 7); ++ rgb[i++] = Swap16IfLE(g * 65535 / 7); ++ rgb[i++] = Swap16IfLE(b * 65535 / 3); ++ } ++ } ++ } ++ ++ len += 256 * 3 * 2; ++ ++ if (WriteExact(cl->sock, buf, len) < 0) { ++ rfbLogPerror("rfbSetClientColourMapBGR233: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* ++ * rfbSetClientColourMap is called to set the client's colour map. If the ++ * client is a true colour client, we simply update our own translation table ++ * and mark the whole screen as having been modified. ++ */ ++ ++Bool ++rfbSetClientColourMap(cl, firstColour, nColours) ++ rfbClientPtr cl; ++ int firstColour; ++ int nColours; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ BoxRec box; ++ ++ if (nColours == 0) { ++#if XFREE86VNC ++ nColours = miInstalledMaps[cl->pScreen->myNum]->pVisual->ColormapEntries; ++#else ++ nColours = pVNC->rfbInstalledColormap->pVisual->ColormapEntries; ++#endif ++ } ++ ++ if (pVNC->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) { ++ return TRUE; ++ } ++ ++ if (cl->format.trueColour) { ++ (*rfbInitColourMapSingleTableFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ REGION_UNINIT(cl->pScreen,&cl->modifiedRegion); ++ box.x1 = box.y1 = 0; ++ box.x2 = pVNC->width; ++ box.y2 = pVNC->height; ++ REGION_INIT(cl->pScreen,&cl->modifiedRegion,&box,0); ++ ++ return TRUE; ++ } ++ ++ return rfbSendSetColourMapEntries(cl, firstColour, nColours); ++} ++ ++ ++/* ++ * rfbSetClientColourMaps sets the colour map for each RFB client. ++ */ ++ ++void ++rfbSetClientColourMaps(firstColour, nColours) ++ int firstColour; ++ int nColours; ++{ ++ rfbClientPtr cl, nextCl; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ rfbSetClientColourMap(cl, firstColour, nColours); ++ } ++} ++ ++ ++static void ++PrintPixelFormat(pf) ++ rfbPixelFormat *pf; ++{ ++ if (pf->bitsPerPixel == 1) { ++ rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n", ++ (pf->bigEndian ? "most" : "least")); ++ } else { ++ rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth, ++ ((pf->bitsPerPixel == 8) ? "" ++ : (pf->bigEndian ? ", big endian" : ", little endian"))); ++ if (pf->trueColour) { ++ rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n", ++ pf->redMax, pf->greenMax, pf->blueMax, ++ pf->redShift, pf->greenShift, pf->blueShift); ++ } else { ++ rfbLog(" uses a colour map (not true colour).\n"); ++ } ++ } ++} +diff --git a/hw/dmx/vnc/vncInit.c b/hw/dmx/vnc/vncInit.c +new file mode 100644 +index 0000000..679cecc +--- /dev/null ++++ b/hw/dmx/vnc/vncInit.c +@@ -0,0 +1,436 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include "rfb.h" ++ ++#if DMXVNC ++#include "../dmx.h" ++#include "../dmxcb.h" ++#endif ++ ++#include ++#include "fb.h" ++ ++#include "dixstruct.h" ++#include "compiler.h" ++ ++#include "mipointer.h" ++#include "mibstore.h" ++ ++#include "globals.h" ++#define DPMS_SERVER ++#include ++ ++#include ++ ++int vncScreenPrivateIndex = -1; ++int rfbGCIndex = -1; ++int inetdSock = -1; ++Atom VNC_LAST_CLIENT_ID = 0; ++Atom VNC_CONNECT = 0; ++char *desktopName = "x11"; ++char rfbThisHost[256]; ++ ++extern void VncExtensionInit(void); ++ ++extern void vncInitMouse(void); ++extern void vncInitKeyb(void); ++Bool VNCInit(ScreenPtr pScreen, DMXScreenInfo *dmxScreen); ++ ++#ifndef XFree86LOADER ++static unsigned long VNCGeneration = 0; ++#endif ++static void rfbWakeupHandler (int i, pointer blockData, unsigned long err, pointer pReadmask); ++ ++/* ++ * rfbLog prints a time-stamped message to the log file (stderr). ++ */ ++ ++void rfbLog(char *format, ...) ++{ ++ va_list args; ++ char buf[256]; ++ time_t clock; ++ ++ va_start(args, format); ++ ++ time(&clock); ++ strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock)); ++ fprintf(stderr, buf); ++ ++ vfprintf(stderr, format, args); ++ fflush(stderr); ++ ++ va_end(args); ++} ++ ++void rfbLogPerror(char *str) ++{ ++ rfbLog(""); ++ perror(str); ++} ++ ++ ++static ScreenPtr TheVNCScreen = NULL; ++ ++ ++static void ++nopGetImage(DrawablePtr pDrawable, int sx, int sy, ++ int w, int h, unsigned int format, ++ unsigned long planemask, char *pdstLine) ++{ ++ int i, j; ++ ++ for (i = 0; i < 1; i++) { ++ unsigned int *dst = (unsigned int *) pdstLine; ++ for (j = 0; j < w*h; j++) { ++ dst[j] = 0xff00ff; ++ } ++ } ++ ++ /* Eventually, call the DMX/Xinerama GetImage function */ ++} ++ ++/* ++ * Called by DMX's InitOutput() ++ */ ++void ++VNCInit2(void) ++{ ++ vncScreenPtr pScreenPriv; ++ VisualPtr v = NULL; ++ int i; ++ ++ rfbLog("DMXVNC: Enter VNCInit2\n"); ++ ++ pScreenPriv = xalloc(sizeof(vncScreenRec)); ++ pScreenPriv->width = dmxGlobalWidth; ++ pScreenPriv->height = dmxGlobalHeight; ++ pScreenPriv->rfbAuthTries = 0; ++ pScreenPriv->rfbAuthTooManyTries = FALSE; ++ pScreenPriv->timer = NULL; ++ pScreenPriv->udpPort = 0; ++ pScreenPriv->rfbListenSock = -1; ++ pScreenPriv->udpSock = -1; ++ pScreenPriv->udpSockConnected = FALSE; ++ pScreenPriv->httpListenSock = -1; ++ pScreenPriv->httpSock = -1; ++ pScreenPriv->maxFd = 0; ++ pScreenPriv->rfbAuthPasswdFile = NULL; ++ pScreenPriv->httpDir = NULL; ++ pScreenPriv->rfbInstalledColormap = NULL; ++ pScreenPriv->interface.s_addr = htonl (INADDR_ANY); ++ ++ pScreenPriv->rfbPort = 0; ++ pScreenPriv->httpPort = 0; ++ pScreenPriv->rfbAuthPasswdFile = NULL; ++ pScreenPriv->httpDir = NULL; ++ pScreenPriv->rfbAlwaysShared = FALSE; ++ pScreenPriv->rfbNeverShared = FALSE; ++ pScreenPriv->rfbUserAccept = FALSE; ++ pScreenPriv->useGetImage = TRUE; /* For DMX */ ++ pScreenPriv->rfbViewOnly = FALSE; ++ pScreenPriv->rfbDontDisconnect = FALSE; ++ pScreenPriv->loginAuthEnabled = FALSE; ++ ++ /* Find the root window's visual. ++ * XXX this might be the wrong info to use below. ++ */ ++ for (i = 0; i < screenInfo.screens[0]->numVisuals; i++) { ++ v = screenInfo.screens[0]->visuals + i; ++ if (v->vid == screenInfo.screens[0]->rootVisual) { ++ break; ++ } ++ } ++ ++ /* XXX is this the right depth and bpp? */ ++ /* With DMX, screenInfo.screens[0]->rootDepth is 24 and that doesn't ++ * work in translate.c! We're just using 32. ++ */ ++ pScreenPriv->rfbServerFormat.bitsPerPixel = 32; ++ pScreenPriv->rfbServerFormat.depth = 32; ++ pScreenPriv->rfbServerFormat.bigEndian = 0; ++ pScreenPriv->rfbServerFormat.trueColour = (v->class == TrueColor); ++ if (pScreenPriv->rfbServerFormat.trueColour) { ++ pScreenPriv->rfbServerFormat.redMax = v->redMask >> v->offsetRed; ++ pScreenPriv->rfbServerFormat.greenMax = v->greenMask >> v->offsetGreen; ++ pScreenPriv->rfbServerFormat.blueMax = v->blueMask >> v->offsetBlue; ++ pScreenPriv->rfbServerFormat.redShift = v->offsetRed; ++ pScreenPriv->rfbServerFormat.greenShift = v->offsetGreen; ++ pScreenPriv->rfbServerFormat.blueShift = v->offsetBlue; ++ } else { ++ pScreenPriv->rfbServerFormat.redMax ++ = pScreenPriv->rfbServerFormat.greenMax ++ = pScreenPriv->rfbServerFormat.blueMax = 0; ++ pScreenPriv->rfbServerFormat.redShift ++ = pScreenPriv->rfbServerFormat.greenShift ++ = pScreenPriv->rfbServerFormat.blueShift = 0; ++ } ++ ++ /* Allocate/init TheVNCScreen object */ ++ vncScreenPrivateIndex = 0; ++ assert(!TheVNCScreen); ++ TheVNCScreen = (ScreenPtr) Xcalloc(1, sizeof(struct _Screen)); ++ TheVNCScreen->devPrivates = (DevUnion *) Xcalloc(1, sizeof(DevUnion)); ++ TheVNCScreen->devPrivates[vncScreenPrivateIndex].ptr = pScreenPriv; ++ TheVNCScreen->GetImage = nopGetImage; ++ ++ rfbInitSockets(TheVNCScreen); ++ if (inetdSock == -1) ++ httpInitSockets(TheVNCScreen); ++} ++ ++ ++Bool ++VNCInit(ScreenPtr pScreen, DMXScreenInfo *pScrn) ++{ ++ VisualPtr visual; ++ vncScreenPtr pScreenPriv; ++#if 0 ++ char *interface_str = NULL; ++#endif ++#ifdef RENDER ++ PictureScreenPtr ps; ++#endif ++ ++ rfbLog("DMXVNC: Enter VNCInit\n"); ++ ++#ifndef XFree86LOADER ++ if (VNCGeneration != serverGeneration) { ++ VNCGeneration = serverGeneration; ++ if ( ((vncScreenPrivateIndex = AllocateScreenPrivateIndex()) < 0) || ++ ((rfbGCIndex = AllocateGCPrivateIndex()) < 0) ) ++ return FALSE; ++ } ++#endif ++ ++ if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec))) { ++ ErrorF("VNCInit(): failed to allocate GCIndex\n"); ++ return FALSE; ++ } ++ ++ if (!(pScreenPriv = xalloc(sizeof(vncScreenRec)))) ++ return FALSE; ++ ++ pScreen->devPrivates[vncScreenPrivateIndex].ptr = (pointer)pScreenPriv; ++ ++ pScreenPriv->rfbAuthTries = 0; ++ pScreenPriv->rfbAuthTooManyTries = FALSE; ++ pScreenPriv->timer = NULL; ++ pScreenPriv->udpPort = 0; ++ pScreenPriv->rfbListenSock = -1; ++ pScreenPriv->udpSock = -1; ++ pScreenPriv->udpSockConnected = FALSE; ++ pScreenPriv->httpListenSock = -1; ++ pScreenPriv->httpSock = -1; ++ pScreenPriv->maxFd = 0; ++ pScreenPriv->rfbAuthPasswdFile = NULL; ++ pScreenPriv->httpDir = NULL; ++ pScreenPriv->rfbInstalledColormap = NULL; ++ pScreenPriv->interface.s_addr = htonl (INADDR_ANY); ++ ++ pScreenPriv->rfbPort = 0; ++ pScreenPriv->httpPort = 0; ++ pScreenPriv->rfbAuthPasswdFile = NULL; ++ pScreenPriv->httpDir = NULL; ++ pScreenPriv->rfbAlwaysShared = FALSE; ++ pScreenPriv->rfbNeverShared = FALSE; ++ pScreenPriv->rfbUserAccept = FALSE; ++ pScreenPriv->useGetImage = TRUE; /* For DMX */ ++ pScreenPriv->rfbViewOnly = FALSE; ++ pScreenPriv->rfbDontDisconnect = FALSE; ++ pScreenPriv->loginAuthEnabled = FALSE; ++ ++#if 0 ++ if (xf86ReturnOptValBool(options, OPTION_LOCALHOST, FALSE)) ++ pScreenPriv->interface.s_addr = htonl (INADDR_LOOPBACK); ++ ++ interface_str = xf86GetOptValString(options, OPTION_INTERFACE); ++ ++ if (interface_str && pScreenPriv->interface.s_addr == htonl(INADDR_ANY)) { ++ Bool failed = FALSE; ++ struct in_addr got; ++ unsigned long octet; ++ char *p = interface_str, *end; ++ int q; ++ ++ for (q = 0; q < 4; q++) { ++ octet = strtoul (p, &end, 10); ++ ++ if (p == end || octet > 255) ++ failed = TRUE; ++ ++ if ((q < 3 && *end != '.') || ++ (q == 3 && *end != '\0')) ++ failed = TRUE; ++ ++ got.s_addr = (got.s_addr << 8) | octet; ++ p = end + 1; ++ } ++ ++ if (!failed) ++ pScreenPriv->interface.s_addr = htonl (got.s_addr); ++ else ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VNC interface option malformed, not using.\n"); ++ } ++#endif ++ ++ if (!VNC_LAST_CLIENT_ID) ++ VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID", ++ strlen("VNC_LAST_CLIENT_ID"), TRUE); ++ if (!VNC_CONNECT) ++ VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE); ++ ++ rfbInitSockets(pScreen); ++ if (inetdSock == -1) ++ httpInitSockets(pScreen); ++ ++#ifdef CORBA ++ initialiseCORBA(argc, argv, desktopName); ++#endif ++ ++ pScreenPriv->width = pScrn->scrnWidth; ++ pScreenPriv->height = pScrn->scrnHeight; ++ pScreenPriv->depth = pScrn->beDepth; ++ pScreenPriv->paddedWidthInBytes = PixmapBytePad(pScrn->scrnWidth, pScrn->beDepth); ++ pScreenPriv->bitsPerPixel = rfbBitsPerPixel(pScrn->beDepth); ++ pScreenPriv->pfbMemory = NULL; ++ pScreenPriv->oldpfbMemory = NULL; ++ ++ pScreenPriv->cursorIsDrawn = TRUE; ++ pScreenPriv->dontSendFramebufferUpdate = FALSE; ++ ++ pScreenPriv->CloseScreen = pScreen->CloseScreen; ++ pScreenPriv->CreateGC = pScreen->CreateGC; ++ pScreenPriv->PaintWindowBackground = pScreen->PaintWindowBackground; ++ pScreenPriv->PaintWindowBorder = pScreen->PaintWindowBorder; ++ pScreenPriv->CopyWindow = pScreen->CopyWindow; ++ pScreenPriv->ClearToBackground = pScreen->ClearToBackground; ++ pScreenPriv->RestoreAreas = pScreen->RestoreAreas; ++ pScreenPriv->WakeupHandler = pScreen->WakeupHandler; ++ pScreenPriv->InstallColormap = pScreen->InstallColormap; ++ pScreenPriv->UninstallColormap = pScreen->UninstallColormap; ++ pScreenPriv->ListInstalledColormaps = pScreen->ListInstalledColormaps; ++ pScreenPriv->StoreColors = pScreen->StoreColors; ++#ifdef CHROMIUM ++ pScreenPriv->RealizeWindow = pScreen->RealizeWindow; ++ pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; ++ pScreenPriv->DestroyWindow = pScreen->DestroyWindow; ++ pScreenPriv->PositionWindow = pScreen->PositionWindow; ++ pScreenPriv->ResizeWindow = pScreen->ResizeWindow; ++ pScreenPriv->ClipNotify = pScreen->ClipNotify; ++#endif ++#ifdef RENDER ++ ps = GetPictureScreenIfSet(pScreen); ++ if (ps) ++ pScreenPriv->Composite = ps->Composite; ++#endif ++ pScreen->CloseScreen = rfbCloseScreen; ++ pScreen->CreateGC = rfbCreateGC; ++ pScreen->PaintWindowBackground = rfbPaintWindowBackground; ++ pScreen->PaintWindowBorder = rfbPaintWindowBorder; ++ pScreen->CopyWindow = rfbCopyWindow; ++ pScreen->ClearToBackground = rfbClearToBackground; ++ pScreen->RestoreAreas = rfbRestoreAreas; ++ pScreen->WakeupHandler = rfbWakeupHandler; ++ pScreen->InstallColormap = rfbInstallColormap; ++ pScreen->UninstallColormap = rfbUninstallColormap; ++ pScreen->ListInstalledColormaps = rfbListInstalledColormaps; ++ pScreen->StoreColors = rfbStoreColors; ++ ++#ifdef CHROMIUM ++ pScreen->RealizeWindow = rfbRealizeWindow; ++ pScreen->UnrealizeWindow = rfbUnrealizeWindow; ++ pScreen->DestroyWindow = rfbDestroyWindow; ++ pScreen->PositionWindow = rfbPositionWindow; ++ pScreen->ResizeWindow = rfbResizeWindow; ++ pScreen->ClipNotify = rfbClipNotify; ++#endif ++#ifdef RENDER ++ if (ps) ++ ps->Composite = rfbComposite; ++#endif ++ ++ for (visual = pScreen->visuals; visual->vid != pScreen->rootVisual; visual++) ++ ; ++ ++ if (!visual) { ++ ErrorF("rfbScreenInit: couldn't find root visual\n"); ++ return FALSE; ++ } ++ ++ pScreenPriv->rfbServerFormat.bitsPerPixel = pScrn->beBPP; ++ pScreenPriv->rfbServerFormat.depth = pScrn->beDepth; ++ pScreenPriv->rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest); ++ pScreenPriv->rfbServerFormat.trueColour = (visual->class == TrueColor); ++ if (pScreenPriv->rfbServerFormat.trueColour) { ++ pScreenPriv->rfbServerFormat.redMax = visual->redMask >> visual->offsetRed; ++ pScreenPriv->rfbServerFormat.greenMax = visual->greenMask >> visual->offsetGreen; ++ pScreenPriv->rfbServerFormat.blueMax = visual->blueMask >> visual->offsetBlue; ++ pScreenPriv->rfbServerFormat.redShift = visual->offsetRed; ++ pScreenPriv->rfbServerFormat.greenShift = visual->offsetGreen; ++ pScreenPriv->rfbServerFormat.blueShift = visual->offsetBlue; ++ } else { ++ pScreenPriv->rfbServerFormat.redMax ++ = pScreenPriv->rfbServerFormat.greenMax ++ = pScreenPriv->rfbServerFormat.blueMax = 0; ++ pScreenPriv->rfbServerFormat.redShift ++ = pScreenPriv->rfbServerFormat.greenShift ++ = pScreenPriv->rfbServerFormat.blueShift = 0; ++ } ++ ++ return TRUE; ++} ++ ++static void ++rfbWakeupHandler ( ++ int i, ++ pointer blockData, ++ unsigned long err, ++ pointer pReadmask ++){ ++ ScreenPtr pScreen = screenInfo.screens[i]; ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ /*DMXScreenInfo *pScrn = &dmxScreens[pScreen->myNum];*/ ++ ++ rfbRootPropertyChange(pScreen); /* Check clipboard */ ++ ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++#ifdef CORBA ++ corbaCheckFds(); ++#endif ++ ++ pScreen->WakeupHandler = pScreenPriv->WakeupHandler; ++ (*pScreen->WakeupHandler) (i, blockData, err, pReadmask); ++ pScreen->WakeupHandler = rfbWakeupHandler; ++} ++ ++ ++/*BP*/ ++void ++rfbWakeupHandler2(void) ++{ ++ ScreenPtr pScreen = TheVNCScreen; ++ rfbRootPropertyChange(pScreen); /* Check clipboard */ ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++} +diff --git a/hw/dmx/vnc/vncauth.c b/hw/dmx/vnc/vncauth.c +new file mode 100644 +index 0000000..9adae0d +--- /dev/null ++++ b/hw/dmx/vnc/vncauth.c +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ * vncauth.c - Functions for VNC password management and authentication. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vncauth.h" ++#include "d3des.h" ++ ++ ++/* ++ * Make sure we call srandom() only once. ++ */ ++ ++static int s_srandom_called = 0; ++ ++/* ++ * We use a fixed key to store passwords, since we assume that our local ++ * file system is secure but nonetheless don't want to store passwords ++ * as plaintext. ++ */ ++ ++static unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7}; ++ ++ ++/* ++ * Encrypt a password and store it in a file. Returns 0 if successful, ++ * 1 if the file could not be written. ++ * ++ * NOTE: This function is preserved only for compatibility with the original ++ * AT&T VNC software. Use vncEncryptAndStorePasswd2() instead. ++ */ ++ ++int ++vncEncryptAndStorePasswd(char *passwd, char *fname) ++{ ++ return (vncEncryptAndStorePasswd2(passwd, NULL, fname) == 0); ++} ++ ++/* ++ * Encrypt one or two passwords and store them in a file. Returns 1 if ++ * successful, 0 if the file could not be written (note that the original ++ * vncEncryptAndStorePasswd() function returns inverse values). The ++ * passwdViewOnly pointer may be NULL. ++ */ ++ ++int ++vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname) ++{ ++ FILE *fp; ++ int i, bytesToWrite, bytesWrote; ++ unsigned char encryptedPasswd[16] = { ++ 0,0,0,0,0,0,0,0, ++ 0,0,0,0,0,0,0,0 ++ }; ++ ++ fp = fopen(fname,"w"); ++ if (fp == NULL) ++ return 0; ++ ++ chmod(fname, S_IRUSR|S_IWUSR); ++ ++ strncpy(encryptedPasswd, passwd, 8); ++ if (passwdViewOnly != NULL) ++ strncpy(encryptedPasswd + 8, passwdViewOnly, 8); ++ ++ /* Do encryption in-place - this way we overwrite our copies of ++ plaintext passwords. */ ++ ++ deskey(s_fixedkey, EN0); ++ des(encryptedPasswd, encryptedPasswd); ++ if (passwdViewOnly != NULL) ++ des(encryptedPasswd + 8, encryptedPasswd + 8); ++ ++ bytesToWrite = (passwdViewOnly == NULL) ? 8 : 16; ++ bytesWrote = fwrite(encryptedPasswd, 1, bytesToWrite, fp); ++ ++ fclose(fp); ++ return (bytesWrote == bytesToWrite); ++} ++ ++ ++/* ++ * Decrypt a password from a file. Returns a pointer to a newly allocated ++ * string containing the password or a null pointer if the password could ++ * not be retrieved for some reason. ++ * ++ * NOTE: This function is preserved only for compatibility with the original ++ * AT&T VNC software. Use vncDecryptPasswdFromFile2() instead. ++ */ ++ ++char * ++vncDecryptPasswdFromFile(char *fname) ++{ ++ char *passwd; ++ ++ passwd = malloc(9); ++ ++ if (passwd != NULL) { ++ if (vncDecryptPasswdFromFile2(fname, passwd, NULL) == 0) { ++ free(passwd); ++ passwd = NULL; ++ } ++ } ++ ++ return passwd; ++} ++ ++/* ++ * Decrypt one or two passwords from a file. Returns the number of ++ * passwords read (1, 2, or 0 on error). On success, the passwords are ++ * written into buffers passwdFullControl[] and passwdViewOnly[] if ++ * they are not NULL. If the pointers to buffers are not NULL, then ++ * the buffers should be at least of 9 bytes length. ++ */ ++ ++int ++vncDecryptPasswdFromFile2(char *fname, ++ char *passwdFullControl, char *passwdViewOnly) ++{ ++ FILE *fp; ++ int i, ch; ++ char passwd[16]; ++ ++ if (strcmp(fname, "-") != 0) { ++ if ((fp = fopen(fname,"r")) == NULL) ++ return 0; /* Could not open the file */ ++ } else { ++ fp = stdin; ++ } ++ ++ for (i = 0; i < 16; i++) { ++ ch = getc(fp); ++ if (ch == EOF) ++ break; ++ passwd[i] = ch; ++ } ++ ++ if (fp != stdin) ++ fclose(fp); ++ ++ if (i < 8) ++ return 0; /* Could not read eight bytes */ ++ ++ deskey(s_fixedkey, DE1); ++ ++ /* Decoding first (full-control) password */ ++ if (passwdFullControl != NULL) { ++ des(passwd, passwd); ++ memcpy(passwdFullControl, passwd, 8); ++ passwdFullControl[8] = '\0'; ++ } ++ ++ /* Decoding second (view-only) password if available */ ++ if (i == 16 && passwdViewOnly != NULL) { ++ des(&passwd[8], &passwd[8]); ++ memcpy(passwdViewOnly, &passwd[8], 8); ++ passwdViewOnly[8] = '\0'; ++ } ++ ++ /* Destroying our copy of clear-text passwords */ ++ memset(passwd, 0, 16); ++ ++ return (i < 16) ? 1 : 2; ++} ++ ++ ++/* ++ * Generate CHALLENGESIZE random bytes for use in challenge-response ++ * authentication. ++ */ ++ ++void ++vncRandomBytes(unsigned char *bytes) ++{ ++ int i; ++ unsigned int seed; ++ ++ if (!s_srandom_called) { ++ seed = (unsigned int)time(0) ^ (unsigned int)getpid(); ++ srandom(seed); ++ s_srandom_called = 1; ++ } ++ ++ for (i = 0; i < CHALLENGESIZE; i++) { ++ bytes[i] = (unsigned char)(random() & 255); ++ } ++} ++ ++ ++/* ++ * Encrypt CHALLENGESIZE bytes in memory using a password. ++ */ ++ ++void ++vncEncryptBytes(unsigned char *bytes, char *passwd) ++{ ++ unsigned char key[8]; ++ int i; ++ ++ /* key is simply password padded with nulls */ ++ ++ for (i = 0; i < 8; i++) { ++ if (i < strlen(passwd)) { ++ key[i] = passwd[i]; ++ } else { ++ key[i] = 0; ++ } ++ } ++ ++ deskey(key, EN0); ++ ++ for (i = 0; i < CHALLENGESIZE; i += 8) { ++ des(bytes+i, bytes+i); ++ } ++} +diff --git a/hw/dmx/vnc/vncauth.h b/hw/dmx/vnc/vncauth.h +new file mode 100644 +index 0000000..5ece2e1 +--- /dev/null ++++ b/hw/dmx/vnc/vncauth.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ * vncauth.h - describes the functions provided by the vncauth library. ++ */ ++ ++#define MAXPWLEN 8 ++#define CHALLENGESIZE 16 ++ ++extern int vncEncryptAndStorePasswd(char *passwd, char *fname); ++extern char *vncDecryptPasswdFromFile(char *fname); ++extern void vncRandomBytes(unsigned char *bytes); ++extern void vncEncryptBytes(unsigned char *bytes, char *passwd); ++ ++extern int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname); ++extern int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly); ++ +diff --git a/hw/dmx/vnc/vncext.c b/hw/dmx/vnc/vncext.c +new file mode 100644 +index 0000000..0bcd109 +--- /dev/null ++++ b/hw/dmx/vnc/vncext.c +@@ -0,0 +1,689 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include "rfb.h" ++#include "extnsionst.h" ++#define _VNC_SERVER ++#include ++#include "../dmx.h" ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CHROMIUM ++extern void rfbSendChromiumStart(unsigned int ipaddress, unsigned int port); ++extern void rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid); ++int GenerateVncChromiumConnectedEvent(int sock); ++#endif ++ ++/*extern void rfbUserAllow(int sock, int accept);*/ ++ ++int VncSelectNotify(ClientPtr client, BOOL onoff); ++int GenerateVncConnectedEvent(int sock); ++int GenerateVncDisconnectedEvent(int sock); ++void VncExtensionInit(void); ++ ++static int VncErrorBase; /* first vnc error number */ ++static int VncEventBase; /* first vnc event number */ ++ ++unsigned long VncResourceGeneration = 0; ++ ++static RESTYPE VncNotifyList; ++ ++static XID faked; ++ ++typedef struct _VncNotifyListRec { ++ struct _VncNotifyListRec *next; ++ ClientPtr client; ++} VncNotifyListRec, *VncNotifyListPtr; ++ ++static int ++ProcVncQueryVersion(ClientPtr client) ++{ ++ xVncQueryVersionReply rep; ++ ++ REQUEST_SIZE_MATCH(xVncQueryVersionReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ rep.majorVersion = VNC_MAJOR_VERSION; ++ rep.minorVersion = VNC_MINOR_VERSION; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.majorVersion, n); ++ swaps(&rep.minorVersion, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncQueryVersionReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncQueryVersion */ ++ ++static int ++ProcVncConnection(ClientPtr client) ++{ ++ REQUEST(xVncConnectionReq); ++ xVncConnectionReply rep; ++ ++ rfbUserAllow( stuff->sock, stuff->accept ); ++ ++ REQUEST_SIZE_MATCH(xVncConnectionReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ rep.sock = 0; ++ rep.accept = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.sock, n); ++ swaps(&rep.accept, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncConnectionReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncConnection */ ++ ++static int ++ProcVncSelectNotify(ClientPtr client) ++{ ++ REQUEST(xVncSelectNotifyReq); ++ xVncSelectNotifyReply rep; ++ ++ VncSelectNotify(client, stuff->onoff); ++ ++ REQUEST_SIZE_MATCH(xVncSelectNotifyReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncSelectNotifyReply), ++ (char *)&rep); ++ return (client->noClientException); ++ ++} ++ ++static int ++ProcVncListConnections(ClientPtr client) ++{ ++ xVncListConnectionsReply rep; ++ rfbClientPtr cl; ++ int count = 0; ++ struct in_addr ipaddress; ++ xVncConnectionListInfo Info; ++ ++ /* count connections */ ++ for (cl = rfbClientHead; cl; cl = cl->next) ++#ifdef CHROMIUM ++ /* ++ * Fix this, as it should be generic, but we're only using it ++ * for Chromium at the moment, so we only list the connections ++ * that have a valid chromium encoding. We should be able to list ++ * any type requested. FIXME! XXXX ++ * See furthur down this function too!!! ++ */ ++ if (cl->enableChromiumEncoding) ++#endif ++ count++; ++ ++ REQUEST_SIZE_MATCH(xVncListConnectionsReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.count = count; ++ rep.length = count * sizeof(xVncConnectionListInfo) >> 2; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.count, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncListConnectionsReply), ++ (char *)&rep); ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++#ifdef CHROMIUM ++ /* ++ * Fix this, as it should be generic, but we're only using it ++ * for Chromium at the moment, so we only list the connections ++ * that have a valid chromium encoding. We should be able to list ++ * any type requested. FIXME! XXXX ++ */ ++ if (!cl->enableChromiumEncoding) ++ continue; ++#endif ++ inet_aton(cl->host, &ipaddress); ++ memcpy(&Info, &ipaddress, sizeof(struct in_addr)); ++ WriteToClient(client, SIZEOF(xVncConnectionListInfo), (char*)&Info); ++ } ++ ++ return (client->noClientException); ++} /* ProcVncListConnections */ ++ ++#ifdef CHROMIUM ++static int ++ProcVncChromiumStart(ClientPtr client) ++{ ++ REQUEST(xVncChromiumStartReq); ++ xVncChromiumStartReply rep; ++ ++ rfbSendChromiumStart(stuff->ipaddress, stuff->port); ++ ++ REQUEST_SIZE_MATCH(xVncChromiumStartReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncChromiumStartReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncChromiumStart */ ++ ++static int ++ProcVncChromiumMonitor(ClientPtr client) ++{ ++ REQUEST(xVncChromiumMonitorReq); ++ xVncChromiumMonitorReply rep; ++ ++ rfbChromiumMonitorWindowID(stuff->cr_windowid, stuff->windowid); ++ ++ REQUEST_SIZE_MATCH(xVncChromiumMonitorReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncChromiumMonitorReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncChromiumMonitor */ ++#endif /* CHROMIUM */ ++ ++static int ++ProcVncDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ ++ switch (stuff->data) ++ { ++ case X_VncQueryVersion: ++ return ProcVncQueryVersion(client); ++ case X_VncSelectNotify: ++ return ProcVncSelectNotify(client); ++ case X_VncConnection: ++ return ProcVncConnection(client); ++ case X_VncListConnections: ++ return ProcVncListConnections(client); ++#ifdef CHROMIUM ++ case X_VncChromiumStart: ++ return ProcVncChromiumStart(client); ++ case X_VncChromiumMonitor: ++ return ProcVncChromiumMonitor(client); ++#endif ++ default: ++ return BadRequest; ++ } ++} /* ProcVncDispatch */ ++ ++static int ++SProcVncQueryVersion(ClientPtr client) ++{ ++ REQUEST(xVncQueryVersionReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncQueryVersionReq); ++ swaps(&stuff->majorVersion, n); ++ swaps(&stuff->minorVersion,n); ++ return ProcVncQueryVersion(client); ++} /* SProcVncQueryVersion */ ++ ++static int ++SProcVncSelectNotify(ClientPtr client) ++{ ++ REQUEST(xVncSelectNotifyReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncSelectNotifyReq); ++ return ProcVncSelectNotify(client); ++} /* SProcVncSelectNotify */ ++ ++static int ++SProcVncListConnections(ClientPtr client) ++{ ++ REQUEST(xVncListConnectionsReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncListConnectionsReq); ++ return ProcVncListConnections(client); ++} /* SProcVncListConnections */ ++ ++#ifdef CHROMIUM ++static int ++SProcVncChromiumStart(ClientPtr client) ++{ ++ REQUEST(xVncChromiumStartReq); ++ register char n; ++ ++ swaps(&stuff->ipaddress, n); ++ swaps(&stuff->port, n); ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncChromiumStartReq); ++ return ProcVncChromiumStart(client); ++} /* SProcVncChromiumStart */ ++ ++static int ++SProcVncChromiumMonitor(ClientPtr client) ++{ ++ REQUEST(xVncChromiumMonitorReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ swaps(&stuff->windowid, n); ++ swaps(&stuff->cr_windowid, n); ++ REQUEST_SIZE_MATCH(xVncChromiumMonitorReq); ++ return ProcVncChromiumMonitor(client); ++} /* SProcVncChromiumMonitor */ ++#endif /* CHROMIUM */ ++ ++static int ++SProcVncConnection(ClientPtr client) ++{ ++ REQUEST(xVncConnectionReq); ++ register char n; ++ ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncConnectionReq); ++ swaps(&stuff->sock, n); ++ swaps(&stuff->accept,n); ++ return ProcVncConnection(client); ++} /* SProcVncConnection */ ++ ++static int ++SProcVncDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ ++ switch (stuff->data) ++ { ++ case X_VncQueryVersion: ++ return SProcVncQueryVersion(client); ++ case X_VncSelectNotify: ++ return SProcVncSelectNotify(client); ++ case X_VncConnection: ++ return SProcVncConnection(client); ++ case X_VncListConnections: ++ return SProcVncListConnections(client); ++#ifdef CHROMIUM ++ case X_VncChromiumStart: ++ return SProcVncChromiumStart(client); ++ case X_VncChromiumMonitor: ++ return SProcVncChromiumMonitor(client); ++#endif ++ default: ++ return BadRequest; ++ } ++} /* SProcVncDispatch */ ++ ++static void ++SwapVncConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++ ++#ifdef CHROMIUM ++static void ++SwapVncChromiumConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++#endif ++ ++static void ++SwapVncDisconnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++ ++int ++GenerateVncConnectedEvent(int sock) ++{ ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++ ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncConnectedEvent conn; ++ SOCKLEN_T peer_len; ++ struct sockaddr_in peer; ++ ++ conn.type = VncEventBase + XVncConnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ ++ peer_len = sizeof(peer); ++ if (getpeername(sock, (struct sockaddr *) &peer, &peer_len) == -1) ++ conn.ipaddress = 0; ++ else ++ conn.ipaddress = (CARD32)peer.sin_addr.s_addr; ++ ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++ ++#ifdef CHROMIUM ++int ++GenerateVncChromiumConnectedEvent(int sock) ++{ ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++ ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncConnectedEvent conn; ++ SOCKLEN_T peer_len; ++ struct sockaddr_in peer; ++ ++ conn.type = VncEventBase + XVncChromiumConnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ ++ peer_len = sizeof(peer); ++ if (getpeername(sock, (struct sockaddr *)&peer, &peer_len) == -1) ++ conn.ipaddress = 0; ++ else ++ conn.ipaddress = (CARD32)peer.sin_addr.s_addr; ++ ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++#endif /* CHROMIUM */ ++ ++int ++GenerateVncDisconnectedEvent(int sock) ++{ ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++ ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncDisconnectedEvent conn; ++ conn.type = VncEventBase + XVncDisconnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++ ++static void ++VncResetProc(ExtensionEntry *extEntry) ++{ ++} /* VncResetProc */ ++ ++int ++VncSelectNotify( ++ ClientPtr client, ++ BOOL onoff ++){ ++ VncNotifyListPtr pn,tpn,fpn; ++ ++ if (!faked) ++ faked = FakeClientID(client->index); ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++ ++ if (!onoff && !pn) return Success; ++ ++ if (!pn) ++ { ++ if (!(tpn = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec)))) ++ return BadAlloc; ++ tpn->next = (VncNotifyListPtr)NULL; ++ tpn->client = (ClientPtr)NULL; ++ if (!AddResource(faked, VncNotifyList, tpn)) ++ { ++ xfree(tpn); ++ return BadAlloc; ++ } ++ } ++ else ++ { ++ fpn = (VncNotifyListPtr)NULL; ++ tpn = pn; ++ ++ /* FIXME - NEED TO HAVE AN OPTION FOR SINGLE CLIENT ONLY!!! */ ++ ++ while (tpn) ++ { ++ if (tpn->client == client) ++ { ++ if (!onoff) tpn->client = (ClientPtr)NULL; ++ return Success; ++ } ++ if (!tpn->client) fpn = tpn; /* TAKE NOTE OF FREE ENTRY */ ++ tpn = tpn->next; ++ } ++ ++ /* IF TUNNING OFF, THEN JUST RETURN */ ++ ++ if (!onoff) return Success; ++ ++ /* IF ONE ISN'T FOUND THEN ALLOCATE ONE AND LINK IT INTO THE LIST */ ++ ++ if (fpn) ++ { ++ tpn = fpn; ++ } ++ else ++ { ++ if (!(tpn = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec)))) ++ return BadAlloc; ++ tpn->next = pn->next; ++ pn->next = tpn; ++ } ++ } ++ ++ /* INIT CLIENT PTR IN CASE WE CAN'T ADD RESOURCE */ ++ /* ADD RESOURCE SO THAT IF CLIENT EXITS THE CLIENT PTR WILL BE CLEARED */ ++ ++ tpn->client = (ClientPtr)NULL; ++ ++ AddResource(faked, VncNotifyList, tpn); ++ ++ tpn->client = client; ++ return Success; ++ ++} ++ ++static int ++VncDestroyNotifyList(pointer pn, XID id) ++{ ++ VncNotifyListPtr cpn = (VncNotifyListPtr) pn; ++ ++ cpn->client = NULL; ++ ++ return Success; ++} ++ ++static Bool ++CreateResourceTypes(void) ++{ ++ if (VncResourceGeneration == serverGeneration) return TRUE; ++ ++ VncResourceGeneration = serverGeneration; ++ ++ if (!(VncNotifyList = CreateNewResourceType(VncDestroyNotifyList))) ++ { ++ ErrorF("CreateResourceTypes: failed to allocate vnc notify list resource.\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++ ++} ++ ++static unsigned long vncCreateScreenResourcesIndex; ++static unsigned long vncExtGeneration = 0; ++extern Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart); ++ ++/* copied from miscrinit.c */ ++typedef struct ++{ ++ pointer pbits; /* pointer to framebuffer */ ++ int width; /* delta to add to a framebuffer addr to move one row down */ ++} miScreenInitParmsRec, *miScreenInitParmsPtr; ++ ++#if 0 ++static Bool ++vncCreateScreenResources(ScreenPtr pScreen) ++{ ++ int ret = TRUE; ++ CreateScreenResourcesProcPtr CreateScreenResources = ++ (CreateScreenResourcesProcPtr)(pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr); ++ miScreenInitParmsPtr pScrInitParms; ++ ++ pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; ++ ++ if ( pScreen->CreateScreenResources != vncCreateScreenResources ) { ++ /* Can't find hook we are hung on */ ++ xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, ++ "vncCreateScreenResources %p called when not in pScreen->CreateScreenResources %p n", ++ vncCreateScreenResources, pScreen->CreateScreenResources ); ++ } ++ ++ /* Now do our stuff */ ++ VNCInit(pScreen, pScrInitParms->pbits); ++ ++ /* Unhook this function ... */ ++ pScreen->CreateScreenResources = CreateScreenResources; ++ pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr = NULL; ++ ++ /* ... and call the previous CreateScreenResources fuction, if any */ ++ if (NULL!=pScreen->CreateScreenResources) { ++ ret = (*pScreen->CreateScreenResources)(pScreen); ++ } ++ ++#ifdef DEBUG ++ ErrorF("vncCreateScreenResources() returns %d\n", ret); ++#endif ++ return (ret); ++} ++#endif ++ ++void ++VncExtensionInit(void) ++{ ++ ExtensionEntry *extEntry; ++ ++ErrorF("INIT1\n"); ++ if (vncExtGeneration != serverGeneration) { ++ unsigned int i; ++ ++ vncExtGeneration = serverGeneration; ++ ++ if ( ((vncCreateScreenResourcesIndex = AllocateScreenPrivateIndex()) < 0) ) ++ return; ++ ++#if 0 ++ for (i = 0 ; i < screenInfo.numScreens; i++) ++ { ++ screenInfo.screens[i]->devPrivates[vncCreateScreenResourcesIndex].ptr ++ = (void*)(&dmxScreens[i]->pScreen->CreateScreenResources); ++ dmxScreens[i].pScreen->CreateScreenResources = vncCreateScreenResources; ++ } ++#endif ++ ++ gethostname(rfbThisHost, 255); ++ } ++ ++ErrorF("INIT2\n"); ++ if (!CreateResourceTypes()) ++ return; ++ErrorF("INIT3\n"); ++ ++ extEntry = AddExtension(VNC_EXTENSION_NAME, ++ XVncNumberEvents, XVncNumberErrors, ++ ProcVncDispatch, SProcVncDispatch, ++ VncResetProc, StandardMinorOpcode); ++ ++ VncErrorBase = extEntry->errorBase; ++ VncEventBase = extEntry->eventBase; ++ ++ EventSwapVector[VncEventBase + XVncConnected] = ++ (EventSwapPtr)SwapVncConnectedEvent; ++ EventSwapVector[VncEventBase + XVncDisconnected] = ++ (EventSwapPtr)SwapVncDisconnectedEvent; ++#ifdef CHROMIUM ++ EventSwapVector[VncEventBase + XVncChromiumConnected] = ++ (EventSwapPtr)SwapVncChromiumConnectedEvent; ++#endif ++ErrorF("INIT EXT\n"); ++} /* VncExtensionInit */ +diff --git a/hw/dmx/vnc/vncint.h b/hw/dmx/vnc/vncint.h +new file mode 100644 +index 0000000..39728eb +--- /dev/null ++++ b/hw/dmx/vnc/vncint.h +@@ -0,0 +1,154 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#ifndef _VNCINT_H_ ++#define _VNCINT_H_ ++ ++#include ++ ++extern int vncScreenPrivateIndex; ++ ++#define VNCPTR(pScreen)\ ++ (vncScreenPtr)((pScreen)->devPrivates[vncScreenPrivateIndex].ptr) ++ ++typedef struct { ++ int rfbPort; ++ int rdpPort; ++ int udpPort; ++ int rfbListenSock; ++ int rdpListenSock; ++ int udpSock; ++ int httpPort; ++ int httpListenSock; ++ int httpSock; ++ char * httpDir; ++ char buf[HTTP_BUF_SIZE]; ++ Bool udpSockConnected; ++ char * rfbAuthPasswdFile; ++ size_t buf_filled; ++ int maxFd; ++ fd_set allFds; ++ unsigned char * oldpfbMemory; ++ Bool useGetImage; ++ Bool rfbAlwaysShared; ++ Bool rfbNeverShared; ++ Bool rfbDontDisconnect; ++ Bool rfbUserAccept; ++ Bool rfbViewOnly; ++ unsigned char * pfbMemory; ++ int paddedWidthInBytes; ++ ColormapPtr rfbInstalledColormap; ++ ColormapPtr savedColormap; ++ rfbPixelFormat rfbServerFormat; ++ Bool rfbAuthTooManyTries; ++ int rfbAuthTries; ++ Bool loginAuthEnabled; ++ struct in_addr interface; ++ OsTimerPtr timer; ++ char updateBuf[UPDATE_BUF_SIZE]; ++ int ublen; ++ int width; ++ int height; ++ int depth; ++ int bitsPerPixel; ++ ++ /* The following two members are used to minimise the amount of unnecessary ++ drawing caused by cursor movement. Whenever any drawing affects the ++ part of the screen where the cursor is, the cursor is removed first and ++ then the drawing is done (this is what the sprite routines test for). ++ Afterwards, however, we do not replace the cursor, even when the cursor ++ is logically being moved across the screen. We only draw the cursor ++ again just as we are about to send the client a framebuffer update. ++ ++ We need to be careful when removing and drawing the cursor because of ++ their relationship with the normal drawing routines. The drawing ++ routines can invoke the cursor routines, but also the cursor routines ++ themselves end up invoking drawing routines. ++ ++ Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by ++ doing a CopyArea from a pixmap to the screen, where the pixmap contains ++ the saved contents of the screen under the cursor. Before doing this, ++ however, we set cursorIsDrawn to FALSE. Then, when CopyArea is called, ++ it sees that cursorIsDrawn is FALSE and so doesn't feel the need to ++ (recursively!) remove the cursor before doing it. ++ ++ Putting up the cursor (rfbSpriteRestoreCursor) involves a call to ++ PushPixels. While this is happening, cursorIsDrawn must be FALSE so ++ that PushPixels doesn't think it has to remove the cursor first. ++ Obviously cursorIsDrawn is set to TRUE afterwards. ++ ++ Another problem we face is that drawing routines sometimes cause a ++ framebuffer update to be sent to the RFB client. When the RFB client is ++ already waiting for a framebuffer update and some drawing to the ++ framebuffer then happens, the drawing routine sees that the client is ++ ready, so it calls rfbSendFramebufferUpdate. If the cursor is not drawn ++ at this stage, it must be put up, and so rfbSpriteRestoreCursor is ++ called. However, if the original drawing routine was actually called ++ from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't ++ want this to happen. So both the cursor routines set ++ dontSendFramebufferUpdate to TRUE, and all the drawing routines check ++ this before calling rfbSendFramebufferUpdate. */ ++ ++ Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ ++ Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the ++ cursor */ ++ ++ /* wrapped screen functions */ ++ ++ CloseScreenProcPtr CloseScreen; ++ CreateGCProcPtr CreateGC; ++ PaintWindowBackgroundProcPtr PaintWindowBackground; ++ PaintWindowBorderProcPtr PaintWindowBorder; ++ CopyWindowProcPtr CopyWindow; ++ ClearToBackgroundProcPtr ClearToBackground; ++ RestoreAreasProcPtr RestoreAreas; ++ ScreenWakeupHandlerProcPtr WakeupHandler; ++ InstallColormapProcPtr InstallColormap; ++ UninstallColormapProcPtr UninstallColormap; ++ ListInstalledColormapsProcPtr ListInstalledColormaps; ++ StoreColorsProcPtr StoreColors; ++ DisplayCursorProcPtr DisplayCursor; ++ CursorPtr pCurs; ++ Bool (*UseHWCursor)(ScreenPtr, CursorPtr); ++ Bool (*UseHWCursorARGB)(ScreenPtr, CursorPtr); ++ Bool *SWCursor; ++#ifdef CHROMIUM ++ RealizeWindowProcPtr RealizeWindow; ++ UnrealizeWindowProcPtr UnrealizeWindow; ++ DestroyWindowProcPtr DestroyWindow; ++ ResizeWindowProcPtr ResizeWindow; ++ PositionWindowProcPtr PositionWindow; ++ ClipNotifyProcPtr ClipNotify; ++#endif ++#ifdef RENDER ++ CompositeProcPtr Composite; ++#endif ++ ++} vncScreenRec, *vncScreenPtr; ++ ++extern Bool vncUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs); ++extern Bool vncUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs); ++ ++extern void ++rfbSendChromiumStart(unsigned int ipaddress, unsigned int port); ++ ++#endif /* _VNCINT_H_ */ ++ +diff --git a/hw/dmx/vnc/xistubs.c b/hw/dmx/vnc/xistubs.c +new file mode 100644 +index 0000000..c25f6d9 +--- /dev/null ++++ b/hw/dmx/vnc/xistubs.c +@@ -0,0 +1,319 @@ ++/* $Xorg: stubs.c,v 1.4 2001/02/09 02:04:35 xorgcvs Exp $ */ ++ ++/************************************************************ ++ ++Copyright 1989, 1998 The Open Group ++ ++Permission to use, copy, modify, distribute, and sell this software and its ++documentation for any purpose is hereby granted without fee, provided that ++the above copyright notice appear in all copies and that both that ++copyright notice and this permission notice appear in supporting ++documentation. ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of The Open Group shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from The Open Group. ++ ++Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. ++ ++ All Rights Reserved ++ ++Permission to use, copy, modify, and distribute this software and its ++documentation for any purpose and without fee is hereby granted, ++provided that the above copyright notice appear in all copies and that ++both that copyright notice and this permission notice appear in ++supporting documentation, and that the name of Hewlett-Packard not be ++used in advertising or publicity pertaining to distribution of the ++software without specific, written prior permission. ++ ++HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ++ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ++HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ++ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ++WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ++ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ++SOFTWARE. ++ ++********************************************************/ ++/* $XFree86: xc/programs/Xserver/Xi/stubs.c,v 3.3 2001/01/17 22:13:26 dawes Exp $ */ ++ ++/* ++ * stubs.c -- stub routines for the X server side of the XINPUT ++ * extension. This file is mainly to be used only as documentation. ++ * There is not much code here, and you can't get a working XINPUT ++ * server just using this. ++ * The Xvfb server uses this file so it will compile with the same ++ * object files as the real X server for a platform that has XINPUT. ++ * Xnest could do the same thing. ++ */ ++ ++#define NEED_EVENTS ++#include "X11/X.h" ++#include "X11/Xproto.h" ++#include "inputstr.h" ++#include ++#include ++/*#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/dmx/vnc/zlib.c b/hw/dmx/vnc/zlib.c +new file mode 100644 +index 0000000..edc4467 +--- /dev/null ++++ b/hw/dmx/vnc/zlib.c +@@ -0,0 +1,306 @@ ++/* ++ * zlib.c ++ * ++ * Routines to implement zlib based encoding (deflate). ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * For the latest source code, please check: ++ * ++ * http://www.developVNC.org/ ++ * ++ * or send email to feedback@developvnc.org. ++ */ ++ ++#include ++#include ++#include "rfb.h" ++ ++/* ++ * zlibBeforeBuf contains pixel data in the client's format. ++ * zlibAfterBuf contains the zlib (deflated) encoding version. ++ * If the zlib compressed/encoded version is ++ * larger than the raw data or if it exceeds zlibAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int zlibBeforeBufSize = 0; ++static char *zlibBeforeBuf = NULL; ++ ++static int zlibAfterBufSize = 0; ++static char *zlibAfterBuf = NULL; ++static int zlibAfterBufLen; ++ ++/* ++ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib ++ * rectangle encoding. ++ */ ++ ++static Bool ++rfbSendOneRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbZlibHeader hdr; ++ int deflateResult; ++ int previousOut; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize; ++ int maxCompSize; ++ ++ maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (zlibBeforeBufSize < maxRawSize) { ++ zlibBeforeBufSize = maxRawSize; ++ if (zlibBeforeBuf == NULL) ++ zlibBeforeBuf = (char *)xalloc(zlibBeforeBufSize); ++ else ++ zlibBeforeBuf = (char *)xrealloc(zlibBeforeBuf, zlibBeforeBufSize); ++ } ++ ++ /* zlib compression is not useful for very small data sets. ++ * So, we just send these raw without any compression. ++ */ ++ if (( w * h * (pVNC->bitsPerPixel / 8)) < ++ VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) { ++ ++ int result; ++ ++ /* The translation function (used also by the in raw encoding) ++ * requires 4/2/1 byte alignment in the output buffer (which is ++ * pVNC->updateBuf for the raw encoding) based on the bitsPerPixel of ++ * the viewer/client. This prevents SIGBUS errors on some ++ * architectures like SPARC, PARISC... ++ */ ++ if (( cl->format.bitsPerPixel > 8 ) && ++ ( pVNC->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ result = rfbSendRectEncodingRaw(cl, x, y, w, h); ++ ++ return result; ++ ++ } ++ ++ /* ++ * zlib requires output buffer to be slightly larger than the input ++ * buffer, in the worst case. ++ */ ++ maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12; ++ ++ if (zlibAfterBufSize < maxCompSize) { ++ zlibAfterBufSize = maxCompSize; ++ if (zlibAfterBuf == NULL) ++ zlibAfterBuf = (char *)xalloc(zlibAfterBufSize); ++ else ++ zlibAfterBuf = (char *)xrealloc(zlibAfterBuf, zlibAfterBufSize); ++ } ++ ++ /* ++ * Convert pixel data to client format. ++ */ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, zlibBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ cl->compStream.next_in = ( Bytef * )zlibBeforeBuf; ++ cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8); ++ cl->compStream.next_out = ( Bytef * )zlibAfterBuf; ++ cl->compStream.avail_out = maxCompSize; ++ cl->compStream.data_type = Z_BINARY; ++ ++ /* Initialize the deflation state. */ ++ if ( cl->compStreamInited == FALSE ) { ++ ++ cl->compStream.total_in = 0; ++ cl->compStream.total_out = 0; ++ cl->compStream.zalloc = Z_NULL; ++ cl->compStream.zfree = Z_NULL; ++ cl->compStream.opaque = Z_NULL; ++ ++ deflateInit2( &(cl->compStream), ++ cl->zlibCompressLevel, ++ Z_DEFLATED, ++ MAX_WBITS, ++ MAX_MEM_LEVEL, ++ Z_DEFAULT_STRATEGY ); ++ /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */ ++ /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */ ++ cl->compStreamInited = TRUE; ++ ++ } ++ ++ previousOut = cl->compStream.total_out; ++ ++ /* Perform the compression here. */ ++ deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH ); ++ ++ /* Find the total size of the resulting compressed data. */ ++ zlibAfterBufLen = cl->compStream.total_out - previousOut; ++ ++ if ( deflateResult != Z_OK ) { ++ rfbLog("zlib deflation error: %s\n", cl->compStream.msg); ++ return FALSE; ++ } ++ ++ /* Note that it is not possible to switch zlib parameters based on ++ * the results of the compression pass. The reason is ++ * that we rely on the compressor and decompressor states being ++ * in sync. Compressing and then discarding the results would ++ * cause lose of synchronization. ++ */ ++ ++ /* Update statics */ ++ cl->rfbRectanglesSent[rfbEncodingZlib]++; ++ cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbZlibHeader + zlibAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingZlib); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nBytes = Swap32IfLE(zlibAfterBufLen); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbZlibHeader); ++ pVNC->ublen += sz_rfbZlibHeader; ++ ++ for (i = 0; i < zlibAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > zlibAfterBufLen) { ++ bytesToCopy = zlibAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &zlibAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ ++} ++ ++ ++/* ++ * rfbSendRectEncodingZlib - send a given rectangle using one or more ++ * Zlib encoding rectangles. ++ */ ++ ++Bool ++rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int maxLines; ++ int linesRemaining; ++ rfbRectangle partialRect; ++ ++ partialRect.x = x; ++ partialRect.y = y; ++ partialRect.w = w; ++ partialRect.h = h; ++ ++ /* Determine maximum pixel/scan lines allowed per rectangle. */ ++ maxLines = ( ZLIB_MAX_SIZE(w) / w ); ++ ++ /* Initialize number of scan lines left to do. */ ++ linesRemaining = h; ++ ++ /* Loop until all work is done. */ ++ while ( linesRemaining > 0 ) { ++ ++ int linesToComp; ++ ++ if ( maxLines < linesRemaining ) ++ linesToComp = maxLines; ++ else ++ linesToComp = linesRemaining; ++ ++ partialRect.h = linesToComp; ++ ++ /* Encode (compress) and send the next rectangle. */ ++ if ( ! rfbSendOneRectEncodingZlib( cl, ++ partialRect.x, ++ partialRect.y, ++ partialRect.w, ++ partialRect.h )) { ++ ++ return FALSE; ++ } ++ ++ /* Technically, flushing the buffer here is not extrememly ++ * efficient. However, this improves the overall throughput ++ * of the system over very slow networks. By flushing ++ * the buffer with every maximum size zlib rectangle, we ++ * improve the pipelining usage of the server CPU, network, ++ * and viewer CPU components. Insuring that these components ++ * are working in parallel actually improves the performance ++ * seen by the user. ++ * Since, zlib is most useful for slow networks, this flush ++ * is appropriate for the desired behavior of the zlib encoding. ++ */ ++ if (( pVNC->ublen > 0 ) && ++ ( linesToComp == maxLines )) { ++ if (!rfbSendUpdateBuf(cl)) { ++ ++ return FALSE; ++ } ++ } ++ ++ /* Update remaining and incremental rectangle location. */ ++ linesRemaining -= linesToComp; ++ partialRect.y += linesToComp; ++ ++ } ++ ++ return TRUE; ++ ++} ++ ++ +diff --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. ++ ++ ++ Copyright (C) 19yy ++ ++ 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. ++ ++ , 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..82dca75 +--- /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.c \ ++ $(top_srcdir)/mi/miinitext.c \ ++ auth.c \ ++ cmap.c \ ++ corre.c \ ++ cursor.c \ ++ cutpaste.c \ ++ d3des.c \ ++ dispcur.c \ ++ dpmsstubs.c \ ++ draw.c \ ++ hextile.c \ ++ httpd.c \ ++ init.c \ ++ kbdptr.c \ ++ loginauth.c \ ++ rfbkeyb.c \ ++ rfbmouse.c \ ++ rfbserver.c \ ++ rre.c \ ++ sprite.c \ ++ sockets.c \ ++ stats.c \ ++ tight.c \ ++ translate.c \ ++ $(top_srcdir)/hw/dmx/vnc/vncauth.c \ ++ vncext.c \ ++ xistubs.c \ ++ zlib.c ++ ++ ++JPEG_LIBS = -ljpeg ++CRYPT_LIBS = -lcrypt ++FB_LIBS = ../../fb/.libs/libfb.a ++ ++AM_CFLAGS = $(DIX_CFLAGS) $(XVNC_CFLAGS) -I$(top_srcdir)/hw/dmx/vnc \ ++ -I$(top_srcdir)/mfb ++ ++Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) ++Xvnc_LDADD = \ ++ $(XORG_CORE_LIBS) \ ++ $(XVNC_LIBS) \ ++ $(JPEG_LIBS) \ ++ $(CRYPT_LIBS) \ ++ $(VNCMODULES_LIBS) ++ ++ ++relink: ++ rm -f Xvnc && $(MAKE) Xvnc +diff --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 ++ ++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..06b6b51 +--- /dev/null ++++ b/hw/vnc/auth.c +@@ -0,0 +1,562 @@ ++/* ++ * auth.c - deal with authentication. ++ * ++ * This file implements authentication when setting up an RFB connection. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2003-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "rfb.h" ++#include "windowstr.h" ++ ++static void rfbSendSecurityType(rfbClientPtr cl, int securityType); ++static void rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType); ++static void rfbSendTunnelingCaps(rfbClientPtr cl); ++static void rfbSendAuthCaps(rfbClientPtr cl); ++static void rfbVncAuthSendChallenge(rfbClientPtr cl); ++ ++/* ++ * rfbAuthNewClient is called right after negotiating the protocol ++ * version. Depending on the protocol version, we send either a code ++ * for authentication scheme to be used (protocol 3.3), or a list of ++ * possible "security types" (protocol 3.7). ++ */ ++ ++void ++rfbAuthNewClient(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int securityType = rfbSecTypeInvalid; ++ ++ if ((!pVNC->rfbAuthPasswdFile && !pVNC->loginAuthEnabled) || cl->reverseConnection) { ++ securityType = rfbSecTypeNone; ++ } else { ++ if (rfbAuthIsBlocked(cl)) { ++ rfbLog("Too many authentication failures - client rejected\n"); ++ rfbClientConnFailed(cl, "Too many authentication failures"); ++ return; ++ } ++ if (pVNC->rfbAuthPasswdFile) ++ securityType = rfbSecTypeVncAuth; ++ } ++ ++ if (cl->protocol_minor_ver < 7) { ++ /* Make sure we use only RFB 3.3 compatible security types. */ ++ if (securityType == rfbSecTypeInvalid) { ++ rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n"); ++ rfbClientConnFailed(cl, "Your viewer cannot handle required " ++ "authentication methods"); ++ return; ++ } ++ rfbSendSecurityType(cl, securityType); ++ } else { ++ /* Here it's ok when securityType is set to rfbSecTypeInvalid. */ ++ rfbSendSecurityTypeList(cl, securityType); ++ } ++} ++ ++ ++/* ++ * Tell the client what security type will be used (protocol 3.3). ++ */ ++ ++static void ++rfbSendSecurityType(cl, securityType) ++ rfbClientPtr cl; ++ int securityType; ++{ ++ CARD32 value32; ++ ++ /* Send the value. */ ++ value32 = Swap32IfLE(securityType); ++ if (WriteExact(cl->sock, (char *)&value32, 4) < 0) { ++ rfbLogPerror("rfbSendSecurityType: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Decide what to do next. */ ++ switch (securityType) { ++ case rfbSecTypeNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbSecTypeVncAuth: ++ /* Begin the standard VNC authentication procedure. */ ++ rfbVncAuthSendChallenge(cl); ++ break; ++ default: ++ /* Impossible case (hopefully). */ ++ rfbLogPerror("rfbSendSecurityType: assertion failed"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Advertise our supported security types (protocol 3.7). The list ++ * will include one standard security type (if primaryType is not set ++ * to rfbSecTypeInvalid), and then one more value telling the client ++ * that we support TightVNC protocol extensions. Thus, currently, ++ * there will be either 1 or 2 items in the list. ++ */ ++ ++static void ++rfbSendSecurityTypeList(cl, primaryType) ++ rfbClientPtr cl; ++ int primaryType; ++{ ++ int count = 1; ++ ++ /* Fill in the list of security types in the client structure. */ ++ if (primaryType != rfbSecTypeInvalid) { ++ cl->securityTypes[count++] = (CARD8)primaryType; ++ } ++ cl->securityTypes[count] = (CARD8)rfbSecTypeTight; ++ cl->securityTypes[0] = (CARD8)count++; ++ ++ /* Send the list. */ ++ if (WriteExact(cl->sock, (char *)cl->securityTypes, count) < 0) { ++ rfbLogPerror("rfbSendSecurityTypeList: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientSecurityType. */ ++ cl->state = RFB_SECURITY_TYPE; ++} ++ ++ ++/* ++ * Read the security type chosen by the client (protocol 3.7). ++ */ ++ ++void ++rfbProcessClientSecurityType(cl) ++ rfbClientPtr cl; ++{ ++ int n, count, i; ++ CARD8 chosenType; ++ ++ /* Read the security type. */ ++ n = ReadExact(cl->sock, (char *)&chosenType, 1); ++ if (n <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientSecurityType: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientSecurityType: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Make sure it was present in the list sent by the server. */ ++ count = (int)cl->securityTypes[0]; ++ for (i = 1; i <= count; i++) { ++ if (chosenType == cl->securityTypes[i]) ++ break; ++ } ++ if (i > count) { ++ rfbLog("rfbProcessClientSecurityType: " ++ "wrong security type requested\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Now go to the proper authentication procedure. */ ++ switch (chosenType) { ++ case rfbSecTypeNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbSecTypeVncAuth: ++ /* Begin the standard VNC authentication procedure. */ ++ rfbVncAuthSendChallenge(cl); ++ break; ++ case rfbSecTypeTight: ++ /* We are lucky: the viewer supports TightVNC extensions. */ ++ rfbLog("Enabling TightVNC protocol extensions\n"); ++ /* Switch to the protocol 3.7t. */ ++ cl->protocol_tightvnc = TRUE; ++ /* Advertise our tunneling capabilities. */ ++ rfbSendTunnelingCaps(cl); ++ break; ++ default: ++ /* Impossible case (hopefully). */ ++ rfbLog("rfbProcessClientSecurityType: " ++ "unknown authentication scheme\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Send the list of our tunneling capabilities (protocol 3.7t). ++ */ ++ ++static void ++rfbSendTunnelingCaps(cl) ++ rfbClientPtr cl; ++{ ++ rfbTunnelingCapsMsg caps; ++ CARD32 nTypes = 0; /* we don't support tunneling yet */ ++ ++ caps.nTunnelTypes = Swap32IfLE(nTypes); ++ if (WriteExact(cl->sock, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) { ++ rfbLogPerror("rfbSendTunnelingCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (nTypes) { ++ /* Dispatch client input to rfbProcessClientTunnelingType(). */ ++ cl->state = RFB_TUNNELING_TYPE; ++ } else { ++ rfbSendAuthCaps(cl); ++ } ++} ++ ++ ++/* ++ * Read tunneling type requested by the client (protocol 3.7t). ++ * NOTE: Currently, we don't support tunneling, and this function ++ * can never be called. ++ */ ++ ++void ++rfbProcessClientTunnelingType(cl) ++ rfbClientPtr cl; ++{ ++ /* If we were called, then something's really wrong. */ ++ rfbLog("rfbProcessClientTunnelingType: not implemented\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++} ++ ++ ++/* ++ * Send the list of our authentication capabilities to the client ++ * (protocol 3.7t). ++ */ ++ ++static void ++rfbSendAuthCaps(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ Bool authRequired; ++ rfbAuthenticationCapsMsg caps; ++ rfbCapabilityInfo caplist[MAX_AUTH_CAPS]; ++ int count = 0; ++ ++ authRequired = ((pVNC->rfbAuthPasswdFile != NULL || pVNC->loginAuthEnabled) && ++ !cl->reverseConnection); ++ ++ if (authRequired) { ++ if (pVNC->loginAuthEnabled) { ++ SetCapInfo(&caplist[count], rfbAuthUnixLogin, rfbTightVncVendor); ++ cl->authCaps[count++] = rfbAuthUnixLogin; ++ } ++ if (pVNC->rfbAuthPasswdFile != NULL) { ++ SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor); ++ cl->authCaps[count++] = rfbAuthVNC; ++ } ++ if (count == 0) { ++ /* Should never happen. */ ++ rfbLog("rfbSendAuthCaps: assertion failed\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ ++ cl->nAuthCaps = count; ++ caps.nAuthTypes = Swap32IfLE((CARD32)count); ++ if (WriteExact(cl->sock, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) { ++ rfbLogPerror("rfbSendAuthCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (count) { ++ if (WriteExact(cl->sock, (char *)&caplist[0], ++ count * sz_rfbCapabilityInfo) < 0) { ++ rfbLogPerror("rfbSendAuthCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ /* Dispatch client input to rfbProcessClientAuthType. */ ++ cl->state = RFB_AUTH_TYPE; ++ } else { ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ } ++} ++ ++ ++/* ++ * Read client's preferred authentication type (protocol 3.7t). ++ */ ++ ++void ++rfbProcessClientAuthType(cl) ++ rfbClientPtr cl; ++{ ++ CARD32 auth_type; ++ int n, i; ++ ++ /* Read authentication type selected by the client. */ ++ n = ReadExact(cl->sock, (char *)&auth_type, sizeof(auth_type)); ++ if (n <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientAuthType: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientAuthType: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ auth_type = Swap32IfLE(auth_type); ++ ++ /* Make sure it was present in the list sent by the server. */ ++ for (i = 0; i < cl->nAuthCaps; i++) { ++ if (auth_type == cl->authCaps[i]) ++ break; ++ } ++ if (i >= cl->nAuthCaps) { ++ rfbLog("rfbProcessClientAuthType: " ++ "wrong authentication type requested\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ switch (auth_type) { ++ case rfbAuthNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbAuthVNC: ++ rfbVncAuthSendChallenge(cl); ++ break; ++ case rfbAuthUnixLogin: ++ /* FIXME: Do (cl->state = RFB_LOGIN_AUTH) instead? */ ++ rfbLoginAuthProcessClientMessage(cl); ++ break; ++ default: ++ rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Send the authentication challenge. ++ */ ++ ++static void ++rfbVncAuthSendChallenge(cl) ++ rfbClientPtr cl; ++{ ++ vncRandomBytes(cl->authChallenge); ++ if (WriteExact(cl->sock, (char *)cl->authChallenge, CHALLENGESIZE) < 0) { ++ rfbLogPerror("rfbVncAuthSendChallenge: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbVncAuthProcessResponse. */ ++ cl->state = RFB_AUTHENTICATION; ++} ++ ++/* ++ * rfbVncAuthProcessResponse is called when the client sends its ++ * authentication response. ++ */ ++ ++void ++rfbVncAuthProcessResponse(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ char passwdFullControl[9]; ++ char passwdViewOnly[9]; ++ int numPasswords; ++ Bool ok; ++ int n; ++ CARD8 encryptedChallenge1[CHALLENGESIZE]; ++ CARD8 encryptedChallenge2[CHALLENGESIZE]; ++ CARD8 response[CHALLENGESIZE]; ++ CARD32 authResult; ++ ++ n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE); ++ if (n <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbVncAuthProcessResponse: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ numPasswords = vncDecryptPasswdFromFile2(pVNC->rfbAuthPasswdFile, ++ passwdFullControl, ++ passwdViewOnly); ++ if (numPasswords == 0) { ++ rfbLog("rfbVncAuthProcessResponse: could not get password from %s\n", ++ pVNC->rfbAuthPasswdFile); ++ ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ memcpy(encryptedChallenge1, cl->authChallenge, CHALLENGESIZE); ++ vncEncryptBytes(encryptedChallenge1, passwdFullControl); ++ memcpy(encryptedChallenge2, cl->authChallenge, CHALLENGESIZE); ++ vncEncryptBytes(encryptedChallenge2, ++ (numPasswords == 2) ? passwdViewOnly : passwdFullControl); ++ ++ /* Lose the passwords from memory */ ++ memset(passwdFullControl, 0, 9); ++ memset(passwdViewOnly, 0, 9); ++ ++ ok = FALSE; ++ if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) { ++ rfbLog("Full-control authentication passed by %s\n", cl->host); ++ ok = TRUE; ++ cl->viewOnly = FALSE; ++ } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) { ++ rfbLog("View-only authentication passed by %s\n", cl->host); ++ ok = TRUE; ++ cl->viewOnly = TRUE; ++ } ++ ++ if (!ok) { ++ rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n", ++ cl->host); ++ ++ if (rfbAuthConsiderBlocking(cl)) { ++ authResult = Swap32IfLE(rfbVncAuthTooMany); ++ } else { ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ } ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ rfbAuthUnblock(cl); ++ ++ authResult = Swap32IfLE(rfbVncAuthOK); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientInitMessage(). */ ++ cl->state = RFB_INITIALISATION; ++} ++ ++ ++/* ++ * Functions to prevent too many successive authentication failures. ++ * FIXME: This should be performed separately per each client IP. ++ */ ++ ++/* Maximum authentication failures before blocking connections */ ++#define MAX_AUTH_TRIES 5 ++ ++/* Delay in ms, doubles for each failure over MAX_AUTH_TRIES */ ++#define AUTH_TOO_MANY_BASE_DELAY 10 * 1000 ++ ++/* ++ * This function should not be called directly, it is called by ++ * setting a timer in rfbAuthConsiderBlocking(). ++ */ ++ ++static CARD32 ++rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg) ++{ ++ rfbClientPtr cl = (rfbClientPtr) arg; ++ VNCSCREENPTR(cl->pScreen); ++ pVNC->rfbAuthTooManyTries = FALSE; ++ return 0; ++} ++ ++/* ++ * This function should be called after each authentication failure. ++ * The return value will be true if there was too many failures. ++ */ ++ ++Bool ++rfbAuthConsiderBlocking(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int i; ++ ++ pVNC->rfbAuthTries++; ++ ++ if (pVNC->rfbAuthTries >= MAX_AUTH_TRIES) { ++ CARD32 delay = AUTH_TOO_MANY_BASE_DELAY; ++ for (i = MAX_AUTH_TRIES; i < pVNC->rfbAuthTries; i++) ++ delay *= 2; ++ pVNC->timer = TimerSet(pVNC->timer, 0, delay, rfbAuthReenable, NULL); ++ pVNC->rfbAuthTooManyTries = TRUE; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function should be called after successful authentication. ++ * It resets the counter of authentication failures. Note that it's ++ * not necessary to clear the rfbAuthTooManyTries flag as it will be ++ * reset by the timer function. ++ */ ++ ++void ++rfbAuthUnblock(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ pVNC->rfbAuthTries = 0; ++} ++ ++/* ++ * This function should be called before authentication process. ++ * The return value will be true if there was too many authentication ++ * failures, and the server should not allow another try. ++ */ ++ ++Bool ++rfbAuthIsBlocked(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ return pVNC->rfbAuthTooManyTries; ++} ++ +diff --git a/hw/vnc/cmap.c b/hw/vnc/cmap.c +new file mode 100644 +index 0000000..88aad12 +--- /dev/null ++++ b/hw/vnc/cmap.c +@@ -0,0 +1,163 @@ ++/* ++ * cmap.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1993 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR ++OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall ++not be used in advertising or otherwise to promote the sale, use or ++other dealings in this Software without prior written authorization ++from the X Consortium. ++ ++*/ ++ ++#include "rfb.h" ++ ++int ++rfbListInstalledColormaps(pScreen, pmaps) ++ ScreenPtr pScreen; ++ Colormap *pmaps; ++{ ++ VNCSCREENPTR(pScreen); ++ /* By the time we are processing requests, we can guarantee that there ++ * is always a colormap installed */ ++ if (pVNC->rfbInstalledColormap) ++ *pmaps = pVNC->rfbInstalledColormap->mid; ++ ++#if XFREE86VNC ++ pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps; ++ (*pScreen->ListInstalledColormaps)(pScreen, pmaps); ++ pScreen->ListInstalledColormaps = rfbListInstalledColormaps; ++#endif ++ ++ return (1); ++} ++ ++ ++void ++rfbInstallColormap(pmap) ++ ColormapPtr pmap; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ ++ if (pmap != pVNC->rfbInstalledColormap) { ++ ++ if(pVNC->rfbInstalledColormap != (ColormapPtr)None) ++ WalkTree(pmap->pScreen, TellLostMap, ++ (char *)&pVNC->rfbInstalledColormap->mid); ++ /* Install pmap */ ++ pVNC->rfbInstalledColormap = pmap; ++ WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); ++ ++ rfbSetClientColourMaps(0, 0); ++ } ++#if XFREE86VNC ++ pmap->pScreen->InstallColormap = pVNC->InstallColormap; ++ (*pmap->pScreen->InstallColormap)(pmap); ++ pmap->pScreen->InstallColormap = rfbInstallColormap; ++#endif ++} ++ ++void ++rfbUninstallColormap(pmap) ++ ColormapPtr pmap; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ ++ if(pmap == pVNC->rfbInstalledColormap) ++ { ++ if (pmap->mid != pmap->pScreen->defColormap) ++ { ++ pVNC->rfbInstalledColormap = ++ (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, ++ RT_COLORMAP); ++ (*pmap->pScreen->InstallColormap)(pVNC->rfbInstalledColormap); ++ } ++ } ++#if XFREE86VNC ++ pmap->pScreen->UninstallColormap = pVNC->UninstallColormap; ++ (*pmap->pScreen->UninstallColormap)(pmap); ++ pmap->pScreen->UninstallColormap = rfbUninstallColormap; ++#endif ++} ++ ++ ++/* ++ * rfbStoreColors. We have a set of pixels but they may be in any order. ++ * If some of them happen to be in continuous ascending order then we can ++ * group them together into a single call to rfbSetClientColourMaps. ++ */ ++ ++void ++rfbStoreColors(pmap, ndef, pdefs) ++ ColormapPtr pmap; ++ int ndef; ++ xColorItem *pdefs; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ int i; ++ int first = -1; ++ int n = 0; ++ ++ if (pmap == pVNC->rfbInstalledColormap) { ++ for (i = 0; i < ndef; i++) { ++ if ((first != -1) && (first + n == pdefs[i].pixel)) { ++ n++; ++ } else { ++ if (first != -1) { ++ rfbSetClientColourMaps(first, n); ++ } ++ first = pdefs[i].pixel; ++ n = 1; ++ } ++ } ++ rfbSetClientColourMaps(first, n); ++ } ++#if XFREE86VNC ++ pmap->pScreen->StoreColors = pVNC->StoreColors; ++ (*pmap->pScreen->StoreColors)(pmap, ndef, pdefs); ++ pmap->pScreen->StoreColors = rfbStoreColors; ++#endif ++} +diff --git a/hw/vnc/corre.c b/hw/vnc/corre.c +new file mode 100644 +index 0000000..f5da8bb +--- /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 ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++ ++/* ++ * rreBeforeBuf contains pixel data in the client's format. ++ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is ++ * larger than the raw data or if it exceeds rreAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int rreBeforeBufSize = 0; ++static char *rreBeforeBuf = NULL; ++ ++static int rreAfterBufSize = 0; ++static char *rreAfterBuf = NULL; ++static int rreAfterBufLen; ++ ++static int subrectEncode8(CARD8 *data, int w, int h); ++static int subrectEncode16(CARD16 *data, int w, int h); ++static int subrectEncode32(CARD32 *data, int w, int h); ++static CARD32 getBgColour(char *data, int size, int bpp); ++static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y, ++ int w, int h); ++ ++ ++/* ++ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE ++ * encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingCoRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ if (h > cl->correMaxHeight) { ++ return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) && ++ rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, ++ w, h - cl->correMaxHeight)); ++ } ++ ++ if (w > cl->correMaxWidth) { ++ return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) && ++ rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y, ++ w - cl->correMaxWidth, h)); ++ } ++ ++ return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h); ++} ++ ++ ++ ++/* ++ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256) ++ * rectangle using CoRRE encoding. ++ */ ++ ++static Bool ++rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbRREHeader hdr; ++ int nSubrects; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (rreBeforeBufSize < maxRawSize) { ++ rreBeforeBufSize = maxRawSize; ++ if (rreBeforeBuf == NULL) ++ rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); ++ else ++ rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); ++ } ++ ++ if (rreAfterBufSize < maxRawSize) { ++ rreAfterBufSize = maxRawSize; ++ if (rreAfterBuf == NULL) ++ rreAfterBuf = (char *)xalloc(rreAfterBufSize); ++ else ++ rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); ++ } ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, rreBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); ++ break; ++ case 16: ++ nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); ++ break; ++ case 32: ++ nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); ++ break; ++ default: ++ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); ++ exit(1); ++ } ++ ++ if (nSubrects < 0) { ++ ++ /* RRE encoding was too large, use raw */ ++ ++ return rfbSendRectEncodingRaw(cl, x, y, w, h); ++ } ++ ++ cl->rfbRectanglesSent[rfbEncodingCoRRE]++; ++ cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbRREHeader + rreAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingCoRRE); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nSubrects = Swap32IfLE(nSubrects); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader); ++ pVNC->ublen += sz_rfbRREHeader; ++ ++ for (i = 0; i < rreAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > rreAfterBufLen) { ++ bytesToCopy = rreAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * subrectEncode() encodes the given multicoloured rectangle as a background ++ * colour overwritten by single-coloured rectangles. It returns the number ++ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't ++ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The ++ * single-colour rectangle partition is not optimal, but does find the biggest ++ * horizontal or vertical rectangle top-left anchored to each consecutive ++ * coordinate position. ++ * ++ * The coding scheme is simply [...] where each ++ * is []. ++ */ ++ ++#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 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) { ++ 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..d25109c +--- /dev/null ++++ b/hw/vnc/cursor.c +@@ -0,0 +1,404 @@ ++/* ++ * cursor.c - support for cursor shape updates. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++#include "mipointer.h" ++#include "sprite.h" ++#include "cursorstr.h" ++#include "servermd.h" ++ ++ ++/* Copied from Xvnc/lib/font/util/utilbitmap.c */ ++static unsigned char _reverse_byte[0x100] = { ++ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, ++ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, ++ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, ++ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, ++ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, ++ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, ++ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, ++ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, ++ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, ++ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, ++ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, ++ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, ++ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, ++ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, ++ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, ++ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, ++ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, ++ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, ++ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, ++ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, ++ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, ++ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, ++ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, ++ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, ++ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, ++ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, ++ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, ++ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, ++ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, ++ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, ++ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, ++ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff ++}; ++ ++ ++static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++static int EncodeRichCursorData16 (ScreenPtr pScreen, ++ char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++static int EncodeRichCursorData32 (ScreenPtr pScreen, ++ char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++ ++ ++/* ++ * Send cursor shape either in X-style format or in client pixel format. ++ */ ++ ++Bool ++rfbSendCursorShape(cl, pScreen) ++ rfbClientPtr cl; ++ ScreenPtr pScreen; ++{ ++ VNCSCREENPTR(pScreen); ++ CursorPtr pCursor; ++ rfbFramebufferUpdateRectHeader rect; ++ rfbXCursorColors colors; ++ int saved_ublen; ++ int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes; ++ int i, j; ++ CARD8 *bitmapData; ++ CARD8 bitmapByte; ++ ++ if (cl->useRichCursorEncoding) { ++ rect.encoding = Swap32IfLE(rfbEncodingRichCursor); ++ } else { ++ rect.encoding = Swap32IfLE(rfbEncodingXCursor); ++ } ++ ++#if XFREE86VNC ++ pCursor = pVNC->pCurs; ++#else ++ pCursor = rfbSpriteGetCursorPtr(pScreen); ++#endif ++ ++ /* If there is no cursor, send update with empty cursor data. */ ++ ++ if ( pCursor != NULL && ++ pCursor->bits->width == 1 && ++ pCursor->bits->height == 1 && ++ pCursor->bits->mask[0] == 0 ) { ++ pCursor = NULL; ++ } ++ ++ if (pCursor == NULL) { ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ rect.r.x = rect.r.y = 0; ++ rect.r.w = rect.r.h = 0; ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ cl->rfbCursorShapeUpdatesSent++; ++ ++ return TRUE; ++ } ++ ++ /* Calculate data sizes. */ ++ ++ bitmapRowBytes = (pCursor->bits->width + 7) / 8; ++ paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1); ++ maskBytes = bitmapRowBytes * pCursor->bits->height; ++ dataBytes = (cl->useRichCursorEncoding) ? ++ (pCursor->bits->width * pCursor->bits->height * ++ (cl->format.bitsPerPixel / 8)) : maskBytes; ++ ++ /* Send buffer contents if needed. */ ++ ++ if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + ++ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + ++ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { ++ return FALSE; /* FIXME. */ ++ } ++ ++ saved_ublen = pVNC->ublen; ++ ++ /* Prepare rectangle header. */ ++ ++ rect.r.x = Swap16IfLE(pCursor->bits->xhot); ++ rect.r.y = Swap16IfLE(pCursor->bits->yhot); ++ rect.r.w = Swap16IfLE(pCursor->bits->width); ++ rect.r.h = Swap16IfLE(pCursor->bits->height); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ /* Prepare actual cursor data (depends on encoding used). */ ++ ++ if (!cl->useRichCursorEncoding) { ++ /* XCursor encoding. */ ++ colors.foreRed = (char)(pCursor->foreRed >> 8); ++ colors.foreGreen = (char)(pCursor->foreGreen >> 8); ++ colors.foreBlue = (char)(pCursor->foreBlue >> 8); ++ colors.backRed = (char)(pCursor->backRed >> 8); ++ colors.backGreen = (char)(pCursor->backGreen >> 8); ++ colors.backBlue = (char)(pCursor->backBlue >> 8); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&colors, sz_rfbXCursorColors); ++ pVNC->ublen += sz_rfbXCursorColors; ++ ++ bitmapData = (CARD8 *)pCursor->bits->source; ++ ++ for (i = 0; i < pCursor->bits->height; i++) { ++ for (j = 0; j < bitmapRowBytes; j++) { ++ bitmapByte = bitmapData[i * paddedRowBytes + j]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte; ++ } ++ } ++ } else { ++ /* RichCursor encoding. */ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ pVNC->ublen += EncodeRichCursorData8(&pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ case 16: ++ pVNC->ublen += EncodeRichCursorData16(pScreen, &pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ case 32: ++ pVNC->ublen += EncodeRichCursorData32(pScreen, &pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ default: ++ return FALSE; ++ } ++ } ++ ++ /* Prepare transparency mask. */ ++ ++ bitmapData = (CARD8 *)pCursor->bits->mask; ++ ++ for (i = 0; i < pCursor->bits->height; i++) { ++ for (j = 0; j < bitmapRowBytes; j++) { ++ bitmapByte = bitmapData[i * paddedRowBytes + j]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte; ++ } ++ } ++ ++ /* Update statistics. */ ++ ++ cl->rfbCursorShapeBytesSent += (pVNC->ublen - saved_ublen); ++ cl->rfbCursorShapeUpdatesSent++; ++ ++ return TRUE; ++} ++ ++/* ++ * Send cursor position (PointerPos pseudo-encoding). ++ */ ++Bool ++rfbSendCursorPos(cl, pScreen) ++ rfbClientPtr cl; ++ ScreenPtr pScreen; ++{ ++ VNCSCREENPTR(pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++#if XFREE86VNC ++ ScreenPtr pCursorScreen = miPointerCurrentScreen(); ++#endif ++ int x, y; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++#if XFREE86VNC ++ if (pScreen == pCursorScreen) ++ miPointerPosition(&x, &y); ++#else ++ rfbSpriteGetCursorPos(pScreen, &x, &y); ++#endif ++ ++ rect.encoding = Swap32IfLE(rfbEncodingPointerPos); ++ rect.r.x = Swap16IfLE((CARD16)x); ++ rect.r.y = Swap16IfLE((CARD16)y); ++ rect.r.w = 0; ++ rect.r.h = 0; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ cl->rfbCursorPosUpdatesSent++; ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ cl->cursorX = x; ++ cl->cursorY = y; ++ ++ return TRUE; ++} ++ ++/* ++ * Code to convert cursor source bitmap to the desired pixel format. ++ */ ++ ++#define RGB48_TO_PIXEL(fmt,r,g,b) \ ++ (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift | \ ++ ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift | \ ++ ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift) ++ ++static int ++EncodeRichCursorData8(buf, fmt, pCursor) ++ char *buf; ++ rfbPixelFormat *fmt; ++ CursorPtr pCursor; ++{ ++ int widthPixels, widthBytes; ++ int x, y, b; ++ CARD8 *src; ++ char pix[2]; ++ CARD8 bitmapByte; ++ ++ pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen, ++ pCursor->backBlue); ++ pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen, ++ pCursor->foreBlue); ++ ++ src = (CARD8 *)pCursor->bits->source; ++ widthPixels = pCursor->bits->width; ++ widthBytes = PixmapBytePad(widthPixels, 1); ++ ++ for (y = 0; y < pCursor->bits->height; y++) { ++ for (x = 0; x < widthPixels / 8; x++) { ++ bitmapByte = src[y * widthBytes + x]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ for (b = 7; b >= 0; b--) { ++ *buf++ = pix[bitmapByte >> b & 1]; ++ } ++ } ++ if (widthPixels % 8) { ++ bitmapByte = src[y * widthBytes + x]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ for (b = 7; b > 7 - widthPixels % 8; b--) { ++ *buf++ = pix[bitmapByte >> b & 1]; ++ } ++ } ++ } ++ ++ return (widthPixels * pCursor->bits->height); ++} ++ ++#define DEFINE_RICH_ENCODE(bpp) \ ++ \ ++static int \ ++EncodeRichCursorData##bpp(pScreen, buf, fmt, pCursor) \ ++ ScreenPtr pScreen; \ ++ char *buf; \ ++ rfbPixelFormat *fmt; \ ++ CursorPtr pCursor; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ int widthPixels, widthBytes; \ ++ int x, y, b; \ ++ CARD8 *src; \ ++ CARD##bpp pix[2]; \ ++ CARD8 bitmapByte; \ ++ \ ++ pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed, \ ++ pCursor->backGreen, \ ++ pCursor->backBlue); \ ++ pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed, \ ++ pCursor->foreGreen, \ ++ pCursor->foreBlue); \ ++ if (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian) { \ ++ pix[0] = Swap##bpp(pix[0]); \ ++ pix[1] = Swap##bpp(pix[1]); \ ++ } \ ++ \ ++ src = (CARD8 *)pCursor->bits->source; \ ++ widthPixels = pCursor->bits->width; \ ++ widthBytes = PixmapBytePad(widthPixels, 1); \ ++ \ ++ for (y = 0; y < pCursor->bits->height; y++) { \ ++ for (x = 0; x < widthPixels / 8; x++) { \ ++ bitmapByte = src[y * widthBytes + x]; \ ++ if (screenInfo.bitmapBitOrder == LSBFirst) { \ ++ bitmapByte = _reverse_byte[bitmapByte]; \ ++ } \ ++ for (b = 7; b >= 0; b--) { \ ++ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ ++ sizeof(CARD##bpp)); \ ++ buf += sizeof(CARD##bpp); \ ++ } \ ++ } \ ++ if (widthPixels % 8) { \ ++ bitmapByte = src[y * widthBytes + x]; \ ++ if (screenInfo.bitmapBitOrder == LSBFirst) { \ ++ bitmapByte = _reverse_byte[bitmapByte]; \ ++ } \ ++ for (b = 7; b > 7 - widthPixels % 8; b--) { \ ++ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ ++ sizeof(CARD##bpp)); \ ++ buf += sizeof(CARD##bpp); \ ++ } \ ++ } \ ++ } \ ++ \ ++ return (widthPixels * pCursor->bits->height * (bpp / 8)); \ ++} ++ ++DEFINE_RICH_ENCODE(16) ++DEFINE_RICH_ENCODE(32) ++ +diff --git a/hw/vnc/cutpaste.c b/hw/vnc/cutpaste.c +new file mode 100644 +index 0000000..13aebbb +--- /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 ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#define NEED_EVENTS ++#include ++#include ++#include ++#include "rfb.h" ++#include "selection.h" ++#include "input.h" ++ ++extern Selection *CurrentSelections; ++extern int NumCurrentSelections; ++ ++ ++static Bool inSetXCutText = FALSE; ++ ++/* ++ * rfbSetXCutText sets the cut buffer to be the given string. We also clear ++ * the primary selection. Ideally we'd like to set it to the same thing, but I ++ * can't work out how to do that without some kind of helper X client. ++ */ ++ ++void ++rfbSetXCutText(char *str, int len) ++{ ++ int i = 0; ++ ++ inSetXCutText = TRUE; ++ ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING, ++ 8, PropModeReplace, len, ++ (pointer)str, TRUE); ++ ++ while ((i < NumCurrentSelections) && ++ CurrentSelections[i].selection != XA_PRIMARY) ++ i++; ++ ++ if (i < NumCurrentSelections) { ++ xEvent event; ++ ++ if (CurrentSelections[i].client) { ++ event.u.u.type = SelectionClear; ++ event.u.selectionClear.time = GetTimeInMillis(); ++ event.u.selectionClear.window = CurrentSelections[i].window; ++ event.u.selectionClear.atom = CurrentSelections[i].selection; ++ (void) TryClientEvents (CurrentSelections[i].client, &event, 1, ++ NoEventMask, NoEventMask /* CantBeFiltered */, ++ NullGrab); ++ } ++ ++ CurrentSelections[i].window = None; ++ CurrentSelections[i].pWin = NULL; ++ CurrentSelections[i].client = NullClient; ++ } ++ ++ inSetXCutText = FALSE; ++} ++ ++ ++void rfbGotXCutText(char *str, int len) ++{ ++ if (!inSetXCutText) ++ rfbSendServerCutText(str, len); ++} +diff --git a/hw/vnc/d3des.c b/hw/vnc/d3des.c +new file mode 100644 +index 0000000..9227ddd +--- /dev/null ++++ b/hw/vnc/d3des.c +@@ -0,0 +1,434 @@ ++/* ++ * This is D3DES (V5.09) by Richard Outerbridge with the double and ++ * triple-length support removed for use in VNC. Also the bytebit[] array ++ * has been reversed so that the most significant bit in each byte of the ++ * key is ignored, not the least significant. ++ * ++ * These changes are: ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++/* D3DES (V5.09) - ++ * ++ * A portable, public domain, version of the Data Encryption Standard. ++ * ++ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. ++ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation ++ * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis ++ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, ++ * for humouring me on. ++ * ++ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. ++ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. ++ */ ++ ++#include "d3des.h" ++ ++static void scrunch(unsigned char *, unsigned long *); ++static void unscrun(unsigned long *, unsigned char *); ++static void desfunc(unsigned long *, unsigned long *); ++static void cookey(unsigned long *); ++ ++static unsigned long KnL[32] = { 0L }; ++ ++static unsigned short bytebit[8] = { ++ 01, 02, 04, 010, 020, 040, 0100, 0200 }; ++ ++static unsigned long bigbyte[24] = { ++ 0x800000L, 0x400000L, 0x200000L, 0x100000L, ++ 0x80000L, 0x40000L, 0x20000L, 0x10000L, ++ 0x8000L, 0x4000L, 0x2000L, 0x1000L, ++ 0x800L, 0x400L, 0x200L, 0x100L, ++ 0x80L, 0x40L, 0x20L, 0x10L, ++ 0x8L, 0x4L, 0x2L, 0x1L }; ++ ++/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ ++ ++static unsigned char pc1[56] = { ++ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, ++ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, ++ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, ++ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; ++ ++static unsigned char totrot[16] = { ++ 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; ++ ++static unsigned char pc2[48] = { ++ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, ++ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, ++ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, ++ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; ++ ++void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */ ++unsigned char *key; ++int edf; ++{ ++ register int i, j, l, m, n; ++ unsigned char pc1m[56], pcr[56]; ++ unsigned long kn[32]; ++ ++ for ( j = 0; j < 56; j++ ) { ++ l = pc1[j]; ++ m = l & 07; ++ pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; ++ } ++ for( i = 0; i < 16; i++ ) { ++ if( edf == DE1 ) m = (15 - i) << 1; ++ else m = i << 1; ++ n = m + 1; ++ kn[m] = kn[n] = 0L; ++ for( j = 0; j < 28; j++ ) { ++ l = j + totrot[i]; ++ if( l < 28 ) pcr[j] = pc1m[l]; ++ else pcr[j] = pc1m[l - 28]; ++ } ++ for( j = 28; j < 56; j++ ) { ++ l = j + totrot[i]; ++ if( l < 56 ) pcr[j] = pc1m[l]; ++ else pcr[j] = pc1m[l - 28]; ++ } ++ for( j = 0; j < 24; j++ ) { ++ if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; ++ if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; ++ } ++ } ++ cookey(kn); ++ return; ++ } ++ ++static void cookey(raw1) ++register unsigned long *raw1; ++{ ++ register unsigned long *cook, *raw0; ++ unsigned long dough[32]; ++ register int i; ++ ++ cook = dough; ++ for( i = 0; i < 16; i++, raw1++ ) { ++ raw0 = raw1++; ++ *cook = (*raw0 & 0x00fc0000L) << 6; ++ *cook |= (*raw0 & 0x00000fc0L) << 10; ++ *cook |= (*raw1 & 0x00fc0000L) >> 10; ++ *cook++ |= (*raw1 & 0x00000fc0L) >> 6; ++ *cook = (*raw0 & 0x0003f000L) << 12; ++ *cook |= (*raw0 & 0x0000003fL) << 16; ++ *cook |= (*raw1 & 0x0003f000L) >> 4; ++ *cook++ |= (*raw1 & 0x0000003fL); ++ } ++ usekey(dough); ++ return; ++ } ++ ++void cpkey(into) ++register unsigned long *into; ++{ ++ register unsigned long *from, *endp; ++ ++ from = KnL, endp = &KnL[32]; ++ while( from < endp ) *into++ = *from++; ++ return; ++ } ++ ++void usekey(from) ++register unsigned long *from; ++{ ++ register unsigned long *to, *endp; ++ ++ to = KnL, endp = &KnL[32]; ++ while( to < endp ) *to++ = *from++; ++ return; ++ } ++ ++void des(inblock, outblock) ++unsigned char *inblock, *outblock; ++{ ++ unsigned long work[2]; ++ ++ scrunch(inblock, work); ++ desfunc(work, KnL); ++ unscrun(work, outblock); ++ return; ++ } ++ ++static void scrunch(outof, into) ++register unsigned char *outof; ++register unsigned long *into; ++{ ++ *into = (*outof++ & 0xffL) << 24; ++ *into |= (*outof++ & 0xffL) << 16; ++ *into |= (*outof++ & 0xffL) << 8; ++ *into++ |= (*outof++ & 0xffL); ++ *into = (*outof++ & 0xffL) << 24; ++ *into |= (*outof++ & 0xffL) << 16; ++ *into |= (*outof++ & 0xffL) << 8; ++ *into |= (*outof & 0xffL); ++ return; ++ } ++ ++static void unscrun(outof, into) ++register unsigned long *outof; ++register unsigned char *into; ++{ ++ *into++ = (*outof >> 24) & 0xffL; ++ *into++ = (*outof >> 16) & 0xffL; ++ *into++ = (*outof >> 8) & 0xffL; ++ *into++ = *outof++ & 0xffL; ++ *into++ = (*outof >> 24) & 0xffL; ++ *into++ = (*outof >> 16) & 0xffL; ++ *into++ = (*outof >> 8) & 0xffL; ++ *into = *outof & 0xffL; ++ return; ++ } ++ ++static unsigned long SP1[64] = { ++ 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, ++ 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, ++ 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, ++ 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, ++ 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, ++ 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, ++ 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, ++ 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, ++ 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, ++ 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, ++ 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, ++ 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, ++ 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, ++ 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, ++ 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, ++ 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; ++ ++static unsigned long SP2[64] = { ++ 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, ++ 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, ++ 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, ++ 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, ++ 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, ++ 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, ++ 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, ++ 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, ++ 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, ++ 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, ++ 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, ++ 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, ++ 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, ++ 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, ++ 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, ++ 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; ++ ++static unsigned long SP3[64] = { ++ 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, ++ 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, ++ 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, ++ 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, ++ 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, ++ 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, ++ 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, ++ 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, ++ 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, ++ 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, ++ 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, ++ 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, ++ 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, ++ 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, ++ 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, ++ 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; ++ ++static unsigned long SP4[64] = { ++ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, ++ 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, ++ 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, ++ 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, ++ 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, ++ 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, ++ 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, ++ 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, ++ 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, ++ 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, ++ 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, ++ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, ++ 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, ++ 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, ++ 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, ++ 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; ++ ++static unsigned long SP5[64] = { ++ 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, ++ 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, ++ 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, ++ 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, ++ 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, ++ 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, ++ 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, ++ 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, ++ 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, ++ 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, ++ 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, ++ 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, ++ 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, ++ 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, ++ 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, ++ 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; ++ ++static unsigned long SP6[64] = { ++ 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, ++ 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, ++ 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, ++ 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, ++ 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, ++ 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, ++ 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, ++ 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, ++ 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, ++ 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, ++ 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, ++ 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, ++ 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, ++ 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, ++ 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, ++ 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; ++ ++static unsigned long SP7[64] = { ++ 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, ++ 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, ++ 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, ++ 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, ++ 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, ++ 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, ++ 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, ++ 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, ++ 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, ++ 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, ++ 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, ++ 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, ++ 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, ++ 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, ++ 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, ++ 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; ++ ++static unsigned long SP8[64] = { ++ 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, ++ 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, ++ 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, ++ 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, ++ 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, ++ 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, ++ 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, ++ 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, ++ 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, ++ 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, ++ 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, ++ 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, ++ 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, ++ 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, ++ 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, ++ 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; ++ ++static void desfunc(block, keys) ++register unsigned long *block, *keys; ++{ ++ register unsigned long fval, work, right, leftt; ++ register int round; ++ ++ leftt = block[0]; ++ right = block[1]; ++ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; ++ right ^= work; ++ leftt ^= (work << 4); ++ work = ((leftt >> 16) ^ right) & 0x0000ffffL; ++ right ^= work; ++ leftt ^= (work << 16); ++ work = ((right >> 2) ^ leftt) & 0x33333333L; ++ leftt ^= work; ++ right ^= (work << 2); ++ work = ((right >> 8) ^ leftt) & 0x00ff00ffL; ++ leftt ^= work; ++ right ^= (work << 8); ++ right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; ++ work = (leftt ^ right) & 0xaaaaaaaaL; ++ leftt ^= work; ++ right ^= work; ++ leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; ++ ++ for( round = 0; round < 8; round++ ) { ++ work = (right << 28) | (right >> 4); ++ work ^= *keys++; ++ fval = SP7[ work & 0x3fL]; ++ fval |= SP5[(work >> 8) & 0x3fL]; ++ fval |= SP3[(work >> 16) & 0x3fL]; ++ fval |= SP1[(work >> 24) & 0x3fL]; ++ work = right ^ *keys++; ++ fval |= SP8[ work & 0x3fL]; ++ fval |= SP6[(work >> 8) & 0x3fL]; ++ fval |= SP4[(work >> 16) & 0x3fL]; ++ fval |= SP2[(work >> 24) & 0x3fL]; ++ leftt ^= fval; ++ work = (leftt << 28) | (leftt >> 4); ++ work ^= *keys++; ++ fval = SP7[ work & 0x3fL]; ++ fval |= SP5[(work >> 8) & 0x3fL]; ++ fval |= SP3[(work >> 16) & 0x3fL]; ++ fval |= SP1[(work >> 24) & 0x3fL]; ++ work = leftt ^ *keys++; ++ fval |= SP8[ work & 0x3fL]; ++ fval |= SP6[(work >> 8) & 0x3fL]; ++ fval |= SP4[(work >> 16) & 0x3fL]; ++ fval |= SP2[(work >> 24) & 0x3fL]; ++ right ^= fval; ++ } ++ ++ right = (right << 31) | (right >> 1); ++ work = (leftt ^ right) & 0xaaaaaaaaL; ++ leftt ^= work; ++ right ^= work; ++ leftt = (leftt << 31) | (leftt >> 1); ++ work = ((leftt >> 8) ^ right) & 0x00ff00ffL; ++ right ^= work; ++ leftt ^= (work << 8); ++ work = ((leftt >> 2) ^ right) & 0x33333333L; ++ right ^= work; ++ leftt ^= (work << 2); ++ work = ((right >> 16) ^ leftt) & 0x0000ffffL; ++ leftt ^= work; ++ right ^= (work << 16); ++ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; ++ leftt ^= work; ++ right ^= (work << 4); ++ *block++ = right; ++ *block = leftt; ++ return; ++ } ++ ++/* Validation sets: ++ * ++ * Single-length key, single-length plaintext - ++ * Key : 0123 4567 89ab cdef ++ * Plain : 0123 4567 89ab cde7 ++ * Cipher : c957 4425 6a5e d31d ++ * ++ * Double-length key, single-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 ++ * Plain : 0123 4567 89ab cde7 ++ * Cipher : 7f1d 0a77 826b 8aff ++ * ++ * Double-length key, double-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 ++ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff ++ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 ++ * ++ * Triple-length key, single-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 ++ * Plain : 0123 4567 89ab cde7 ++ * Cipher : de0b 7c06 ae5e 0ed5 ++ * ++ * Triple-length key, double-length plaintext - ++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 ++ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff ++ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 ++ * ++ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery ++ **********************************************************************/ +diff --git a/hw/vnc/dispcur.c b/hw/vnc/dispcur.c +new file mode 100644 +index 0000000..b278ed2 +--- /dev/null ++++ b/hw/vnc/dispcur.c +@@ -0,0 +1,804 @@ ++/* ++ * dispcur.c ++ * ++ * cursor display routines - based on midispcur.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#if HAVE_DIX_CONFIG_H ++#include "dix-config.h" ++#endif ++ ++#define NEED_EVENTS ++# include ++# include "misc.h" ++# include "input.h" ++# include "cursorstr.h" ++# include "windowstr.h" ++# include "regionstr.h" ++# include "dixstruct.h" ++# include "scrnintstr.h" ++# include "servermd.h" ++# include "mipointer.h" ++# include "sprite.h" ++# include "gcstruct.h" ++ ++#ifdef ARGB_CURSOR ++# include "picturestr.h" ++#endif ++ ++/* per-screen private data */ ++ ++static int rfbDCScreenIndex; ++static unsigned long rfbDCGeneration = 0; ++ ++static Bool rfbDCCloseScreen(int index, ScreenPtr pScreen); ++ ++typedef struct { ++ GCPtr pSourceGC, pMaskGC; ++ GCPtr pSaveGC, pRestoreGC; ++ GCPtr pMoveGC; ++ GCPtr pPixSourceGC, pPixMaskGC; ++ CloseScreenProcPtr CloseScreen; ++ PixmapPtr pSave, pTemp; ++#ifdef ARGB_CURSOR ++ PicturePtr pRootPicture; ++ PicturePtr pTempPicture; ++#endif ++} rfbDCScreenRec, *rfbDCScreenPtr; ++ ++/* per-cursor per-screen private data */ ++typedef struct { ++ PixmapPtr sourceBits; /* source bits */ ++ PixmapPtr maskBits; /* mask bits */ ++#ifdef ARGB_CURSOR ++ PicturePtr pPicture; ++#endif ++} rfbDCCursorRec, *rfbDCCursorPtr; ++ ++/* ++ * sprite/cursor method table ++ */ ++ ++static Bool rfbDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); ++static Bool rfbDCUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); ++static Bool rfbDCPutUpCursor(ScreenPtr pScreen, CursorPtr pCursor, ++ int x, int y, unsigned long source, ++ unsigned long mask); ++static Bool rfbDCSaveUnderCursor(ScreenPtr pScreen, int x, int y, ++ int w, int h); ++static Bool rfbDCRestoreUnderCursor(ScreenPtr pScreen, int x, int y, ++ int w, int h); ++static Bool rfbDCMoveCursor(ScreenPtr pScreen, CursorPtr pCursor, ++ int x, int y, int w, int h, int dx, int dy, ++ unsigned long source, unsigned long mask); ++static Bool rfbDCChangeSave(ScreenPtr pScreen, int x, int y, int w, int h, ++ int dx, int dy); ++ ++static rfbSpriteCursorFuncRec rfbDCFuncs = { ++ rfbDCRealizeCursor, ++ rfbDCUnrealizeCursor, ++ rfbDCPutUpCursor, ++ rfbDCSaveUnderCursor, ++ rfbDCRestoreUnderCursor, ++ rfbDCMoveCursor, ++ rfbDCChangeSave, ++}; ++ ++Bool ++rfbDCInitialize (pScreen, screenFuncs) ++ ScreenPtr pScreen; ++ miPointerScreenFuncPtr screenFuncs; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ ++ if (rfbDCGeneration != serverGeneration) ++ { ++ rfbDCScreenIndex = AllocateScreenPrivateIndex (); ++ if (rfbDCScreenIndex < 0) ++ return FALSE; ++ rfbDCGeneration = serverGeneration; ++ } ++ pScreenPriv = (rfbDCScreenPtr) xalloc (sizeof (rfbDCScreenRec)); ++ if (!pScreenPriv) ++ return FALSE; ++ ++ /* ++ * initialize the entire private structure to zeros ++ */ ++ ++ pScreenPriv->pSourceGC = ++ pScreenPriv->pMaskGC = ++ pScreenPriv->pSaveGC = ++ pScreenPriv->pRestoreGC = ++ pScreenPriv->pMoveGC = ++ pScreenPriv->pPixSourceGC = ++ pScreenPriv->pPixMaskGC = NULL; ++#ifdef ARGB_CURSOR ++ pScreenPriv->pRootPicture = NULL; ++ pScreenPriv->pTempPicture = NULL; ++#endif ++ ++ pScreenPriv->pSave = pScreenPriv->pTemp = NULL; ++ ++ pScreenPriv->CloseScreen = pScreen->CloseScreen; ++ pScreen->CloseScreen = rfbDCCloseScreen; ++ ++ pScreen->devPrivates[rfbDCScreenIndex].ptr = (pointer) pScreenPriv; ++ ++ if (!rfbSpriteInitialize (pScreen, &rfbDCFuncs, screenFuncs)) ++ { ++ xfree ((pointer) pScreenPriv); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++#define tossGC(gc) (gc ? FreeGC (gc, (GContext) 0) : 0) ++#define tossPix(pix) (pix ? (*pScreen->DestroyPixmap) (pix) : TRUE) ++#define tossPict(pict) (pict ? FreePicture (pict, 0) : 0) ++ ++static Bool ++rfbDCCloseScreen (index, pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pScreen->CloseScreen = pScreenPriv->CloseScreen; ++ tossGC (pScreenPriv->pSourceGC); ++ tossGC (pScreenPriv->pMaskGC); ++ tossGC (pScreenPriv->pSaveGC); ++ tossGC (pScreenPriv->pRestoreGC); ++ tossGC (pScreenPriv->pMoveGC); ++ tossGC (pScreenPriv->pPixSourceGC); ++ tossGC (pScreenPriv->pPixMaskGC); ++ tossPix (pScreenPriv->pSave); ++ tossPix (pScreenPriv->pTemp); ++#ifdef ARGB_CURSOR ++ tossPict (pScreenPriv->pRootPicture); ++ tossPict (pScreenPriv->pTempPicture); ++#endif ++ xfree ((pointer) pScreenPriv); ++ return (*pScreen->CloseScreen) (index, pScreen); ++} ++ ++static Bool ++rfbDCRealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ if (pCursor->bits->refcnt <= 1) ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; ++ return TRUE; ++} ++ ++#ifdef ARGB_CURSOR ++#define EnsurePicture(picture,draw,win) (picture || rfbDCMakePicture(&picture,draw,win)) ++ ++static VisualPtr ++rfbDCGetWindowVisual (WindowPtr pWin) ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ VisualID vid = wVisual (pWin); ++ int i; ++ ++ for (i = 0; i < pScreen->numVisuals; i++) ++ if (pScreen->visuals[i].vid == vid) ++ return &pScreen->visuals[i]; ++ return 0; ++} ++ ++static PicturePtr ++rfbDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) ++{ ++ ScreenPtr pScreen = pDraw->pScreen; ++ VisualPtr pVisual; ++ PictFormatPtr pFormat; ++ XID subwindow_mode = IncludeInferiors; ++ PicturePtr pPicture; ++ int error; ++ ++ pVisual = rfbDCGetWindowVisual (pWin); ++ if (!pVisual) ++ return 0; ++ pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); ++ if (!pFormat) ++ return 0; ++ pPicture = CreatePicture (0, pDraw, pFormat, ++ CPSubwindowMode, &subwindow_mode, ++ serverClient, &error); ++ *ppPicture = pPicture; ++ return pPicture; ++} ++#endif ++ ++static rfbDCCursorPtr ++rfbDCRealize (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbDCCursorPtr pPriv; ++ GCPtr pGC; ++ XID gcvals[3]; ++ ++ pPriv = (rfbDCCursorPtr) xalloc (sizeof (rfbDCCursorRec)); ++ if (!pPriv) ++ return (rfbDCCursorPtr)NULL; ++#ifdef ARGB_CURSOR ++ if (pCursor->bits->argb) ++ { ++ PixmapPtr pPixmap; ++ PictFormatPtr pFormat; ++ int error; ++ ++ pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); ++ if (!pFormat) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ ++ pPriv->sourceBits = 0; ++ pPriv->maskBits = 0; ++ pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, ++ pCursor->bits->height, 32); ++ if (!pPixmap) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pGC = GetScratchGC (32, pScreen); ++ if (!pGC) ++ { ++ (*pScreen->DestroyPixmap) (pPixmap); ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ ValidateGC (&pPixmap->drawable, pGC); ++ (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, ++ 0, 0, pCursor->bits->width, ++ pCursor->bits->height, ++ 0, ZPixmap, (char *) pCursor->bits->argb); ++ FreeScratchGC (pGC); ++ pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, ++ pFormat, 0, 0, serverClient, &error); ++ (*pScreen->DestroyPixmap) (pPixmap); ++ if (!pPriv->pPicture) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; ++ return pPriv; ++ } ++ pPriv->pPicture = 0; ++#endif ++ pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); ++ if (!pPriv->sourceBits) ++ { ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); ++ if (!pPriv->maskBits) ++ { ++ (*pScreen->DestroyPixmap) (pPriv->sourceBits); ++ xfree ((pointer) pPriv); ++ return (rfbDCCursorPtr)NULL; ++ } ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; ++ ++ /* create the two sets of bits, clipping as appropriate */ ++ ++ pGC = GetScratchGC (1, pScreen); ++ if (!pGC) ++ { ++ (void) rfbDCUnrealizeCursor (pScreen, pCursor); ++ return (rfbDCCursorPtr)NULL; ++ } ++ ++ ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->source); ++ gcvals[0] = GXand; ++ ChangeGC (pGC, GCFunction, gcvals); ++ ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->mask); ++ ++ /* mask bits -- pCursor->mask & ~pCursor->source */ ++ gcvals[0] = GXcopy; ++ ChangeGC (pGC, GCFunction, gcvals); ++ ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->mask); ++ gcvals[0] = GXandInverted; ++ ChangeGC (pGC, GCFunction, gcvals); ++ ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); ++ (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, ++ 0, 0, pCursor->bits->width, pCursor->bits->height, ++ 0, XYPixmap, (char *)pCursor->bits->source); ++ FreeScratchGC (pGC); ++ return pPriv; ++} ++ ++static Bool ++rfbDCUnrealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbDCCursorPtr pPriv; ++ ++ pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; ++ if (pPriv && (pCursor->bits->refcnt <= 1)) ++ { ++ if (pPriv->sourceBits) ++ (*pScreen->DestroyPixmap) (pPriv->sourceBits); ++ if (pPriv->maskBits) ++ (*pScreen->DestroyPixmap) (pPriv->maskBits); ++#ifdef ARGB_CURSOR ++ if (pPriv->pPicture) ++ FreePicture (pPriv->pPicture, 0); ++#endif ++ xfree ((pointer) pPriv); ++ pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; ++ } ++ return TRUE; ++} ++ ++static void ++rfbDCPutBits (pDrawable, pPriv, sourceGC, maskGC, x, y, w, h, source, mask) ++ DrawablePtr pDrawable; ++ GCPtr sourceGC, maskGC; ++ int x, y; ++ unsigned w, h; ++ rfbDCCursorPtr pPriv; ++ unsigned long source, mask; ++{ ++ XID gcvals[1]; ++ ++ if (sourceGC->fgPixel != source) ++ { ++ gcvals[0] = source; ++ DoChangeGC (sourceGC, GCForeground, gcvals, 0); ++ } ++ if (sourceGC->serialNumber != pDrawable->serialNumber) ++ ValidateGC (pDrawable, sourceGC); ++ (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); ++ if (maskGC->fgPixel != mask) ++ { ++ gcvals[0] = mask; ++ DoChangeGC (maskGC, GCForeground, gcvals, 0); ++ } ++ if (maskGC->serialNumber != pDrawable->serialNumber) ++ ValidateGC (pDrawable, maskGC); ++ (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); ++} ++ ++#define EnsureGC(gc,win) (gc || rfbDCMakeGC(&gc, win)) ++ ++static GCPtr ++rfbDCMakeGC(ppGC, pWin) ++ GCPtr *ppGC; ++ WindowPtr pWin; ++{ ++ GCPtr pGC; ++ int status; ++ XID gcvals[2]; ++ ++ gcvals[0] = IncludeInferiors; ++ gcvals[1] = FALSE; ++ pGC = CreateGC((DrawablePtr)pWin, ++ GCSubwindowMode|GCGraphicsExposures, gcvals, &status); ++ if (pGC && pWin->drawable.pScreen->DrawGuarantee) ++ (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); ++ *ppGC = pGC; ++ return pGC; ++} ++ ++static Bool ++rfbDCPutUpCursor (pScreen, pCursor, x, y, source, mask) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++ int x, y; ++ unsigned long source, mask; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ rfbDCCursorPtr pPriv; ++ WindowPtr pWin; ++ ++ pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; ++ if (!pPriv) ++ { ++ pPriv = rfbDCRealize(pScreen, pCursor); ++ if (!pPriv) ++ return FALSE; ++ } ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pWin = WindowTable[pScreen->myNum]; ++#ifdef ARGB_CURSOR ++ if (pPriv->pPicture) ++ { ++ if (!EnsurePicture(pScreenPriv->pRootPicture, &pWin->drawable, pWin)) ++ return FALSE; ++ CompositePicture (PictOpOver, ++ pPriv->pPicture, ++ NULL, ++ pScreenPriv->pRootPicture, ++ 0, 0, 0, 0, ++ x, y, ++ pCursor->bits->width, ++ pCursor->bits->height); ++ } ++ else ++#endif ++ { ++ if (!EnsureGC(pScreenPriv->pSourceGC, pWin)) ++ return FALSE; ++ if (!EnsureGC(pScreenPriv->pMaskGC, pWin)) ++ { ++ FreeGC (pScreenPriv->pSourceGC, (GContext) 0); ++ pScreenPriv->pSourceGC = 0; ++ return FALSE; ++ } ++ rfbDCPutBits ((DrawablePtr)pWin, pPriv, ++ pScreenPriv->pSourceGC, pScreenPriv->pMaskGC, ++ x, y, pCursor->bits->width, pCursor->bits->height, ++ source, mask); ++ } ++ return TRUE; ++} ++ ++static Bool ++rfbDCSaveUnderCursor (pScreen, x, y, w, h) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ PixmapPtr pSave; ++ WindowPtr pWin; ++ GCPtr pGC; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pSave = pScreenPriv->pSave; ++ pWin = WindowTable[pScreen->myNum]; ++ if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) ++ { ++ if (pSave) ++ (*pScreen->DestroyPixmap) (pSave); ++ pScreenPriv->pSave = pSave = ++ (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth); ++ if (!pSave) ++ return FALSE; ++ } ++ if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pSaveGC; ++ if (pSave->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pSave, pGC); ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, y, w, h, 0, 0); ++ return TRUE; ++} ++ ++static Bool ++rfbDCRestoreUnderCursor (pScreen, x, y, w, h) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ PixmapPtr pSave; ++ WindowPtr pWin; ++ GCPtr pGC; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pSave = pScreenPriv->pSave; ++ pWin = WindowTable[pScreen->myNum]; ++ if (!pSave) ++ return FALSE; ++ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pRestoreGC; ++ if (pWin->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pWin, pGC); ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, 0, w, h, x, y); ++ return TRUE; ++} ++ ++static Bool ++rfbDCChangeSave (pScreen, x, y, w, h, dx, dy) ++ ScreenPtr pScreen; ++ int x, y, w, h, dx, dy; ++{ ++ rfbDCScreenPtr pScreenPriv; ++ PixmapPtr pSave; ++ WindowPtr pWin; ++ GCPtr pGC; ++ int sourcex, sourcey, destx, desty, copyw, copyh; ++ ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pSave = pScreenPriv->pSave; ++ pWin = WindowTable[pScreen->myNum]; ++ /* ++ * restore the bits which are about to get trashed ++ */ ++ if (!pSave) ++ return FALSE; ++ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pRestoreGC; ++ if (pWin->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pWin, pGC); ++ /* ++ * copy the old bits to the screen. ++ */ ++ if (dy > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, h - dy, w, dy, x + dx, y + h); ++ } ++ else if (dy < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, 0, w, -dy, x + dx, y + dy); ++ } ++ if (dy >= 0) ++ { ++ desty = y + dy; ++ sourcey = 0; ++ copyh = h - dy; ++ } ++ else ++ { ++ desty = y; ++ sourcey = - dy; ++ copyh = h + dy; ++ } ++ if (dx > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ w - dx, sourcey, dx, copyh, x + w, desty); ++ } ++ else if (dx < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, ++ 0, sourcey, -dx, copyh, x + dx, desty); ++ } ++ if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pSaveGC; ++ if (pSave->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pSave, pGC); ++ /* ++ * move the bits that are still valid within the pixmap ++ */ ++ if (dx >= 0) ++ { ++ sourcex = 0; ++ destx = dx; ++ copyw = w - dx; ++ } ++ else ++ { ++ destx = 0; ++ sourcex = - dx; ++ copyw = w + dx; ++ } ++ if (dy >= 0) ++ { ++ sourcey = 0; ++ desty = dy; ++ copyh = h - dy; ++ } ++ else ++ { ++ desty = 0; ++ sourcey = -dy; ++ copyh = h + dy; ++ } ++ (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pSave, pGC, ++ sourcex, sourcey, copyw, copyh, destx, desty); ++ /* ++ * copy the new bits from the screen into the remaining areas of the ++ * pixmap ++ */ ++ if (dy > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, y, w, dy, 0, 0); ++ } ++ else if (dy < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, y + h + dy, w, -dy, 0, h + dy); ++ } ++ if (dy >= 0) ++ { ++ desty = dy; ++ sourcey = y + dy; ++ copyh = h - dy; ++ } ++ else ++ { ++ desty = 0; ++ sourcey = y; ++ copyh = h + dy; ++ } ++ if (dx > 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x, sourcey, dx, copyh, 0, desty); ++ } ++ else if (dx < 0) ++ { ++ (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, ++ x + w + dx, sourcey, -dx, copyh, w + dx, desty); ++ } ++ return TRUE; ++} ++ ++static Bool ++rfbDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++ int x, y, w, h, dx, dy; ++ unsigned long source, mask; ++{ ++ rfbDCCursorPtr pPriv; ++ rfbDCScreenPtr pScreenPriv; ++ int status; ++ WindowPtr pWin; ++ GCPtr pGC; ++ XID gcval = FALSE; ++ PixmapPtr pTemp; ++ ++ pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; ++ if (!pPriv) ++ { ++ pPriv = rfbDCRealize(pScreen, pCursor); ++ if (!pPriv) ++ return FALSE; ++ } ++ pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; ++ pWin = WindowTable[pScreen->myNum]; ++ pTemp = pScreenPriv->pTemp; ++ if (!pTemp || ++ pTemp->drawable.width != pScreenPriv->pSave->drawable.width || ++ pTemp->drawable.height != pScreenPriv->pSave->drawable.height) ++ { ++ if (pTemp) ++ (*pScreen->DestroyPixmap) (pTemp); ++#ifdef ARGB_CURSOR ++ if (pScreenPriv->pTempPicture) ++ { ++ FreePicture (pScreenPriv->pTempPicture, 0); ++ pScreenPriv->pTempPicture = 0; ++ } ++#endif ++ pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap) ++ (pScreen, w, h, pScreenPriv->pSave->drawable.depth); ++ if (!pTemp) ++ return FALSE; ++ } ++ if (!pScreenPriv->pMoveGC) ++ { ++ pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp, ++ GCGraphicsExposures, &gcval, &status); ++ if (!pScreenPriv->pMoveGC) ++ return FALSE; ++ } ++ /* ++ * copy the saved area to a temporary pixmap ++ */ ++ pGC = pScreenPriv->pMoveGC; ++ if (pGC->serialNumber != pTemp->drawable.serialNumber) ++ ValidateGC ((DrawablePtr) pTemp, pGC); ++ (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave, ++ (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0); ++ ++ /* ++ * draw the cursor in the temporary pixmap ++ */ ++#ifdef ARGB_CURSOR ++ if (pPriv->pPicture) ++ { ++ if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin)) ++ return FALSE; ++ CompositePicture (PictOpOver, ++ pPriv->pPicture, ++ NULL, ++ pScreenPriv->pTempPicture, ++ 0, 0, 0, 0, ++ dx, dy, ++ pCursor->bits->width, ++ pCursor->bits->height); ++ } ++ else ++#endif ++ { ++ if (!pScreenPriv->pPixSourceGC) ++ { ++ pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp, ++ GCGraphicsExposures, &gcval, &status); ++ if (!pScreenPriv->pPixSourceGC) ++ return FALSE; ++ } ++ if (!pScreenPriv->pPixMaskGC) ++ { ++ pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp, ++ GCGraphicsExposures, &gcval, &status); ++ if (!pScreenPriv->pPixMaskGC) ++ return FALSE; ++ } ++ rfbDCPutBits ((DrawablePtr)pTemp, pPriv, ++ pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC, ++ dx, dy, pCursor->bits->width, pCursor->bits->height, ++ source, mask); ++ } ++ ++ /* ++ * copy the temporary pixmap onto the screen ++ */ ++ ++ if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) ++ return FALSE; ++ pGC = pScreenPriv->pRestoreGC; ++ if (pWin->drawable.serialNumber != pGC->serialNumber) ++ ValidateGC ((DrawablePtr) pWin, pGC); ++ ++ (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin, ++ pGC, ++ 0, 0, w, h, x, y); ++ return TRUE; ++} +diff --git a/hw/vnc/dpmsstubs.c b/hw/vnc/dpmsstubs.c +new file mode 100644 +index 0000000..e121cf5 +--- /dev/null ++++ b/hw/vnc/dpmsstubs.c +@@ -0,0 +1,48 @@ ++/* $Xorg: dpmsstubs.c,v 1.3 2000/08/17 19:47:56 cpqbld Exp $ */ ++/***************************************************************** ++ ++Copyright (c) 1996 Digital Equipment Corporation, Maynard, Massachusetts. ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software. ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, ++BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, ++WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR ++IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of Digital Equipment Corporation ++shall not be used in advertising or otherwise to promote the sale, use or other ++dealings in this Software without prior written authorization from Digital ++Equipment Corporation. ++ ++******************************************************************/ ++/* $XFree86: xc/programs/Xserver/Xext/dpmsstubs.c,v 3.3 1999/12/16 02:26:23 robin Exp $ */ ++ ++typedef int Bool; ++ ++#define FALSE 0 ++ ++Bool DPMSSupported(void) ++{ ++ return FALSE; ++} ++ ++int DPSMGet(int *level) ++{ ++ return -1; ++} ++ ++void DPMSSet(int level) ++{ ++ ++} +diff --git a/hw/vnc/draw.c b/hw/vnc/draw.c +new file mode 100644 +index 0000000..889db6f +--- /dev/null ++++ b/hw/vnc/draw.c +@@ -0,0 +1,2108 @@ ++/* ++ * draw.c - drawing routines for the RFB X server. This is a set of ++ * wrappers around the standard MI/MFB/CFB drawing routines which work out ++ * to a fair approximation the region of the screen being modified by the ++ * drawing. If the RFB client is ready then the modified region of the screen ++ * is sent to the client, otherwise the modified region will simply grow with ++ * each drawing request until the client is ready. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#include "rfb.h" ++ ++int rfbDeferUpdateTime = 40; /* ms */ ++ ++ ++/****************************************************************************/ ++/* ++ * Macro definitions ++ */ ++/****************************************************************************/ ++ ++#define TRC(x) /* (rfbLog x) */ ++ ++/* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each ++ client */ ++ ++#define ADD_TO_MODIFIED_REGION(pScreen,reg) \ ++ { \ ++ rfbClientPtr cl; \ ++ for (cl = rfbClientHead; cl; cl = cl->next) { \ ++ REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\ ++ } \ ++ } ++ ++/* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an ++ update to be sent to each client if there is one pending and the client is ++ ready for it. */ ++ ++#define SCHEDULE_FB_UPDATE(pScreen,pVNC) \ ++ if (!pVNC->dontSendFramebufferUpdate) { \ ++ rfbClientPtr cl, nextCl; \ ++ for (cl = rfbClientHead; cl; cl = nextCl) { \ ++ nextCl = cl->next; \ ++ if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && \ ++ REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) \ ++ { \ ++ rfbScheduleDeferredUpdate(pScreen, cl); \ ++ } \ ++ } \ ++ } ++ ++/* function prototypes */ ++ ++static void rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl); ++static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl, ++ RegionPtr src, RegionPtr dst, int dx, int dy); ++#ifdef DEBUG ++static void PrintRegion(ScreenPtr pScreen, RegionPtr reg); ++#endif ++ ++/* GC funcs */ ++ ++static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr); ++static void rfbChangeGC(GCPtr, unsigned long /*mask*/); ++static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/); ++static void rfbDestroyGC(GCPtr); ++static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/, ++ int /*nrects*/); ++static void rfbDestroyClip(GCPtr); ++static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/); ++ ++/* GC ops */ ++ ++static void rfbFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted); ++static void rfbSetSpans(DrawablePtr pDrawable, ++ GCPtr pGC, ++ char *psrc, ++ register DDXPointPtr ppt, ++ int *pwidth, ++ int nspans, ++ int fSorted); ++static void rfbPutImage(); ++static RegionPtr rfbCopyArea(); ++static RegionPtr rfbCopyPlane(); ++static void rfbPolyPoint(); ++static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts); ++static void rfbPolySegment(); ++static void rfbPolyRectangle(); ++static void rfbPolyArc(); ++static void rfbFillPolygon(); ++static void rfbPolyFillRect(); ++static void rfbPolyFillArc(); ++static int rfbPolyText8(); ++static int rfbPolyText16(); ++static void rfbImageText8(); ++static void rfbImageText16(); ++static void rfbImageGlyphBlt(); ++static void rfbPolyGlyphBlt(); ++static void rfbPushPixels(); ++ ++ ++static GCFuncs rfbGCFuncs = { ++ rfbValidateGC, ++ rfbChangeGC, ++ rfbCopyGC, ++ rfbDestroyGC, ++ rfbChangeClip, ++ rfbDestroyClip, ++ rfbCopyClip, ++}; ++ ++ ++static GCOps rfbGCOps = { ++ rfbFillSpans, rfbSetSpans, rfbPutImage, ++ rfbCopyArea, rfbCopyPlane, rfbPolyPoint, ++ rfbPolylines, rfbPolySegment, rfbPolyRectangle, ++ rfbPolyArc, rfbFillPolygon, rfbPolyFillRect, ++ rfbPolyFillArc, rfbPolyText8, rfbPolyText16, ++ rfbImageText8, rfbImageText16, rfbImageGlyphBlt, ++ rfbPolyGlyphBlt, rfbPushPixels ++}; ++ ++ ++ ++/****************************************************************************/ ++/* ++ * Screen functions wrapper stuff ++ */ ++/****************************************************************************/ ++ ++#define SCREEN_PROLOGUE(scrn, field) \ ++ ScreenPtr pScreen = scrn; \ ++ VNCSCREENPTR(pScreen); \ ++ pScreen->field = pVNC->field; ++ ++#define SCREEN_EPILOGUE(field, wrapper) \ ++ pScreen->field = wrapper; ++ ++ ++/* ++ * CloseScreen wrapper -- unwrap everything, free the private data ++ * and call the wrapped CloseScreen function. ++ */ ++ ++Bool ++rfbCloseScreen (int i, ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++#if XFREE86VNC ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++#endif ++ int sock; ++ ++ for (sock = 0; sock <= pVNC->maxFd; sock++) { ++ if (FD_ISSET(sock, &pVNC->allFds)) ++ if (sock != pVNC->rfbListenSock && sock != pVNC->httpListenSock) { ++ rfbCloseSock(pScreen, sock); ++ } ++ } ++ ++ if (pVNC->rfbListenSock > 0) ++ if (close(pVNC->rfbListenSock)) ++ ErrorF("Close of port %d failed\n",pVNC->rfbPort); ++ ++ if (pVNC->httpListenSock > 0) ++ if (close(pVNC->httpListenSock)) ++ ErrorF("Close of port %d failed\n",pVNC->httpPort); ++ ++ pScreen->CloseScreen = pVNC->CloseScreen; ++ pScreen->CreateGC = pVNC->CreateGC; ++ pScreen->PaintWindowBackground = pVNC->PaintWindowBackground; ++ pScreen->PaintWindowBorder = pVNC->PaintWindowBorder; ++ pScreen->CopyWindow = pVNC->CopyWindow; ++ pScreen->ClearToBackground = pVNC->ClearToBackground; ++ pScreen->RestoreAreas = pVNC->RestoreAreas; ++ pScreen->WakeupHandler = pVNC->WakeupHandler; ++ ++#if XFREE86VNC ++ pScreen->InstallColormap = pVNC->InstallColormap; ++ pScreen->UninstallColormap = pVNC->UninstallColormap; ++ pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps; ++ pScreen->StoreColors = pVNC->StoreColors; ++ pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess; ++ ++ xfree(pVNC); ++#endif ++ ++ TRC((stderr,"Unwrapped screen functions\n")); ++ ++ return (*pScreen->CloseScreen) (i, pScreen); ++} ++ ++#if XFREE86VNC ++void ++rfbEnableDisableFBAccess (int index, Bool enable) ++{ ++ ScrnInfoPtr pScrn = xf86Screens[index]; ++ VNCSCREENPTR(pScrn->pScreen); ++ ++ /* ++ * Blank the screen for security while inputs are disabled. ++ * When VT switching is fixed, we might be able to allow ++ * control even when switched away. ++ */ ++ if (!enable) { ++ WindowPtr pWin = WindowTable[index]; ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ GCPtr pGC; ++ xRectangle rect; ++ ++ rect.x = 0; ++ rect.y = 0; ++ rect.width = pScrn->virtualX; ++ rect.height = pScrn->virtualY; ++ ++ if (!(pGC = GetScratchGC(pScreen->rootDepth, pScreen))) { ++ ErrorF("Couldn't blank screen"); ++ } else { ++ CARD32 attributes[2]; ++ attributes[0] = pScreen->whitePixel; ++ attributes[1] = pScreen->blackPixel; ++ (void)ChangeGC(pGC, GCForeground | GCBackground, attributes); ++ ++ ValidateGC((DrawablePtr)pWin, pGC); ++ ++ (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, 1, &rect); ++ ++ FreeScratchGC(pGC); ++ ++ /* Flush pending packets */ ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++ } ++ } ++ ++ pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess; ++ (*pScrn->EnableDisableFBAccess)(index, enable); ++ pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess; ++} ++#endif ++ ++/* ++ * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC ++ * func "ValidateGC" is called). ++ */ ++ ++Bool ++rfbCreateGC (GCPtr pGC) ++{ ++ Bool ret; ++ rfbGCPtr pGCPriv; ++ ++ SCREEN_PROLOGUE(pGC->pScreen,CreateGC); ++ ++ pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr; ++ ++ ret = (*pScreen->CreateGC) (pGC); ++ ++ TRC((stderr,"rfbCreateGC called\n")); ++ ++ pGCPriv->wrapOps = NULL; ++ pGCPriv->wrapFuncs = pGC->funcs; ++ pGC->funcs = &rfbGCFuncs; ++ ++ SCREEN_EPILOGUE(CreateGC,rfbCreateGC); ++ ++ return ret; ++} ++ ++/* ++ * PaintWindowBackground - the region being modified is just the given region. ++ */ ++ ++void ++rfbPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what) ++{ ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground); ++ ++ TRC((stderr,"rfbPaintWindowBackground called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen,pRegion); ++ ++ (*pScreen->PaintWindowBackground) (pWin, pRegion, what); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground); ++} ++ ++/* ++ * PaintWindowBorder - the region being modified is just the given region. ++ */ ++ ++void ++rfbPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what) ++{ ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder); ++ ++ TRC((stderr,"rfbPaintWindowBorder called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen,pRegion); ++ ++ (*pScreen->PaintWindowBorder) (pWin, pRegion, what); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder); ++} ++ ++#ifdef CHROMIUM ++Bool ++rfbRealizeWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,RealizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 1); ++ } ++ } ++ ++ ret = (*pScreen->RealizeWindow)(pWin); ++ ++ SCREEN_EPILOGUE(RealizeWindow,rfbRealizeWindow); ++ ++ return ret; ++} ++ ++Bool ++rfbUnrealizeWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,UnrealizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 0); ++ } ++ } ++ ++ ret = (*pScreen->UnrealizeWindow)(pWin); ++ ++ SCREEN_EPILOGUE(UnrealizeWindow,rfbUnrealizeWindow); ++ ++ return ret; ++} ++ ++Bool ++rfbDestroyWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 0); ++ } ++ } ++ ++ ret = (*pScreen->DestroyWindow)(pWin); ++ ++ SCREEN_EPILOGUE(DestroyWindow,rfbDestroyWindow); ++ ++ return ret; ++} ++ ++void ++rfbResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ResizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumMoveResizeWindow(wt->CRwinId, pWin->drawable.x, pWin->drawable.y, w, h); ++ } ++ } ++ ++ (*pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); ++ ++ SCREEN_EPILOGUE(ResizeWindow,rfbResizeWindow); ++} ++ ++Bool ++rfbPositionWindow(WindowPtr pWin, int x, int y) ++{ ++ Bool ret; ++ CRWindowTable *wt, *nextWt; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PositionWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumMoveResizeWindow(wt->CRwinId, x, y, pWin->drawable.width, pWin->drawable.height); ++ } ++ } ++ ++ ret = (*pScreen->PositionWindow)(pWin, x, y); ++ ++ SCREEN_EPILOGUE(PositionWindow,rfbPositionWindow); ++ ++ return ret; ++} ++ ++void ++rfbClipNotify(WindowPtr pWin, int x, int y) ++{ ++ CRWindowTable *wt, *nextWt; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ClipNotify); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ int numClipRects = REGION_NUM_RECTS(&pWin->clipList); ++ BoxPtr pClipRects = REGION_RECTS(&pWin->clipList); ++ ++ /* Possible optimization - has the cliplist really? changed */ ++ ++ rfbSendChromiumClipList(wt->CRwinId, pClipRects, numClipRects); ++ } ++ } ++ ++ if (*pScreen->ClipNotify) ++ (*pScreen->ClipNotify)(pWin, x, y); ++ ++ SCREEN_EPILOGUE(ClipNotify,rfbClipNotify); ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * CopyWindow - the region being modified is the translation of the old ++ * region, clipped to the border clip region of the window. Note that any ++ * parts of the window which have become newly-visible will not be affected by ++ * this call - a separate PaintWindowBackground/Border will be called to do ++ * that. If the client will accept CopyRect messages then use rfbCopyRegion to ++ * optimise the pending screen changes into a single "copy region" plus the ++ * ordinary modified region. ++ */ ++ ++void ++rfbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) ++{ ++ rfbClientPtr cl; ++ RegionRec srcRegion, dstRegion; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow); ++ ++ TRC((stderr,"rfbCopyWindow called\n")); ++ ++ REGION_NULL(pScreen,&dstRegion); ++ REGION_COPY(pScreen,&dstRegion,pOldRegion); ++ REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion, ++ pWin->drawable.x - ptOldOrg.x, ++ pWin->drawable.y - ptOldOrg.y); ++ REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion, ++ &pWin->borderClip); ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->useCopyRect) { ++ REGION_NULL(pScreen,&srcRegion); ++ REGION_COPY(pScreen,&srcRegion,pOldRegion); ++ ++ rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion, ++ pWin->drawable.x - ptOldOrg.x, ++ pWin->drawable.y - ptOldOrg.y); ++ ++ REGION_UNINIT(pScreen, &srcRegion); ++ ++ } else { ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &dstRegion); ++ } ++ } ++ ++ REGION_UNINIT(pScreen, &dstRegion); ++ ++ (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow); ++} ++ ++/* ++ * ClearToBackground - when generateExposures is false, the region being ++ * modified is the given rectangle (clipped to the "window clip region"). ++ */ ++ ++void ++rfbClearToBackground (WindowPtr pWin, int x, int y, int w, int h, ++ Bool generateExposures) ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground); ++ ++ TRC((stderr,"rfbClearToBackground called\n")); ++ ++ if (!generateExposures) { ++ box.x1 = x + pWin->drawable.x; ++ box.y1 = y + pWin->drawable.y; ++ box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); ++ box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); ++ ++ SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pScreen, &tmpRegion); ++ } ++ ++ (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); ++ ++ if (!generateExposures) { ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ } ++ ++ SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground); ++} ++ ++/* ++ * RestoreAreas - just be safe here - the region being modified is the whole ++ * exposed region. ++ */ ++ ++RegionPtr ++rfbRestoreAreas (WindowPtr pWin, RegionPtr prgnExposed) ++{ ++ RegionPtr result; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas); ++ ++ TRC((stderr,"rfbRestoreAreas called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, prgnExposed); ++ ++ result = (*pScreen->RestoreAreas) (pWin, prgnExposed); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas); ++ ++ return result; ++} ++ ++ ++ ++/****************************************************************************/ ++/* ++ * GC funcs wrapper stuff ++ * ++ * We only really want to wrap the GC ops, but to do this we need to wrap ++ * ValidateGC and so all the other GC funcs must be wrapped as well. ++ */ ++/****************************************************************************/ ++ ++#define GC_FUNC_PROLOGUE(pGC) \ ++ rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \ ++ (pGC)->funcs = pGCPriv->wrapFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ (pGC)->ops = pGCPriv->wrapOps; ++ ++#define GC_FUNC_EPILOGUE(pGC) \ ++ pGCPriv->wrapFuncs = (pGC)->funcs; \ ++ (pGC)->funcs = &rfbGCFuncs; \ ++ if (pGCPriv->wrapOps) { \ ++ pGCPriv->wrapOps = (pGC)->ops; \ ++ (pGC)->ops = &rfbGCOps; \ ++ } ++ ++ ++/* ++ * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if ++ * the drawing will be to a viewable window. ++ */ ++ ++static void ++rfbValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) ++{ ++ VNCSCREENPTR(pGC->pScreen); ++ GC_FUNC_PROLOGUE(pGC); ++ ++ TRC((stderr,"rfbValidateGC called\n")); ++ ++ (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); ++ ++ pGCPriv->wrapOps = NULL; ++ if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) ++ { ++ WindowPtr pWin = (WindowPtr) pDrawable; ++ RegionPtr pRegion = &pWin->clipList; ++ ++ if (pGC->subWindowMode == IncludeInferiors) ++ pRegion = &pWin->borderClip; ++ if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) { ++ pGCPriv->wrapOps = pGC->ops; ++ TRC((stderr,"rfbValidateGC: wrapped GC ops\n")); ++ } ++ } ++ ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++/* ++ * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped ++ * function and then rewrap the funcs and ops. ++ */ ++ ++static void ++rfbChangeGC (pGC, mask) ++ GCPtr pGC; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->ChangeGC) (pGC, mask); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbCopyGC (pGCSrc, mask, pGCDst) ++ GCPtr pGCSrc, pGCDst; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE(pGCDst); ++ (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); ++ GC_FUNC_EPILOGUE(pGCDst); ++} ++ ++static void ++rfbDestroyGC (pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->DestroyGC) (pGC); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbChangeClip (pGC, type, pvalue, nrects) ++ GCPtr pGC; ++ int type; ++ pointer pvalue; ++ int nrects; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbDestroyClip(pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (* pGC->funcs->DestroyClip)(pGC); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbCopyClip(pgcDst, pgcSrc) ++ GCPtr pgcDst, pgcSrc; ++{ ++ GC_FUNC_PROLOGUE(pgcDst); ++ (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); ++ GC_FUNC_EPILOGUE(pgcDst); ++} ++ ++ ++/****************************************************************************/ ++/* ++ * GC ops wrapper stuff ++ * ++ * Note that these routines will only have been wrapped for drawing to ++ * viewable windows so we don't need to check each time that the drawable ++ * is a viewable window. ++ */ ++/****************************************************************************/ ++ ++#define GC_OP_PROLOGUE(pDrawable,pGC) \ ++ ScreenPtr pScreen = pGC->pScreen; \ ++ VNCSCREENPTR(pScreen); \ ++ rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \ ++ GCFuncs *oldFuncs = pGC->funcs; \ ++ (void) pScreen; /* silence compiler */ \ ++ (pGC)->funcs = pGCPrivate->wrapFuncs; \ ++ (pGC)->ops = pGCPrivate->wrapOps; ++ ++#define GC_OP_EPILOGUE(pGC) \ ++ pGCPrivate->wrapOps = (pGC)->ops; \ ++ (pGC)->funcs = oldFuncs; \ ++ (pGC)->ops = &rfbGCOps; ++ ++ ++/* ++ * FillSpans - being very safe - the region being modified is the border clip ++ * region of the window. ++ */ ++ ++static void ++rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nInit; /* number of spans to fill */ ++ DDXPointPtr pptInit; /* pointer to list of start points */ ++ int *pwidthInit; /* pointer to list of n widths */ ++ int fSorted; ++{ ++ GC_OP_PROLOGUE(pDrawable,pGC); ++ ++ TRC((stderr,"rfbFillSpans called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, ++ &((WindowPtr)pDrawable)->borderClip); ++ ++ (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * SetSpans - being very safe - the region being modified is the border clip ++ * region of the window. ++ */ ++ ++static void ++rfbSetSpans(DrawablePtr pDrawable, ++ GCPtr pGC, ++ char *psrc, ++ register DDXPointPtr ppt, ++ int *pwidth, ++ int nspans, ++ int fSorted) ++{ ++ GC_OP_PROLOGUE(pDrawable,pGC); ++ ++ TRC((stderr,"rfbSetSpans called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, ++ &((WindowPtr)pDrawable)->borderClip); ++ ++ (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PutImage - the region being modified is the rectangle of the ++ * PutImage (clipped to the window clip region). ++ */ ++ ++static void ++rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int depth; ++ int x; ++ int y; ++ int w; ++ int h; ++ int leftPad; ++ int format; ++ char *pBits; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPutImage called\n")); ++ ++ box.x1 = x + pDrawable->x; ++ box.y1 = y + pDrawable->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ ++ (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, ++ leftPad, format, pBits); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * CopyArea - the region being modified is the destination rectangle (clipped ++ * to the window clip region). ++ * If the client will accept CopyRect messages then use rfbCopyRegion ++ * to optimise the pending screen changes into a single "copy region" plus ++ * the ordinary modified region. ++ */ ++ ++static RegionPtr ++rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ GCPtr pGC; ++ int srcx; ++ int srcy; ++ int w; ++ int h; ++ int dstx; ++ int dsty; ++{ ++ rfbClientPtr cl; ++ RegionPtr rgn; ++ RegionRec srcRegion, dstRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDst, pGC); ++ ++ TRC((stderr,"rfbCopyArea called\n")); ++ ++ box.x1 = dstx + pDst->x; ++ box.y1 = dsty + pDst->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0); ++ REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion, ++ pGC->pCompositeClip); ++ ++ if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) { ++ box.x1 = srcx + pSrc->x; ++ box.y1 = srcy + pSrc->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->useCopyRect) { ++ SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0); ++ REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion, ++ &((WindowPtr)pSrc)->clipList); ++ ++ rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion, ++ dstx + pDst->x - srcx - pSrc->x, ++ dsty + pDst->y - srcy - pSrc->y); ++ ++ REGION_UNINIT(pSrc->pScreen, &srcRegion); ++ ++ } else { ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &dstRegion); ++ } ++ } ++ ++ } else { ++ ++ ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion); ++ } ++ ++ REGION_UNINIT(pDst->pScreen, &dstRegion); ++ ++ rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty); ++ ++ SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++ ++ return rgn; ++} ++ ++ ++/* ++ * CopyPlane - the region being modified is the destination rectangle (clipped ++ * to the window clip region). ++ */ ++ ++static RegionPtr ++rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ register GCPtr pGC; ++ int srcx, ++ srcy; ++ int w, ++ h; ++ int dstx, ++ dsty; ++ unsigned long plane; ++{ ++ RegionPtr rgn; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDst, pGC); ++ ++ TRC((stderr,"rfbCopyPlane called\n")); ++ ++ box.x1 = dstx + pDst->x; ++ box.y1 = dsty + pDst->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDst->pScreen, &tmpRegion); ++ ++ rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty, plane); ++ ++ SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++ ++ return rgn; ++} ++ ++/* ++ * PolyPoint - find the smallest rectangle which encloses the points drawn ++ * (and clip). ++ */ ++ ++static void ++rfbPolyPoint (pDrawable, pGC, mode, npt, pts) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; /* Origin or Previous */ ++ int npt; ++ xPoint *pts; ++{ ++ int i; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyPoint called\n")); ++ ++ if (npt) { ++ int minX = pts[0].x, maxX = pts[0].x; ++ int minY = pts[0].y, maxY = pts[0].y; ++ ++ if (mode == CoordModePrevious) ++ { ++ int x = pts[0].x, y = pts[0].y; ++ ++ for (i = 1; i < npt; i++) { ++ x += pts[i].x; ++ y += pts[i].y; ++ if (x < minX) minX = x; ++ if (x > maxX) maxX = x; ++ if (y < minY) minY = y; ++ if (y > maxY) maxY = y; ++ } ++ } ++ else ++ { ++ for (i = 1; i < npt; i++) { ++ if (pts[i].x < minX) minX = pts[i].x; ++ if (pts[i].x > maxX) maxX = pts[i].x; ++ if (pts[i].y < minY) minY = pts[i].y; ++ if (pts[i].y > maxY) maxY = pts[i].y; ++ } ++ } ++ ++ box.x1 = minX + pDrawable->x; ++ box.y1 = minY + pDrawable->y; ++ box.x2 = maxX + 1 + pDrawable->x; ++ box.y2 = maxY + 1 + pDrawable->y; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); ++ ++ if (npt) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyLines - take the union of bounding boxes around each line (and clip). ++ */ ++ ++static void ++rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts) ++{ ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ int i, extra, nlines, lw; ++ int x1, x2, y1, y2; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolylines called\n")); ++ ++ if (npt) { ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ if (npt == 1) ++ { ++ nlines = 1; ++ rects = (xRectangle *)xalloc(sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolylines: xalloc failed\n"); ++ } ++ ++ rects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe here */ ++ rects[0].y = ppts[0].y - lw + pDrawable->y; ++ rects[0].width = 2*lw; ++ rects[0].height = 2*lw; ++ } ++ else ++ { ++ nlines = npt - 1; ++ rects = (xRectangle *)xalloc(nlines*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolylines: xalloc failed\n"); ++ } ++ ++ /* ++ * mitered joins can project quite a way from ++ * the line end; the 11 degree miter limit limits ++ * this extension to lw / (2 * tan(11/2)), rounded up ++ * and converted to int yields 6 * lw ++ */ ++ ++ if (pGC->joinStyle == JoinMiter) { ++ extra = 6 * lw; ++ } else { ++ extra = lw / 2; ++ } ++ ++ x1 = ppts[0].x + pDrawable->x; ++ y1 = ppts[0].y + pDrawable->y; ++ ++ for (i = 0; i < nlines; i++) { ++ if (mode == CoordModeOrigin) { ++ x2 = pDrawable->x + ppts[i+1].x; ++ y2 = pDrawable->y + ppts[i+1].y; ++ } else { ++ x2 = x1 + ppts[i+1].x; ++ y2 = y1 + ppts[i+1].y; ++ } ++ ++ if (x1 > x2) { ++ rects[i].x = x2 - extra; ++ rects[i].width = x1 - x2 + 1 + 2 * extra; ++ } else { ++ rects[i].x = x1 - extra; ++ rects[i].width = x2 - x1 + 1 + 2 * extra; ++ } ++ ++ if (y1 > y2) { ++ rects[i].y = y2 - extra; ++ rects[i].height = y1 - y2 + 1 + 2 * extra; ++ } else { ++ rects[i].y = y1 - extra; ++ rects[i].height = y2 - y1 + 1 + 2 * extra; ++ } ++ ++ x1 = x2; ++ y1 = y2; ++ } ++ } ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nlines, rects,CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); ++ ++ if (npt) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolySegment - take the union of bounding boxes around each segment (and ++ * clip). ++ */ ++ ++static void ++rfbPolySegment(pDrawable, pGC, nseg, segs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nseg; ++ xSegment *segs; ++{ ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ int i, extra, lw; ++ ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolySegment called\n")); ++ ++ if (nseg) { ++ rects = (xRectangle *)xalloc(nseg*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolySegment: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < nseg; i++) ++ { ++ if (segs[i].x1 > segs[i].x2) { ++ rects[i].x = segs[i].x2 - extra + pDrawable->x; ++ rects[i].width = segs[i].x1 - segs[i].x2 + 1 + 2 * extra; ++ } else { ++ rects[i].x = segs[i].x1 - extra + pDrawable->x; ++ rects[i].width = segs[i].x2 - segs[i].x1 + 1 + 2 * extra; ++ } ++ ++ if (segs[i].y1 > segs[i].y2) { ++ rects[i].y = segs[i].y2 - extra + pDrawable->y; ++ rects[i].height = segs[i].y1 - segs[i].y2 + 1 + 2 * extra; ++ } else { ++ rects[i].y = segs[i].y1 - extra + pDrawable->y; ++ rects[i].height = segs[i].y2 - segs[i].y1 + 1 + 2 * extra; ++ } ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nseg, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); ++ ++ if (nseg) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyRectangle (rectangle outlines) - take the union of bounding boxes ++ * around each line (and clip). ++ */ ++ ++static void ++rfbPolyRectangle(pDrawable, pGC, nrects, rects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *rects; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *regRects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyRectangle called\n")); ++ ++ if (nrects) { ++ regRects = (xRectangle *)xalloc(nrects*4*sizeof(xRectangle)); ++ if (!regRects) { ++ FatalError("rfbPolyRectangle: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < nrects; i++) ++ { ++ regRects[i*4].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4].width = rects[i].width + 1 + 2 * extra; ++ regRects[i*4].height = 1 + 2 * extra; ++ ++ regRects[i*4+1].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4+1].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4+1].width = 1 + 2 * extra; ++ regRects[i*4+1].height = rects[i].height + 1 + 2 * extra; ++ ++ regRects[i*4+2].x ++ = rects[i].x + rects[i].width - extra + pDrawable->x; ++ regRects[i*4+2].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4+2].width = 1 + 2 * extra; ++ regRects[i*4+2].height = rects[i].height + 1 + 2 * extra; ++ ++ regRects[i*4+3].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4+3].y ++ = rects[i].y + rects[i].height - extra + pDrawable->y; ++ regRects[i*4+3].width = rects[i].width + 1 + 2 * extra; ++ regRects[i*4+3].height = 1 + 2 * extra; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects*4, ++ regRects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)regRects); ++ } ++ ++ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); ++ ++ if (nrects) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyArc - take the union of bounding boxes around each arc (and clip). ++ * Bounding boxes assume each is a full circle / ellipse. ++ */ ++ ++static void ++rfbPolyArc(pDrawable, pGC, narcs, arcs) ++ DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int narcs; ++ xArc *arcs; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyArc called\n")); ++ ++ if (narcs) { ++ rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolyArc: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < narcs; i++) ++ { ++ rects[i].x = arcs[i].x - extra + pDrawable->x; ++ rects[i].y = arcs[i].y - extra + pDrawable->y; ++ rects[i].width = arcs[i].width + lw; ++ rects[i].height = arcs[i].height + lw; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); ++ ++ if (narcs) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * FillPolygon - take bounding box around polygon (and clip). ++ */ ++ ++static void ++rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts) ++ register DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int shape, mode; ++ int count; ++ DDXPointPtr pts; ++{ ++ int i; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbFillPolygon called\n")); ++ ++ if (count) { ++ int minX = pts[0].x, maxX = pts[0].x; ++ int minY = pts[0].y, maxY = pts[0].y; ++ ++ if (mode == CoordModePrevious) ++ { ++ int x = pts[0].x, y = pts[0].y; ++ ++ for (i = 1; i < count; i++) { ++ x += pts[i].x; ++ y += pts[i].y; ++ if (x < minX) minX = x; ++ if (x > maxX) maxX = x; ++ if (y < minY) minY = y; ++ if (y > maxY) maxY = y; ++ } ++ } ++ else ++ { ++ for (i = 1; i < count; i++) { ++ if (pts[i].x < minX) minX = pts[i].x; ++ if (pts[i].x > maxX) maxX = pts[i].x; ++ if (pts[i].y < minY) minY = pts[i].y; ++ if (pts[i].y > maxY) maxY = pts[i].y; ++ } ++ } ++ ++ box.x1 = minX + pDrawable->x; ++ box.y1 = minY + pDrawable->y; ++ box.x2 = maxX + 1 + pDrawable->x; ++ box.y2 = maxY + 1 + pDrawable->y; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyFillRect - take the union of the given rectangles (and clip). ++ */ ++ ++static void ++rfbPolyFillRect(pDrawable, pGC, nrects, rects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *rects; ++{ ++ RegionPtr tmpRegion; ++ xRectangle *regRects; ++ int i; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyFillRect called\n")); ++ ++ if (nrects) { ++ regRects = (xRectangle *)xalloc(nrects*sizeof(xRectangle)); ++ if (!regRects) { ++ FatalError("rfbPolyFillRect: xalloc failed\n"); ++ } ++ ++ for (i = 0; i < nrects; i++) { ++ regRects[i].x = rects[i].x + pDrawable->x; ++ regRects[i].y = rects[i].y + pDrawable->y; ++ regRects[i].width = rects[i].width; ++ regRects[i].height = rects[i].height; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects, regRects, ++ CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)regRects); ++ } ++ ++ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); ++ ++ if (nrects) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyFillArc - take the union of bounding boxes around each arc (and clip). ++ * Bounding boxes assume each is a full circle / ellipse. ++ */ ++ ++static void ++rfbPolyFillArc(pDrawable, pGC, narcs, arcs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int narcs; ++ xArc *arcs; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyFillArc called\n")); ++ ++ if (narcs) { ++ rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolyFillArc: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < narcs; i++) ++ { ++ rects[i].x = arcs[i].x - extra + pDrawable->x; ++ rects[i].y = arcs[i].y - extra + pDrawable->y; ++ rects[i].width = arcs[i].width + lw; ++ rects[i].height = arcs[i].height + lw; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); ++ ++ if (narcs) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * Get a rough bounding box around n characters of the given font. ++ */ ++ ++static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox) ++ DrawablePtr pDrawable; ++ FontPtr font; ++ int x, y, n; ++ BoxPtr pbox; ++{ ++ int maxAscent, maxDescent, maxCharWidth; ++ ++ if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent)) ++ maxAscent = FONTASCENT(font); ++ else ++ maxAscent = FONTMAXBOUNDS(font,ascent); ++ ++ if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent)) ++ maxDescent = FONTDESCENT(font); ++ else ++ maxDescent = FONTMAXBOUNDS(font,descent); ++ ++ if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth)) ++ maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing); ++ else ++ maxCharWidth = FONTMAXBOUNDS(font,characterWidth); ++ ++ pbox->x1 = pDrawable->x + x; ++ pbox->y1 = pDrawable->y + y - maxAscent; ++ pbox->x2 = pbox->x1 + maxCharWidth * n; ++ pbox->y2 = pbox->y1 + maxAscent + maxDescent; ++ ++ if (FONTMINBOUNDS(font,leftSideBearing) < 0) { ++ pbox->x1 += FONTMINBOUNDS(font,leftSideBearing); ++ } ++} ++ ++ ++/* ++ * PolyText8 - use rough bounding box. ++ */ ++ ++static int ++rfbPolyText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ int ret; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyText8 called '%.*s'\n",count,chars)); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++ return ret; ++} ++ ++/* ++ * PolyText16 - use rough bounding box. ++ */ ++ ++static int ++rfbPolyText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ int ret; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyText16 called\n")); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++ return ret; ++} ++ ++/* ++ * ImageText8 - use rough bounding box. ++ */ ++ ++static void ++rfbImageText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageText8 called '%.*s'\n",count,chars)); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * ImageText16 - use rough bounding box. ++ */ ++ ++static void ++rfbImageText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageText16 called\n")); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * ImageGlyphBlt - use rough bounding box. ++ */ ++ ++static void ++rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageGlyphBlt called\n")); ++ ++ if (nglyph) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); ++ ++ if (nglyph) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyGlyphBlt - use rough bounding box. ++ */ ++ ++static void ++rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyGlyphBlt called\n")); ++ ++ if (nglyph) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ if (nglyph) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PushPixels - be fairly safe - region modified is intersection of the given ++ * rectangle with the window clip region. ++ */ ++ ++static void ++rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y) ++ GCPtr pGC; ++ PixmapPtr pBitMap; ++ DrawablePtr pDrawable; ++ int w, h, x, y; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPushPixels called\n")); ++ ++ box.x1 = x + pDrawable->x; ++ box.y1 = y + pDrawable->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ ++ (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++#ifdef RENDER ++void ++rfbComposite( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height ++){ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ RegionRec tmpRegion; ++ BoxRec box; ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ ++ box.x1 = pDst->pDrawable->x + xDst; ++ box.y1 = pDst->pDrawable->y + yDst; ++ box.x2 = box.x1 + width; ++ box.y2 = box.y1 + height; ++ ++ REGION_INIT(pScreen, &tmpRegion, &box, 0); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion); ++ ++ ps->Composite = pVNC->Composite; ++ (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, ++ xMask, yMask, xDst, yDst, width, height); ++ ps->Composite = rfbComposite; ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ REGION_UNINIT(pScreen, &tmpRegion); ++} ++#endif /* RENDER */ ++ ++/****************************************************************************/ ++/* ++ * Other functions ++ */ ++/****************************************************************************/ ++ ++/* ++ * rfbCopyRegion. Args are src and dst regions plus a translation (dx,dy). ++ * Takes these args together with the existing modified region and possibly an ++ * existing copy region and translation. Produces a combined modified region ++ * plus copy region and translation. Note that the copy region is the ++ * destination of the copy. ++ * ++ * First we trim parts of src which are invalid (ie in the modified region). ++ * Then we see if there is any overlap between the src and the existing copy ++ * region. If not then the two copies cannot be combined, so we choose ++ * whichever is bigger to form the basis of a new copy, while the other copy is ++ * just done the hard way by being added to the modified region. So if the ++ * existing copy is bigger then we simply add the destination of the new copy ++ * to the modified region and we're done. If the new copy is bigger, we add ++ * the old copy region to the modified region and behave as though there is no ++ * existing copy region. ++ * ++ * At this stage we now know that either the two copies can be combined, or ++ * that there is no existing copy. We temporarily add both the existing copy ++ * region and dst to the modified region (this is the entire area of the screen ++ * affected in any way). Finally we calculate the new copy region, and remove ++ * it from the modified region. ++ * ++ * Note: ++ * 1. The src region is modified by this routine. ++ * 2. When the copy region is empty, copyDX and copyDY MUST be set to zero. ++ */ ++ ++static void ++rfbCopyRegion(pScreen, cl, src, dst, dx, dy) ++ ScreenPtr pScreen; ++ rfbClientPtr cl; ++ RegionPtr src; ++ RegionPtr dst; ++ int dx, dy; ++{ ++ RegionRec tmp; ++ ++ /* src = src - modifiedRegion */ ++ ++ REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion); ++ ++ if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ ++ REGION_NULL(pScreen, &tmp); ++ REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion); ++ ++ if (REGION_NOTEMPTY(pScreen, &tmp)) { ++ ++ /* if src and copyRegion overlap: ++ src = src intersect copyRegion */ ++ ++ REGION_COPY(pScreen, src, &tmp); ++ ++ } else { ++ ++ /* if no overlap, find bigger region */ ++ ++ int newArea = (((REGION_EXTENTS(pScreen,src))->x2 ++ - (REGION_EXTENTS(pScreen,src))->x1) ++ * ((REGION_EXTENTS(pScreen,src))->y2 ++ - (REGION_EXTENTS(pScreen,src))->y1)); ++ ++ int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2 ++ - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1) ++ * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2 ++ - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1)); ++ ++ if (oldArea > newArea) { ++ ++ /* existing copy is bigger: ++ modifiedRegion = modifiedRegion union dst ++ copyRegion = copyRegion - dst ++ return */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ dst); ++ REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion, ++ dst); ++ if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ } ++ return; ++ } ++ ++ /* new copy is bigger: ++ modifiedRegion = modifiedRegion union copyRegion ++ copyRegion = empty */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ REGION_EMPTY(pScreen, &cl->copyRegion); ++ cl->copyDX = cl->copyDY = 0; ++ } ++ } ++ ++ ++ /* modifiedRegion = modifiedRegion union dst union copyRegion */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst); ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ ++ /* copyRegion = T(src) intersect dst */ ++ ++ REGION_TRANSLATE(pScreen, src, dx, dy); ++ REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst); ++ ++ /* modifiedRegion = modifiedRegion - copyRegion */ ++ ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ ++ /* combine new translation T with existing translation */ ++ ++ if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ cl->copyDX += dx; ++ cl->copyDY += dy; ++ } else { ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ } ++} ++ ++ ++/* ++ * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer ++ * goes off. ++ */ ++ ++static CARD32 ++rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) ++{ ++ rfbClientPtr cl = (rfbClientPtr)arg; ++ ++ rfbSendFramebufferUpdate(cl->pScreen, cl); ++ ++ cl->deferredUpdateScheduled = FALSE; ++ return 0; ++} ++ ++ ++/* ++ * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro ++ * to schedule an update. ++ */ ++ ++static void ++rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl) ++{ ++ if (rfbDeferUpdateTime != 0) { ++ cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0, ++ rfbDeferUpdateTime, ++ rfbDeferredUpdateCallback, cl); ++ cl->deferredUpdateScheduled = TRUE; ++ } else { ++ rfbSendFramebufferUpdate(pScreen, cl); ++ } ++} ++ ++ ++/* ++ * PrintRegion is useful for debugging. ++ */ ++ ++#ifdef DEBUG ++static void ++PrintRegion(ScreenPtr pScreen, RegionPtr reg) ++{ ++ int nrects = REGION_NUM_RECTS(reg); ++ int i; ++ ++ ErrorF("Region num rects %d extents %d,%d %d,%d\n",nrects, ++ (REGION_EXTENTS(pScreen,reg))->x1, ++ (REGION_EXTENTS(pScreen,reg))->y1, ++ (REGION_EXTENTS(pScreen,reg))->x2, ++ (REGION_EXTENTS(pScreen,reg))->y2); ++ ++ for (i = 0; i < nrects; i++) { ++ ErrorF(" rect %d,%d %dx%d\n", ++ REGION_RECTS(reg)[i].x1, ++ REGION_RECTS(reg)[i].y1, ++ REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1, ++ REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1); ++ } ++} ++#endif ++ ++ ++/** ++ * Allow scheduling updates from other functions in other files. ++ */ ++void ++rfbScheduleUpdate(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++} +diff --git a/hw/vnc/hextile.c b/hw/vnc/hextile.c +new file mode 100644 +index 0000000..df0d86e +--- /dev/null ++++ b/hw/vnc/hextile.c +@@ -0,0 +1,351 @@ ++/* ++ * hextile.c ++ * ++ * Routines to implement Hextile Encoding ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++ ++static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h); ++static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h); ++static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h); ++ ++ ++/* ++ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingHextile(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingHextile); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingHextile]++; ++ cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader; ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ return sendHextiles8(cl, x, y, w, h); ++ case 16: ++ return sendHextiles16(cl, x, y, w, h); ++ case 32: ++ return sendHextiles32(cl, x, y, w, h); ++ } ++ ++ rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel); ++ return FALSE; ++} ++ ++ ++#define PUT_PIXEL8(pix) (pVNC->updateBuf[pVNC->ublen++] = (pix)) ++ ++#define PUT_PIXEL16(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1]) ++ ++#define PUT_PIXEL32(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[2], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[3]) ++ ++ ++#define DEFINE_SEND_HEXTILES(bpp) \ ++ \ ++ \ ++static Bool subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, \ ++ int h, CARD##bpp bg, \ ++ CARD##bpp fg, Bool mono); \ ++static void testColours##bpp(CARD##bpp *data, int size, Bool *mono, \ ++ Bool *solid, CARD##bpp *bg, CARD##bpp *fg); \ ++ \ ++ \ ++/* \ ++ * rfbSendHextiles \ ++ */ \ ++ \ ++static Bool \ ++sendHextiles##bpp(cl, rx, ry, rw, rh) \ ++ rfbClientPtr cl; \ ++ int rx, ry, rw, rh; \ ++{ \ ++ VNCSCREENPTR(cl->pScreen); \ ++ int x, y, w, h; \ ++ int startUblen; \ ++ unsigned char *fbptr; \ ++ CARD##bpp bg = 0, fg = 0, newBg, newFg; \ ++ Bool mono, solid; \ ++ Bool validBg = FALSE; \ ++ Bool validFg = FALSE; \ ++ CARD##bpp clientPixelData[16*16*(bpp/8)]; \ ++ \ ++ for (y = ry; y < ry+rh; y += 16) { \ ++ for (x = rx; x < rx+rw; x += 16) { \ ++ w = h = 16; \ ++ if (rx+rw - x < 16) \ ++ w = rx+rw - x; \ ++ if (ry+rh - y < 16) \ ++ h = ry+rh - y; \ ++ \ ++ if ((pVNC->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \ ++ if (!rfbSendUpdateBuf(cl)) \ ++ return FALSE; \ ++ } \ ++ \ ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) \ ++ + (x * (pVNC->bitsPerPixel / 8))); \ ++ \ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \ ++ &pVNC->rfbServerFormat, \ ++ &cl->format, fbptr, (char *)clientPixelData, \ ++ pVNC->paddedWidthInBytes, w, h, x, y); \ ++ \ ++ startUblen = pVNC->ublen; \ ++ pVNC->updateBuf[startUblen] = 0; \ ++ pVNC->ublen++; \ ++ \ ++ testColours##bpp(clientPixelData, w * h, \ ++ &mono, &solid, &newBg, &newFg); \ ++ \ ++ if (!validBg || (newBg != bg)) { \ ++ validBg = TRUE; \ ++ bg = newBg; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \ ++ PUT_PIXEL##bpp(bg); \ ++ } \ ++ \ ++ if (solid) { \ ++ cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \ ++ continue; \ ++ } \ ++ \ ++ pVNC->updateBuf[startUblen] |= rfbHextileAnySubrects; \ ++ \ ++ if (mono) { \ ++ if (!validFg || (newFg != fg)) { \ ++ validFg = TRUE; \ ++ fg = newFg; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \ ++ PUT_PIXEL##bpp(fg); \ ++ } \ ++ } else { \ ++ validFg = FALSE; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileSubrectsColoured; \ ++ } \ ++ \ ++ if (!subrectEncode##bpp(cl->pScreen, clientPixelData, w, h, bg, fg, mono)) { \ ++ /* encoding was too large, use raw */ \ ++ validBg = FALSE; \ ++ validFg = FALSE; \ ++ pVNC->ublen = startUblen; \ ++ pVNC->updateBuf[pVNC->ublen++] = rfbHextileRaw; \ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \ ++ &pVNC->rfbServerFormat, &cl->format, fbptr,\ ++ (char *)clientPixelData, \ ++ pVNC->paddedWidthInBytes, w, h, x, y); \ ++ \ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)clientPixelData,\ ++ w * h * (bpp/8)); \ ++ \ ++ pVNC->ublen += w * h * (bpp/8); \ ++ } \ ++ \ ++ cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \ ++ } \ ++ } \ ++ \ ++ return TRUE; \ ++} \ ++ \ ++ \ ++static Bool \ ++subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, int h, \ ++ CARD##bpp bg, CARD##bpp fg, Bool mono) \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp clientdata; \ ++ int x,y; \ ++ int i,j; \ ++ int hx=0,hy,vx=0,vy; \ ++ int hyflag; \ ++ CARD##bpp *seg; \ ++ CARD##bpp *line; \ ++ int hw,hh,vw,vh; \ ++ int thex,they,thew,theh; \ ++ int numsubs = 0; \ ++ int newLen; \ ++ int nSubrectsUblen; \ ++ \ ++ nSubrectsUblen = pVNC->ublen; \ ++ pVNC->ublen++; \ ++ \ ++ for (y=0; y 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..db13a06 +--- /dev/null ++++ b/hw/vnc/httpd.c +@@ -0,0 +1,516 @@ ++/* ++ * httpd.c - a simple HTTP server ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef USE_LIBWRAP ++#define USE_LIBWRAP 0 ++#endif ++#if USE_LIBWRAP ++#include ++#endif ++ ++#include "rfb.h" ++ ++#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \ ++ "File Not Found\n" \ ++ "

File Not Found

\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 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(¶m_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, ++ "\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..5856734 +--- /dev/null ++++ b/hw/vnc/init.c +@@ -0,0 +1,1066 @@ ++/* ++ * init.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1993 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR ++OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall ++not be used in advertising or otherwise to promote the sale, use or ++other dealings in this Software without prior written authorization ++from the X Consortium. ++ ++*/ ++ ++/* Use ``#define CORBA'' to enable CORBA control interface */ ++ ++/* XXX this definition should probably go elsewhere */ ++#ifndef XVNCRELEASE ++#define XVNCRELEASE "X.org/xf4vnc custom version" ++#endif ++ ++#include "rfb.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "X11/X.h" ++#define NEED_EVENTS ++#include "X11/Xproto.h" ++#include "X11/Xos.h" ++#include ++#include "scrnintstr.h" ++#include "servermd.h" ++#include "fb.h" ++#include "mfb.h" ++#include "mibstore.h" ++#include "colormapst.h" ++#include "gcstruct.h" ++#include "input.h" ++#include "mipointer.h" ++#include "dixstruct.h" ++#include ++#include ++#include "dix.h" ++#include "micmap.h" ++ ++#ifdef CORBA ++#include ++#endif ++ ++#define RFB_DEFAULT_WIDTH 640 ++#define RFB_DEFAULT_HEIGHT 480 ++#define RFB_DEFAULT_DEPTH 8 ++#define RFB_DEFAULT_WHITEPIXEL 0 ++#define RFB_DEFAULT_BLACKPIXEL 1 ++ ++static unsigned long VNCGeneration = 0; ++rfbScreenInfo rfbScreen; ++int rfbGCIndex; ++extern char dispatchExceptionAtReset; ++ ++extern void VncExtensionInit(void); ++extern Bool rfbDCInitialize(ScreenPtr, miPointerScreenFuncPtr); ++ ++static Bool initOutputCalled = FALSE; ++static Bool noCursor = FALSE; ++char *desktopName = "x11"; ++ ++char rfbThisHost[256]; ++ ++Atom VNC_LAST_CLIENT_ID; ++Atom VNC_CONNECT; ++ ++static HWEventQueueType alwaysCheckForInput[2] = { 0, 1 }; ++static HWEventQueueType *mieqCheckForInput[2]; ++ ++static char primaryOrder[4] = ""; ++static int redBits, greenBits, blueBits; ++ ++static Bool rfbScreenInit(int index, ScreenPtr pScreen, int argc, ++ char **argv); ++static int rfbKeybdProc(DeviceIntPtr pDevice, int onoff); ++static int rfbMouseProc(DeviceIntPtr pDevice, int onoff); ++static Bool CheckDisplayNumber(int n); ++ ++static Bool rfbAlwaysTrue(void); ++static unsigned char *rfbAllocateFramebufferMemory(rfbScreenInfoPtr prfb); ++static Bool rfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y); ++static void rfbCrossScreen(ScreenPtr pScreen, Bool entering); ++ ++static miPointerScreenFuncRec rfbPointerCursorFuncs = { ++ rfbCursorOffScreen, ++ rfbCrossScreen, ++ miPointerWarpCursor ++}; ++ ++ ++int inetdSock = -1; ++static char inetdDisplayNumStr[10]; ++ ++/* ++ * ddxProcessArgument is our first entry point and will be called at the ++ * very start for each argument. It is not called again on server reset. ++ */ ++ ++int ++ddxProcessArgument (argc, argv, i) ++ int argc; ++ char *argv[]; ++ int i; ++{ ++ ScreenPtr pScreen = screenInfo.screens[i]; ++ VNCSCREENPTR(pScreen); ++ static Bool firstTime = TRUE; ++ ++ if (firstTime) ++ { ++ pVNC->width = RFB_DEFAULT_WIDTH; ++ pVNC->height = RFB_DEFAULT_HEIGHT; ++ pVNC->depth = RFB_DEFAULT_DEPTH; ++ pVNC->blackPixel = RFB_DEFAULT_BLACKPIXEL; ++ pVNC->whitePixel = RFB_DEFAULT_WHITEPIXEL; ++ pVNC->pfbMemory = NULL; ++ pVNC->httpPort = 0; ++ pVNC->httpDir = NULL; ++ pVNC->rfbAuthPasswdFile = NULL; ++ pVNC->udpPort = 0; ++ pVNC->rfbPort = 0; ++ pVNC->rdpPort = 3389; ++ noCursor = FALSE; ++ pVNC->loginAuthEnabled = FALSE; ++ pVNC->rfbAlwaysShared = FALSE; ++ pVNC->rfbNeverShared = FALSE; ++ pVNC->rfbDontDisconnect = FALSE; ++ pVNC->rfbViewOnly = FALSE; ++ pVNC->useGetImage = FALSE; ++ ++ gethostname(rfbThisHost, 255); ++ pVNC->interface.s_addr = htonl (INADDR_ANY); ++ firstTime = FALSE; ++ } ++ ++ if (strcmp (argv[i], "-geometry") == 0) /* -geometry WxH */ ++ { ++ if (i + 1 >= argc) UseMsg(); ++ if (sscanf(argv[i+1],"%dx%d", ++ &pVNC->width,&pVNC->height) != 2) { ++ ErrorF("Invalid geometry %s\n", argv[i+1]); ++ UseMsg(); ++ } ++#ifdef CORBA ++ screenWidth= pVNC->width; ++ screenHeight= pVNC->height; ++#endif ++ return 2; ++ } ++ ++ if (strcmp (argv[i], "-depth") == 0) /* -depth D */ ++ { ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->depth = atoi(argv[i+1]); ++#ifdef CORBA ++ screenDepth= pVNC->depth; ++#endif ++ return 2; ++ } ++ ++ if (strcmp (argv[i], "-pixelformat") == 0) { ++ if (i + 1 >= argc) UseMsg(); ++ if (sscanf(argv[i+1], "%3s", primaryOrder) < 1) { ++ ErrorF("Invalid pixel format %s\n", argv[i+1]); ++ UseMsg(); ++ } ++ ++ return 2; ++ } ++ ++ if (strcmp (argv[i], "-blackpixel") == 0) { /* -blackpixel n */ ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->blackPixel = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp (argv[i], "-whitepixel") == 0) { /* -whitepixel n */ ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->whitePixel = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp (argv[i], "-usegetimage") == 0) { ++ pVNC->useGetImage = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-udpinputport") == 0) { /* -udpinputport port */ ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->udpPort = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-rfbport") == 0) { /* -rfbport port */ ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->rfbPort = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-rfbwait") == 0) { /* -rfbwait ms */ ++ if (i + 1 >= argc) UseMsg(); ++ rfbMaxClientWait = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-nocursor") == 0) { ++ noCursor = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-rfbauth") == 0) { /* -rfbauth passwd-file */ ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->rfbAuthPasswdFile = argv[i+1]; ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-loginauth") == 0) { ++ if (geteuid() == 0) { ++ /* Only when run as root! */ ++ pVNC->loginAuthEnabled = TRUE; ++ } ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-httpd") == 0) { ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->httpDir = argv[i+1]; ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-httpport") == 0) { ++ if (i + 1 >= argc) UseMsg(); ++ pVNC->httpPort = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-deferupdate") == 0) { /* -deferupdate ms */ ++ if (i + 1 >= argc) UseMsg(); ++ rfbDeferUpdateTime = atoi(argv[i+1]); ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-economictranslate") == 0) { ++ rfbEconomicTranslate = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-lazytight") == 0) { ++ rfbTightDisableGradient = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-desktop") == 0) { /* -desktop desktop-name */ ++ if (i + 1 >= argc) UseMsg(); ++ desktopName = argv[i+1]; ++ return 2; ++ } ++ ++#if 0 /* not deemed useful on standalone server - leave for completeness */ ++ if (strcmp(argv[i], "-useraccept") == 0) { ++ pVNC->rfbUserAccept = TRUE; ++ return 1; ++ } ++#endif ++ ++ if (strcmp(argv[i], "-alwaysshared") == 0) { ++ pVNC->rfbAlwaysShared = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-nevershared") == 0) { ++ pVNC->rfbNeverShared = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-dontdisconnect") == 0) { ++ pVNC->rfbDontDisconnect = TRUE; ++ return 1; ++ } ++ ++ /* Run server in view-only mode - Ehud Karni SW */ ++ if (strcmp(argv[i], "-viewonly") == 0) { ++ pVNC->rfbViewOnly = TRUE; ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-localhost") == 0) { ++ pVNC->interface.s_addr = htonl (INADDR_LOOPBACK); ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-interface") == 0) { /* -interface ipaddr */ ++ struct in_addr got; ++ unsigned long octet; ++ char *p, *end; ++ int q; ++ if (i + 1 >= argc) { ++ UseMsg(); ++ return 2; ++ } ++ if (pVNC->interface.s_addr != htonl (INADDR_ANY)) { ++ /* Already set (-localhost?). */ ++ return 2; ++ } ++ p = argv[i + 1]; ++ for (q = 0; q < 4; q++) { ++ octet = strtoul (p, &end, 10); ++ if (p == end || octet > 255) { ++ UseMsg (); ++ return 2; ++ } ++ if ((q < 3 && *end != '.') || ++ (q == 3 && *end != '\0')) { ++ UseMsg (); ++ return 2; ++ } ++ got.s_addr = (got.s_addr << 8) | octet; ++ p = end + 1; ++ } ++ pVNC->interface.s_addr = htonl (got.s_addr); ++ return 2; ++ } ++ ++ if (strcmp(argv[i], "-inetd") == 0) { /* -inetd */ ++ int n; ++ for (n = 1; n < 100; n++) { ++ if (CheckDisplayNumber(n)) ++ break; ++ } ++ ++ if (n >= 100) ++ FatalError("-inetd: couldn't find free display number"); ++ ++ sprintf(inetdDisplayNumStr, "%d", n); ++ display = inetdDisplayNumStr; ++ ++ /* fds 0, 1 and 2 (stdin, out and err) are all the same socket to the ++ RFB client. OsInit() closes stdout and stdin, and we don't want ++ stderr to go to the RFB client, so make the client socket 3 and ++ close stderr. OsInit() will redirect stderr logging to an ++ appropriate log file or /dev/null if that doesn't work. */ ++ ++ dup2(0,3); ++ inetdSock = 3; ++ close(2); ++ ++ return 1; ++ } ++ ++ if (strcmp(argv[i], "-version") == 0) { ++ ErrorF("Xvnc version %s\n", XVNCRELEASE); ++ exit(0); ++ } ++ ++ if (inetdSock != -1 && argv[i][0] == ':') { ++ FatalError("can't specify both -inetd and :displaynumber"); ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * InitOutput is called every time the server resets. It should call ++ * AddScreen for each screen (FIXME - but we only ever have one), ++ * and in turn this will call rfbScreenInit. ++ */ ++ ++/* Common pixmap formats */ ++ ++static PixmapFormatRec formats[MAXFORMATS] = { ++ { 1, 1, BITMAP_SCANLINE_PAD }, ++ { 4, 8, BITMAP_SCANLINE_PAD }, ++ { 8, 8, BITMAP_SCANLINE_PAD }, ++ { 15, 16, BITMAP_SCANLINE_PAD }, ++ { 16, 16, BITMAP_SCANLINE_PAD }, ++ { 24, 32, BITMAP_SCANLINE_PAD }, ++#ifdef RENDER ++ { 32, 32, BITMAP_SCANLINE_PAD }, ++#endif ++}; ++#ifdef RENDER ++static int numFormats = 7; ++#else ++static int numFormats = 6; ++#endif ++ ++void ++InitOutput(screenInfo, argc, argv) ++ ScreenInfo *screenInfo; ++ int argc; ++ char **argv; ++{ ++ int i; ++ initOutputCalled = TRUE; ++ ++ rfbLog("Xvnc version %s\n", XVNCRELEASE); ++ rfbLog("Copyright (C) 2001-2004 Alan Hourihane.\n"); ++ rfbLog("Copyright (C) 2000-2004 Constantin Kaplinsky\n"); ++ rfbLog("Copyright (C) 1999 AT&T Laboratories Cambridge\n"); ++ rfbLog("All Rights Reserved.\n"); ++ rfbLog("See http://www.tightvnc.com/ for information on TightVNC\n"); ++ rfbLog("See http://xf4vnc.sf.net for xf4vnc-specific information\n"); ++ rfbLog("Desktop name '%s' (%s:%s)\n",desktopName,rfbThisHost,display); ++ rfbLog("Protocol versions supported: %d.%d, %d.%d\n", ++ rfbProtocolMajorVersion, rfbProtocolMinorVersion, ++ rfbProtocolMajorVersion, rfbProtocolFallbackMinorVersion); ++ ++ VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID", ++ strlen("VNC_LAST_CLIENT_ID"), TRUE); ++ VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE); ++ ++ /* initialize pixmap formats */ ++ ++ screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; ++ screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; ++ screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; ++ screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; ++ screenInfo->numPixmapFormats = numFormats; ++ for (i = 0; i < numFormats; i++) ++ screenInfo->formats[i] = formats[i]; ++ ++ rfbGCIndex = AllocateGCPrivateIndex(); ++ if (rfbGCIndex < 0) { ++ FatalError("InitOutput: AllocateGCPrivateIndex failed\n"); ++ } ++ ++ /* initialize screen */ ++ ++ if (AddScreen(rfbScreenInit, argc, argv) == -1) { ++ FatalError("Couldn't add screen"); ++ } ++ ++#ifdef CORBA ++ initialiseCORBA(argc, argv, desktopName); ++#endif ++} ++ ++static void ++rfbWakeupHandler ( ++ int i, ++ pointer blockData, ++ unsigned long err, ++ pointer pReadmask ++){ ++ ScreenPtr pScreen = screenInfo.screens[i]; ++ VNCSCREENPTR(pScreen); ++ int e = (int)err; ++ ++ if (e < 0) ++ goto SKIPME; ++ ++ rfbRootPropertyChange(pScreen); ++ ++#if XFREE86VNC ++ if (pScrn->vtSema) { ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++#if 0 ++ rdpCheckFds(pScreen); ++#endif ++#ifdef CORBA ++ corbaCheckFds(); ++#endif ++ } else { ++ rfbCheckFds(pScreen); ++#if 0 ++ rdpCheckFds(pScreen); ++#endif ++ } ++#else ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++#if 0 ++ rdpCheckFds(pScreen); ++#endif ++#ifdef CORBA ++ corbaCheckFds(); ++#endif ++#endif ++ ++SKIPME: ++ ++ pScreen->WakeupHandler = pVNC->WakeupHandler; ++ (*pScreen->WakeupHandler) (i, blockData, err, pReadmask); ++ pScreen->WakeupHandler = rfbWakeupHandler; ++} ++ ++static Bool ++rfbScreenInit(index, pScreen, argc, argv) ++ int index; ++ ScreenPtr pScreen; ++ int argc; ++ char ** argv; ++{ ++ rfbScreenInfoPtr prfb = &rfbScreen; ++ int dpix = 75, dpiy = 75; ++ int ret; ++ unsigned char *pbits; ++ VisualPtr vis; ++#ifdef RENDER ++ PictureScreenPtr ps; ++#endif ++ ++ if (VNCGeneration != serverGeneration) { ++ VncExtensionInit(); ++ VNCGeneration = serverGeneration; ++ } ++ ++ if (monitorResolution != 0) { ++ dpix = monitorResolution; ++ dpiy = monitorResolution; ++ } ++ ++ prfb->rfbAuthTries = 0; ++ prfb->rfbAuthTooManyTries = FALSE; ++ prfb->rfbUserAccept = FALSE; ++ prfb->udpSockConnected = FALSE; ++ prfb->timer = NULL; ++ prfb->httpListenSock = -1; ++ prfb->httpSock = -1; ++ prfb->rfbListenSock = -1; ++ prfb->rdpListenSock = -1; ++ prfb->paddedWidthInBytes = PixmapBytePad(prfb->width, prfb->depth); ++ prfb->bitsPerPixel = rfbBitsPerPixel(prfb->depth); ++ pbits = rfbAllocateFramebufferMemory(prfb); ++ if (!pbits) return FALSE; ++ ++ miClearVisualTypes(); ++ ++ if (defaultColorVisualClass == -1) ++ defaultColorVisualClass = TrueColor; ++ ++ if (!miSetVisualTypes(prfb->depth, miGetDefaultVisualMask(prfb->depth), 8, ++ defaultColorVisualClass) ) ++ return FALSE; ++ ++ miSetPixmapDepths(); ++ ++ switch (prfb->bitsPerPixel) ++ { ++ case 1: ++ ret = mfbScreenInit(pScreen, pbits, prfb->width, prfb->height, ++ dpix, dpiy, prfb->paddedWidthInBytes * 8); ++ break; ++ case 8: ++ ret = fbScreenInit(pScreen, pbits, prfb->width, prfb->height, ++ dpix, dpiy, prfb->paddedWidthInBytes, 8); ++ break; ++ case 16: ++ ret = fbScreenInit(pScreen, pbits, prfb->width, prfb->height, ++ dpix, dpiy, prfb->paddedWidthInBytes / 2, 16); ++ if (prfb->depth == 15) { ++ blueBits = 5; greenBits = 5; redBits = 5; ++ } else { ++ blueBits = 5; greenBits = 6; redBits = 5; ++ } ++ break; ++ case 32: ++ ret = fbScreenInit(pScreen, pbits, prfb->width, prfb->height, ++ dpix, dpiy, prfb->paddedWidthInBytes / 4, 32); ++ blueBits = 8; greenBits = 8; redBits = 8; ++ break; ++ default: ++ return FALSE; ++ } ++ ++ if (!ret) return FALSE; ++ ++ miInitializeBackingStore(pScreen); ++ ++ if (prfb->bitsPerPixel > 8) { ++ if (strcasecmp(primaryOrder, "bgr") == 0) { ++ rfbLog("BGR format %d %d %d\n", blueBits, greenBits, redBits); ++ vis = pScreen->visuals + pScreen->numVisuals; ++ while (--vis >= pScreen->visuals) { ++ if ((vis->class | DynamicClass) == DirectColor) { ++ vis->offsetRed = 0; ++ vis->redMask = (1 << redBits) - 1; ++ vis->offsetGreen = redBits; ++ vis->greenMask = ((1 << greenBits) - 1) << vis->offsetGreen; ++ vis->offsetBlue = redBits + greenBits; ++ vis->blueMask = ((1 << blueBits) - 1) << vis->offsetBlue; ++ } ++ } ++ } else { ++ rfbLog("RGB format %d %d %d\n", blueBits, greenBits, redBits); ++ vis = pScreen->visuals + pScreen->numVisuals; ++ while (--vis >= pScreen->visuals) { ++ if ((vis->class | DynamicClass) == DirectColor) { ++ vis->offsetBlue = 0; ++ vis->blueMask = (1 << blueBits) - 1; ++ vis->offsetGreen = blueBits; ++ vis->greenMask = ((1 << greenBits) - 1) << vis->offsetGreen; ++ vis->offsetRed = blueBits + greenBits; ++ vis->redMask = ((1 << redBits) - 1) << vis->offsetRed; ++ } ++ } ++ } ++ } ++ ++ if (prfb->bitsPerPixel > 4) ++ fbPictureInit(pScreen, 0, 0); ++ ++ if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec))) { ++ FatalError("rfbScreenInit: AllocateGCPrivate failed\n"); ++ } ++ ++ prfb->cursorIsDrawn = FALSE; ++ prfb->dontSendFramebufferUpdate = FALSE; ++ ++ prfb->CloseScreen = pScreen->CloseScreen; ++ prfb->WakeupHandler = pScreen->WakeupHandler; ++ prfb->CreateGC = pScreen->CreateGC; ++ prfb->PaintWindowBackground = pScreen->PaintWindowBackground; ++ prfb->PaintWindowBorder = pScreen->PaintWindowBorder; ++ prfb->CopyWindow = pScreen->CopyWindow; ++ prfb->ClearToBackground = pScreen->ClearToBackground; ++ prfb->RestoreAreas = pScreen->RestoreAreas; ++#ifdef CHROMIUM ++ prfb->RealizeWindow = pScreen->RealizeWindow; ++ prfb->UnrealizeWindow = pScreen->UnrealizeWindow; ++ prfb->DestroyWindow = pScreen->DestroyWindow; ++ prfb->PositionWindow = pScreen->PositionWindow; ++ prfb->ResizeWindow = pScreen->ResizeWindow; ++ prfb->ClipNotify = pScreen->ClipNotify; ++#endif ++#ifdef RENDER ++ ps = GetPictureScreenIfSet(pScreen); ++ if (ps) ++ prfb->Composite = ps->Composite; ++#endif ++ pScreen->CloseScreen = rfbCloseScreen; ++ pScreen->WakeupHandler = rfbWakeupHandler; ++ pScreen->CreateGC = rfbCreateGC; ++ pScreen->PaintWindowBackground = rfbPaintWindowBackground; ++ pScreen->PaintWindowBorder = rfbPaintWindowBorder; ++ pScreen->CopyWindow = rfbCopyWindow; ++ pScreen->ClearToBackground = rfbClearToBackground; ++ pScreen->RestoreAreas = rfbRestoreAreas; ++#ifdef CHROMIUM ++ pScreen->RealizeWindow = rfbRealizeWindow; ++ pScreen->UnrealizeWindow = rfbUnrealizeWindow; ++ pScreen->DestroyWindow = rfbDestroyWindow; ++ pScreen->PositionWindow = rfbPositionWindow; ++ pScreen->ResizeWindow = rfbResizeWindow; ++ pScreen->ClipNotify = rfbClipNotify; ++#endif ++#ifdef RENDER ++ if (ps) ++ ps->Composite = rfbComposite; ++#endif ++ ++ pScreen->InstallColormap = rfbInstallColormap; ++ pScreen->UninstallColormap = rfbUninstallColormap; ++ pScreen->ListInstalledColormaps = rfbListInstalledColormaps; ++ pScreen->StoreColors = rfbStoreColors; ++ ++ pScreen->SaveScreen = rfbAlwaysTrue; ++ ++ rfbDCInitialize(pScreen, &rfbPointerCursorFuncs); ++ ++ if (noCursor) { ++ pScreen->DisplayCursor = rfbAlwaysTrue; ++ prfb->cursorIsDrawn = TRUE; ++ } ++ ++ pScreen->blackPixel = prfb->blackPixel; ++ pScreen->whitePixel = prfb->whitePixel; ++ ++ prfb->rfbServerFormat.bitsPerPixel = prfb->bitsPerPixel; ++ prfb->rfbServerFormat.depth = prfb->depth; ++ prfb->rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest); ++ ++ /* Find the root visual and set the server format */ ++ for (vis = pScreen->visuals; vis->vid != pScreen->rootVisual; vis++) ++ ; ++ prfb->rfbServerFormat.trueColour = (vis->class == TrueColor); ++ ++ if ( (vis->class == TrueColor) || (vis->class == DirectColor) ) { ++ prfb->rfbServerFormat.redMax = vis->redMask >> vis->offsetRed; ++ prfb->rfbServerFormat.greenMax = vis->greenMask >> vis->offsetGreen; ++ prfb->rfbServerFormat.blueMax = vis->blueMask >> vis->offsetBlue; ++ prfb->rfbServerFormat.redShift = vis->offsetRed; ++ prfb->rfbServerFormat.greenShift = vis->offsetGreen; ++ prfb->rfbServerFormat.blueShift = vis->offsetBlue; ++ } else { ++ prfb->rfbServerFormat.redMax ++ = prfb->rfbServerFormat.greenMax ++ = prfb->rfbServerFormat.blueMax = 0; ++ prfb->rfbServerFormat.redShift ++ = prfb->rfbServerFormat.greenShift ++ = prfb->rfbServerFormat.blueShift = 0; ++ } ++ ++ if (prfb->bitsPerPixel == 1) ++ { ++ ret = mfbCreateDefColormap(pScreen); ++ } ++ else ++ { ++ ret = fbCreateDefColormap(pScreen); ++ } ++ ++ rfbInitSockets(pScreen); ++#if 0 ++ rdpInitSockets(pScreen); ++#endif ++ if (inetdSock == -1) ++ httpInitSockets(pScreen); ++ ++ return ret; ++ ++} /* end rfbScreenInit */ ++ ++ ++ ++/* ++ * InitInput is also called every time the server resets. It is called after ++ * InitOutput so we can assume that rfbInitSockets has already been called. ++ */ ++ ++void ++InitInput(argc, argv) ++ int argc; ++ char *argv[]; ++{ ++ DeviceIntPtr p, k; ++ k = AddInputDevice(rfbKeybdProc, TRUE); ++ p = AddInputDevice(rfbMouseProc, TRUE); ++ RegisterKeyboardDevice(k); ++ RegisterPointerDevice(p); ++ miRegisterPointerDevice(screenInfo.screens[0], p); ++ (void)mieqInit ((DevicePtr)k, (DevicePtr)p); ++#if 0 ++ mieqCheckForInput[0] = checkForInput[0]; ++ mieqCheckForInput[1] = checkForInput[1]; ++ SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]); ++#endif ++} ++ ++ ++static int ++rfbKeybdProc(pDevice, onoff) ++ DeviceIntPtr pDevice; ++ int onoff; ++{ ++ KeySymsRec keySyms; ++ CARD8 modMap[MAP_LENGTH]; ++ DevicePtr pDev = (DevicePtr)pDevice; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ KbdDeviceInit(pDevice, &keySyms, modMap); ++ InitKeyboardDeviceStruct(pDev, &keySyms, modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++ break; ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ KbdDeviceOn(); ++ break; ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ KbdDeviceOff(); ++ break; ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ KbdDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static int ++rfbMouseProc(pDevice, onoff) ++ DeviceIntPtr pDevice; ++ int onoff; ++{ ++ BYTE map[6]; ++ DevicePtr pDev = (DevicePtr)pDevice; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ PtrDeviceInit(); ++ map[1] = 1; ++ map[2] = 2; ++ map[3] = 3; ++ map[4] = 4; ++ map[5] = 5; ++ InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents, ++ PtrDeviceControl, ++ miPointerGetMotionBufferSize()); ++ break; ++ ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ PtrDeviceOn(pDevice); ++ break; ++ ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ PtrDeviceOff(); ++ break; ++ ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ PtrDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++ ++Bool ++LegalModifier(key, pDev) ++ unsigned int key; ++ DevicePtr pDev; ++{ ++ return TRUE; ++} ++ ++ ++void ++ProcessInputEvents() ++{ ++#if 0 ++ if (*mieqCheckForInput[0] != *mieqCheckForInput[1]) { ++#endif ++ mieqProcessInputEvents(); ++ miPointerUpdate(); ++#if 0 ++ } ++#endif ++} ++ ++ ++static Bool CheckDisplayNumber(int n) ++{ ++ char fname[32]; ++ int sock; ++ struct sockaddr_in addr; ++ ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_addr.s_addr = htonl(INADDR_ANY); ++ addr.sin_port = htons(6000+n); ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ close(sock); ++ return FALSE; ++ } ++ close(sock); ++ ++ sprintf(fname, "/tmp/.X%d-lock", n); ++ if (access(fname, F_OK) == 0) ++ return FALSE; ++ ++ sprintf(fname, "/tmp/.X11-unix/X%d", n); ++ if (access(fname, F_OK) == 0) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static Bool ++rfbAlwaysTrue(void) ++{ ++ return TRUE; ++} ++ ++ ++static unsigned char * ++rfbAllocateFramebufferMemory(prfb) ++ rfbScreenInfoPtr prfb; ++{ ++ if (prfb->pfbMemory) return prfb->pfbMemory; /* already done */ ++ ++ prfb->sizeInBytes = (prfb->paddedWidthInBytes * prfb->height); ++ ++ prfb->pfbMemory = (unsigned char *)Xalloc(prfb->sizeInBytes); ++ ++ return prfb->pfbMemory; ++} ++ ++ ++static Bool ++rfbCursorOffScreen (ppScreen, x, y) ++ ScreenPtr *ppScreen; ++ int *x, *y; ++{ ++ return FALSE; ++} ++ ++static void ++rfbCrossScreen (pScreen, entering) ++ ScreenPtr pScreen; ++ Bool entering; ++{ ++} ++ ++void ++ddxGiveUp() ++{ ++ Xfree(rfbScreen.pfbMemory); ++ if (initOutputCalled) { ++ char unixSocketName[32]; ++ sprintf(unixSocketName,"/tmp/.X11-unix/X%s",display); ++ unlink(unixSocketName); ++#ifdef CORBA ++ shutdownCORBA(); ++#endif ++ } ++} ++ ++void ++AbortDDX() ++{ ++ ddxGiveUp(); ++} ++ ++void ++OsVendorInit() ++{ ++} ++ ++void ++OsVendorFatalError() ++{ ++} ++ ++#ifdef DDXTIME /* from ServerOSDefines */ ++CARD32 ++GetTimeInMillis() ++{ ++ struct timeval tp; ++ ++ X_GETTIMEOFDAY(&tp); ++ return(tp.tv_sec * 1000) + (tp.tv_usec / 1000); ++} ++#endif ++ ++void ++ddxUseMsg() ++{ ++ ErrorF("-geometry WxH set framebuffer width & height\n"); ++ ErrorF("-depth D set framebuffer depth\n"); ++ ErrorF("-pixelformat format set pixel format (BGRnnn or RGBnnn)\n"); ++ ErrorF("-udpinputport port UDP port for keyboard/pointer data\n"); ++ ErrorF("-rfbport port TCP port for RFB protocol\n"); ++ ErrorF("-rfbwait time max time in ms to wait for RFB client\n"); ++ ErrorF("-nocursor don't put up a cursor\n"); ++ ErrorF("-rfbauth passwd-file use authentication on RFB protocol\n"); ++ ErrorF("-loginauth use login-style Unix authentication\n"); ++ ErrorF("-httpd dir serve files via HTTP from here\n"); ++ ErrorF("-httpport port port for HTTP\n"); ++ ErrorF("-deferupdate time time in ms to defer updates " ++ "(default 40)\n"); ++ ErrorF("-economictranslate less memory-hungry translation\n"); ++ ErrorF("-lazytight disable \"gradient\" filter in tight " ++ "encoding\n"); ++ ErrorF("-desktop name VNC desktop name (default x11)\n"); ++ ErrorF("-alwaysshared always treat new clients as shared\n"); ++ ErrorF("-nevershared never treat new clients as shared\n"); ++ ErrorF("-dontdisconnect don't disconnect existing clients when a " ++ "new non-shared\n" ++ " connection comes in (refuse new connection " ++ "instead)\n"); ++ ErrorF("-localhost only allow connections from localhost\n" ++ " to the vnc ports. Use -nolisten tcp to disable\n" ++ " remote X clients as well.\n"); ++ ErrorF("-viewonly let clients only view the desktop\n"); ++ ErrorF("-interface ipaddr only bind to specified interface " ++ "address\n"); ++ ErrorF("-inetd Xvnc is launched by inetd\n"); ++ exit(1); ++} ++ ++ ++void ddxInitGlobals(void) ++{ ++ /* dummy function called by InitGlobals in os/utils.c */ ++} ++ ++ ++/* ++ * rfbLog prints a time-stamped message to the log file (stderr). ++ */ ++void rfbLog(char *format, ...) ++{ ++ va_list args; ++ char buf[256]; ++ time_t clock; ++ ++ va_start(args, format); ++ ++ time(&clock); ++ strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock)); ++ fprintf(stderr, buf); ++ ++ vfprintf(stderr, format, args); ++ fflush(stderr); ++ ++ va_end(args); ++} ++ ++void rfbLogPerror(char *str) ++{ ++ rfbLog(""); ++ perror(str); ++} +diff --git a/hw/vnc/kbdptr.c b/hw/vnc/kbdptr.c +new file mode 100644 +index 0000000..46e8f2d +--- /dev/null ++++ b/hw/vnc/kbdptr.c +@@ -0,0 +1,425 @@ ++/* ++ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ * ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "rfb.h" ++#include ++#define NEED_EVENTS ++#include ++#include "inputstr.h" ++#define XK_CYRILLIC ++#include ++#include ++#include "mi.h" ++#include "mipointer.h" ++ ++#if XFREE86VNC ++#ifdef XINPUT ++#include "xf86Xinput.h" ++#define Enqueue(ev) xf86eqEnqueue(ev) ++#else ++#define Enqueue(ev) mieqEnqueue(ev) ++#endif ++#else ++#define Enqueue(ev) mieqEnqueue(ev) ++#endif ++ ++#define KEY_IS_PRESSED(keycode) \ ++ (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7))) ++ ++static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper); ++ ++DeviceIntPtr kbdDevice; ++ ++#include "keyboard.h" ++ ++/* ++ * Called when the rfbserver receives a rfbKeyEvent event from a client. ++ * Put an X keyboard event into the event queue. ++ */ ++void ++KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl) ++{ ++ xEvent ev, fake; ++ KeySymsPtr keySyms; ++ int i; ++ int keyCode = 0; ++ int freeIndex = -1; ++ unsigned long time; ++ Bool fakeShiftPress = FALSE; ++ Bool fakeShiftLRelease = FALSE; ++ Bool fakeShiftRRelease = FALSE; ++ Bool shiftMustBeReleased = FALSE; ++ Bool shiftMustBePressed = FALSE; ++ ++ if (!kbdDevice) return; ++ ++ keySyms = &kbdDevice->key->curKeySyms; ++ ++#ifdef CORBA ++ if (cl) { ++ CARD32 clientId = cl->sock; ++ ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, ++ 32, PropModeReplace, 1, (pointer)&clientId, TRUE); ++ } ++#endif ++ ++ if (down) { ++ ev.u.u.type = KeyPress; ++ } else { ++ ev.u.u.type = KeyRelease; ++ } ++ ++ /* NOTE: This is where it gets hairy for XFree86 servers. ++ * I think the best way to deal with this is invent a new protocol ++ * to send over the wire the remote keyboard type and correctly ++ * handle that as XINPUT extension device (we're part of the way ++ * there for that. ++ * ++ * Alan. ++ */ ++#if !XFREE86VNC ++ /* First check if it's one of our predefined keys. If so then we can make ++ some attempt at allowing an xmodmap inside a VNC desktop behave ++ something like you'd expect - e.g. if keys A & B are swapped over and ++ the VNC client sends an A, then map it to a B when generating the X ++ event. We don't attempt to do this for keycodes which we make up on the ++ fly because it's too hard... */ ++ ++ for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { ++ if (keySym == map[i]) { ++ keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY; ++ ++ if (map[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) { ++ ++ /* this keycode has more than one symbol associated with it, ++ so shift state is important */ ++ ++ if ((i % GLYPHS_PER_KEY) == 0) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ break; ++ } ++ } ++#endif ++ ++ if (!keyCode) { ++ ++ /* not one of our predefined keys - see if it's in the current keyboard ++ mapping (i.e. we've already allocated an extra keycode for it) */ ++ ++ if (keySyms->mapWidth < 2) { ++ ErrorF("KbdAddEvent: Sanity check failed - Keyboard mapping has " ++ "less than 2 keysyms per keycode (KeySym 0x%x)\n", keySym); ++ return; ++ } ++ ++ for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) { ++ if (keySym == keySyms->map[i]) { ++ keyCode = MIN_KEY_CODE + i / keySyms->mapWidth; ++ ++ if (keySyms->map[(i / keySyms->mapWidth) ++ * keySyms->mapWidth + 1] != NoSymbol) { ++ ++ /* this keycode has more than one symbol associated with ++ it, so shift state is important */ ++ ++ if ((i % keySyms->mapWidth) == 0) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ break; ++ } ++ if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol) ++ && (i % keySyms->mapWidth) == 0) ++ { ++ freeIndex = i; ++ } ++ } ++ } ++ ++ if (!keyCode) { ++ KeySym lower, upper; ++ ++ /* we don't have an existing keycode - make one up on the fly and add ++ it to the keyboard mapping. Thanks to Vlad Harchev for pointing ++ out problems with non-ascii capitalisation. */ ++ ++ if (freeIndex == -1) { ++ ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n", ++ keySym); ++ return; ++ } ++ ++ keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth; ++ ++ XConvertCase(keySym, &lower, &upper); ++ ++ if (lower == upper) { ++ keySyms->map[freeIndex] = keySym; ++ ++ } else { ++ keySyms->map[freeIndex] = lower; ++ keySyms->map[freeIndex+1] = upper; ++ ++ if (keySym == lower) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ ++ SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient); ++ ++ ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n", ++ keySym, keyCode); ++ } ++ ++ time = GetTimeInMillis(); ++ ++ if (down) { ++ if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) { ++ fakeShiftPress = TRUE; ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) { ++ if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) { ++ fakeShiftLRelease = TRUE; ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) { ++ fakeShiftRRelease = TRUE; ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_R_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ } ++ } ++ ++ ev.u.u.detail = keyCode; ++ ev.u.keyButtonPointer.time = time; ++ Enqueue(&ev); ++ ++ if (fakeShiftPress) { ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (fakeShiftLRelease) { ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (fakeShiftRRelease) { ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_R_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++} ++ ++/* ++ * Called when the rfbserver receives a rfbPointerEvent event from a client. ++ * Put an X mouse event into the event queue. ++ */ ++void ++PtrAddEvent(buttonMask, x, y, cl) ++ int buttonMask; ++ int x; ++ int y; ++ rfbClientPtr cl; ++{ ++ xEvent ev; ++ int i; ++ unsigned long time; ++ static int oldButtonMask = 0; ++ ++#ifdef CORBA ++ if (cl) { ++ CARD32 clientId = cl->sock; ++ ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, ++ 32, PropModeReplace, 1, (pointer)&clientId, TRUE); ++ } ++#endif ++ ++ time = GetTimeInMillis(); ++ ++ miPointerAbsoluteCursor(x, y, time); ++ ++ for (i = 0; i < 5; i++) { ++ if ((buttonMask ^ oldButtonMask) & (1<key->down[i] != 0) { ++ for (j = 0; j < 8; j++) { ++ if (kbdDevice->key->down[i] & (1 << j)) { ++ ev.u.u.type = KeyRelease; ++ ev.u.u.detail = (i << 3) | j; ++ ev.u.keyButtonPointer.time = time; ++ Enqueue(&ev); ++ } ++ } ++ } ++ } ++} ++ ++ ++/* copied from Xlib source */ ++ ++static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper) ++{ ++ *lower = sym; ++ *upper = sym; ++ switch(sym >> 8) { ++ case 0: /* Latin 1 */ ++ if ((sym >= XK_A) && (sym <= XK_Z)) ++ *lower += (XK_a - XK_A); ++ else if ((sym >= XK_a) && (sym <= XK_z)) ++ *upper -= (XK_a - XK_A); ++ else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) ++ *lower += (XK_agrave - XK_Agrave); ++ else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) ++ *upper -= (XK_agrave - XK_Agrave); ++ else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) ++ *lower += (XK_oslash - XK_Ooblique); ++ else if ((sym >= XK_oslash) && (sym <= XK_thorn)) ++ *upper -= (XK_oslash - XK_Ooblique); ++ break; ++ case 1: /* Latin 2 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym == XK_Aogonek) ++ *lower = XK_aogonek; ++ else if (sym >= XK_Lstroke && sym <= XK_Sacute) ++ *lower += (XK_lstroke - XK_Lstroke); ++ else if (sym >= XK_Scaron && sym <= XK_Zacute) ++ *lower += (XK_scaron - XK_Scaron); ++ else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) ++ *lower += (XK_zcaron - XK_Zcaron); ++ else if (sym == XK_aogonek) ++ *upper = XK_Aogonek; ++ else if (sym >= XK_lstroke && sym <= XK_sacute) ++ *upper -= (XK_lstroke - XK_Lstroke); ++ else if (sym >= XK_scaron && sym <= XK_zacute) ++ *upper -= (XK_scaron - XK_Scaron); ++ else if (sym >= XK_zcaron && sym <= XK_zabovedot) ++ *upper -= (XK_zcaron - XK_Zcaron); ++ else if (sym >= XK_Racute && sym <= XK_Tcedilla) ++ *lower += (XK_racute - XK_Racute); ++ else if (sym >= XK_racute && sym <= XK_tcedilla) ++ *upper -= (XK_racute - XK_Racute); ++ break; ++ case 2: /* Latin 3 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) ++ *lower += (XK_hstroke - XK_Hstroke); ++ else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) ++ *lower += (XK_gbreve - XK_Gbreve); ++ else if (sym >= XK_hstroke && sym <= XK_hcircumflex) ++ *upper -= (XK_hstroke - XK_Hstroke); ++ else if (sym >= XK_gbreve && sym <= XK_jcircumflex) ++ *upper -= (XK_gbreve - XK_Gbreve); ++ else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) ++ *lower += (XK_cabovedot - XK_Cabovedot); ++ else if (sym >= XK_cabovedot && sym <= XK_scircumflex) ++ *upper -= (XK_cabovedot - XK_Cabovedot); ++ break; ++ case 3: /* Latin 4 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Rcedilla && sym <= XK_Tslash) ++ *lower += (XK_rcedilla - XK_Rcedilla); ++ else if (sym >= XK_rcedilla && sym <= XK_tslash) ++ *upper -= (XK_rcedilla - XK_Rcedilla); ++ else if (sym == XK_ENG) ++ *lower = XK_eng; ++ else if (sym == XK_eng) ++ *upper = XK_ENG; ++ else if (sym >= XK_Amacron && sym <= XK_Umacron) ++ *lower += (XK_amacron - XK_Amacron); ++ else if (sym >= XK_amacron && sym <= XK_umacron) ++ *upper -= (XK_amacron - XK_Amacron); ++ break; ++ case 6: /* Cyrillic */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) ++ *lower -= (XK_Serbian_DJE - XK_Serbian_dje); ++ else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) ++ *upper += (XK_Serbian_DJE - XK_Serbian_dje); ++ else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) ++ *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); ++ else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) ++ *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); ++ break; ++ case 7: /* Greek */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) ++ *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); ++ else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && ++ sym != XK_Greek_iotaaccentdieresis && ++ sym != XK_Greek_upsilonaccentdieresis) ++ *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); ++ else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) ++ *lower += (XK_Greek_alpha - XK_Greek_ALPHA); ++ else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && ++ sym != XK_Greek_finalsmallsigma) ++ *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); ++ break; ++ } ++} +diff --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 ++ */ ++ ++#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..2915c4f +--- /dev/null ++++ b/hw/vnc/loginauth.c +@@ -0,0 +1,138 @@ ++/* ++ * loginauth.c - deal with login-style Unix authentication. ++ * ++ * This file implements the UnixLogin authentication protocol when setting up ++ * an RFB connection. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef linux ++#include /* XXX xserver has a shadow.h file too */ ++#endif ++#include ++#include ++#include ++#include ++#include ++#include "rfb.h" ++ ++void rfbLoginAuthProcessClientMessage(rfbClientPtr cl) ++{ ++ int n1 = 0, n2 = 0; ++ CARD32 loginLen, passwdLen, authResult; ++ char *loginBuf, *passwdBuf; ++ struct passwd *ps; ++ char *encPasswd1, *encPasswd2; ++ Bool ok; ++ ++ if ((n1 = ReadExact(cl->sock, (char *)&loginLen, ++ sizeof(loginLen))) <= 0 || ++ (n2 = ReadExact(cl->sock, (char *)&passwdLen, ++ sizeof(passwdLen))) <= 0) { ++ if (n1 != 0 || n2 != 0) ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ loginLen = Swap32IfLE(loginLen); ++ passwdLen = Swap32IfLE(passwdLen); ++ loginBuf = (char *)xalloc(loginLen + 1); ++ passwdBuf = (char *)xalloc(passwdLen + 1); ++ ++ n1 = n2 = 0; ++ if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 || ++ (n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) { ++ if (n1 != 0 || n2 != 0) ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ loginBuf[loginLen] = '\0'; ++ passwdBuf[passwdLen] = '\0'; ++ ++ encPasswd1 = encPasswd2 = NULL; ++ ++ ps = getpwnam(loginBuf); ++ if (ps == NULL) { ++ rfbLog("rfbLoginAuthProcessClientMessage: " ++ "Cannot get password file entry for \"%s\"\n", loginBuf); ++ } else { ++ encPasswd1 = ps->pw_passwd; ++#ifdef linux ++ if (strlen(ps->pw_passwd) == 1) { ++ struct spwd *sps; ++ ++ sps = getspnam(loginBuf); ++ if (sps == NULL) { ++ rfbLog("rfbLoginAuthProcessClientMessage:" ++ " getspnam() failed for user \"%s\"\n", loginBuf); ++ } else { ++ encPasswd1 = sps->sp_pwdp; ++ } ++ } ++#endif ++ encPasswd2 = crypt(passwdBuf, encPasswd1); ++ memset(passwdBuf, 0, strlen(passwdBuf)); ++ } ++ ++ ok = FALSE; ++ if (encPasswd1 != NULL && encPasswd2 != NULL) { ++ if (strcmp(encPasswd1, encPasswd2) == 0) ++ ok = TRUE; ++ } ++ ++ if (!ok) { ++ rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n", ++ cl->host); ++ ++ if (rfbAuthConsiderBlocking(cl)) { ++ authResult = Swap32IfLE(rfbVncAuthTooMany); ++ } else { ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ } ++ ++ if (WriteExact(cl->sock, (char *)&authResult, ++ sizeof(authResult)) < 0) { ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ rfbAuthUnblock(cl); ++ ++ cl->login = strdup(loginBuf); ++ rfbLog("Login-style authentication passed for user %s at %s\n", ++ cl->login, cl->host); ++ ++ authResult = Swap32IfLE(rfbVncAuthOK); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) { ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ cl->state = RFB_INITIALISATION; ++} ++ +diff --git a/hw/vnc/rdp.c b/hw/vnc/rdp.c +new file mode 100644 +index 0000000..cd9aedb +--- /dev/null ++++ b/hw/vnc/rdp.c +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (C) 2004 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#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..ccb0411 +--- /dev/null ++++ b/hw/vnc/rfb.h +@@ -0,0 +1,725 @@ ++/* ++ * rfb.h - header file for RFB DDX implementation. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000-2004 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if HAVE_DIX_CONFIG_H ++#include "dix-config.h" ++#endif ++ ++#include ++#if 0 && XFREE86VNC /* not yet */ ++#include "xf86.h" ++#include "xf86_OSproc.h" ++#include "xf86_ansic.h" ++#endif ++#include "scrnintstr.h" ++#include "colormapst.h" ++#include "dixstruct.h" ++#include "gcstruct.h" ++#include "regionstr.h" ++#include "windowstr.h" ++#include "dixfontstr.h" ++#if 1 /* && !XFREE86VNC */ ++/*#include "osdep.h"*/ ++#endif ++#include ++#include ++#define _VNC_SERVER ++#include ++#if 1/*def RENDER*/ ++#include "picturestr.h" ++#endif ++ ++#if defined(sun) || defined(hpux) ++#define SOCKLEN_T int ++#else ++#define SOCKLEN_T socklen_t ++#endif ++ ++/* It's a good idea to keep these values a bit greater than required. */ ++#define MAX_ENCODINGS 10 ++#define MAX_SECURITY_TYPES 4 ++#define MAX_TUNNELING_CAPS 16 ++#define MAX_AUTH_CAPS 16 ++ ++/* ++ * HTTP_BUF_SIZE for http transfers ++ */ ++#define HTTP_BUF_SIZE 32768 ++ ++/* ++ * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the ++ * framebuffer. So for a max screen width of say 2K with 32-bit pixels this ++ * means 8K minimum. ++ */ ++#define UPDATE_BUF_SIZE 30000 ++ ++#if XFREE86VNC ++#include "xf86.h" ++#include "vnc.h" ++#define VNCSCREENPTR(ptr) \ ++ vncScreenPtr pVNC = VNCPTR(ptr) ++#else ++#define VNCSCREENPTR(ptr) \ ++/* Soon \ ++ rfbScreenInfoPtr pVNC = rfbScreen[ptr->myNum] \ ++*/ \ ++ rfbScreenInfoPtr pVNC = &rfbScreen ++#endif ++ ++/* ++ * Per-screen (framebuffer) structure. There is only one of these, since we ++ * don't allow the X server to have multiple screens. ++ */ ++ ++typedef struct ++{ ++ int rfbPort; ++ int rdpPort; ++ int udpPort; ++ int rfbListenSock; ++ int rdpListenSock; ++ int udpSock; ++ int httpPort; ++ int httpListenSock; ++ int httpSock; ++ char * httpDir; ++ char buf[HTTP_BUF_SIZE]; ++ Bool udpSockConnected; ++ char * rfbAuthPasswdFile; ++ size_t buf_filled; ++ int maxFd; ++ fd_set allFds; ++ Bool useGetImage; ++ Bool noCursor; ++ Bool rfbAlwaysShared; ++ Bool rfbNeverShared; ++ Bool rfbDontDisconnect; ++ Bool rfbUserAccept; ++ Bool rfbViewOnly; ++ ColormapPtr savedColormap; ++ ColormapPtr rfbInstalledColormap; ++ rfbPixelFormat rfbServerFormat; ++ Bool rfbAuthTooManyTries; ++ int rfbAuthTries; ++ Bool loginAuthEnabled; ++ struct in_addr interface; ++ OsTimerPtr timer; ++ char updateBuf[UPDATE_BUF_SIZE]; ++ int ublen; ++ int width; ++ int paddedWidthInBytes; ++ int height; ++ int depth; ++ int bitsPerPixel; ++ int sizeInBytes; ++ unsigned char *pfbMemory; ++ Pixel blackPixel; ++ Pixel whitePixel; ++ ++ /* The following two members are used to minimise the amount of unnecessary ++ drawing caused by cursor movement. Whenever any drawing affects the ++ part of the screen where the cursor is, the cursor is removed first and ++ then the drawing is done (this is what the sprite routines test for). ++ Afterwards, however, we do not replace the cursor, even when the cursor ++ is logically being moved across the screen. We only draw the cursor ++ again just as we are about to send the client a framebuffer update. ++ ++ We need to be careful when removing and drawing the cursor because of ++ their relationship with the normal drawing routines. The drawing ++ routines can invoke the cursor routines, but also the cursor routines ++ themselves end up invoking drawing routines. ++ ++ Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by ++ doing a CopyArea from a pixmap to the screen, where the pixmap contains ++ the saved contents of the screen under the cursor. Before doing this, ++ however, we set cursorIsDrawn to FALSE. Then, when CopyArea is called, ++ it sees that cursorIsDrawn is FALSE and so doesn't feel the need to ++ (recursively!) remove the cursor before doing it. ++ ++ Putting up the cursor (rfbSpriteRestoreCursor) involves a call to ++ PushPixels. While this is happening, cursorIsDrawn must be FALSE so ++ that PushPixels doesn't think it has to remove the cursor first. ++ Obviously cursorIsDrawn is set to TRUE afterwards. ++ ++ Another problem we face is that drawing routines sometimes cause a ++ framebuffer update to be sent to the RFB client. When the RFB client is ++ already waiting for a framebuffer update and some drawing to the ++ framebuffer then happens, the drawing routine sees that the client is ++ ready, so it calls rfbSendFramebufferUpdate. If the cursor is not drawn ++ at this stage, it must be put up, and so rfbSpriteRestoreCursor is ++ called. However, if the original drawing routine was actually called ++ from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't ++ want this to happen. So both the cursor routines set ++ dontSendFramebufferUpdate to TRUE, and all the drawing routines check ++ this before calling rfbSendFramebufferUpdate. */ ++ ++ Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ ++ Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the ++ cursor */ ++ ++ /* wrapped screen functions */ ++ ++ CloseScreenProcPtr CloseScreen; ++ CreateGCProcPtr CreateGC; ++ PaintWindowBackgroundProcPtr PaintWindowBackground; ++ PaintWindowBorderProcPtr PaintWindowBorder; ++ CopyWindowProcPtr CopyWindow; ++ ClearToBackgroundProcPtr ClearToBackground; ++ RestoreAreasProcPtr RestoreAreas; ++ ScreenWakeupHandlerProcPtr WakeupHandler; ++#ifdef CHROMIUM ++ RealizeWindowProcPtr RealizeWindow; ++ UnrealizeWindowProcPtr UnrealizeWindow; ++ DestroyWindowProcPtr DestroyWindow; ++ ResizeWindowProcPtr ResizeWindow; ++ PositionWindowProcPtr PositionWindow; ++ ClipNotifyProcPtr ClipNotify; ++#endif ++#ifdef RENDER ++ CompositeProcPtr Composite; ++#endif ++ ++} rfbScreenInfo, *rfbScreenInfoPtr; ++ ++ ++/* ++ * rfbTranslateFnType is the type of translation functions. ++ */ ++ ++struct rfbClientRec; ++typedef void (*rfbTranslateFnType)(ScreenPtr pScreen, ++ char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y); ++ ++ ++/* ++ * Per-client structure. ++ */ ++ ++typedef struct rfbClientRec { ++ int sock; ++ char *host; ++ char *login; ++ ++ int protocol_minor_ver; /* RFB protocol minor version in use. */ ++ Bool protocol_tightvnc; /* TightVNC protocol extensions enabled */ ++ ++ /* Possible client states: */ ++ ++ enum { ++ RFB_PROTOCOL_VERSION, /* establishing protocol version */ ++ RFB_SECURITY_TYPE, /* negotiating security (RFB v.3.7) */ ++ RFB_TUNNELING_TYPE, /* establishing tunneling (RFB v.3.7t) */ ++ RFB_AUTH_TYPE, /* negotiating authentication (RFB v.3.7t) */ ++ RFB_AUTHENTICATION, /* authenticating (VNC authentication) */ ++ RFB_INITIALISATION, /* sending initialisation messages */ ++ RFB_NORMAL /* normal protocol messages */ ++ } state; ++ ++ Bool viewOnly; /* Do not accept input from this client. */ ++ ++ Bool reverseConnection; ++ ++ Bool readyForSetColourMapEntries; ++ ++ Bool useCopyRect; ++ int preferredEncoding; ++ int correMaxWidth, correMaxHeight; ++ ++ /* The list of security types sent to this client (protocol 3.7). ++ Note that the first entry is the number of list items following. */ ++ ++ CARD8 securityTypes[MAX_SECURITY_TYPES + 1]; ++ ++ /* Lists of capability codes sent to clients. We remember these ++ lists to restrict clients from choosing those tunneling and ++ authentication types that were not advertised. */ ++ ++ int nAuthCaps; ++ CARD32 authCaps[MAX_AUTH_CAPS]; ++ ++ /* This is not useful while we don't support tunneling: ++ int nTunnelingCaps; ++ CARD32 tunnelingCaps[MAX_TUNNELING_CAPS]; */ ++ ++ /* The following member is only used during VNC authentication */ ++ ++ CARD8 authChallenge[CHALLENGESIZE]; ++ ++ /* The following members represent the update needed to get the client's ++ framebuffer from its present state to the current state of our ++ framebuffer. ++ ++ If the client does not accept CopyRect encoding then the update is ++ simply represented as the region of the screen which has been modified ++ (modifiedRegion). ++ ++ If the client does accept CopyRect encoding, then the update consists of ++ two parts. First we have a single copy from one region of the screen to ++ another (the destination of the copy is copyRegion), and second we have ++ the region of the screen which has been modified in some other way ++ (modifiedRegion). ++ ++ Although the copy is of a single region, this region may have many ++ rectangles. When sending an update, the copyRegion is always sent ++ before the modifiedRegion. This is because the modifiedRegion may ++ overlap parts of the screen which are in the source of the copy. ++ ++ In fact during normal processing, the modifiedRegion may even overlap ++ the destination copyRegion. Just before an update is sent we remove ++ from the copyRegion anything in the modifiedRegion. */ ++ ++ RegionRec copyRegion; /* the destination region of the copy */ ++ int copyDX, copyDY; /* the translation by which the copy happens */ ++ ++ RegionRec modifiedRegion; /* the region of the screen modified in any ++ other way */ ++ ++ /* As part of the FramebufferUpdateRequest, a client can express interest ++ in a subrectangle of the whole framebuffer. This is stored in the ++ requestedRegion member. In the normal case this is the whole ++ framebuffer if the client is ready, empty if it's not. */ ++ ++ RegionRec requestedRegion; ++ ++ /* The following members represent the state of the "deferred update" timer ++ - when the framebuffer is modified and the client is ready, in most ++ cases it is more efficient to defer sending the update by a few ++ milliseconds so that several changes to the framebuffer can be combined ++ into a single update. */ ++ ++ Bool deferredUpdateScheduled; ++ OsTimerPtr deferredUpdateTimer; ++ ++ /* translateFn points to the translation function which is used to copy ++ and translate a rectangle from the framebuffer to an output buffer. */ ++ ++ rfbTranslateFnType translateFn; ++ ++ char *translateLookupTable; ++ ++ rfbPixelFormat format; ++ ++ /* statistics */ ++ ++ int rfbBytesSent[MAX_ENCODINGS]; ++ int rfbRectanglesSent[MAX_ENCODINGS]; ++ int rfbLastRectMarkersSent; ++ int rfbLastRectBytesSent; ++ int rfbCursorShapeBytesSent; ++ int rfbCursorShapeUpdatesSent; ++ int rfbCursorPosBytesSent; ++ int rfbCursorPosUpdatesSent; ++ int rfbFramebufferUpdateMessagesSent; ++ int rfbRawBytesEquivalent; ++ int rfbKeyEventsRcvd; ++ int rfbPointerEventsRcvd; ++ ++ /* zlib encoding -- necessary compression state info per client */ ++ ++ struct z_stream_s compStream; ++ Bool compStreamInited; ++ ++ CARD32 zlibCompressLevel; ++ ++ /* tight encoding -- preserve zlib streams' state for each client */ ++ ++ z_stream zsStruct[4]; ++ Bool zsActive[4]; ++ int zsLevel[4]; ++ int tightCompressLevel; ++ int tightQualityLevel; ++ ++ Bool enableLastRectEncoding; /* client supports LastRect encoding */ ++ Bool enableCursorShapeUpdates; /* client supports cursor shape updates */ ++ Bool enableCursorPosUpdates; /* client supports PointerPos updates */ ++#ifdef CHROMIUM ++ Bool enableChromiumEncoding; /* client supports Chromium encoding */ ++#endif ++ Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */ ++ Bool cursorWasChanged; /* cursor shape update should be sent */ ++ Bool cursorWasMoved; /* cursor position update should be sent */ ++ ++ int cursorX, cursorY; /* client's cursor position */ ++ ++ struct rfbClientRec *next; ++ ++ ScreenPtr pScreen; ++ int userAccepted; ++ ++#ifdef CHROMIUM ++ unsigned int chromium_port; ++ unsigned int chromium_msport; ++#endif ++} rfbClientRec, *rfbClientPtr; ++ ++#ifdef CHROMIUM ++typedef struct CRWindowTable { ++ unsigned long CRwinId; ++ unsigned long XwinId; ++ BoxPtr clipRects; ++ int numRects; ++ struct CRWindowTable *next; ++} CRWindowTable, *CRWindowTablePtr; ++ ++extern struct CRWindowTable *windowTable; ++#endif ++ ++/* ++ * This macro is used to test whether there is a framebuffer update needing to ++ * be sent to the client. ++ */ ++ ++#define FB_UPDATE_PENDING(cl) \ ++ ((!(cl)->enableCursorShapeUpdates && !pVNC->cursorIsDrawn) || \ ++ ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \ ++ ((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) || \ ++ REGION_NOTEMPTY(((cl)->pScreen),&(cl)->copyRegion) || \ ++ REGION_NOTEMPTY(((cl)->pScreen),&(cl)->modifiedRegion)) ++ ++/* ++ * This macro creates an empty region (ie. a region with no areas) if it is ++ * given a rectangle with a width or height of zero. It appears that ++ * REGION_INTERSECT does not quite do the right thing with zero-width ++ * rectangles, but it should with completely empty regions. ++ */ ++ ++#define SAFE_REGION_INIT(pscreen, preg, rect, size) \ ++{ \ ++ if ( ( (rect) ) && \ ++ ( ( (rect)->x2 == (rect)->x1 ) || \ ++ ( (rect)->y2 == (rect)->y1 ) ) ) { \ ++ REGION_NULL( (pscreen), (preg) ); \ ++ } else { \ ++ REGION_INIT( (pscreen), (preg), (rect), (size) ); \ ++ } \ ++} ++ ++/* ++ * An rfbGCRec is where we store the pointers to the original GC funcs and ops ++ * which we wrap (NULL means not wrapped). ++ */ ++ ++typedef struct { ++ GCFuncs *wrapFuncs; ++ GCOps *wrapOps; ++} rfbGCRec, *rfbGCPtr; ++ ++ ++ ++/* ++ * Macros for endian swapping. ++ */ ++ ++#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) ++ ++#define Swap32(l) (((l) >> 24) | \ ++ (((l) & 0x00ff0000) >> 8) | \ ++ (((l) & 0x0000ff00) << 8) | \ ++ ((l) << 24)) ++ ++static const int rfbEndianTest = 1; ++ ++#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s)) ++ ++#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l)) ++ ++ ++/* ++ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.130). ++ * Normally, using macros is no good, but this macro saves us from ++ * writing constants twice -- it constructs signature names from codes. ++ * Note that "code_sym" argument should be a single symbol, not an expression. ++ */ ++ ++#define SetCapInfo(cap_ptr, code_sym, vendor) \ ++{ \ ++ rfbCapabilityInfo *pcap; \ ++ pcap = (cap_ptr); \ ++ pcap->code = Swap32IfLE(code_sym); \ ++ memcpy(pcap->vendorSignature, (vendor), \ ++ sz_rfbCapabilityInfoVendor); \ ++ memcpy(pcap->nameSignature, sig_##code_sym, \ ++ sz_rfbCapabilityInfoName); \ ++} ++ ++ ++/* init.c */ ++ ++extern char *desktopName; ++extern char rfbThisHost[]; ++extern Atom VNC_LAST_CLIENT_ID; ++ ++extern rfbScreenInfo rfbScreen; ++extern int rfbGCIndex; ++ ++extern int inetdSock; ++ ++extern int rfbBitsPerPixel(int depth); ++extern void rfbLog(char *format, ...); ++extern void rfbLogPerror(char *str); ++ ++ ++/* sockets.c */ ++ ++extern int rfbMaxClientWait; ++ ++extern Bool rfbInitSockets(ScreenPtr pScreen); ++extern void rfbDisconnectUDPSock(ScreenPtr pScreen); ++extern void rfbCloseSock(ScreenPtr pScreen, int sock); ++extern void rfbCheckFds(ScreenPtr pScreen); ++extern void rfbWaitForClient(int sock); ++extern int rfbConnect(ScreenPtr pScreen, char *host, int port); ++ ++extern int ReadExact(int sock, char *buf, int len); ++extern int WriteExact(int sock, char *buf, int len); ++extern int ListenOnTCPPort(ScreenPtr pScreen, int port); ++extern int ListenOnUDPPort(ScreenPtr pScreen, int port); ++extern int ConnectToTcpAddr(char *host, int port); ++ ++ ++/* cmap.c */ ++ ++ ++extern int rfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps); ++extern void rfbInstallColormap(ColormapPtr pmap); ++extern void rfbUninstallColormap(ColormapPtr pmap); ++extern void rfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs); ++ ++ ++/* draw.c */ ++ ++extern int rfbDeferUpdateTime; ++ ++extern void ++rfbComposite( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height ++); ++ ++extern void rfbGlyphs( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlistInit, ++ GlyphListPtr listInit, ++ GlyphPtr *glyphsInit ++); ++extern Bool rfbCloseScreen(int,ScreenPtr); ++extern Bool rfbCreateGC(GCPtr); ++extern void rfbPaintWindowBackground(WindowPtr, RegionPtr, int what); ++extern void rfbPaintWindowBorder(WindowPtr, RegionPtr, int what); ++extern void rfbCopyWindow(WindowPtr, DDXPointRec, RegionPtr); ++#ifdef CHROMIUM ++extern Bool rfbRealizeWindow(WindowPtr); ++extern Bool rfbUnrealizeWindow(WindowPtr); ++extern Bool rfbDestroyWindow(WindowPtr); ++extern void rfbResizeWindow(WindowPtr, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib); ++extern Bool rfbPositionWindow(WindowPtr, int x, int y); ++extern void rfbClipNotify(WindowPtr, int x, int y); ++#endif ++extern void rfbClearToBackground(WindowPtr, int x, int y, int w, ++ int h, Bool generateExposures); ++extern RegionPtr rfbRestoreAreas(WindowPtr, RegionPtr); ++ ++ ++/* cutpaste.c */ ++ ++extern void rfbSetXCutText(char *str, int len); ++extern void rfbGotXCutText(char *str, int len); ++ ++ ++/* kbdptr.c */ ++ ++extern Bool compatibleKbd; ++extern unsigned char ptrAcceleration; ++ ++extern void PtrDeviceInit(void); ++extern void PtrDeviceOn(DeviceIntPtr pDev); ++extern void PtrDeviceOff(void); ++extern void PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl); ++extern void PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl); ++ ++extern void KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap); ++extern void KbdDeviceOn(void); ++extern void KbdDeviceOff(void); ++extern void KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl); ++extern void KbdReleaseAllKeys(void); ++ ++ ++/* rfbserver.c */ ++ ++ ++extern rfbClientPtr rfbClientHead; ++extern rfbClientPtr pointerClient; ++ ++extern void rfbNewClientConnection(ScreenPtr pScreen, int sock); ++extern rfbClientPtr rfbReverseConnection(ScreenPtr pScreen, char *host, int port); ++extern void rfbRootPropertyChange(ScreenPtr pScreen); ++extern void rfbClientConnectionGone(int sock); ++extern void rfbProcessClientMessage(ScreenPtr pScreen, int sock); ++extern void rfbClientConnFailed(rfbClientPtr cl, char *reason); ++extern void rfbNewUDPConnection(int sock); ++extern void rfbProcessUDPInput(ScreenPtr pScreen, int sock); ++extern Bool rfbSendFramebufferUpdate(ScreenPtr pScreen, rfbClientPtr cl); ++extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h); ++extern Bool rfbSendUpdateBuf(rfbClientPtr cl); ++extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, ++ int nColours); ++extern void rfbSendBell(void); ++extern void rfbSendServerCutText(char *str, int len); ++extern void rfbUserAllow(int sock, int accept); ++extern void rfbSetClip (WindowPtr pWin, BOOL enable); ++ ++extern int GenerateVncConnectedEvent(int sock); ++extern int GenerateVncDisconnectedEvent(int sock); ++ ++#ifdef CHROMIUM ++extern void rfbSendChromiumWindowShow(unsigned int winid, unsigned int show); ++extern void rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h); ++extern void rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects); ++#endif ++ ++/* translate.c */ ++ ++extern Bool rfbEconomicTranslate; ++ ++extern void rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y); ++extern Bool rfbSetTranslateFunction(rfbClientPtr cl); ++extern void rfbSetClientColourMaps(int firstColour, int nColours); ++extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour, ++ int nColours); ++ ++ ++/* httpd.c */ ++ ++extern Bool httpInitSockets(ScreenPtr pScreen); ++extern void httpCheckFds(ScreenPtr pScreen); ++ ++ ++/* vncext.c */ ++ ++#ifdef CHROMIUM ++extern void rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort, unsigned int mothershipPort); ++extern void rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid); ++int GenerateVncChromiumConnectedEvent(int sock); ++#endif ++ ++ ++/* auth.c */ ++ ++extern void rfbAuthNewClient(rfbClientPtr cl); ++extern void rfbProcessClientSecurityType(rfbClientPtr cl); ++extern void rfbProcessClientTunnelingType(rfbClientPtr cl); ++extern void rfbProcessClientAuthType(rfbClientPtr cl); ++extern void rfbVncAuthProcessResponse(rfbClientPtr cl); ++ ++/* Functions to prevent too many successive authentication failures */ ++extern Bool rfbAuthConsiderBlocking(rfbClientPtr cl); ++extern void rfbAuthUnblock(rfbClientPtr cl); ++extern Bool rfbAuthIsBlocked(rfbClientPtr cl); ++ ++/* loginauth.c */ ++ ++extern void rfbLoginAuthProcessClientMessage(rfbClientPtr cl); ++ ++/* rre.c */ ++ ++extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* corre.c */ ++ ++extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* hextile.c */ ++ ++extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w, ++ int h); ++ ++ ++/* zlib.c */ ++ ++/* Minimum zlib rectangle size in bytes. Anything smaller will ++ * not compress well due to overhead. ++ */ ++#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17) ++ ++/* Set maximum zlib rectangle size in pixels. Always allow at least ++ * two scan lines. ++ */ ++#define ZLIB_MAX_RECT_SIZE (128*256) ++#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \ ++ ( min * 2 ) : ZLIB_MAX_RECT_SIZE ) ++ ++extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, ++ int h); ++ ++ ++/* tight.c */ ++ ++#define TIGHT_DEFAULT_COMPRESSION 6 ++ ++extern Bool rfbTightDisableGradient; ++ ++extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h); ++extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* cursor.c */ ++ ++extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen); ++extern Bool rfbSendCursorPos(rfbClientPtr cl, ScreenPtr pScreen); ++ ++ ++/* stats.c */ ++ ++extern void rfbResetStats(rfbClientPtr cl); ++extern void rfbPrintStats(rfbClientPtr cl); +diff --git a/hw/vnc/rfbkeyb.c b/hw/vnc/rfbkeyb.c +new file mode 100644 +index 0000000..c65854b +--- /dev/null ++++ b/hw/vnc/rfbkeyb.c +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#if XFREE86VNC ++#ifndef XFree86LOADER ++#include ++#include ++#endif ++ ++#include ++#include ++#define NEED_XF86_TYPES ++#if !defined(DGUX) ++#include ++#include ++#endif ++#include ++#include ++#include /* Needed for InitValuator/Proximity stuff */ ++#include ++#include ++ ++#ifdef XFree86LOADER ++#include ++#endif ++#else ++#include ++#include ++#include ++#endif ++ ++ ++extern Bool noXkbExtension; ++extern void rfbSendBell(void); ++extern DeviceIntPtr kbdDevice; ++ ++static const char *DEFAULTS[] = { ++ NULL ++}; ++ ++#include "keyboard.h" ++ ++#undef XKB ++#ifdef XKB ++#include ++#include ++#include ++ ++#if XFREE86VNC ++ /* ++ * would like to use an XkbComponentNamesRec here but can't without ++ * pulling in a bunch of header files. :-( ++ */ ++static char * xkbkeymap; ++static char * xkbkeycodes; ++static char * xkbtypes; ++static char * xkbcompat; ++static char * xkbsymbols; ++static char * xkbgeometry; ++static Bool xkbcomponents_specified; ++static char * xkbrules; ++static char * xkbmodel; ++static char * xkblayout; ++static char * xkbvariant; ++static char * xkboptions; ++#endif ++#endif ++ ++void ++KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap) ++{ ++ int i; ++ ++ kbdDevice = pDevice; ++ ++ for (i = 0; i < MAP_LENGTH; i++) ++ pModMap[i] = NoSymbol; ++ ++ pModMap[CONTROL_L_KEY_CODE] = ControlMask; ++ pModMap[CONTROL_R_KEY_CODE] = ControlMask; ++ pModMap[SHIFT_L_KEY_CODE] = ShiftMask; ++ pModMap[SHIFT_R_KEY_CODE] = ShiftMask; ++ pModMap[META_L_KEY_CODE] = Mod1Mask; ++ pModMap[META_R_KEY_CODE] = Mod1Mask; ++ pModMap[ALT_L_KEY_CODE] = Mod1Mask; ++ pModMap[ALT_R_KEY_CODE] = Mod1Mask; ++ ++ pKeySyms->minKeyCode = MIN_KEY_CODE; ++ pKeySyms->maxKeyCode = MAX_KEY_CODE; ++ pKeySyms->mapWidth = GLYPHS_PER_KEY; ++ ++ pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym) ++ * MAP_LENGTH * GLYPHS_PER_KEY); ++ ++ if (!pKeySyms->map) { ++ ErrorF("xalloc failed\n"); ++ exit(1); ++ } ++ ++ for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++) ++ pKeySyms->map[i] = NoSymbol; ++ ++ for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { ++ pKeySyms->map[i] = map[i]; ++ } ++} ++ ++ ++void ++KbdDeviceOn(void) ++{ ++} ++ ++ ++void ++KbdDeviceOff(void) ++{ ++} ++ ++ ++#if XFREE86VNC ++static int ++xf86rfbKeybControlProc(DeviceIntPtr device, int onoff) ++{ ++ KeySymsRec keySyms; ++ CARD8 modMap[MAP_LENGTH]; ++ DevicePtr pDev = (DevicePtr)device; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ KbdDeviceInit(device, &keySyms, modMap); ++#ifdef XKB ++ if (noXkbExtension) { ++#endif ++ InitKeyboardDeviceStruct(pDev, &keySyms, modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++#ifdef XKB ++ } else { ++ XkbComponentNamesRec names; ++ if (XkbInitialMap) { ++ if ((xkbkeymap = strchr(XkbInitialMap, '/')) != NULL) ++ xkbkeymap++; ++ else ++ xkbkeymap = XkbInitialMap; ++ } ++ if (xkbkeymap) { ++ names.keymap = xkbkeymap; ++ names.keycodes = NULL; ++ names.types = NULL; ++ names.compat = NULL; ++ names.symbols = NULL; ++ names.geometry = NULL; ++ } else { ++ names.keymap = NULL; ++ names.keycodes = xkbkeycodes; ++ names.types = xkbtypes; ++ names.compat = xkbcompat; ++ names.symbols = xkbsymbols; ++ names.geometry = xkbgeometry; ++ } ++ if ((xkbkeymap || xkbcomponents_specified) ++ && (xkbmodel == NULL || xkblayout == NULL)) { ++ xkbrules = NULL; ++ } ++#if 0 ++ XkbSetRulesDflts(xkbrules, xkbmodel, ++ xkblayout, xkbvariant, ++ xkboptions); ++#endif ++ XkbInitKeyboardDeviceStruct(device, ++ &names, ++ &keySyms, ++ modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++ } ++#endif ++ break; ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ KbdDeviceOn(); ++ break; ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ KbdDeviceOff(); ++ break; ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ KbdDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static void ++xf86rfbKeybUninit(InputDriverPtr drv, ++ InputInfoPtr pInfo, ++ int flags) ++{ ++ xf86rfbKeybControlProc(pInfo->dev, DEVICE_OFF); ++} ++ ++static InputInfoPtr ++xf86rfbKeybInit(InputDriverPtr drv, ++ IDevPtr dev, ++ int flags) ++{ ++ InputInfoPtr pInfo; ++ char *s; ++ Bool from; ++ ++ if (!(pInfo = xf86AllocateInput(drv, 0))) ++ return NULL; ++ ++ /* Initialise the InputInfoRec. */ ++ pInfo->name = dev->identifier; ++ pInfo->type_name = "rfbKeyb"; ++ pInfo->flags = XI86_KEYBOARD_CAPABLE; ++ pInfo->device_control = xf86rfbKeybControlProc; ++ pInfo->read_input = NULL; ++ pInfo->motion_history_proc = NULL; ++ pInfo->history_size = 0; ++ pInfo->control_proc = NULL; ++ pInfo->close_proc = NULL; ++ pInfo->switch_mode = NULL; ++ pInfo->conversion_proc = NULL; ++ pInfo->reverse_conversion_proc = NULL; ++ pInfo->fd = -1; ++ pInfo->dev = NULL; ++ pInfo->private_flags = 0; ++ pInfo->always_core_feedback = 0; ++ pInfo->conf_idev = dev; ++ ++ /* Collect the options, and process the common options. */ ++ xf86CollectInputOptions(pInfo, DEFAULTS, NULL); ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ /* Mark the device configured */ ++ pInfo->flags |= XI86_CONFIGURED; ++ ++#ifdef XKB ++ from = X_DEFAULT; ++ if (noXkbExtension) ++ from = X_CMDLINE; ++ else if (xf86FindOption(dev->commonOptions, "XkbDisable")) { ++ noXkbExtension = ++ xf86SetBoolOption(dev->commonOptions, "XkbDisable", FALSE); ++ from = X_CONFIG; ++ } ++ if (noXkbExtension) ++ xf86Msg(from, "XKB: disabled\n"); ++ ++#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL)) ++ ++ if (!noXkbExtension && !XkbInitialMap) { ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeymap", NULL))) { ++ xkbkeymap = NULL_IF_EMPTY(s); ++ xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" " ++ "(overrides other XKB settings)\n", xkbkeymap); ++ } else { ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbCompat", NULL))) { ++ xkbcompat = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbTypes", NULL))) { ++ xkbtypes = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeycodes", NULL))) { ++ xkbkeycodes = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbGeometry", NULL))) { ++ xkbgeometry = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbSymbols", NULL))) { ++ xkbsymbols = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbRules", NULL))) { ++ xkbrules = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbModel", NULL))) { ++ xkbmodel = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbLayout", NULL))) { ++ xkblayout = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbVariant", NULL))) { ++ xkbvariant = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbOptions", NULL))) { ++ xkboptions = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s); ++ } ++ } ++ } ++#undef NULL_IF_EMPTY ++#endif ++ ++ /* Return the configured device */ ++ return (pInfo); ++} ++ ++#ifdef XFree86LOADER ++static ++#endif ++InputDriverRec RFBKEYB = { ++ 1, /* driver version */ ++ "rfbkeyb", /* driver name */ ++ NULL, /* identify */ ++ xf86rfbKeybInit, /* pre-init */ ++ xf86rfbKeybUninit, /* un-init */ ++ NULL, /* module */ ++ 0 /* ref count */ ++}; ++ ++/* ++ *************************************************************************** ++ * ++ * Dynamic loading functions ++ * ++ *************************************************************************** ++ */ ++#ifdef XFree86LOADER ++static void ++xf86rfbKeybUnplug(pointer p) ++{ ++} ++ ++static pointer ++xf86rfbKeybPlug(pointer module, ++ pointer options, ++ int *errmaj, ++ int *errmin) ++{ ++ xf86AddInputDriver(&RFBKEYB, module, 0); ++ ++ return module; ++} ++ ++void ++vncInitKeyb(void) ++{ ++ xf86AddInputDriver(&RFBKEYB, NULL, 0); ++} ++ ++static XF86ModuleVersionInfo xf86rfbKeybVersionRec = ++{ ++ "rfbkeyb", ++ "xf4vnc Project, see http://xf4vnc.sf.net", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XF86_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_XINPUT, ++ ABI_XINPUT_VERSION, ++ MOD_CLASS_XINPUT, ++ {0, 0, 0, 0} /* signature, to be patched into the file by */ ++ /* a tool */ ++}; ++ ++XF86ModuleData rfbkeybModuleData = {&xf86rfbKeybVersionRec, ++ xf86rfbKeybPlug, ++ xf86rfbKeybUnplug}; ++ ++#endif /* XFree86LOADER */ ++#endif +diff --git a/hw/vnc/rfbmouse.c b/hw/vnc/rfbmouse.c +new file mode 100644 +index 0000000..de5fd65 +--- /dev/null ++++ b/hw/vnc/rfbmouse.c +@@ -0,0 +1,244 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#if XFREE86VNC ++ ++#ifndef XFree86LOADER ++#include ++#include ++#endif ++ ++#include ++#include ++#define NEED_XF86_TYPES ++ ++#if !defined(DGUX) ++#include ++#include ++#endif ++ ++#include ++#include ++#include /* Needed for InitValuator/Proximity stuff */ ++#include ++#include ++ ++#ifdef XFree86LOADER ++#include ++#endif ++ ++static const char *DEFAULTS[] = { ++ NULL ++}; ++#else ++#include ++#include ++#include ++#endif ++ ++ ++unsigned char ptrAcceleration = 50; ++ ++void ++PtrDeviceOn(DeviceIntPtr pDev) ++{ ++#if 0 ++ ptrAcceleration = (unsigned char)pDev->ptrfeed->ctrl.num; ++#endif ++} ++ ++void ++PtrDeviceInit(void) ++{ ++} ++ ++void ++PtrDeviceOff(void) ++{ ++} ++ ++ ++void ++PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl) ++{ ++#if 0 ++ ptrAcceleration = (char)ctrl->num; ++ ++ if (udpSockConnected) { ++ if (write(udpSock, &ptrAcceleration, 1) <= 0) { ++ ErrorF("PtrDeviceControl: UDP input: write"); ++ rfbDisconnectUDPSock(); ++ } ++ } ++#endif ++} ++ ++#if XFREE86VNC ++static int ++xf86rfbMouseControlProc(DeviceIntPtr device, int onoff) ++{ ++ BYTE map[6]; ++ DevicePtr pDev = (DevicePtr)device; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ PtrDeviceInit(); ++ map[1] = 1; ++ map[2] = 2; ++ map[3] = 3; ++ map[4] = 4; ++ map[5] = 5; ++ InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents, ++ PtrDeviceControl, ++ miPointerGetMotionBufferSize()); ++ break; ++ ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ PtrDeviceOn(device); ++ break; ++ ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ PtrDeviceOff(); ++ break; ++ ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ PtrDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static void ++xf86rfbMouseUninit(InputDriverPtr drv, ++ InputInfoPtr pInfo, ++ int flags) ++{ ++ xf86rfbMouseControlProc(pInfo->dev, DEVICE_OFF); ++} ++ ++static InputInfoPtr ++xf86rfbMouseInit(InputDriverPtr drv, ++ IDevPtr dev, ++ int flags) ++{ ++ InputInfoPtr pInfo; ++ ++ if (!(pInfo = xf86AllocateInput(drv, 0))) ++ return NULL; ++ ++ /* Initialise the InputInfoRec. */ ++ pInfo->name = dev->identifier; ++ pInfo->type_name = "rfbMouse"; ++ pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; ++ pInfo->device_control = xf86rfbMouseControlProc; ++ pInfo->read_input = NULL; ++ pInfo->motion_history_proc = xf86GetMotionEvents; ++ pInfo->history_size = 0; ++ pInfo->control_proc = NULL; ++ pInfo->close_proc = NULL; ++ pInfo->switch_mode = NULL; ++ pInfo->conversion_proc = NULL; ++ pInfo->reverse_conversion_proc = NULL; ++ pInfo->fd = -1; ++ pInfo->dev = NULL; ++ pInfo->private_flags = 0; ++ pInfo->always_core_feedback = 0; ++ pInfo->conf_idev = dev; ++ ++ /* Collect the options, and process the common options. */ ++ xf86CollectInputOptions(pInfo, DEFAULTS, NULL); ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ /* Mark the device configured */ ++ pInfo->flags |= XI86_CONFIGURED; ++ ++ /* Return the configured device */ ++ return (pInfo); ++} ++ ++#ifdef XFree86LOADER ++static ++#endif ++InputDriverRec RFBMOUSE = { ++ 1, /* driver version */ ++ "rfbmouse", /* driver name */ ++ NULL, /* identify */ ++ xf86rfbMouseInit, /* pre-init */ ++ xf86rfbMouseUninit, /* un-init */ ++ NULL, /* module */ ++ 0 /* ref count */ ++}; ++ ++/* ++ *************************************************************************** ++ * ++ * Dynamic loading functions ++ * ++ *************************************************************************** ++ */ ++#ifdef XFree86LOADER ++static void ++xf86rfbMouseUnplug(pointer p) ++{ ++} ++ ++static pointer ++xf86rfbMousePlug(pointer module, ++ pointer options, ++ int *errmaj, ++ int *errmin) ++{ ++ xf86AddInputDriver(&RFBMOUSE, module, 0); ++ ++ return module; ++} ++ ++void ++vncInitMouse(void) ++{ ++ xf86AddInputDriver(&RFBMOUSE, NULL, 0); ++} ++ ++static XF86ModuleVersionInfo xf86rfbMouseVersionRec = ++{ ++ "rfbmouse", ++ "xf4vnc Project, see http://xf4vnc.sf.net", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XF86_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_XINPUT, ++ ABI_XINPUT_VERSION, ++ MOD_CLASS_XINPUT, ++ {0, 0, 0, 0} /* signature, to be patched into the file by */ ++ /* a tool */ ++}; ++ ++XF86ModuleData rfbmouseModuleData = {&xf86rfbMouseVersionRec, ++ xf86rfbMousePlug, ++ xf86rfbMouseUnplug}; ++ ++#endif /* XFree86LOADER */ ++#endif +diff --git a/hw/vnc/rfbproto.h b/hw/vnc/rfbproto.h +new file mode 100644 +index 0000000..bbef703 +--- /dev/null ++++ b/hw/vnc/rfbproto.h +@@ -0,0 +1,1347 @@ ++/* ++ * Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ * rfbproto.h - header file for the RFB protocol, versions 3.3, 3.7 and 3.7t ++ * (protocol 3.7t is effectively 3.7 with TightVNC extensions enabled) ++ * ++ * Uses types CARD for an n-bit unsigned integer, INT for an n-bit signed ++ * integer (for n = 8, 16 and 32). ++ * ++ * All multiple byte integers are in big endian (network) order (most ++ * significant byte first). Unless noted otherwise there is no special ++ * alignment of protocol structures. ++ * ++ * ++ * Once the initial handshaking is done, all messages start with a type byte, ++ * (usually) followed by message-specific data. The order of definitions in ++ * this file is as follows: ++ * ++ * (1) Structures used in several types of message. ++ * (2) Structures used in the initial handshaking. ++ * (3) Message types. ++ * (4) Encoding types. ++ * (5) For each message type, the form of the data following the type byte. ++ * Sometimes this is defined by a single structure but the more complex ++ * messages have to be explained by comments. ++ */ ++ ++ ++/***************************************************************************** ++ * ++ * Structures used in several messages ++ * ++ *****************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to specify a rectangle. This structure is a multiple of 4 ++ * bytes so that it can be interspersed with 32-bit pixel data without ++ * affecting alignment. ++ */ ++ ++typedef struct _rfbRectangle { ++ CARD16 x; ++ CARD16 y; ++ CARD16 w; ++ CARD16 h; ++} rfbRectangle; ++ ++#define sz_rfbRectangle 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to specify pixel format. ++ */ ++ ++typedef struct _rfbPixelFormat { ++ ++ CARD8 bitsPerPixel; /* 8,16,32 only */ ++ ++ CARD8 depth; /* 8 to 32 */ ++ ++ CARD8 bigEndian; /* True if multi-byte pixels are interpreted ++ as big endian, or if single-bit-per-pixel ++ has most significant bit of the byte ++ corresponding to first (leftmost) pixel. Of ++ course this is meaningless for 8 bits/pix */ ++ ++ CARD8 trueColour; /* If false then we need a "colour map" to ++ convert pixels to RGB. If true, xxxMax and ++ xxxShift specify bits used for red, green ++ and blue */ ++ ++ /* the following fields are only meaningful if trueColour is true */ ++ ++ CARD16 redMax; /* maximum red value (= 2^n - 1 where n is the ++ number of bits used for red). Note this ++ value is always in big endian order. */ ++ ++ CARD16 greenMax; /* similar for green */ ++ ++ CARD16 blueMax; /* and blue */ ++ ++ CARD8 redShift; /* number of shifts needed to get the red ++ value in a pixel to the least significant ++ bit. To find the red value from a given ++ pixel, do the following: ++ 1) Swap pixel value according to bigEndian ++ (e.g. if bigEndian is false and host byte ++ order is big endian, then swap). ++ 2) Shift right by redShift. ++ 3) AND with redMax (in host byte order). ++ 4) You now have the red value between 0 and ++ redMax. */ ++ ++ CARD8 greenShift; /* similar for green */ ++ ++ CARD8 blueShift; /* and blue */ ++ ++ CARD8 pad1; ++ CARD16 pad2; ++ ++} rfbPixelFormat; ++ ++#define sz_rfbPixelFormat 16 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to describe protocol options such as tunneling methods, ++ * authentication schemes and message types (protocol version 3.7t). ++ */ ++ ++typedef struct _rfbCapabilityInfo { ++ ++ CARD32 code; /* numeric identifier */ ++ CARD8 vendorSignature[4]; /* vendor identification */ ++ CARD8 nameSignature[8]; /* abbreviated option name */ ++ ++} rfbCapabilityInfo; ++ ++#define sz_rfbCapabilityInfoVendor 4 ++#define sz_rfbCapabilityInfoName 8 ++#define sz_rfbCapabilityInfo 16 ++ ++/* ++ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC. ++ */ ++ ++#define rfbStandardVendor "STDV" ++#define rfbTridiaVncVendor "TRDV" ++#define rfbTightVncVendor "TGHT" ++#define rfbTungstenGraphicsVendor "TGIV" ++ ++ ++/***************************************************************************** ++ * ++ * Initial handshaking messages ++ * ++ *****************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * Protocol Version ++ * ++ * The server always sends 12 bytes to start which identifies the latest RFB ++ * protocol version number which it supports. These bytes are interpreted ++ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where ++ * xxx and yyy are the major and minor version numbers (for version 3.7 ++ * this is "RFB 003.007\n"). ++ * ++ * The client then replies with a similar 12-byte message giving the version ++ * number of the protocol which should actually be used (which may be different ++ * to that quoted by the server). ++ * ++ * It is intended that both clients and servers may provide some level of ++ * backwards compatibility by this mechanism. Servers in particular should ++ * attempt to provide backwards compatibility, and even forwards compatibility ++ * to some extent. For example if a client demands version 3.1 of the ++ * protocol, a 3.0 server can probably assume that by ignoring requests for ++ * encoding types it doesn't understand, everything will still work OK. This ++ * will probably not be the case for changes in the major version number. ++ * ++ * The format string below can be used in sprintf or sscanf to generate or ++ * decode the version string respectively. ++ */ ++ ++#define rfbProtocolVersionFormat "RFB %03d.%03d\n" ++#define rfbProtocolMajorVersion 3 ++#define rfbProtocolMinorVersion 7 ++#define rfbProtocolFallbackMinorVersion 3 ++ ++typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */ ++ ++#define sz_rfbProtocolVersionMsg 12 ++ ++ ++/* ++ * Negotiation of the security type (protocol version 3.7) ++ * ++ * Once the protocol version has been decided, the server either sends a list ++ * of supported security types, or informs the client about an error (when the ++ * number of security types is 0). Security type rfbSecTypeTight is used to ++ * enable TightVNC-specific protocol extensions. The value rfbSecTypeVncAuth ++ * stands for classic VNC authentication. ++ * ++ * The client selects a particular security type from the list provided by the ++ * server. ++ */ ++ ++#define rfbSecTypeInvalid 0 ++#define rfbSecTypeNone 1 ++#define rfbSecTypeVncAuth 2 ++#define rfbSecTypeTight 16 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Negotiation of Tunneling Capabilities (protocol version 3.7t) ++ * ++ * If the chosen security type is rfbSecTypeTight, the server sends a list of ++ * supported tunneling methods ("tunneling" refers to any additional layer of ++ * data transformation, such as encryption or external compression.) ++ * ++ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures ++ * that list all supported tunneling methods in the order of preference. ++ * ++ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be ++ * used, and the client should not send a response requesting a tunneling ++ * method. ++ */ ++ ++typedef struct _rfbTunnelingCapsMsg { ++ CARD32 nTunnelTypes; ++ /* followed by nTunnelTypes * rfbCapabilityInfo structures */ ++} rfbTunnelingCapsMsg; ++ ++#define sz_rfbTunnelingCapsMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Tunneling Method Request (protocol version 3.7t) ++ * ++ * If the list of tunneling capabilities sent by the server was not empty, the ++ * client should reply with a 32-bit code specifying a particular tunneling ++ * method. The following code should be used for no tunneling. ++ */ ++ ++#define rfbNoTunneling 0 ++#define sig_rfbNoTunneling "NOTUNNEL" ++ ++ ++/*----------------------------------------------------------------------------- ++ * Negotiation of Authentication Capabilities (protocol version 3.7t) ++ * ++ * After setting up tunneling, the server sends a list of supported ++ * authentication schemes. ++ * ++ * nAuthTypes specifies the number of following rfbCapabilityInfo structures ++ * that list all supported authentication schemes in the order of preference. ++ * ++ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is ++ * necessary, and the client should not send a response requesting an ++ * authentication scheme. ++ */ ++ ++typedef struct _rfbAuthenticationCapsMsg { ++ CARD32 nAuthTypes; ++ /* followed by nAuthTypes * rfbCapabilityInfo structures */ ++} rfbAuthenticationCapsMsg; ++ ++#define sz_rfbAuthenticationCapsMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Authentication Scheme Request (protocol version 3.7t) ++ * ++ * If the list of authentication capabilities sent by the server was not empty, ++ * the client should reply with a 32-bit code specifying a particular ++ * authentication scheme. The following codes are supported. ++ */ ++ ++#define rfbAuthNone 1 ++#define rfbAuthVNC 2 ++#define rfbAuthUnixLogin 129 ++#define rfbAuthExternal 130 ++ ++#define sig_rfbAuthNone "NOAUTH__" ++#define sig_rfbAuthVNC "VNCAUTH_" ++#define sig_rfbAuthUnixLogin "ULGNAUTH" ++#define sig_rfbAuthExternal "XTRNAUTH" ++ ++ ++/*----------------------------------------------------------------------------- ++ * Standard VNC Authentication (all protocol versions) ++ * ++ * Standard authentication result codes are defined below. ++ */ ++ ++#define rfbVncAuthOK 0 ++#define rfbVncAuthFailed 1 ++#define rfbVncAuthTooMany 2 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Client Initialisation Message ++ * ++ * Once the client and server are sure that they're happy to talk to one ++ * another, the client sends an initialisation message. At present this ++ * message only consists of a boolean indicating whether the server should try ++ * to share the desktop by leaving other clients connected, or give exclusive ++ * access to this client by disconnecting all other clients. ++ */ ++ ++typedef struct _rfbClientInitMsg { ++ CARD8 shared; ++} rfbClientInitMsg; ++ ++#define sz_rfbClientInitMsg 1 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Server Initialisation Message ++ * ++ * After the client initialisation message, the server sends one of its own. ++ * This tells the client the width and height of the server's framebuffer, ++ * its pixel format and the name associated with the desktop. ++ */ ++ ++typedef struct _rfbServerInitMsg { ++ CARD16 framebufferWidth; ++ CARD16 framebufferHeight; ++ rfbPixelFormat format; /* the server's preferred pixel format */ ++ CARD32 nameLength; ++ /* followed by char name[nameLength] */ ++} rfbServerInitMsg; ++ ++#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat) ++ ++ ++/*----------------------------------------------------------------------------- ++ * Server Interaction Capabilities Message (protocol version 3.7t) ++ * ++ * In the protocol version 3.7t, the server informs the client what message ++ * types it supports in addition to ones defined in the protocol version 3.7. ++ * Also, the server sends the list of all supported encodings (note that it's ++ * not necessary to advertise the "raw" encoding sinse it MUST be supported in ++ * RFB 3.x protocols). ++ * ++ * This data immediately follows the server initialisation message. ++ */ ++ ++typedef struct _rfbInteractionCapsMsg { ++ CARD16 nServerMessageTypes; ++ CARD16 nClientMessageTypes; ++ CARD16 nEncodingTypes; ++ CARD16 pad; /* reserved, must be 0 */ ++ /* followed by nServerMessageTypes * rfbCapabilityInfo structures */ ++ /* followed by nClientMessageTypes * rfbCapabilityInfo structures */ ++} rfbInteractionCapsMsg; ++ ++#define sz_rfbInteractionCapsMsg 8 ++ ++ ++/* ++ * Following the server initialisation message it's up to the client to send ++ * whichever protocol messages it wants. Typically it will send a ++ * SetPixelFormat message and a SetEncodings message, followed by a ++ * FramebufferUpdateRequest. From then on the server will send ++ * FramebufferUpdate messages in response to the client's ++ * FramebufferUpdateRequest messages. The client should send ++ * FramebufferUpdateRequest messages with incremental set to true when it has ++ * finished processing one FramebufferUpdate and is ready to process another. ++ * With a fast client, the rate at which FramebufferUpdateRequests are sent ++ * should be regulated to avoid hogging the network. ++ */ ++ ++ ++ ++/***************************************************************************** ++ * ++ * Message types ++ * ++ *****************************************************************************/ ++ ++/* server -> client */ ++ ++#define rfbFramebufferUpdate 0 ++#define rfbSetColourMapEntries 1 ++#define rfbBell 2 ++#define rfbServerCutText 3 ++/* Chromium extensions, use higher values */ ++#define rfbChromiumStart 50 ++#define rfbChromiumMoveResizeWindow 51 ++#define rfbChromiumClipList 52 ++#define rfbChromiumWindowShow 53 ++ ++#define rfbFileListData 130 ++#define rfbFileDownloadData 131 ++#define rfbFileUploadCancel 132 ++#define rfbFileDownloadFailed 133 ++ ++/* signatures for non-standard messages */ ++#define sig_rfbFileListData "FTS_LSDT" ++#define sig_rfbFileDownloadData "FTS_DNDT" ++#define sig_rfbFileUploadCancel "FTS_UPCN" ++#define sig_rfbFileDownloadFailed "FTS_DNFL" ++ ++ ++/* client -> server */ ++ ++#define rfbSetPixelFormat 0 ++#define rfbFixColourMapEntries 1 /* not currently supported */ ++#define rfbSetEncodings 2 ++#define rfbFramebufferUpdateRequest 3 ++#define rfbKeyEvent 4 ++#define rfbPointerEvent 5 ++#define rfbClientCutText 6 ++/* Chromium extensions, use higher values */ ++#define rfbChromiumStop 50 ++#define rfbChromiumExpose 51 ++ ++#define rfbFileListRequest 130 ++#define rfbFileDownloadRequest 131 ++#define rfbFileUploadRequest 132 ++#define rfbFileUploadData 133 ++#define rfbFileDownloadCancel 134 ++#define rfbFileUploadFailed 135 ++#define rfbFileCreateDirRequest 136 ++ ++/* signatures for non-standard messages */ ++#define sig_rfbFileListRequest "FTC_LSRQ" ++#define sig_rfbFileDownloadRequest "FTC_DNRQ" ++#define sig_rfbFileUploadRequest "FTC_UPRQ" ++#define sig_rfbFileUploadData "FTC_UPDT" ++#define sig_rfbFileDownloadCancel "FTC_DNCN" ++#define sig_rfbFileUploadFailed "FTC_UPFL" ++#define sig_rfbFileCreateDirRequest "FTC_FCDR" ++ ++/***************************************************************************** ++ * ++ * Encoding types ++ * ++ *****************************************************************************/ ++ ++#define rfbEncodingRaw 0 ++#define rfbEncodingCopyRect 1 ++#define rfbEncodingRRE 2 ++#define rfbEncodingCoRRE 4 ++#define rfbEncodingHextile 5 ++#define rfbEncodingZlib 6 ++#define rfbEncodingTight 7 ++#define rfbEncodingZlibHex 8 ++ ++/* signatures for basic encoding types */ ++#define sig_rfbEncodingRaw "RAW_____" ++#define sig_rfbEncodingCopyRect "COPYRECT" ++#define sig_rfbEncodingRRE "RRE_____" ++#define sig_rfbEncodingCoRRE "CORRE___" ++#define sig_rfbEncodingHextile "HEXTILE_" ++#define sig_rfbEncodingZlib "ZLIB____" ++#define sig_rfbEncodingTight "TIGHT___" ++#define sig_rfbEncodingZlibHex "ZLIBHEX_" ++#define sig_rfbEncodingChromium "CHROMIUM" ++ ++/* ++ * Special encoding numbers: ++ * 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels; ++ * 0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data; ++ * 0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions; ++ * 0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet; ++ * 0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor; ++ * 0xFFFFFFF0 .. 0xFFFFFFFF -- not allocated yet. ++ */ ++ ++#define rfbEncodingCompressLevel0 0xFFFFFF00 ++#define rfbEncodingCompressLevel1 0xFFFFFF01 ++#define rfbEncodingCompressLevel2 0xFFFFFF02 ++#define rfbEncodingCompressLevel3 0xFFFFFF03 ++#define rfbEncodingCompressLevel4 0xFFFFFF04 ++#define rfbEncodingCompressLevel5 0xFFFFFF05 ++#define rfbEncodingCompressLevel6 0xFFFFFF06 ++#define rfbEncodingCompressLevel7 0xFFFFFF07 ++#define rfbEncodingCompressLevel8 0xFFFFFF08 ++#define rfbEncodingCompressLevel9 0xFFFFFF09 ++ ++#define rfbEncodingXCursor 0xFFFFFF10 ++#define rfbEncodingRichCursor 0xFFFFFF11 ++#define rfbEncodingPointerPos 0xFFFFFF18 ++ ++#define rfbEncodingLastRect 0xFFFFFF20 ++#define rfbEncodingNewFBSize 0xFFFFFF21 ++#define rfbEncodingChromium 0xFFFFFF2F ++#define rfbEncodingChromium2 0xFFFFFF30 ++ ++#define rfbEncodingQualityLevel0 0xFFFFFFE0 ++#define rfbEncodingQualityLevel1 0xFFFFFFE1 ++#define rfbEncodingQualityLevel2 0xFFFFFFE2 ++#define rfbEncodingQualityLevel3 0xFFFFFFE3 ++#define rfbEncodingQualityLevel4 0xFFFFFFE4 ++#define rfbEncodingQualityLevel5 0xFFFFFFE5 ++#define rfbEncodingQualityLevel6 0xFFFFFFE6 ++#define rfbEncodingQualityLevel7 0xFFFFFFE7 ++#define rfbEncodingQualityLevel8 0xFFFFFFE8 ++#define rfbEncodingQualityLevel9 0xFFFFFFE9 ++ ++/* signatures for "fake" encoding types */ ++#define sig_rfbEncodingCompressLevel0 "COMPRLVL" ++#define sig_rfbEncodingXCursor "X11CURSR" ++#define sig_rfbEncodingRichCursor "RCHCURSR" ++#define sig_rfbEncodingPointerPos "POINTPOS" ++#define sig_rfbEncodingLastRect "LASTRECT" ++#define sig_rfbEncodingNewFBSize "NEWFBSIZ" ++#define sig_rfbEncodingQualityLevel0 "JPEGQLVL" ++ ++ ++/***************************************************************************** ++ * ++ * Server -> client message definitions ++ * ++ *****************************************************************************/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer. ++ * ++ * This message consists of a header giving the number of rectangles of pixel ++ * data followed by the rectangles themselves. The header is padded so that ++ * together with the type byte it is an exact multiple of 4 bytes (to help ++ * with alignment of 32-bit pixels): ++ */ ++ ++typedef struct _rfbFramebufferUpdateMsg { ++ CARD8 type; /* always rfbFramebufferUpdate */ ++ CARD8 pad; ++ CARD16 nRects; ++ /* followed by nRects rectangles */ ++} rfbFramebufferUpdateMsg; ++ ++#define sz_rfbFramebufferUpdateMsg 4 ++ ++/* ++ * Each rectangle of pixel data consists of a header describing the position ++ * and size of the rectangle and a type word describing the encoding of the ++ * pixel data, followed finally by the pixel data. Note that if the client has ++ * not sent a SetEncodings message then it will only receive raw pixel data. ++ * Also note again that this structure is a multiple of 4 bytes. ++ */ ++ ++typedef struct _rfbFramebufferUpdateRectHeader { ++ rfbRectangle r; ++ CARD32 encoding; /* one of the encoding types rfbEncoding... */ ++} rfbFramebufferUpdateRectHeader; ++ ++#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Raw Encoding. Pixels are sent in top-to-bottom scanline order, ++ * left-to-right within a scanline with no padding in between. ++ */ ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * CopyRect Encoding. The pixels are specified simply by the x and y position ++ * of the source rectangle. ++ */ ++ ++typedef struct _rfbCopyRect { ++ CARD16 srcX; ++ CARD16 srcY; ++} rfbCopyRect; ++ ++#define sz_rfbCopyRect 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * RRE - Rise-and-Run-length Encoding. We have an rfbRREHeader structure ++ * giving the number of subrectangles following. Finally the data follows in ++ * the form [...] where each is ++ * []. ++ */ ++ ++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 ++ * [...] where each is ++ * []. This means that ++ * the whole rectangle must be at most 255x255 pixels. ++ */ ++ ++typedef struct _rfbCoRRERectangle { ++ CARD8 x; ++ CARD8 y; ++ CARD8 w; ++ CARD8 h; ++} rfbCoRRERectangle; ++ ++#define sz_rfbCoRRERectangle 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Hextile Encoding. The rectangle is divided up into "tiles" of 16x16 pixels, ++ * starting at the top left going in left-to-right, top-to-bottom order. If ++ * the width of the rectangle is not an exact multiple of 16 then the width of ++ * the last tile in each row will be correspondingly smaller. Similarly if the ++ * height is not an exact multiple of 16 then the height of each tile in the ++ * final row will also be smaller. Each tile begins with a "subencoding" type ++ * byte, which is a mask made up of a number of bits. If the Raw bit is set ++ * then the other bits are irrelevant; w*h pixel values follow (where w and h ++ * are the width and height of the tile). Otherwise the tile is encoded in a ++ * similar way to RRE, except that the position and size of each subrectangle ++ * can be specified in just two bytes. The other bits in the mask are as ++ * follows: ++ * ++ * BackgroundSpecified - if set, a pixel value follows which specifies ++ * the background colour for this tile. The first non-raw tile in a ++ * rectangle must have this bit set. If this bit isn't set then the ++ * background is the same as the last tile. ++ * ++ * ForegroundSpecified - if set, a pixel value follows which specifies ++ * the foreground colour to be used for all subrectangles in this tile. ++ * If this bit is set then the SubrectsColoured bit must be zero. ++ * ++ * AnySubrects - if set, a single byte follows giving the number of ++ * subrectangles following. If not set, there are no subrectangles (i.e. ++ * the whole tile is just solid background colour). ++ * ++ * SubrectsColoured - if set then each subrectangle is preceded by a pixel ++ * value giving the colour of that subrectangle. If not set, all ++ * subrectangles are the same colour, the foreground colour; if the ++ * ForegroundSpecified bit wasn't set then the foreground is the same as ++ * the last tile. ++ * ++ * The position and size of each subrectangle is specified in two bytes. The ++ * Pack macros below can be used to generate the two bytes from x, y, w, h, ++ * and the Extract macros can be used to extract the x, y, w, h values from ++ * the two bytes. ++ */ ++ ++#define rfbHextileRaw (1 << 0) ++#define rfbHextileBackgroundSpecified (1 << 1) ++#define rfbHextileForegroundSpecified (1 << 2) ++#define rfbHextileAnySubrects (1 << 3) ++#define rfbHextileSubrectsColoured (1 << 4) ++ ++#define rfbHextilePackXY(x,y) (((x) << 4) | (y)) ++#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1)) ++#define rfbHextileExtractX(byte) ((byte) >> 4) ++#define rfbHextileExtractY(byte) ((byte) & 0xf) ++#define rfbHextileExtractW(byte) (((byte) >> 4) + 1) ++#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1) ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ZLIB - zlib compression Encoding. We have an rfbZlibHeader structure ++ * giving the number of bytes to follow. Finally the data follows in ++ * zlib compressed format. ++ */ ++ ++typedef struct _rfbZlibHeader { ++ CARD32 nBytes; ++} rfbZlibHeader; ++ ++#define sz_rfbZlibHeader 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Tight Encoding. ++ * ++ *-- The first byte of each Tight-encoded rectangle is a "compression control ++ * byte". Its format is as follows (bit 0 is the least significant one): ++ * ++ * bit 0: if 1, then compression stream 0 should be reset; ++ * bit 1: if 1, then compression stream 1 should be reset; ++ * bit 2: if 1, then compression stream 2 should be reset; ++ * bit 3: if 1, then compression stream 3 should be reset; ++ * bits 7-4: if 1000 (0x08), then the compression type is "fill", ++ * if 1001 (0x09), then the compression type is "jpeg", ++ * if 0xxx, then the compression type is "basic", ++ * values greater than 1001 are not valid. ++ * ++ * If the compression type is "basic", then bits 6..4 of the ++ * compression control byte (those xxx in 0xxx) specify the following: ++ * ++ * bits 5-4: decimal representation is the index of a particular zlib ++ * stream which should be used for decompressing the data; ++ * bit 6: if 1, then a "filter id" byte is following this byte. ++ * ++ *-- The data that follows after the compression control byte described ++ * above depends on the compression type ("fill", "jpeg" or "basic"). ++ * ++ *-- If the compression type is "fill", then the only pixel value follows, in ++ * client pixel format (see NOTE 1). This value applies to all pixels of the ++ * rectangle. ++ * ++ *-- If the compression type is "jpeg", the following data stream looks like ++ * this: ++ * ++ * 1..3 bytes: data size (N) in compact representation; ++ * N bytes: JPEG image. ++ * ++ * Data size is compactly represented in one, two or three bytes, according ++ * to the following scheme: ++ * ++ * 0xxxxxxx (for values 0..127) ++ * 1xxxxxxx 0yyyyyyy (for values 128..16383) ++ * 1xxxxxxx 1yyyyyyy zzzzzzzz (for values 16384..4194303) ++ * ++ * Here each character denotes one bit, xxxxxxx are the least significant 7 ++ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the ++ * most significant 8 bits (bits 14-21). For example, decimal value 10000 ++ * should be represented as two bytes: binary 10010000 01001110, or ++ * hexadecimal 90 4E. ++ * ++ *-- If the compression type is "basic" and bit 6 of the compression control ++ * byte was set to 1, then the next (second) byte specifies "filter id" which ++ * tells the decoder what filter type was used by the encoder to pre-process ++ * pixel data before the compression. The "filter id" byte can be one of the ++ * following: ++ * ++ * 0: no filter ("copy" filter); ++ * 1: "palette" filter; ++ * 2: "gradient" filter. ++ * ++ *-- If bit 6 of the compression control byte is set to 0 (no "filter id" ++ * byte), or if the filter id is 0, then raw pixel values in the client ++ * format (see NOTE 1) will be compressed. See below details on the ++ * compression. ++ * ++ *-- The "gradient" filter pre-processes pixel data with a simple algorithm ++ * which converts each color component to a difference between a "predicted" ++ * intensity and the actual intensity. Such a technique does not affect ++ * uncompressed data size, but helps to compress photo-like images better. ++ * Pseudo-code for converting intensities to differences is the following: ++ * ++ * P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1]; ++ * if (P[i,j] < 0) then P[i,j] := 0; ++ * if (P[i,j] > MAX) then P[i,j] := MAX; ++ * D[i,j] := V[i,j] - P[i,j]; ++ * ++ * Here V[i,j] is the intensity of a color component for a pixel at ++ * coordinates (i,j). MAX is the maximum value of intensity for a color ++ * component. ++ * ++ *-- The "palette" filter converts true-color pixel data to indexed colors ++ * and a palette which can consist of 2..256 colors. If the number of colors ++ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to ++ * encode one pixel. 1-bit encoding is performed such way that the most ++ * significant bits correspond to the leftmost pixels, and each raw of pixels ++ * is aligned to the byte boundary. When "palette" filter is used, the ++ * palette is sent before the pixel data. The palette begins with an unsigned ++ * byte which value is the number of colors in the palette minus 1 (i.e. 1 ++ * means 2 colors, 255 means 256 colors in the palette). Then follows the ++ * palette itself which consist of pixel values in client pixel format (see ++ * NOTE 1). ++ * ++ *-- The pixel data is compressed using the zlib library. But if the data ++ * size after applying the filter but before the compression is less then 12, ++ * then the data is sent as is, uncompressed. Four separate zlib streams ++ * (0..3) can be used and the decoder should read the actual stream id from ++ * the compression control byte (see NOTE 2). ++ * ++ * If the compression is not used, then the pixel data is sent as is, ++ * otherwise the data stream looks like this: ++ * ++ * 1..3 bytes: data size (N) in compact representation; ++ * N bytes: zlib-compressed data. ++ * ++ * Data size is compactly represented in one, two or three bytes, just like ++ * in the "jpeg" compression method (see above). ++ * ++ *-- NOTE 1. If the color depth is 24, and all three color components are ++ * 8-bit wide, then one pixel in Tight encoding is always represented by ++ * three bytes, where the first byte is red component, the second byte is ++ * green component, and the third byte is blue component of the pixel color ++ * value. This applies to colors in palettes as well. ++ * ++ *-- NOTE 2. The decoder must reset compression streams' states before ++ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control ++ * byte are set to 1. Note that the decoder must reset zlib streams even if ++ * the compression type is "fill" or "jpeg". ++ * ++ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only ++ * when bits-per-pixel value is either 16 or 32, not 8. ++ * ++ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048 ++ * pixels. If a rectangle is wider, it must be split into several rectangles ++ * and each one should be encoded separately. ++ * ++ */ ++ ++#define rfbTightExplicitFilter 0x04 ++#define rfbTightFill 0x08 ++#define rfbTightJpeg 0x09 ++#define rfbTightMaxSubencoding 0x09 ++ ++/* Filters to improve compression efficiency */ ++#define rfbTightFilterCopy 0x00 ++#define rfbTightFilterPalette 0x01 ++#define rfbTightFilterGradient 0x02 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ZLIBHEX - zlib compressed Hextile Encoding. Essentially, this is the ++ * hextile encoding with zlib compression on the tiles that can not be ++ * efficiently encoded with one of the other hextile subencodings. The ++ * new zlib subencoding uses two bytes to specify the length of the ++ * compressed tile and then the compressed data follows. As with the ++ * raw sub-encoding, the zlib subencoding invalidates the other ++ * values, if they are also set. ++ */ ++ ++#define rfbHextileZlibRaw (1 << 5) ++#define rfbHextileZlibHex (1 << 6) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * XCursor encoding. This is a special encoding used to transmit X-style ++ * cursor shapes from server to clients. Note that for this encoding, ++ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot ++ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB ++ * samples are sent after header in the rfbXCursorColors structure. They ++ * denote foreground and background colors of the cursor. If a client ++ * supports only black-and-white cursors, it should ignore these colors and ++ * assume that foreground is black and background is white. Next, two bitmaps ++ * (1 bits per pixel) follow: first one with actual data (value 0 denotes ++ * background color, value 1 denotes foreground color), second one with ++ * transparency data (bits with zero value mean that these pixels are ++ * transparent). Both bitmaps represent cursor data in a byte stream, from ++ * left to right, from top to bottom, and each row is byte-aligned. Most ++ * significant bits correspond to leftmost pixels. The number of bytes in ++ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor ++ * should be hidden (or default local cursor should be set by the client). ++ */ ++ ++typedef struct _rfbXCursorColors { ++ CARD8 foreRed; ++ CARD8 foreGreen; ++ CARD8 foreBlue; ++ CARD8 backRed; ++ CARD8 backGreen; ++ CARD8 backBlue; ++} rfbXCursorColors; ++ ++#define sz_rfbXCursorColors 6 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * RichCursor encoding. This is a special encoding used to transmit cursor ++ * shapes from server to clients. It is similar to the XCursor encoding but ++ * uses client pixel format instead of two RGB colors to represent cursor ++ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader ++ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h). ++ * After header, two pixmaps follow: first one with cursor image in current ++ * client pixel format (like in raw encoding), second with transparency data ++ * (1 bit per pixel, exactly the same format as used for transparency bitmap ++ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or ++ * default local cursor should be set by the client). ++ */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetColourMapEntries - these messages are only sent if the pixel ++ * format uses a "colour map" (i.e. trueColour false) and the client has not ++ * fixed the entire colour map using FixColourMapEntries. In addition they ++ * will only start being sent after the client has sent its first ++ * FramebufferUpdateRequest. So if the client always tells the server to use ++ * trueColour then it never needs to process this type of message. ++ */ ++ ++typedef struct _rfbSetColourMapEntriesMsg { ++ CARD8 type; /* always rfbSetColourMapEntries */ ++ CARD8 redIndex; /* used to be pad, but used for DirectColor */ ++ CARD16 firstColour; ++ CARD16 nColours; ++ ++ /* Followed by nColours * 3 * CARD16 ++ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */ ++ ++} rfbSetColourMapEntriesMsg; ++ ++#define sz_rfbSetColourMapEntriesMsg 6 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Bell - ring a bell on the client if it has one. ++ */ ++ ++typedef struct _rfbBellMsg { ++ CARD8 type; /* always rfbBell */ ++} rfbBellMsg; ++ ++#define sz_rfbBellMsg 1 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * ServerCutText - the server has new text in its cut buffer. ++ */ ++ ++typedef struct _rfbServerCutTextMsg { ++ CARD8 type; /* always rfbServerCutText */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 length; ++ /* followed by char text[length] */ ++} rfbServerCutTextMsg; ++ ++#define sz_rfbServerCutTextMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumStart - a port number for the crserver ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumStart */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 crServerPort; ++ CARD32 mothershipPort; ++} rfbChromiumStartMsg; ++ ++#define sz_rfbChromiumStartMsg 12 ++ ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumMoveResizeWindow - move a chromium window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumMoveResizeWindow */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 x; ++ CARD32 y; ++ CARD32 w; ++ CARD32 h; ++} rfbChromiumMoveResizeWindowMsg; ++ ++#define sz_rfbChromiumMoveResizeWindowMsg 24 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumClipList - send clip list ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumClipList */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 length; ++} rfbChromiumClipListMsg; ++ ++#define sz_rfbChromiumClipListMsg 12 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumWindowShow - map or unmap a window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumWindowShow */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 show; ++} rfbChromiumWindowShowMsg; ++ ++#define sz_rfbChromiumWindowShowMsg 12 ++ ++/*----------------------------------------------------------------------------- ++ * FileListData ++ */ ++ ++typedef struct _rfbFileListDataMsg { ++ CARD8 type; ++ CARD8 flags; ++ CARD16 numFiles; ++ CARD16 dataSize; ++ CARD16 compressedSize; ++ /* Followed by SizeData[numFiles] */ ++ /* Followed by Filenames[compressedSize] */ ++} rfbFileListDataMsg; ++ ++#define sz_rfbFileListDataMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadData ++ */ ++ ++typedef struct _rfbFileDownloadDataMsg { ++ CARD8 type; ++ CARD8 compressLevel; ++ CARD16 realSize; ++ CARD16 compressedSize; ++ /* Followed by File[copressedSize] */ ++} rfbFileDownloadDataMsg; ++ ++#define sz_rfbFileDownloadDataMsg 6 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadCancel ++ */ ++ ++typedef struct _rfbFileUploadCancelMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileUploadCancelMsg; ++ ++#define sz_rfbFileUploadCancelMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadFailed ++ */ ++ ++typedef struct _rfbFileDownloadFailedMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileDownloadFailedMsg; ++ ++#define sz_rfbFileDownloadFailedMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Union of all server->client messages. ++ */ ++ ++typedef union _rfbServerToClientMsg { ++ CARD8 type; ++ rfbFramebufferUpdateMsg fu; ++ rfbSetColourMapEntriesMsg scme; ++ rfbBellMsg b; ++ rfbServerCutTextMsg sct; ++ rfbFileListDataMsg fld; ++ rfbFileDownloadDataMsg fdd; ++ rfbFileUploadCancelMsg fuc; ++ rfbFileDownloadFailedMsg fdf; ++ rfbChromiumStartMsg scd; ++ rfbChromiumMoveResizeWindowMsg scm; ++ rfbChromiumClipListMsg sccl; ++ rfbChromiumWindowShowMsg scws; ++} rfbServerToClientMsg; ++ ++ ++ ++/***************************************************************************** ++ * ++ * Message definitions (client -> server) ++ * ++ *****************************************************************************/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetPixelFormat - tell the RFB server the format in which the client wants ++ * pixels sent. ++ */ ++ ++typedef struct _rfbSetPixelFormatMsg { ++ CARD8 type; /* always rfbSetPixelFormat */ ++ CARD8 pad1; ++ CARD16 pad2; ++ rfbPixelFormat format; ++} rfbSetPixelFormatMsg; ++ ++#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4) ++ ++ ++/*----------------------------------------------------------------------------- ++ * FixColourMapEntries - when the pixel format uses a "colour map", fix ++ * read-only colour map entries. ++ * ++ * ***************** NOT CURRENTLY SUPPORTED ***************** ++ */ ++ ++typedef struct _rfbFixColourMapEntriesMsg { ++ CARD8 type; /* always rfbFixColourMapEntries */ ++ CARD8 pad; ++ CARD16 firstColour; ++ CARD16 nColours; ++ ++ /* Followed by nColours * 3 * CARD16 ++ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */ ++ ++} rfbFixColourMapEntriesMsg; ++ ++#define sz_rfbFixColourMapEntriesMsg 6 ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetEncodings - tell the RFB server which encoding types we accept. Put them ++ * in order of preference, if we have any. We may always receive raw ++ * encoding, even if we don't specify it here. ++ */ ++ ++typedef struct _rfbSetEncodingsMsg { ++ CARD8 type; /* always rfbSetEncodings */ ++ CARD8 pad; ++ CARD16 nEncodings; ++ /* followed by nEncodings * CARD32 encoding types */ ++} rfbSetEncodingsMsg; ++ ++#define sz_rfbSetEncodingsMsg 4 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FramebufferUpdateRequest - request for a framebuffer update. If incremental ++ * is true then the client just wants the changes since the last update. If ++ * false then it wants the whole of the specified rectangle. ++ */ ++ ++typedef struct _rfbFramebufferUpdateRequestMsg { ++ CARD8 type; /* always rfbFramebufferUpdateRequest */ ++ CARD8 incremental; ++ CARD16 x; ++ CARD16 y; ++ CARD16 w; ++ CARD16 h; ++} rfbFramebufferUpdateRequestMsg; ++ ++#define sz_rfbFramebufferUpdateRequestMsg 10 ++ ++ ++/*----------------------------------------------------------------------------- ++ * KeyEvent - key press or release ++ * ++ * Keys are specified using the "keysym" values defined by the X Window System. ++ * For most ordinary keys, the keysym is the same as the corresponding ASCII ++ * value. Other common keys are: ++ * ++ * BackSpace 0xff08 ++ * Tab 0xff09 ++ * Return or Enter 0xff0d ++ * Escape 0xff1b ++ * Insert 0xff63 ++ * Delete 0xffff ++ * Home 0xff50 ++ * End 0xff57 ++ * Page Up 0xff55 ++ * Page Down 0xff56 ++ * Left 0xff51 ++ * Up 0xff52 ++ * Right 0xff53 ++ * Down 0xff54 ++ * F1 0xffbe ++ * F2 0xffbf ++ * ... ... ++ * F12 0xffc9 ++ * Shift 0xffe1 ++ * Control 0xffe3 ++ * Meta 0xffe7 ++ * Alt 0xffe9 ++ */ ++ ++typedef struct _rfbKeyEventMsg { ++ CARD8 type; /* always rfbKeyEvent */ ++ CARD8 down; /* true if down (press), false if up */ ++ CARD16 pad; ++ CARD32 key; /* key is specified as an X keysym */ ++} rfbKeyEventMsg; ++ ++#define sz_rfbKeyEventMsg 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * PointerEvent - mouse/pen move and/or button press. ++ */ ++ ++typedef struct _rfbPointerEventMsg { ++ CARD8 type; /* always rfbPointerEvent */ ++ CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */ ++ CARD16 x; ++ CARD16 y; ++} rfbPointerEventMsg; ++ ++#define rfbButton1Mask 1 ++#define rfbButton2Mask 2 ++#define rfbButton3Mask 4 ++#define rfbButton4Mask 8 ++#define rfbButton5Mask 16 ++ ++#define sz_rfbPointerEventMsg 6 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * ClientCutText - the client has new text in its cut buffer. ++ */ ++ ++typedef struct _rfbClientCutTextMsg { ++ CARD8 type; /* always rfbClientCutText */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 length; ++ /* followed by char text[length] */ ++} rfbClientCutTextMsg; ++ ++#define sz_rfbClientCutTextMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileListRequest ++ */ ++ ++typedef struct _rfbFileListRequestMsg { ++ CARD8 type; ++ CARD8 flags; ++ CARD16 dirNameSize; ++ /* Followed by char Dirname[dirNameSize] */ ++} rfbFileListRequestMsg; ++ ++#define sz_rfbFileListRequestMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadRequest ++ */ ++ ++typedef struct _rfbFileDownloadRequestMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 fNameSize; ++ CARD32 position; ++ /* Followed by char Filename[fNameSize] */ ++} rfbFileDownloadRequestMsg; ++ ++#define sz_rfbFileDownloadRequestMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadRequest ++ */ ++ ++typedef struct _rfbFileUploadRequestMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 fNameSize; ++ CARD32 position; ++ /* Followed by char Filename[fNameSize] */ ++} rfbFileUploadRequestMsg; ++ ++#define sz_rfbFileUploadRequestMsg 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadData ++ */ ++ ++typedef struct _rfbFileUploadDataMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 realSize; ++ CARD16 compressedSize; ++ /* Followed by File[compressedSize] */ ++} rfbFileUploadDataMsg; ++ ++#define sz_rfbFileUploadDataMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadCancel ++ */ ++ ++typedef struct _rfbFileDownloadCancelMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileDownloadCancelMsg; ++ ++#define sz_rfbFileDownloadCancelMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadFailed ++ */ ++ ++typedef struct _rfbFileUploadFailedMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileUploadFailedMsg; ++ ++#define sz_rfbFileUploadFailedMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileCreateDirRequest ++ */ ++ ++typedef struct _rfbFileCreateDirRequestMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 dNameLen; ++ CARD32 dModTime; ++ /* Followed by dName[dNameLen] */ ++} rfbFileCreateDirRequestMsg; ++ ++#define sz_rfbFileCreateDirRequestMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumStop - the client has stopped the GL app. ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumStop */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 port; ++} rfbChromiumStopMsg; ++ ++#define sz_rfbChromiumStopMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumExpose - redraw the window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumExpose */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++} rfbChromiumExposeMsg; ++ ++#define sz_rfbChromiumExposeMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * Union of all client->server messages. ++ */ ++ ++typedef union _rfbClientToServerMsg { ++ CARD8 type; ++ rfbSetPixelFormatMsg spf; ++ rfbFixColourMapEntriesMsg fcme; ++ rfbSetEncodingsMsg se; ++ rfbFramebufferUpdateRequestMsg fur; ++ rfbKeyEventMsg ke; ++ rfbPointerEventMsg pe; ++ rfbClientCutTextMsg cct; ++ rfbFileListRequestMsg flr; ++ rfbFileDownloadRequestMsg fdr; ++ rfbFileUploadRequestMsg fupr; ++ rfbFileUploadDataMsg fud; ++ rfbFileDownloadCancelMsg fdc; ++ rfbFileUploadFailedMsg fuf; ++ rfbFileCreateDirRequestMsg fcdr; ++ rfbChromiumStopMsg csd; ++ rfbChromiumExposeMsg cse; ++} rfbClientToServerMsg; +diff --git a/hw/vnc/rfbserver.c b/hw/vnc/rfbserver.c +new file mode 100644 +index 0000000..6e912e7 +--- /dev/null ++++ b/hw/vnc/rfbserver.c +@@ -0,0 +1,2273 @@ ++/* ++ * rfbserver.c - deal with server-side of the RFB protocol. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* Use ``#define CORBA'' to enable CORBA control interface */ ++ ++#include "rfb.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "windowstr.h" ++#include "input.h" ++#include "mipointer.h" ++#if XFREE86VNC ++#include ++#endif ++#ifdef CHROMIUM ++#include "mivalidate.h" ++#endif ++#include "sprite.h" ++#include "propertyst.h" ++#include ++ ++#ifdef CORBA ++#include ++#endif ++ ++#ifdef CHROMIUM ++struct CRWindowTable *windowTable = NULL; ++#endif ++ ++extern Atom VNC_CONNECT; ++ ++rfbClientPtr rfbClientHead = NULL; ++rfbClientPtr pointerClient = NULL; /* Mutex for pointer events */ ++ ++static rfbClientPtr rfbNewClient(ScreenPtr pScreen, int sock); ++static void rfbProcessClientProtocolVersion(rfbClientPtr cl); ++static void rfbProcessClientInitMessage(rfbClientPtr cl); ++static void rfbSendInteractionCaps(rfbClientPtr cl); ++static void rfbProcessClientNormalMessage(rfbClientPtr cl); ++static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy); ++static Bool rfbSendLastRectMarker(rfbClientPtr cl); ++ ++static char *text = NULL; ++ ++void ++rfbRootPropertyChange(ScreenPtr pScreen) ++{ ++ PropertyPtr pProp; ++ WindowPtr pWin = WindowTable[pScreen->myNum]; ++ ++ pProp = wUserProps (pWin); ++ ++ while (pProp) { ++ if ((pProp->propertyName == XA_CUT_BUFFER0) && ++ (pProp->type == XA_STRING) && ++ (pProp->format == 8)) ++ { ++ /* Ensure we don't keep re-sending cut buffer */ ++ ++ if ( (text && pProp->data && strncmp(text, pProp->data, pProp->size)) || !text) ++ rfbGotXCutText(pProp->data, pProp->size); ++ ++ if (text) xfree(text); ++ text = xalloc(1 + pProp->size); ++ if (! text) return; ++ if (pProp->data) memcpy(text, pProp->data, pProp->size); ++ text[pProp->size] = '\0'; ++ ++ return; ++ } ++ if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING) ++ && (pProp->format == 8) && (pProp->size > 0)) ++ { ++ int i; ++ rfbClientPtr cl; ++ int port = 5500; ++ char *host = (char *)Xalloc(pProp->size+1); ++ memcpy(host, pProp->data, pProp->size); ++ host[pProp->size] = 0; ++ for (i = 0; i < pProp->size; i++) { ++ if (host[i] == ':') { ++ port = atoi(&host[i+1]); ++ host[i] = 0; ++ } ++ } ++ ++ cl = rfbReverseConnection(pScreen, host, port); ++ ++#ifdef CORBA ++ if (cl != NULL) ++ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1); ++#endif ++ ++ ChangeWindowProperty(pWin, ++ pProp->propertyName, pProp->type, ++ pProp->format, PropModeReplace, ++ 0, NULL, ++ FALSE ++ ); ++ ++ free(host); ++ } ++ pProp = pProp->next; ++ } ++} ++ ++int ++rfbBitsPerPixel(depth) ++ int depth; ++{ ++ if (depth == 1) return 1; ++ else if (depth <= 8) return 8; ++ else if (depth <= 16) return 16; ++ else return 32; ++} ++ ++void ++rfbUserAllow(int sock, int accept) ++{ ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->sock == sock) { ++ cl->userAccepted = accept; ++ } ++ } ++} ++ ++/* ++ * rfbNewClientConnection is called from sockets.c when a new connection ++ * comes in. ++ */ ++ ++void ++rfbNewClientConnection(ScreenPtr pScreen, int sock) ++{ ++ rfbClientPtr cl; ++ ++ cl = rfbNewClient(pScreen, sock); ++ ++ GenerateVncConnectedEvent(sock); ++ ++#if XFREE86VNC ++ /* Someone is connected - disable VT switching */ ++ xf86EnableVTSwitch(FALSE); ++#endif ++ ++#ifdef CORBA ++ if (cl != NULL) ++ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1); ++#endif ++} ++ ++ ++/* ++ * rfbReverseConnection is called by the CORBA stuff to make an outward ++ * connection to a "listening" RFB client. ++ */ ++ ++rfbClientPtr ++rfbReverseConnection(ScreenPtr pScreen, char *host, int port) ++{ ++ int sock; ++ rfbClientPtr cl; ++ ++ if ((sock = rfbConnect(pScreen, host, port)) < 0) ++ return (rfbClientPtr)NULL; ++ ++ cl = rfbNewClient(pScreen, sock); ++ ++ if (cl) { ++ cl->reverseConnection = TRUE; ++ } ++ ++ return cl; ++} ++ ++ ++#ifdef CHROMIUM ++/* ++ * rfbSetClip -- ++ * Generate expose event. ++ * This function is overkill and should be cleaned up, but it ++ * works for now. ++ */ ++ ++void ++rfbSetClip (WindowPtr pWin, BOOL enable) ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ WindowPtr pChild; ++ Bool WasViewable = (Bool)(pWin->viewable); ++ Bool anyMarked = FALSE; ++ RegionPtr pOldClip = NULL, bsExposed; ++#ifdef DO_SAVE_UNDERS ++ Bool dosave = FALSE; ++#endif ++ WindowPtr pLayerWin; ++ BoxRec box; ++ ++ if (WasViewable) ++ { ++ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) ++ { ++ (void) (*pScreen->MarkOverlappedWindows)(pChild, ++ pChild, ++ &pLayerWin); ++ } ++ (*pScreen->MarkWindow) (pWin); ++ anyMarked = TRUE; ++ if (pWin->valdata) ++ { ++ if (HasBorder (pWin)) ++ { ++ RegionPtr borderVisible; ++ ++ borderVisible = REGION_CREATE(pScreen, NullBox, 1); ++ REGION_SUBTRACT(pScreen, borderVisible, ++ &pWin->borderClip, &pWin->winSize); ++ pWin->valdata->before.borderVisible = borderVisible; ++ } ++ pWin->valdata->before.resized = TRUE; ++ } ++ } ++ ++ /* ++ * Use REGION_BREAK to avoid optimizations in ValidateTree ++ * that assume the root borderClip can't change well, normally ++ * it doesn't...) ++ */ ++ if (enable) ++ { ++ box.x1 = 0; ++ box.y1 = 0; ++ box.x2 = pScreen->width; ++ box.y2 = pScreen->height; ++ REGION_INIT (pScreen, &pWin->winSize, &box, 1); ++ REGION_INIT (pScreen, &pWin->borderSize, &box, 1); ++ if (WasViewable) ++ REGION_RESET(pScreen, &pWin->borderClip, &box); ++ pWin->drawable.width = pScreen->width; ++ pWin->drawable.height = pScreen->height; ++ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); ++ } ++ else ++ { ++ REGION_EMPTY(pScreen, &pWin->borderClip); ++ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); ++ } ++ ++ ResizeChildrenWinSize (pWin, 0, 0, 0, 0); ++ ++ if (WasViewable) ++ { ++ if (pWin->backStorage) ++ { ++ pOldClip = REGION_CREATE(pScreen, NullBox, 1); ++ REGION_COPY(pScreen, pOldClip, &pWin->clipList); ++ } ++ ++ if (pWin->firstChild) ++ { ++ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, ++ pWin->firstChild, ++ (WindowPtr *)NULL); ++ } ++ else ++ { ++ (*pScreen->MarkWindow) (pWin); ++ anyMarked = TRUE; ++ } ++ ++#ifdef DO_SAVE_UNDERS ++ if (DO_SAVE_UNDERS(pWin)) ++ { ++ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin); ++ } ++#endif /* DO_SAVE_UNDERS */ ++ ++ if (anyMarked) ++ (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); ++ } ++ ++ if (pWin->backStorage && ++ ((pWin->backingStore == Always) || WasViewable)) ++ { ++ if (!WasViewable) ++ pOldClip = &pWin->clipList; /* a convenient empty region */ ++ bsExposed = (*pScreen->TranslateBackingStore) ++ (pWin, 0, 0, pOldClip, ++ pWin->drawable.x, pWin->drawable.y); ++ if (WasViewable) ++ REGION_DESTROY(pScreen, pOldClip); ++ if (bsExposed) ++ { ++ RegionPtr valExposed = NullRegion; ++ ++ if (pWin->valdata) ++ valExposed = &pWin->valdata->after.exposed; ++ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); ++ if (valExposed) ++ REGION_EMPTY(pScreen, valExposed); ++ REGION_DESTROY(pScreen, bsExposed); ++ } ++ } ++ if (WasViewable) ++ { ++ if (anyMarked) ++ (*pScreen->HandleExposures)(pWin); ++#ifdef DO_SAVE_UNDERS ++ if (dosave) ++ (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin); ++#endif /* DO_SAVE_UNDERS */ ++ if (anyMarked && pScreen->PostValidateTree) ++ (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); ++ } ++ if (pWin->realized) ++ WindowsRestructured (); ++ FlushAllOutput (); ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * rfbNewClient is called when a new connection has been made by whatever ++ * means. ++ */ ++ ++static rfbClientPtr ++rfbNewClient(ScreenPtr pScreen, int sock) ++{ ++ rfbProtocolVersionMsg pv; ++ rfbClientPtr cl; ++ BoxRec box; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(struct sockaddr_in); ++ VNCSCREENPTR(pScreen); ++ int i; ++ ++ if (rfbClientHead == NULL) { ++ /* no other clients - make sure we don't think any keys are pressed */ ++ KbdReleaseAllKeys(); ++ } else { ++ rfbLog(" (other clients"); ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ rfbLog(" %s",cl->host); ++ } ++ rfbLog(")\n"); ++ } ++ ++ cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec)); ++ ++#ifdef CHROMIUM ++ cl->chromium_port = 0; /* no GL application on this port, yet */ ++#endif ++ cl->userAccepted = 0; /* user hasn't even approached this yet .... */ ++ cl->sock = sock; ++ getpeername(sock, (struct sockaddr *)&addr, &addrlen); ++ cl->host = strdup(inet_ntoa(addr.sin_addr)); ++ cl->login = NULL; ++ ++ /* Dispatch client input to rfbProcessClientProtocolVersion(). */ ++ cl->state = RFB_PROTOCOL_VERSION; ++ ++ cl->viewOnly = FALSE; ++ cl->reverseConnection = FALSE; ++ cl->readyForSetColourMapEntries = FALSE; ++ cl->useCopyRect = FALSE; ++ cl->preferredEncoding = rfbEncodingRaw; ++ cl->correMaxWidth = 48; ++ cl->correMaxHeight = 48; ++ cl->pScreen = pScreen; ++ ++ REGION_NULL(pScreen,&cl->copyRegion); ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ ++ box.x1 = box.y1 = 0; ++ box.x2 = pVNC->width; ++ box.y2 = pVNC->height; ++ REGION_INIT(pScreen,&cl->modifiedRegion,&box,0); ++ ++ REGION_NULL(pScreen,&cl->requestedRegion); ++ ++ cl->deferredUpdateScheduled = FALSE; ++ cl->deferredUpdateTimer = NULL; ++ ++ cl->format = pVNC->rfbServerFormat; ++ cl->translateFn = rfbTranslateNone; ++ cl->translateLookupTable = NULL; ++ ++ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; ++ cl->tightQualityLevel = -1; ++ for (i = 0; i < 4; i++) ++ cl->zsActive[i] = FALSE; ++ ++ cl->enableCursorShapeUpdates = FALSE; ++ cl->enableCursorPosUpdates = FALSE; ++ cl->enableLastRectEncoding = FALSE; ++#ifdef CHROMIUM ++ cl->enableChromiumEncoding = FALSE; ++#endif ++ ++ cl->next = rfbClientHead; ++ rfbClientHead = cl; ++ ++ rfbResetStats(cl); ++ ++ cl->compStreamInited = FALSE; ++ cl->compStream.total_in = 0; ++ cl->compStream.total_out = 0; ++ cl->compStream.zalloc = Z_NULL; ++ cl->compStream.zfree = Z_NULL; ++ cl->compStream.opaque = Z_NULL; ++ ++ cl->zlibCompressLevel = 5; ++ ++ sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion, ++ rfbProtocolMinorVersion); ++ ++ if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) { ++ rfbLogPerror("rfbNewClient: write"); ++ rfbCloseSock(pScreen, sock); ++ return NULL; ++ } ++ ++ return cl; ++} ++ ++ ++/* ++ * rfbClientConnectionGone is called from sockets.c just after a connection ++ * has gone away. ++ */ ++ ++void ++rfbClientConnectionGone(sock) ++ int sock; ++{ ++ rfbClientPtr cl, prev; ++ int i; ++#if XFREE86VNC ++ int allowvt = TRUE; ++#endif ++ ++ for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) { ++ if (sock == cl->sock) ++ break; ++ } ++ ++ if (!cl) { ++ rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock); ++ return; ++ } ++ ++ if (cl->login != NULL) { ++ rfbLog("Client %s (%s) gone\n", cl->login, cl->host); ++ free(cl->login); ++ } else { ++ rfbLog("Client %s gone\n", cl->host); ++ } ++ free(cl->host); ++ ++ /* Release the compression state structures if any. */ ++ if ( cl->compStreamInited == TRUE ) { ++ deflateEnd( &(cl->compStream) ); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ if (cl->zsActive[i]) ++ deflateEnd(&cl->zsStruct[i]); ++ } ++ ++ if (pointerClient == cl) ++ pointerClient = NULL; ++ ++#ifdef CORBA ++ destroyConnection(cl); ++#endif ++ ++ if (prev) ++ prev->next = cl->next; ++ else ++ rfbClientHead = cl->next; ++ ++ REGION_UNINIT(cl->pScreen,&cl->copyRegion); ++ REGION_UNINIT(cl->pScreen,&cl->modifiedRegion); ++ TimerFree(cl->deferredUpdateTimer); ++ ++ rfbPrintStats(cl); ++ ++ if (cl->translateLookupTable) free(cl->translateLookupTable); ++ ++ xfree(cl); ++ ++ GenerateVncDisconnectedEvent(sock); ++ ++#if XFREE86VNC ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ /* still someone connected */ ++ allowvt = FALSE; ++ } ++ ++ xf86EnableVTSwitch(allowvt); ++#endif ++} ++ ++ ++/* ++ * rfbProcessClientMessage is called when there is data to read from a client. ++ */ ++ ++void ++rfbProcessClientMessage(ScreenPtr pScreen, int sock) ++{ ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (sock == cl->sock) ++ break; ++ } ++ ++ if (!cl) { ++ rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock); ++ rfbCloseSock(pScreen, sock); ++ return; ++ } ++ ++#ifdef CORBA ++ if (isClosePending(cl)) { ++ rfbLog("Closing connection to client %s\n", cl->host); ++ rfbCloseSock(pScreen, sock); ++ return; ++ } ++#endif ++ ++ switch (cl->state) { ++ case RFB_PROTOCOL_VERSION: ++ rfbProcessClientProtocolVersion(cl); ++ break; ++ case RFB_SECURITY_TYPE: /* protocol 3.7 */ ++ rfbProcessClientSecurityType(cl); ++ break; ++ case RFB_TUNNELING_TYPE: /* protocol 3.7t */ ++ rfbProcessClientTunnelingType(cl); ++ break; ++ case RFB_AUTH_TYPE: /* protocol 3.7t */ ++ rfbProcessClientAuthType(cl); ++ break; ++ case RFB_AUTHENTICATION: ++ rfbVncAuthProcessResponse(cl); ++ break; ++ case RFB_INITIALISATION: ++ rfbProcessClientInitMessage(cl); ++ break; ++ default: ++ rfbProcessClientNormalMessage(cl); ++ } ++} ++ ++ ++/* ++ * rfbProcessClientProtocolVersion is called when the client sends its ++ * protocol version. ++ */ ++ ++static void ++rfbProcessClientProtocolVersion(cl) ++ rfbClientPtr cl; ++{ ++ rfbProtocolVersionMsg pv; ++ int n, major, minor; ++ ++ if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientProtocolVersion: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientProtocolVersion: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ pv[sz_rfbProtocolVersionMsg] = 0; ++ if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) { ++ rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ rfbLog("Using protocol version %d.%d\n", major, minor); ++ ++ if (major != rfbProtocolMajorVersion) { ++ rfbLog("RFB protocol version mismatch - server %d.%d, client %d.%d\n", ++ rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Always use one of the two standard versions of the RFB protocol. */ ++ cl->protocol_minor_ver = minor; ++ if (minor > rfbProtocolMinorVersion) { ++ cl->protocol_minor_ver = rfbProtocolMinorVersion; ++ } else if (minor < rfbProtocolMinorVersion) { ++ cl->protocol_minor_ver = rfbProtocolFallbackMinorVersion; ++ } ++ if (minor != rfbProtocolMinorVersion && ++ minor != rfbProtocolFallbackMinorVersion) { ++ rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n", ++ major, minor, rfbProtocolMajorVersion, cl->protocol_minor_ver); ++ } ++ ++ /* TightVNC protocol extensions are not enabled yet. */ ++ cl->protocol_tightvnc = FALSE; ++ ++ rfbAuthNewClient(cl); ++} ++ ++/* ++ * rfbClientConnFailed is called when a client connection has failed ++ * before the authentication stage. ++ */ ++ ++void ++rfbClientConnFailed(cl, reason) ++ rfbClientPtr cl; ++ char *reason; ++{ ++ int headerLen, reasonLen; ++ char buf[8]; ++ ++ headerLen = (cl->protocol_minor_ver >= 7) ? 1 : 4; ++ reasonLen = strlen(reason); ++ ((CARD32 *)buf)[0] = 0; ++ ((CARD32 *)buf)[1] = Swap32IfLE(reasonLen); ++ ++ if ( WriteExact(cl->sock, buf, headerLen) < 0 || ++ WriteExact(cl->sock, buf + 4, 4) < 0 || ++ WriteExact(cl->sock, reason, reasonLen) < 0 ) { ++ rfbLogPerror("rfbClientConnFailed: write"); ++ } ++ ++ rfbCloseSock(cl->pScreen, cl->sock); ++} ++ ++ ++/* ++ * rfbProcessClientInitMessage is called when the client sends its ++ * initialisation message. ++ */ ++ ++static void ++rfbProcessClientInitMessage(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbClientInitMsg ci; ++ char buf[256]; ++ rfbServerInitMsg *si = (rfbServerInitMsg *)buf; ++ struct passwd *user; ++ int len, n; ++ rfbClientPtr otherCl, nextCl; ++ ++ if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientInitMessage: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientInitMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ si->framebufferWidth = Swap16IfLE(pVNC->width); ++ si->framebufferHeight = Swap16IfLE(pVNC->height); ++ si->format = pVNC->rfbServerFormat; ++ si->format.redMax = Swap16IfLE(si->format.redMax); ++ si->format.greenMax = Swap16IfLE(si->format.greenMax); ++ si->format.blueMax = Swap16IfLE(si->format.blueMax); ++ ++ user = getpwuid(getuid()); ++ ++ if (strlen(desktopName) > 128) /* sanity check on desktop name len */ ++ desktopName[128] = 0; ++ ++ if (user) { ++ sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)", ++ user->pw_name, desktopName, rfbThisHost, display); ++ } else { ++ sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)", ++ desktopName, rfbThisHost, display); ++ } ++ len = strlen(buf + sz_rfbServerInitMsg); ++ si->nameLength = Swap32IfLE(len); ++ ++ if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) { ++ rfbLogPerror("rfbProcessClientInitMessage: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (cl->protocol_tightvnc) ++ rfbSendInteractionCaps(cl); /* protocol 3.7t */ ++ ++ /* Dispatch client input to rfbProcessClientNormalMessage(). */ ++ cl->state = RFB_NORMAL; ++ ++ if (!cl->reverseConnection && ++ (pVNC->rfbNeverShared || (!pVNC->rfbAlwaysShared && !ci.shared))) { ++ ++ if (pVNC->rfbDontDisconnect) { ++ for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) { ++ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { ++ rfbLog("-dontdisconnect: Not shared & existing client\n"); ++ rfbLog(" refusing new client %s\n", cl->host); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ } else { ++ for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) { ++ nextCl = otherCl->next; ++ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { ++ rfbLog("Not shared - closing connection to client %s\n", ++ otherCl->host); ++ rfbCloseSock(otherCl->pScreen, otherCl->sock); ++ } ++ } ++ } ++ } ++} ++ ++ ++/* ++ * rfbSendInteractionCaps is called after sending the server ++ * initialisation message, only if the protocol version is 3.130. ++ * In this function, we send the lists of supported protocol messages ++ * and encodings. ++ */ ++ ++/* Update these constants on changing capability lists below! */ ++#define N_SMSG_CAPS 0 ++#define N_CMSG_CAPS 0 ++#define N_ENC_CAPS 12 ++ ++void ++rfbSendInteractionCaps(cl) ++ rfbClientPtr cl; ++{ ++ rfbInteractionCapsMsg intr_caps; ++ rfbCapabilityInfo enc_list[N_ENC_CAPS]; ++ int i; ++ ++ /* Fill in the header structure sent prior to capability lists. */ ++ intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS); ++ intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS); ++ intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS); ++ intr_caps.pad = 0; ++ ++ /* Supported server->client message types. */ ++ /* For future file transfer support: ++ i = 0; ++ SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor); ++ if (i != N_SMSG_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ */ ++ ++ /* Supported client->server message types. */ ++ /* For future file transfer support: ++ i = 0; ++ SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor); ++ if (i != N_CMSG_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ */ ++ ++ /* Encoding types. */ ++ i = 0; ++ SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor); ++ if (i != N_ENC_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Send header and capability lists */ ++ if (WriteExact(cl->sock, (char *)&intr_caps, ++ sz_rfbInteractionCapsMsg) < 0 || ++ WriteExact(cl->sock, (char *)&enc_list[0], ++ sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) { ++ rfbLogPerror("rfbSendInteractionCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientNormalMessage(). */ ++ cl->state = RFB_NORMAL; ++} ++ ++ ++/* ++ * rfbProcessClientNormalMessage is called when the client has sent a normal ++ * protocol message. ++ */ ++ ++static void ++rfbProcessClientNormalMessage(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int n; ++ rfbClientToServerMsg msg; ++ char *str; ++ ++ if (pVNC->rfbUserAccept) { ++ /* ++ * We've asked for another level of user authentication ++ * If the user has not validated this connected, don't ++ * process it. ++ */ ++ /* ++ * NOTE: we do it here, so the vncviewer knows it's ++ * connected, but waiting for the first screen update ++ */ ++ if (cl->userAccepted == VNC_USER_UNDEFINED) { ++ usleep(10); ++ return; ++ } ++ if (cl->userAccepted == VNC_USER_DISCONNECT) { ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ ++ if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ switch (msg.type) { ++ ++ case rfbSetPixelFormat: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbSetPixelFormatMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel; ++ cl->format.depth = msg.spf.format.depth; ++ cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0); ++ cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0); ++ cl->format.redMax = Swap16IfLE(msg.spf.format.redMax); ++ cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax); ++ cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax); ++ cl->format.redShift = msg.spf.format.redShift; ++ cl->format.greenShift = msg.spf.format.greenShift; ++ cl->format.blueShift = msg.spf.format.blueShift; ++ ++ cl->readyForSetColourMapEntries = TRUE; ++ ++ rfbSetTranslateFunction(cl); ++ return; ++ ++ ++ case rfbFixColourMapEntries: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbFixColourMapEntriesMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ rfbLog("rfbProcessClientNormalMessage: %s", ++ "FixColourMapEntries unsupported\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ ++ ++ case rfbSetEncodings: ++ { ++ int i; ++ CARD32 enc; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbSetEncodingsMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings); ++ ++ cl->preferredEncoding = -1; ++ cl->useCopyRect = FALSE; ++ cl->enableCursorShapeUpdates = FALSE; ++ cl->enableCursorPosUpdates = FALSE; ++ cl->enableLastRectEncoding = FALSE; ++#ifdef CHROMIUM ++ cl->enableChromiumEncoding = FALSE; ++#endif ++ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; ++ cl->tightQualityLevel = -1; ++ ++ for (i = 0; i < msg.se.nEncodings; i++) { ++ if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ enc = Swap32IfLE(enc); ++ ++ switch (enc) { ++ ++ case rfbEncodingCopyRect: ++ cl->useCopyRect = TRUE; ++ rfbLog("Using copyrect encoding for client %s\n", ++ cl->host); ++ break; ++ case rfbEncodingRaw: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using raw encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingRRE: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using rre encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingCoRRE: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using CoRRE encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingHextile: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using hextile encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingZlib: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using zlib encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingTight: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using tight encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingXCursor: ++ rfbLog("Enabling X-style cursor updates for client %s\n", ++ cl->host); ++ cl->enableCursorShapeUpdates = TRUE; ++ cl->useRichCursorEncoding = FALSE; ++ cl->cursorWasChanged = TRUE; ++ break; ++ case rfbEncodingRichCursor: ++ if (!cl->enableCursorShapeUpdates) { ++ rfbLog("Enabling full-color cursor updates for client " ++ "%s\n", cl->host); ++ cl->enableCursorShapeUpdates = TRUE; ++ cl->useRichCursorEncoding = TRUE; ++ cl->cursorWasChanged = TRUE; ++ } ++ break; ++ case rfbEncodingPointerPos: ++ if (!cl->enableCursorPosUpdates) { ++ rfbLog("Enabling cursor position updates for client %s\n", ++ cl->host); ++ cl->enableCursorPosUpdates = TRUE; ++ cl->cursorWasMoved = TRUE; ++ cl->cursorX = -1; ++ cl->cursorY = -1; ++ } ++ break; ++ case rfbEncodingLastRect: ++ if (!cl->enableLastRectEncoding) { ++ rfbLog("Enabling LastRect protocol extension for client " ++ "%s\n", cl->host); ++ cl->enableLastRectEncoding = TRUE; ++ } ++ break; ++#ifdef CHROMIUM ++ case rfbEncodingChromium: ++ case rfbEncodingChromium2: ++ if (!cl->enableChromiumEncoding) { ++ cl->enableChromiumEncoding = TRUE; ++ /* This tells OpenGL apps/replicate SPUs that new viewer ++ * has attached. ++ */ ++ GenerateVncChromiumConnectedEvent(cl->sock); ++ if (enc == rfbEncodingChromium) { ++ /* Generate exposures for all windows */ ++ WindowPtr pWin = WindowTable[cl->pScreen->myNum]; ++ rfbSetClip(pWin, 1); ++ } ++ else { ++ /* don't generate exposures for Chromium2 because ++ * that confused DMX. ++ */ ++ } ++ } ++ break; ++#endif ++ default: ++ if ( enc >= (CARD32)rfbEncodingCompressLevel0 && ++ enc <= (CARD32)rfbEncodingCompressLevel9 ) { ++ cl->zlibCompressLevel = enc & 0x0F; ++ cl->tightCompressLevel = enc & 0x0F; ++ rfbLog("Using compression level %d for client %s\n", ++ cl->tightCompressLevel, cl->host); ++ } else if ( enc >= (CARD32)rfbEncodingQualityLevel0 && ++ enc <= (CARD32)rfbEncodingQualityLevel9 ) { ++ cl->tightQualityLevel = enc & 0x0F; ++ rfbLog("Using image quality level %d for client %s\n", ++ cl->tightQualityLevel, cl->host); ++ } else { ++ rfbLog("rfbProcessClientNormalMessage: ignoring unknown " ++ "encoding %d\n", (int)enc); ++ } ++ } ++ } ++ ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = rfbEncodingRaw; ++ rfbLog("No encoding specified - using raw encoding for client %s\n", ++ cl->host); ++ } ++ ++ if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) { ++ rfbLog("Disabling cursor position updates for client %s\n", ++ cl->host); ++ cl->enableCursorPosUpdates = FALSE; ++ } ++ ++#if XFREE86VNC ++ /* ++ * With XFree86 and the hardware cursor's we need to put up the ++ * cursor again, and if we've detected a cursor shapeless client ++ * we need to disable hardware cursors. ++ */ ++ if (!cl->enableCursorShapeUpdates) ++ pVNC->SWCursor = (Bool *)TRUE; ++ else ++ pVNC->SWCursor = (Bool *)FALSE; ++ ++ { ++ int x, y; ++ miPointerPosition(&x, &y); ++ (*pVNC->spriteFuncs->SetCursor)(cl->pScreen, pVNC->pCurs, x, y); ++ } ++#endif ++ ++ return; ++ } ++ ++ ++ case rfbFramebufferUpdateRequest: ++ { ++ RegionRec tmpRegion; ++ BoxRec box; ++ ++#ifdef CORBA ++ addCapability(cl, DISPLAY_DEVICE); ++#endif ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ box.x1 = Swap16IfLE(msg.fur.x); ++ box.y1 = Swap16IfLE(msg.fur.y); ++ box.x2 = box.x1 + Swap16IfLE(msg.fur.w); ++ box.y2 = box.y1 + Swap16IfLE(msg.fur.h); ++ SAFE_REGION_INIT(cl->pScreen,&tmpRegion,&box,0); ++ ++ REGION_UNION(cl->pScreen, &cl->requestedRegion, &cl->requestedRegion, ++ &tmpRegion); ++ ++ if (!cl->readyForSetColourMapEntries) { ++ /* client hasn't sent a SetPixelFormat so is using server's */ ++ cl->readyForSetColourMapEntries = TRUE; ++ if (!cl->format.trueColour) { ++ if (!rfbSetClientColourMap(cl, 0, 0)) { ++ REGION_UNINIT(cl->pScreen,&tmpRegion); ++ return; ++ } ++ } ++ } ++ ++ if (!msg.fur.incremental) { ++ REGION_UNION(cl->pScreen,&cl->modifiedRegion,&cl->modifiedRegion, ++ &tmpRegion); ++ REGION_SUBTRACT(cl->pScreen,&cl->copyRegion,&cl->copyRegion, ++ &tmpRegion); ++ } ++ ++ if (FB_UPDATE_PENDING(cl)) { ++ rfbSendFramebufferUpdate(cl->pScreen, cl); ++ } ++ ++ REGION_UNINIT(cl->pScreen,&tmpRegion); ++ return; ++ } ++ ++ case rfbKeyEvent: ++ ++ cl->rfbKeyEventsRcvd++; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbKeyEventMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++#ifdef CORBA ++ addCapability(cl, KEYBOARD_DEVICE); ++ ++ if (!isKeyboardEnabled(cl)) ++ return; ++#endif ++ if (!pVNC->rfbViewOnly && !cl->viewOnly) { ++ KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl); ++ } ++ return; ++ ++ ++ case rfbPointerEvent: ++ ++ cl->rfbPointerEventsRcvd++; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbPointerEventMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++#ifdef CORBA ++ addCapability(cl, POINTER_DEVICE); ++ ++ if (!isPointerEnabled(cl)) ++ return; ++#endif ++ ++ if (pointerClient && (pointerClient != cl)) ++ return; ++ ++ if (msg.pe.buttonMask == 0) ++ pointerClient = NULL; ++ else ++ pointerClient = cl; ++ ++ if (!pVNC->rfbViewOnly && !cl->viewOnly) { ++ cl->cursorX = (int)Swap16IfLE(msg.pe.x); ++ cl->cursorY = (int)Swap16IfLE(msg.pe.y); ++ PtrAddEvent(msg.pe.buttonMask, cl->cursorX, cl->cursorY, cl); ++ } ++ return; ++ ++ ++ case rfbClientCutText: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbClientCutTextMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ msg.cct.length = Swap32IfLE(msg.cct.length); ++ ++ str = (char *)xalloc(msg.cct.length); ++ ++ if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ xfree(str); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* NOTE: We do not accept cut text from a view-only client */ ++ if (!cl->viewOnly) ++ rfbSetXCutText(str, msg.cct.length); ++ ++ xfree(str); ++ return; ++ ++#ifdef CHROMIUM ++ case rfbChromiumStop: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbChromiumStopMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* would we use msg.csd.port ??? */ ++ ++ cl->chromium_port = 0; ++ ++ /* tear down window information */ ++ { ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ xfree(wt); ++ } ++ ++ windowTable = NULL; ++ } ++ ++ return; ++ ++ case rfbChromiumExpose: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbChromiumExposeMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* find the window and re-expose it */ ++ { ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->CRwinId == msg.cse.winid) { ++ WindowPtr pWin; ++ pWin = LookupIDByType(wt->XwinId, RT_WINDOW); ++ if (pWin) { ++ miSendExposures(pWin, &pWin->clipList, ++ pWin->drawable.x, ++ pWin->drawable.y); ++ FlushAllOutput(); ++ } ++ } ++ } ++ } ++ ++ return; ++#endif ++ ++ default: ++ ++ rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n", ++ msg.type); ++ rfbLog(" ... closing connection\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++} ++ ++ ++ ++/* ++ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to ++ * the RFB client. ++ */ ++ ++Bool ++rfbSendFramebufferUpdate(pScreen, cl) ++ ScreenPtr pScreen; ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(pScreen); ++ int i; ++ int nUpdateRegionRects; ++ rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)pVNC->updateBuf; ++ RegionRec updateRegion, updateCopyRegion; ++ int dx, dy; ++ Bool sendCursorShape = FALSE; ++ Bool sendCursorPos = FALSE; ++ ++ /* ++ * If this client understands cursor shape updates, cursor should be ++ * removed from the framebuffer. Otherwise, make sure it's put up. ++ */ ++ ++#if !XFREE86VNC ++ if (cl->enableCursorShapeUpdates) { ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor(pScreen); ++ if (!pVNC->cursorIsDrawn && cl->cursorWasChanged) ++ sendCursorShape = TRUE; ++ } else { ++ if (!pVNC->cursorIsDrawn) ++ rfbSpriteRestoreCursor(pScreen); ++ } ++#else ++ if (cl->enableCursorShapeUpdates) ++ if (cl->cursorWasChanged) ++ sendCursorShape = TRUE; ++#endif ++ ++ /* ++ * Do we plan to send cursor position update? ++ */ ++ ++ if (cl->enableCursorPosUpdates && cl->cursorWasMoved) ++ sendCursorPos = TRUE; ++ ++ /* ++ * The modifiedRegion may overlap the destination copyRegion. We remove ++ * any overlapping bits from the copyRegion (since they'd only be ++ * overwritten anyway). ++ */ ++ ++ REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion, ++ &cl->modifiedRegion); ++ ++ /* ++ * The client is interested in the region requestedRegion. The region ++ * which should be updated now is the intersection of requestedRegion ++ * and the union of modifiedRegion and copyRegion. If it's empty then ++ * no update is needed. ++ */ ++ ++ REGION_NULL(pScreen,&updateRegion); ++ REGION_UNION(pScreen, &updateRegion, &cl->copyRegion, ++ &cl->modifiedRegion); ++ REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion, ++ &updateRegion); ++ ++ if ( !REGION_NOTEMPTY(pScreen,&updateRegion) && ++ !sendCursorShape && !sendCursorPos ) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return TRUE; ++ } ++ ++ /* ++ * We assume that the client doesn't have any pixel data outside the ++ * requestedRegion. In other words, both the source and destination of a ++ * copy must lie within requestedRegion. So the region we can send as a ++ * copy is the intersection of the copyRegion with both the requestedRegion ++ * and the requestedRegion translated by the amount of the copy. We set ++ * updateCopyRegion to this. ++ */ ++ ++ REGION_NULL(pScreen,&updateCopyRegion); ++ REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion, ++ &cl->requestedRegion); ++ REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY); ++ REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion, ++ &cl->requestedRegion); ++ dx = cl->copyDX; ++ dy = cl->copyDY; ++ ++ /* ++ * Next we remove updateCopyRegion from updateRegion so that updateRegion ++ * is the part of this update which is sent as ordinary pixel data (i.e not ++ * a copy). ++ */ ++ ++ REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion); ++ ++ /* ++ * Finally we leave modifiedRegion to be the remainder (if any) of parts of ++ * the screen which are modified but outside the requestedRegion. We also ++ * empty both the requestedRegion and the copyRegion - note that we never ++ * carry over a copyRegion for a future update. ++ */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &updateRegion); ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &updateCopyRegion); ++ ++ REGION_EMPTY(pScreen, &cl->requestedRegion); ++ REGION_EMPTY(pScreen, &cl->copyRegion); ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ ++ /* ++ * Now send the update. ++ */ ++ ++ cl->rfbFramebufferUpdateMessagesSent++; ++ ++ if (cl->preferredEncoding == rfbEncodingCoRRE) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1) ++ * ((h-1) / cl->correMaxHeight + 1)); ++ } ++ } else if (cl->preferredEncoding == rfbEncodingZlib) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1); ++ } ++ } else if (cl->preferredEncoding == rfbEncodingTight) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ int n = rfbNumCodedRectsTight(cl, x, y, w, h); ++ if (n == 0) { ++ nUpdateRegionRects = 0xFFFF; ++ break; ++ } ++ nUpdateRegionRects += n; ++ } ++ } else { ++ nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion); ++ } ++ ++ fu->type = rfbFramebufferUpdate; ++ if (nUpdateRegionRects != 0xFFFF) { ++ fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) + ++ nUpdateRegionRects + ++ !!sendCursorShape + !!sendCursorPos); ++ } else { ++ fu->nRects = 0xFFFF; ++ } ++ pVNC->ublen = sz_rfbFramebufferUpdateMsg; ++ ++ if (sendCursorShape) { ++ cl->cursorWasChanged = FALSE; ++ if (!rfbSendCursorShape(cl, pScreen)) ++ return FALSE; ++ } ++ ++ if (sendCursorPos) { ++ cl->cursorWasMoved = FALSE; ++ if (!rfbSendCursorPos(cl, pScreen)) ++ return FALSE; ++ } ++ ++ if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) { ++ if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ REGION_UNINIT(pScreen,&updateCopyRegion); ++ return FALSE; ++ } ++ } ++ ++ REGION_UNINIT(pScreen,&updateCopyRegion); ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ ++ cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader ++ + w * (cl->format.bitsPerPixel / 8) * h); ++ ++ switch (cl->preferredEncoding) { ++ case rfbEncodingRaw: ++ if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingRRE: ++ if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingCoRRE: ++ if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingHextile: ++ if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingZlib: ++ if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingTight: ++ if (!rfbSendRectEncodingTight(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ } ++ } ++ ++ REGION_UNINIT(pScreen,&updateRegion); ++ ++ if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl)) ++ return FALSE; ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * Send the copy region as a string of CopyRect encoded rectangles. ++ * The only slightly tricky thing is that we should send the messages in ++ * the correct order so that an earlier CopyRect will not corrupt the source ++ * of a later one. ++ */ ++ ++static Bool ++rfbSendCopyRegion(cl, reg, dx, dy) ++ rfbClientPtr cl; ++ RegionPtr reg; ++ int dx, dy; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand; ++ int x, y, w, h; ++ rfbFramebufferUpdateRectHeader rect; ++ rfbCopyRect cr; ++ ++ nrects = REGION_NUM_RECTS(reg); ++ ++ if (dx <= 0) { ++ x_inc = 1; ++ } else { ++ x_inc = -1; ++ } ++ ++ if (dy <= 0) { ++ thisRect = 0; ++ y_inc = 1; ++ } else { ++ thisRect = nrects - 1; ++ y_inc = -1; ++ } ++ ++ while (nrects > 0) { ++ ++ firstInNextBand = thisRect; ++ nrectsInBand = 0; ++ ++ while ((nrects > 0) && ++ (REGION_RECTS(reg)[firstInNextBand].y1 ++ == REGION_RECTS(reg)[thisRect].y1)) ++ { ++ firstInNextBand += y_inc; ++ nrects--; ++ nrectsInBand++; ++ } ++ ++ if (x_inc != y_inc) { ++ thisRect = firstInNextBand - y_inc; ++ } ++ ++ while (nrectsInBand > 0) { ++ if ((pVNC->ublen + sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbCopyRect) > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ x = REGION_RECTS(reg)[thisRect].x1; ++ y = REGION_RECTS(reg)[thisRect].y1; ++ w = REGION_RECTS(reg)[thisRect].x2 - x; ++ h = REGION_RECTS(reg)[thisRect].y2 - y; ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingCopyRect); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cr.srcX = Swap16IfLE(x - dx); ++ cr.srcY = Swap16IfLE(y - dy); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&cr, sz_rfbCopyRect); ++ pVNC->ublen += sz_rfbCopyRect; ++ ++ cl->rfbRectanglesSent[rfbEncodingCopyRect]++; ++ cl->rfbBytesSent[rfbEncodingCopyRect] ++ += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect; ++ ++ thisRect += x_inc; ++ nrectsInBand--; ++ } ++ ++ thisRect = firstInNextBand; ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Send a given rectangle in raw encoding (rfbEncodingRaw). ++ */ ++ ++Bool ++rfbSendRectEncodingRaw(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ int nlines; ++ int bytesPerLine = w * (cl->format.bitsPerPixel / 8); ++ unsigned char *fbptr = NULL; ++ int newy = 0; ++ ++ if (pVNC->useGetImage) { ++ newy = y; ++ } else { ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ } ++ ++ /* Flush the buffer to guarantee correct alignment for translateFn(). */ ++ if (pVNC->ublen > 0) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingRaw); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingRaw]++; ++ cl->rfbBytesSent[rfbEncodingRaw] ++ += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h; ++ ++ nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine; ++ ++ while (TRUE) { ++ if (nlines > h) ++ nlines = h; ++ ++ if (pVNC->useGetImage) { ++ (*cl->pScreen->GetImage)((DrawablePtr)WindowTable[cl->pScreen->myNum], x, newy, w, nlines, ZPixmap, ~0, &pVNC->updateBuf[pVNC->ublen]); ++ newy += nlines; ++ } else { ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat, ++ &cl->format, fbptr, &pVNC->updateBuf[pVNC->ublen], ++ pVNC->paddedWidthInBytes, w, nlines, x, y); ++ } ++ ++ pVNC->ublen += nlines * bytesPerLine; ++ h -= nlines; ++ ++ if (h == 0) /* rect fitted in buffer, do next one */ ++ return TRUE; ++ ++ /* buffer full - flush partial rect and do another nlines */ ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ if (!pVNC->useGetImage) ++ fbptr += (pVNC->paddedWidthInBytes * nlines); ++ ++ nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine; ++ if (nlines == 0) { ++ rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d " ++ "bytes per line\n", bytesPerLine); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ } ++} ++ ++ ++/* ++ * Send an empty rectangle with encoding field set to value of ++ * rfbEncodingLastRect to notify client that this is the last ++ * rectangle in framebuffer update ("LastRect" extension of RFB ++ * protocol). ++ */ ++ ++static Bool ++rfbSendLastRectMarker(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.encoding = Swap32IfLE(rfbEncodingLastRect); ++ rect.r.x = 0; ++ rect.r.y = 0; ++ rect.r.w = 0; ++ rect.r.h = 0; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbLastRectMarkersSent++; ++ cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Send the contents of pVNC->updateBuf. Returns 1 if successful, -1 if ++ * not (errno should be set). ++ */ ++ ++Bool ++rfbSendUpdateBuf(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ ++ /* ++ int i; ++ for (i = 0; i < pVNC->ublen; i++) { ++ rfbLog("%02x ",((unsigned char *)pVNC->updateBuf)[i]); ++ } ++ rfbLog("\n"); ++ */ ++ ++ if (pVNC->ublen > 0 && WriteExact(cl->sock, pVNC->updateBuf, pVNC->ublen) < 0) { ++ rfbLogPerror("rfbSendUpdateBuf: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ pVNC->ublen = 0; ++ return TRUE; ++} ++ ++ ++ ++/* ++ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the ++ * client, using values from the currently installed colormap. ++ */ ++ ++Bool ++rfbSendSetColourMapEntries(cl, firstColour, nColours) ++ rfbClientPtr cl; ++ int firstColour; ++ int nColours; ++{ ++#if !XFREE86VNC ++ VNCSCREENPTR(cl->pScreen); ++#endif ++ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; ++ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; ++ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); ++ EntryPtr pent; ++ EntryPtr redEntry, greenEntry, blueEntry; ++ unsigned short redPart, greenPart, bluePart; ++ int i, len; ++ ++ scme->type = rfbSetColourMapEntries; ++ scme->nColours = Swap16IfLE(nColours); ++ ++ len = sz_rfbSetColourMapEntriesMsg; ++ ++ /* PseudoColor */ ++#if XFREE86VNC ++ if (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor) { ++#else ++ if (pVNC->rfbInstalledColormap->class == PseudoColor) { ++#endif ++ scme->firstColour = Swap16IfLE(firstColour); ++#if XFREE86VNC ++ pent = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[firstColour]; ++#else ++ pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[firstColour]; ++#endif ++ for (i = 0; i < nColours; i++) { ++ if (pent->fShared) { ++ rgb[i*3] = Swap16IfLE(pent->co.shco.red->color); ++ rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color); ++ rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color); ++ } else { ++ rgb[i*3] = Swap16IfLE(pent->co.local.red); ++ rgb[i*3+1] = Swap16IfLE(pent->co.local.green); ++ rgb[i*3+2] = Swap16IfLE(pent->co.local.blue); ++ } ++ pent++; ++ } ++ } ++ ++ else { ++ ++ /* Break the DirectColor pixel into its r/g/b components */ ++#if XFREE86VNC ++ redPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->redMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetRed; ++ greenPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->greenMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetGreen; ++ bluePart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->blueMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetBlue; ++#else ++ redPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->redMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetRed; ++ greenPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->greenMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetGreen; ++ bluePart = (firstColour & pVNC->rfbInstalledColormap->pVisual->blueMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetBlue; ++#endif ++ ++ /* ++ * The firstColour field is only 16 bits. To support 24-bit pixels we ++ * sneak the red component in the 8-bit padding field which we renamed ++ * to redIndex. Green and blue are in firstColour (MSB, LSB respectively). ++ */ ++ scme->redIndex = Swap16IfLE(redPart); ++ scme->firstColour = Swap16IfLE((greenPart << 8) | bluePart); ++ ++#if XFREE86VNC ++ redEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[redPart]; ++ greenEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->green[greenPart]; ++ blueEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->blue[bluePart]; ++#else ++ redEntry = (EntryPtr)&pVNC->rfbInstalledColormap->red[redPart]; ++ greenEntry = (EntryPtr)&pVNC->rfbInstalledColormap->green[greenPart]; ++ blueEntry = (EntryPtr)&pVNC->rfbInstalledColormap->blue[bluePart]; ++#endif ++ for (i = 0; i < nColours; i++) { ++ if (redEntry->fShared) ++ rgb[i*3] = Swap16IfLE(redEntry->co.shco.red->color); ++ else ++ rgb[i*3] = Swap16IfLE(redEntry->co.local.red); ++ ++ if (greenEntry->fShared) ++ rgb[i*3+1] = Swap16IfLE(greenEntry->co.shco.green->color); ++ else ++ rgb[i*3+1] = Swap16IfLE(greenEntry->co.local.green); ++ ++ if (blueEntry->fShared) ++ rgb[i*3+2] = Swap16IfLE(blueEntry->co.shco.blue->color); ++ else ++ rgb[i*3+2] = Swap16IfLE(blueEntry->co.local.blue); ++ ++ redEntry++; ++ greenEntry++; ++ blueEntry++; ++ } ++ } ++ ++ len += nColours * 3 * 2; ++ ++ if (WriteExact(cl->sock, buf, len) < 0) { ++ rfbLogPerror("rfbSendSetColourMapEntries: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* ++ * rfbSendBell sends a Bell message to all the clients. ++ */ ++ ++void ++rfbSendBell() ++{ ++ rfbClientPtr cl, nextCl; ++ rfbBellMsg b; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ b.type = rfbBell; ++ if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) { ++ rfbLogPerror("rfbSendBell: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ } ++} ++ ++#ifdef CHROMIUM ++#ifdef sun ++extern int inet_aton(const char *cp, struct in_addr *inp); ++#endif ++ ++void ++rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort, ++ unsigned int mothershipPort) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumStartMsg scd; ++ struct in_addr ip; ++ unsigned int vncipaddress; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ inet_aton(cl->host, &ip); ++ memcpy(&vncipaddress, &ip, sizeof(unsigned int)); ++ if (ipaddress == vncipaddress /***&& !cl->chromium_port***/) { ++ cl->chromium_port = crServerPort; ++ cl->chromium_msport = mothershipPort; ++ scd.type = rfbChromiumStart; ++ scd.crServerPort = crServerPort; ++ scd.mothershipPort = mothershipPort; ++ if (WriteExact(cl->sock, (char *)&scd, ++ sz_rfbChromiumStartMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumStart: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ /* We only start one client at at time, so break now! */ ++ break; ++ } ++ } ++} ++ ++ ++/** ++ * Begin monitoring the given X windowid. ++ * When we detect size/position/visibiliy changes we'll send a ++ * rfbChromiumMoveResizeWindow, rfbChromiumClipList, or rfbChromiumWindowShow ++ * message to the VNC viewer, passing the corresponding Chromium window id. ++ */ ++void ++rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long xwindowid) ++{ ++ CRWindowTable *newRec, *wt, *nextWt = NULL; ++ ++ if (xwindowid && !cr_windowid) { ++ /* stop monitoring the X window, remove from list */ ++ CRWindowTable *prev = NULL; ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == xwindowid) { ++ /* remove */ ++ if (prev) ++ prev->next = wt->next; ++ else ++ windowTable = wt->next; ++ xfree(wt); ++ } ++ else { ++ prev = wt; ++ } ++ } ++ return; ++ } ++ ++ /* See if we're already managing this window */ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ /* and if so, update it's window ID */ ++ if (wt->CRwinId == cr_windowid) { ++ wt->XwinId = xwindowid; ++ return; ++ } ++ } ++ ++ /* o.k, new window so create new slot information */ ++ newRec = (CRWindowTable *)xalloc(sizeof(CRWindowTable)); ++ if (!newRec) { ++ rfbLog("Out of memory allocating CRWindowTable.\n"); ++ return; ++ } ++ ++ newRec->next = NULL; ++ newRec->CRwinId = cr_windowid; ++ newRec->XwinId = xwindowid; ++ newRec->clipRects = NULL; ++ newRec->numRects = 0; ++ ++ if (!windowTable) { ++ windowTable = newRec; ++ } ++ else { ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (!wt->next) /* found the next slot */ ++ wt->next = newRec; ++ } ++ } ++} ++ ++ ++void ++rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumMoveResizeWindowMsg scm; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ scm.type = rfbChromiumMoveResizeWindow; ++ scm.winid = winid; ++ scm.x = x; ++ scm.y = y; ++ scm.w = w; ++ scm.h = h; ++ if (WriteExact(cl->sock, (char *)&scm, ++ sz_rfbChromiumMoveResizeWindowMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumMoveResizeWindow: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++ ++void ++rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumClipListMsg sccl; ++ int len = sizeof(BoxRec) * numClipRects; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ sccl.type = rfbChromiumClipList; ++ sccl.winid = winid; ++ sccl.length = Swap32IfLE(len); ++ if (WriteExact(cl->sock, (char *)&sccl, ++ sz_rfbChromiumClipListMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumClipList: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ if (WriteExact(cl->sock, (char *)pClipRects, len) < 0) { ++ rfbLogPerror("rfbSendChromiumClipList: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++ ++void ++rfbSendChromiumWindowShow(unsigned int winid, unsigned int show) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumWindowShowMsg scws; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ scws.type = rfbChromiumWindowShow; ++ scws.winid = winid; ++ scws.show = show; ++ if (WriteExact(cl->sock, (char *)&scws, ++ sz_rfbChromiumWindowShowMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumWindowShow: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * rfbSendServerCutText sends a ServerCutText message to all the clients. ++ */ ++ ++void ++rfbSendServerCutText(char *str, int len) ++{ ++ rfbClientPtr cl, nextCl = NULL; ++ rfbServerCutTextMsg sct; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ if (cl->state != RFB_NORMAL) continue; ++ nextCl = cl->next; ++ sct.type = rfbServerCutText; ++ sct.length = Swap32IfLE(len); ++ if (WriteExact(cl->sock, (char *)&sct, ++ sz_rfbServerCutTextMsg) < 0) { ++ rfbLogPerror("rfbSendServerCutText: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ if (WriteExact(cl->sock, str, len) < 0) { ++ rfbLogPerror("rfbSendServerCutText: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ } ++} ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * UDP can be used for keyboard and pointer events when the underlying ++ * network is highly reliable. This is really here to support ORL's ++ * videotile, whose TCP implementation doesn't like sending lots of small ++ * packets (such as 100s of pen readings per second!). ++ */ ++ ++void ++rfbNewUDPConnection(sock) ++ int sock; ++{ ++ if (write(sock, &ptrAcceleration, 1) < 0) { ++ rfbLogPerror("rfbNewUDPConnection: write"); ++ } ++} ++ ++/* ++ * Because UDP is a message based service, we can't read the first byte and ++ * then the rest of the packet separately like we do with TCP. We will always ++ * get a whole packet delivered in one go, so we ask read() for the maximum ++ * number of bytes we can possibly get. ++ */ ++ ++void ++rfbProcessUDPInput(ScreenPtr pScreen, int sock) ++{ ++ VNCSCREENPTR(pScreen); ++ int n; ++ rfbClientToServerMsg msg; ++ ++ if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) { ++ if (n < 0) { ++ rfbLogPerror("rfbProcessUDPInput: read"); ++ } ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ ++ switch (msg.type) { ++ ++ case rfbKeyEvent: ++ if (n != sz_rfbKeyEventMsg) { ++ rfbLog("rfbProcessUDPInput: key event incorrect length\n"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ if (!pVNC->rfbViewOnly) { ++ KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), 0); ++ } ++ break; ++ ++ case rfbPointerEvent: ++ if (n != sz_rfbPointerEventMsg) { ++ rfbLog("rfbProcessUDPInput: ptr event incorrect length\n"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ if (!pVNC->rfbViewOnly) { ++ PtrAddEvent(msg.pe.buttonMask, ++ Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), 0); ++ } ++ break; ++ ++ default: ++ rfbLog("rfbProcessUDPInput: unknown message type %d\n", ++ msg.type); ++ rfbDisconnectUDPSock(pScreen); ++ } ++} +diff --git a/hw/vnc/rre.c b/hw/vnc/rre.c +new file mode 100644 +index 0000000..04c0b4e +--- /dev/null ++++ b/hw/vnc/rre.c +@@ -0,0 +1,323 @@ ++/* ++ * rre.c ++ * ++ * Routines to implement Rise-and-Run-length Encoding (RRE). This ++ * code is based on krw's original javatel rfbserver. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++ ++/* ++ * rreBeforeBuf contains pixel data in the client's format. ++ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is ++ * larger than the raw data or if it exceeds rreAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int rreBeforeBufSize = 0; ++static char *rreBeforeBuf = NULL; ++ ++static int rreAfterBufSize = 0; ++static char *rreAfterBuf = NULL; ++static int rreAfterBufLen; ++ ++static int subrectEncode8(CARD8 *data, int w, int h); ++static int subrectEncode16(CARD16 *data, int w, int h); ++static int subrectEncode32(CARD32 *data, int w, int h); ++static CARD32 getBgColour(char *data, int size, int bpp); ++ ++ ++/* ++ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbRREHeader hdr; ++ int nSubrects; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (rreBeforeBufSize < maxRawSize) { ++ rreBeforeBufSize = maxRawSize; ++ if (rreBeforeBuf == NULL) ++ rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); ++ else ++ rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); ++ } ++ ++ if (rreAfterBufSize < maxRawSize) { ++ rreAfterBufSize = maxRawSize; ++ if (rreAfterBuf == NULL) ++ rreAfterBuf = (char *)xalloc(rreAfterBufSize); ++ else ++ rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); ++ } ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, rreBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); ++ break; ++ case 16: ++ nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); ++ break; ++ case 32: ++ nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); ++ break; ++ default: ++ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); ++ exit(1); ++ } ++ ++ if (nSubrects < 0) { ++ ++ /* RRE encoding was too large, use raw */ ++ ++ return rfbSendRectEncodingRaw(cl, x, y, w, h); ++ } ++ ++ cl->rfbRectanglesSent[rfbEncodingRRE]++; ++ cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbRREHeader + rreAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingRRE); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nSubrects = Swap32IfLE(nSubrects); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader); ++ pVNC->ublen += sz_rfbRREHeader; ++ ++ for (i = 0; i < rreAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > rreAfterBufLen) { ++ bytesToCopy = rreAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * subrectEncode() encodes the given multicoloured rectangle as a background ++ * colour overwritten by single-coloured rectangles. It returns the number ++ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't ++ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The ++ * single-colour rectangle partition is not optimal, but does find the biggest ++ * horizontal or vertical rectangle top-left anchored to each consecutive ++ * coordinate position. ++ * ++ * The coding scheme is simply [...] where each ++ * is []. ++ */ ++ ++#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 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) { ++ 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..cdfccad +--- /dev/null ++++ b/hw/vnc/sockets.c +@@ -0,0 +1,654 @@ ++/* ++ * sockets.c - deal with TCP & UDP sockets. ++ * ++ * This code should be independent of any changes in the RFB protocol. It just ++ * deals with the X server scheduling stuff, calling rfbNewClientConnection and ++ * rfbProcessClientMessage to actually deal with the protocol. If a socket ++ * needs to be closed for any reason then rfbCloseSock should be called, and ++ * this in turn will call rfbClientConnectionGone. To make an active ++ * connection out, call rfbConnect - note that this does _not_ call ++ * rfbNewClientConnection. ++ * ++ * This file is divided into two types of function. Those beginning with ++ * "rfb" are specific to sockets using the RFB protocol. Those without the ++ * "rfb" prefix are more general socket routines (which are used by the http ++ * code). ++ * ++ * Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN ++ * not EWOULDBLOCK. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if HAVE_DIX_CONFIG_H ++#include "dix-config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "windowstr.h" ++ ++#ifndef USE_LIBWRAP ++#define USE_LIBWRAP 0 ++#endif ++#if USE_LIBWRAP ++#include ++#include ++int allow_severity = LOG_INFO; ++int deny_severity = LOG_WARNING; ++#endif ++ ++#include "rfb.h" ++ ++int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has ++ gone away - needed to stop us hanging */ ++ ++static struct sockaddr_in udpRemoteAddr; ++ ++/* ++ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB ++ * connections. It does nothing if called again. ++ */ ++ ++Bool ++rfbInitSockets(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if (inetdSock != -1) { ++ const int one = 1; ++ ++ if (fcntl(inetdSock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("fcntl"); ++ return FALSE; ++ } ++ ++ if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("setsockopt"); ++ return FALSE; ++ } ++ ++ AddEnabledDevice(inetdSock); ++ FD_ZERO(&pVNC->allFds); ++ FD_SET(inetdSock, &pVNC->allFds); ++ pVNC->maxFd = inetdSock; ++ return TRUE; ++ } ++ ++ if (pVNC->rfbPort == 0) { ++ pVNC->rfbPort = 5900 + atoi(display) + pScreen->myNum; ++ } ++ ++ if ((pVNC->rfbListenSock = ListenOnTCPPort(pScreen, pVNC->rfbPort)) < 0) { ++ rfbLogPerror("ListenOnTCPPort"); ++ pVNC->rfbPort = 0; ++ return FALSE; ++ } ++ ++ rfbLog("Listening for VNC connections on TCP port %d\n", pVNC->rfbPort); ++ ++ AddEnabledDevice(pVNC->rfbListenSock); ++ ++ FD_ZERO(&pVNC->allFds); ++ FD_SET(pVNC->rfbListenSock, &pVNC->allFds); ++ pVNC->maxFd = pVNC->rfbListenSock; ++ ++ if (pVNC->udpPort != 0) { ++ rfbLog("rfbInitSockets: listening for input on UDP port %d\n",pVNC->udpPort); ++ ++ if ((pVNC->udpSock = ListenOnUDPPort(pScreen, pVNC->udpPort)) < 0) { ++ rfbLogPerror("ListenOnUDPPort"); ++ return FALSE; ++ } ++ AddEnabledDevice(pVNC->udpSock); ++ FD_SET(pVNC->udpSock, &pVNC->allFds); ++ pVNC->maxFd = max(pVNC->udpSock,pVNC->maxFd); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB ++ * socket(s). If there is input to process, the appropriate function in the ++ * RFB server code will be called (rfbNewClientConnection, ++ * rfbProcessClientMessage, etc). ++ */ ++ ++void ++rfbCheckFds(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++#if XFREE86VNC ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++#endif ++ int nfds; ++ fd_set fds; ++ struct timeval tv; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(addr); ++ char buf[6]; ++ const int one = 1; ++ int sock; ++ static Bool inetdInitDone = FALSE; ++ ++ if (!inetdInitDone && inetdSock != -1) { ++ rfbNewClientConnection(pScreen, inetdSock); ++ inetdInitDone = TRUE; ++ } ++ ++ memcpy((char *)&fds, (char *)&pVNC->allFds, sizeof(fd_set)); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ nfds = select(pVNC->maxFd + 1, &fds, NULL, NULL, &tv); ++ if (nfds == 0) { ++ return; ++ } ++ if (nfds < 0) { ++ if (errno != EINTR) ++ rfbLogPerror("rfbCheckFds: select"); ++ return; ++ } ++ ++ if (pVNC->rfbListenSock != -1 && FD_ISSET(pVNC->rfbListenSock, &fds)) { ++ ++ if ((sock = accept(pVNC->rfbListenSock, ++ (struct sockaddr *)&addr, &addrlen)) < 0) { ++ rfbLogPerror("rfbCheckFds: accept"); ++ return; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("rfbCheckFds: fcntl"); ++ close(sock); ++ return; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("rfbCheckFds: setsockopt"); ++ close(sock); ++ return; ++ } ++ ++ rfbLog("\n"); ++ ++#if USE_LIBWRAP ++ if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), ++ STRING_UNKNOWN)) { ++ rfbLog("Rejected connection from client %s\n", ++ inet_ntoa(addr.sin_addr)); ++ close(sock); ++ return; ++ } ++#endif ++ ++ rfbLog("Got VNC connection from client %s\n", inet_ntoa(addr.sin_addr)); ++ ++ AddEnabledDevice(sock); ++ FD_SET(sock, &pVNC->allFds); ++ pVNC->maxFd = max(sock,pVNC->maxFd); ++ ++ rfbNewClientConnection(pScreen, sock); ++ ++ FD_CLR(pVNC->rfbListenSock, &fds); ++ if (--nfds == 0) ++ return; ++ } ++ ++ if ((pVNC->udpSock != -1) && FD_ISSET(pVNC->udpSock, &fds)) { ++ ++ if (recvfrom(pVNC->udpSock, buf, 1, MSG_PEEK, ++ (struct sockaddr *)&addr, &addrlen) < 0) { ++ ++ rfbLogPerror("rfbCheckFds: UDP: recvfrom"); ++ rfbDisconnectUDPSock(pScreen); ++ ++ } else { ++ ++ if (!pVNC->udpSockConnected || ++ (memcmp(&addr, &udpRemoteAddr, addrlen) != 0)) ++ { ++ /* new remote end */ ++ rfbLog("rfbCheckFds: UDP: got connection\n"); ++ ++ memcpy(&udpRemoteAddr, &addr, addrlen); ++ pVNC->udpSockConnected = TRUE; ++ ++ if (connect(pVNC->udpSock, ++ (struct sockaddr *)&addr, addrlen) < 0) { ++ rfbLogPerror("rfbCheckFds: UDP: connect"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ ++ rfbNewUDPConnection(pVNC->udpSock); ++ } ++ ++ rfbProcessUDPInput(pScreen, pVNC->udpSock); ++ } ++ ++ FD_CLR(pVNC->udpSock, &fds); ++ if (--nfds == 0) ++ return; ++ } ++ ++ for (sock = 0; sock <= pVNC->maxFd; sock++) { ++ if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &pVNC->allFds)) { ++#if XFREE86VNC ++ if (!pScrn->vtSema) ++ rfbCloseSock(pScreen, sock); ++ else ++#endif ++ rfbProcessClientMessage(pScreen, sock); ++ } ++ } ++} ++ ++ ++void ++rfbDisconnectUDPSock(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ pVNC->udpSockConnected = FALSE; ++} ++ ++ ++void ++rfbCloseSock(ScreenPtr pScreen, int sock) ++{ ++ VNCSCREENPTR(pScreen); ++ close(sock); ++ RemoveEnabledDevice(sock); ++ FD_CLR(sock, &pVNC->allFds); ++ rfbClientConnectionGone(sock); ++ if (sock == inetdSock) ++ GiveUp(0); ++} ++ ++#if 0 ++/* ++ * rfbWaitForClient can be called to wait for the RFB client to send us a ++ * message. When one is received it is processed by calling ++ * rfbProcessClientMessage(). ++ */ ++ ++void ++rfbWaitForClient(sock) ++ int sock; ++{ ++ int n; ++ fd_set fds; ++ struct timeval tv; ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = rfbMaxClientWait / 1000; ++ tv.tv_usec = (rfbMaxClientWait % 1000) * 1000; ++ n = select(sock+1, &fds, NULL, NULL, &tv); ++ if (n < 0) { ++ rfbLogPerror("rfbWaitForClient: select"); ++ exit(1); ++ } ++ if (n == 0) { ++ rfbCloseSock(sock); ++ return; ++ } ++ ++ rfbProcessClientMessage(sock); ++} ++#endif ++ ++/* ++ * rfbConnect is called to make a connection out to a given TCP address. ++ */ ++ ++int ++rfbConnect(ScreenPtr pScreen, char *host, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ int sock; ++ int one = 1; ++ ++ rfbLog("\n"); ++ rfbLog("Making connection to client on host %s port %d\n", ++ host,port); ++ ++ if ((sock = ConnectToTcpAddr(host, port)) < 0) { ++ rfbLogPerror("connection failed"); ++ return -1; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("fcntl failed"); ++ close(sock); ++ return -1; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("setsockopt failed"); ++ close(sock); ++ return -1; ++ } ++ ++ AddEnabledDevice(sock); ++ FD_SET(sock, &pVNC->allFds); ++ pVNC->maxFd = max(sock,pVNC->maxFd); ++ ++ return sock; ++} ++ ++ ++ ++ ++/* ++ * ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if ++ * those bytes have been read, 0 if the other end has closed, or -1 if an error ++ * occurred (errno is set to ETIMEDOUT if it timed out). ++ */ ++ ++int ++ReadExact(sock, buf, len) ++ int sock; ++ char *buf; ++ int len; ++{ ++ int n; ++ fd_set fds; ++ int tries = 5; ++ struct timeval tv; ++ ++ while (len > 0) { ++ n = read(sock, buf, len); ++ ++ if (n > 0) { ++ ++ buf += n; ++ len -= n; ++ ++ } else if (n == 0) { ++ ++ return 0; ++ ++ } else { ++ if (errno != EWOULDBLOCK && errno != EAGAIN) { ++ return n; ++ } ++ ++ do { ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = rfbMaxClientWait / 1000; ++ tv.tv_usec = (rfbMaxClientWait % 1000) * 1000; ++ n = select(sock+1, &fds, NULL, NULL, &tv); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((n < 0 && errno == EINTR) && tries > 0); ++ ++ if (n < 0) { ++ rfbLogPerror("ReadExact: select"); ++ return n; ++ } ++ if (n == 0) { ++ errno = ETIMEDOUT; ++ return -1; ++ } ++ } ++ } ++ return 1; ++} ++ ++ ++ ++/* ++ * WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if ++ * those bytes have been written, or -1 if an error occurred (errno is set to ++ * ETIMEDOUT if it timed out). ++ */ ++ ++int ++WriteExact(sock, buf, len) ++ int sock; ++ char *buf; ++ int len; ++{ ++ int n; ++ fd_set fds; ++ struct timeval tv; ++ int totalTimeWaited = 0; ++ ++ while (len > 0) { ++ n = write(sock, buf, len); ++ ++ if (n > 0) { ++ ++ buf += n; ++ len -= n; ++ ++ } else if (n == 0) { ++ ++ rfbLog("WriteExact: write returned 0?\n"); ++ return -1; ++ ++ } else { ++ if (errno != EWOULDBLOCK && errno != EAGAIN) { ++ return n; ++ } ++ ++#if 0 ++ /* Retry every 5 seconds until we exceed rfbMaxClientWait. We ++ need to do this because select doesn't necessarily return ++ immediately when the other end has gone away */ ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = 5; ++ tv.tv_usec = 0; ++#else ++ /* We're in the WakeupHandler now, so don't wait */ ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++#endif ++ n = select(sock+1, NULL, &fds, NULL, &tv); ++#if 0 ++ if (n < 0) { ++ rfbLogPerror("WriteExact: select"); ++ return n; ++ } ++ if (n == 0) { ++ totalTimeWaited += 5000; ++ if (totalTimeWaited >= rfbMaxClientWait) { ++ errno = ETIMEDOUT; ++ return -1; ++ } ++ } else { ++ totalTimeWaited = 0; ++ } ++#endif ++ } ++ } ++ return 1; ++} ++ ++ ++int ++ListenOnTCPPort(ScreenPtr pScreen, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ struct sockaddr_in addr; ++ int sock; ++ int one = 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = pVNC->interface.s_addr; ++ ++ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ return -1; ++ } ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { ++ close(sock); ++ return -1; ++ } ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ close(sock); ++ return -1; ++ } ++ if (listen(sock, 5) < 0) { ++ close(sock); ++ return -1; ++ } ++ ++ return sock; ++} ++ ++ ++int ++ConnectToTcpAddr(host, port) ++ char *host; ++ int port; ++{ ++ struct hostent *hp; ++ int sock, n; ++ struct sockaddr_in addr; ++ int tries = 5; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ ++ if ((addr.sin_addr.s_addr = inet_addr(host)) == -1) ++ { ++ if (!(hp = gethostbyname(host))) { ++ errno = EINVAL; ++ return -1; ++ } ++ addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr; ++ } ++ ++ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ return -1; ++ } ++ ++ do { ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((sock < 0 && errno == EINTR) && tries > 0); ++ ++ if (sock < 0) { ++ return -1; ++ } ++ ++ tries = 5; ++ ++ do { ++ n = connect(sock, (struct sockaddr *)&addr, (sizeof(addr))); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((n < 0 && errno == EINTR) && tries > 0); ++ ++ if (n < 0) { ++ close(sock); ++ return -1; ++ } ++ ++ return sock; ++} ++ ++ ++int ++ListenOnUDPPort(ScreenPtr pScreen, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ struct sockaddr_in addr; ++ int sock; ++ int one = 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = pVNC->interface.s_addr; ++ ++ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ++ return -1; ++ } ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { ++ return -1; ++ } ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ return -1; ++ } ++ ++ return sock; ++} ++ ++#if 0 ++/* ++ * rdpInitSockets sets up the TCP for RDP ++ * connections. It does nothing if called again. ++ */ ++ ++Bool ++rdpInitSockets(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if ((pVNC->rdpListenSock = ListenOnTCPPort(pScreen, pVNC->rdpPort)) < 0) { ++ rfbLogPerror("ListenOnTCPPort"); ++ pVNC->rdpPort = 0; ++ return FALSE; ++ } ++ ++ rfbLog("Listening for RDP connections on TCP port %d\n", pVNC->rdpPort); ++ ++ AddEnabledDevice(pVNC->rdpListenSock); ++ ++ return TRUE; ++} ++#endif +diff --git a/hw/vnc/sprite.c b/hw/vnc/sprite.c +new file mode 100644 +index 0000000..03f21b2 +--- /dev/null ++++ b/hw/vnc/sprite.c +@@ -0,0 +1,2491 @@ ++/* ++ * sprite.c ++ * ++ * software sprite routines - based on misprite ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* $XConsortium: misprite.c,v 5.47 94/04/17 20:27:53 dpw Exp $ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#include "rfb.h" ++# include ++# include ++# include ++# include ++# include "misc.h" ++# include "pixmapstr.h" ++# include "input.h" ++# include "mi.h" ++# include "cursorstr.h" ++# include "scrnintstr.h" ++# include "colormapst.h" ++# include "windowstr.h" ++# include "gcstruct.h" ++# include "mipointer.h" ++# include "spritest.h" ++# include "dixfontstr.h" ++#ifdef RENDER ++# include "mipict.h" ++#endif ++ ++/* ++ * screen wrappers ++ */ ++ ++static int rfbSpriteScreenIndex; ++static unsigned long rfbSpriteGeneration = 0; ++ ++static Bool rfbSpriteCloseScreen(int i, ScreenPtr pScreen); ++static void rfbSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, ++ int w, int h, unsigned int format, ++ unsigned long planemask, char *pdstLine); ++static void rfbSpriteGetSpans(DrawablePtr pDrawable, int wMax, ++ DDXPointPtr ppt, int *pwidth, int nspans, ++ char *pdstStart); ++static void rfbSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, ++ int width, int height); ++static Bool rfbSpriteCreateGC(GCPtr pGC); ++static void rfbSpriteBlockHandler(int i, pointer blockData, ++ pointer pTimeout, ++ pointer pReadMask); ++static void rfbSpriteInstallColormap(ColormapPtr pMap); ++static void rfbSpriteStoreColors(ColormapPtr pMap, int ndef, ++ xColorItem *pdef); ++ ++static void rfbSpritePaintWindowBackground(WindowPtr pWin, ++ RegionPtr pRegion, int what); ++static void rfbSpritePaintWindowBorder(WindowPtr pWin, ++ RegionPtr pRegion, int what); ++static void rfbSpriteCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, ++ RegionPtr pRegion); ++static void rfbSpriteClearToBackground(WindowPtr pWin, int x, int y, ++ int w, int h, ++ Bool generateExposures); ++ ++#ifdef RENDER ++static void rfbSpriteComposite(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height); ++ ++static void rfbSpriteGlyphs(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlist, ++ GlyphListPtr list, ++ GlyphPtr *glyphs); ++#endif ++ ++static void rfbSpriteSaveDoomedAreas(WindowPtr pWin, ++ RegionPtr pObscured, int dx, ++ int dy); ++static RegionPtr rfbSpriteRestoreAreas(WindowPtr pWin, RegionPtr pRgnExposed); ++static void rfbSpriteComputeSaved(ScreenPtr pScreen); ++ ++#define SCREEN_PROLOGUE(pScreen, field)\ ++ ((pScreen)->field = \ ++ ((rfbSpriteScreenPtr) (pScreen)->devPrivates[rfbSpriteScreenIndex].ptr)->field) ++ ++#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ ++ ((pScreen)->field = wrapper) ++ ++/* ++ * GC func wrappers ++ */ ++ ++static int rfbSpriteGCIndex; ++ ++static void rfbSpriteValidateGC(GCPtr pGC, unsigned long stateChanges, ++ DrawablePtr pDrawable); ++static void rfbSpriteCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); ++static void rfbSpriteDestroyGC(GCPtr pGC); ++static void rfbSpriteChangeGC(GCPtr pGC, unsigned long mask); ++static void rfbSpriteChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); ++static void rfbSpriteDestroyClip(GCPtr pGC); ++static void rfbSpriteCopyClip(GCPtr pgcDst, GCPtr pgcSrc); ++ ++static GCFuncs rfbSpriteGCFuncs = { ++ rfbSpriteValidateGC, ++ rfbSpriteChangeGC, ++ rfbSpriteCopyGC, ++ rfbSpriteDestroyGC, ++ rfbSpriteChangeClip, ++ rfbSpriteDestroyClip, ++ rfbSpriteCopyClip, ++}; ++ ++#define GC_FUNC_PROLOGUE(pGC) \ ++ rfbSpriteGCPtr pGCPriv = \ ++ (rfbSpriteGCPtr) (pGC)->devPrivates[rfbSpriteGCIndex].ptr;\ ++ (pGC)->funcs = pGCPriv->wrapFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ (pGC)->ops = pGCPriv->wrapOps; ++ ++#define GC_FUNC_EPILOGUE(pGC) \ ++ pGCPriv->wrapFuncs = (pGC)->funcs; \ ++ (pGC)->funcs = &rfbSpriteGCFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ { \ ++ pGCPriv->wrapOps = (pGC)->ops; \ ++ (pGC)->ops = &rfbSpriteGCOps; \ ++ } ++ ++/* ++ * GC op wrappers ++ */ ++ ++static void rfbSpriteFillSpans(DrawablePtr pDrawable, GCPtr pGC, ++ int nInit, DDXPointPtr pptInit, ++ int *pwidthInit, int fSorted); ++static void rfbSpriteSetSpans(DrawablePtr pDrawable, GCPtr pGC, ++ char *psrc, DDXPointPtr ppt, int *pwidth, ++ int nspans, int fSorted); ++static void rfbSpritePutImage(DrawablePtr pDrawable, GCPtr pGC, ++ int depth, int x, int y, int w, int h, ++ int leftPad, int format, char *pBits); ++static RegionPtr rfbSpriteCopyArea(DrawablePtr pSrc, DrawablePtr pDst, ++ GCPtr pGC, int srcx, int srcy, int w, ++ int h, int dstx, int dsty); ++static RegionPtr rfbSpriteCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, ++ GCPtr pGC, int srcx, int srcy, int w, ++ int h, int dstx, int dsty, ++ unsigned long plane); ++static void rfbSpritePolyPoint(DrawablePtr pDrawable, GCPtr pGC, ++ int mode, int npt, xPoint *pptInit); ++static void rfbSpritePolylines(DrawablePtr pDrawable, GCPtr pGC, ++ int mode, int npt, DDXPointPtr pptInit); ++static void rfbSpritePolySegment(DrawablePtr pDrawable, GCPtr pGC, ++ int nseg, xSegment *pSegs); ++static void rfbSpritePolyRectangle(DrawablePtr pDrawable, GCPtr pGC, ++ int nrects, xRectangle *pRects); ++static void rfbSpritePolyArc(DrawablePtr pDrawable, GCPtr pGC, ++ int narcs, xArc *parcs); ++static void rfbSpriteFillPolygon(DrawablePtr pDrawable, GCPtr pGC, ++ int shape, int mode, int count, ++ DDXPointPtr pPts); ++static void rfbSpritePolyFillRect(DrawablePtr pDrawable, GCPtr pGC, ++ int nrectFill, xRectangle *prectInit); ++static void rfbSpritePolyFillArc(DrawablePtr pDrawable, GCPtr pGC, ++ int narcs, xArc *parcs); ++static int rfbSpritePolyText8(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, char *chars); ++static int rfbSpritePolyText16(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, ++ unsigned short *chars); ++static void rfbSpriteImageText8(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, char *chars); ++static void rfbSpriteImageText16(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, int count, ++ unsigned short *chars); ++static void rfbSpriteImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, unsigned int nglyph, ++ CharInfoPtr *ppci, ++ pointer pglyphBase); ++static void rfbSpritePolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, ++ int x, int y, unsigned int nglyph, ++ CharInfoPtr *ppci, ++ pointer pglyphBase); ++static void rfbSpritePushPixels(GCPtr pGC, PixmapPtr pBitMap, ++ DrawablePtr pDst, int w, int h, ++ int x, int y); ++#ifdef NEED_LINEHELPER ++static void rfbSpriteLineHelper(); ++#endif ++ ++static GCOps rfbSpriteGCOps = { ++ rfbSpriteFillSpans, rfbSpriteSetSpans, rfbSpritePutImage, ++ rfbSpriteCopyArea, rfbSpriteCopyPlane, rfbSpritePolyPoint, ++ rfbSpritePolylines, rfbSpritePolySegment, rfbSpritePolyRectangle, ++ rfbSpritePolyArc, rfbSpriteFillPolygon, rfbSpritePolyFillRect, ++ rfbSpritePolyFillArc, rfbSpritePolyText8, rfbSpritePolyText16, ++ rfbSpriteImageText8, rfbSpriteImageText16, rfbSpriteImageGlyphBlt, ++ rfbSpritePolyGlyphBlt, rfbSpritePushPixels ++#ifdef NEED_LINEHELPER ++ , rfbSpriteLineHelper ++#endif ++}; ++ ++/* ++ * testing only -- remove cursor for every draw. Eventually, ++ * each draw operation will perform a bounding box check against ++ * the saved cursor area ++ */ ++ ++#define GC_SETUP_CHEAP(pDrawable) \ ++ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr) \ ++ (pDrawable)->pScreen->devPrivates[rfbSpriteScreenIndex].ptr; \ ++ ++#define GC_SETUP(pDrawable, pGC) \ ++ GC_SETUP_CHEAP(pDrawable) \ ++ rfbSpriteGCPtr pGCPrivate = (rfbSpriteGCPtr) \ ++ (pGC)->devPrivates[rfbSpriteGCIndex].ptr; \ ++ GCFuncs *oldFuncs = pGC->funcs; ++ ++#define GC_SETUP_AND_CHECK(pDrawable, pGC) \ ++ GC_SETUP(pDrawable, pGC); \ ++ if (GC_CHECK((WindowPtr)pDrawable)) \ ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ ++#define GC_CHECK(pWin) \ ++ (pVNC->cursorIsDrawn && \ ++ (pScreenPriv->pCacheWin == pWin ? \ ++ pScreenPriv->isInCacheWin : ( \ ++ (pScreenPriv->pCacheWin = (pWin)) , \ ++ (pScreenPriv->isInCacheWin = \ ++ (pWin)->drawable.x < pScreenPriv->saved.x2 && \ ++ pScreenPriv->saved.x1 < (pWin)->drawable.x + \ ++ (int) (pWin)->drawable.width && \ ++ (pWin)->drawable.y < pScreenPriv->saved.y2 && \ ++ pScreenPriv->saved.y1 < (pWin)->drawable.y + \ ++ (int) (pWin)->drawable.height &&\ ++ RECT_IN_REGION((pWin)->drawable.pScreen, &(pWin)->borderClip, \ ++ &pScreenPriv->saved) != rgnOUT)))) ++ ++#define GC_OP_PROLOGUE(pGC) { \ ++ (pGC)->funcs = pGCPrivate->wrapFuncs; \ ++ (pGC)->ops = pGCPrivate->wrapOps; \ ++ } ++ ++#define GC_OP_EPILOGUE(pGC) { \ ++ pGCPrivate->wrapOps = (pGC)->ops; \ ++ (pGC)->funcs = oldFuncs; \ ++ (pGC)->ops = &rfbSpriteGCOps; \ ++ } ++ ++/* ++ * pointer-sprite method table ++ */ ++ ++static Bool rfbSpriteRealizeCursor (), rfbSpriteUnrealizeCursor (); ++static void rfbSpriteSetCursor (), rfbSpriteMoveCursor (); ++ ++miPointerSpriteFuncRec rfbSpritePointerFuncs = { ++ rfbSpriteRealizeCursor, ++ rfbSpriteUnrealizeCursor, ++ rfbSpriteSetCursor, ++ rfbSpriteMoveCursor, ++}; ++ ++/* ++ * other misc functions ++ */ ++ ++static Bool rfbDisplayCursor (ScreenPtr pScreen, CursorPtr pCursor); ++ ++ ++/* ++ * rfbSpriteInitialize -- called from device-dependent screen ++ * initialization proc after all of the function pointers have ++ * been stored in the screen structure. ++ */ ++ ++Bool ++rfbSpriteInitialize (pScreen, cursorFuncs, screenFuncs) ++ ScreenPtr pScreen; ++ rfbSpriteCursorFuncPtr cursorFuncs; ++ miPointerScreenFuncPtr screenFuncs; ++{ ++ rfbSpriteScreenPtr pPriv; ++ VisualPtr pVisual; ++#ifdef RENDER ++ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); ++#endif ++ ++ if (rfbSpriteGeneration != serverGeneration) ++ { ++ rfbSpriteScreenIndex = AllocateScreenPrivateIndex (); ++ if (rfbSpriteScreenIndex < 0) ++ return FALSE; ++ rfbSpriteGeneration = serverGeneration; ++ rfbSpriteGCIndex = AllocateGCPrivateIndex (); ++ } ++ if (!AllocateGCPrivate(pScreen, rfbSpriteGCIndex, sizeof(rfbSpriteGCRec))) ++ return FALSE; ++ pPriv = (rfbSpriteScreenPtr) xalloc (sizeof (rfbSpriteScreenRec)); ++ if (!pPriv) ++ return FALSE; ++ if (!miPointerInitialize (pScreen, &rfbSpritePointerFuncs, screenFuncs,TRUE)) ++ { ++ xfree ((pointer) pPriv); ++ return FALSE; ++ } ++ for (pVisual = pScreen->visuals; ++ pVisual->vid != pScreen->rootVisual; ++ pVisual++) ++ ; ++ pPriv->pVisual = pVisual; ++ pPriv->CloseScreen = pScreen->CloseScreen; ++ pPriv->GetImage = pScreen->GetImage; ++ pPriv->GetSpans = pScreen->GetSpans; ++ pPriv->SourceValidate = pScreen->SourceValidate; ++ pPriv->CreateGC = pScreen->CreateGC; ++#if 0 ++ pPriv->BlockHandler = pScreen->BlockHandler; ++#endif ++ pPriv->InstallColormap = pScreen->InstallColormap; ++ pPriv->StoreColors = pScreen->StoreColors; ++ pPriv->DisplayCursor = pScreen->DisplayCursor; ++ ++ pPriv->PaintWindowBackground = pScreen->PaintWindowBackground; ++ pPriv->PaintWindowBorder = pScreen->PaintWindowBorder; ++ pPriv->CopyWindow = pScreen->CopyWindow; ++ pPriv->ClearToBackground = pScreen->ClearToBackground; ++ ++ pPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas; ++ pPriv->RestoreAreas = pScreen->RestoreAreas; ++#ifdef RENDER ++ if (ps) ++ { ++ pPriv->Composite = ps->Composite; ++ pPriv->Glyphs = ps->Glyphs; ++ } ++#endif ++ ++ pPriv->pCursor = NULL; ++ pPriv->x = 0; ++ pPriv->y = 0; ++ pPriv->shouldBeUp = FALSE; ++ pPriv->pCacheWin = NullWindow; ++ pPriv->isInCacheWin = FALSE; ++ pPriv->checkPixels = TRUE; ++ pPriv->pInstalledMap = NULL; ++ pPriv->pColormap = NULL; ++ pPriv->funcs = cursorFuncs; ++ pPriv->colors[SOURCE_COLOR].red = 0; ++ pPriv->colors[SOURCE_COLOR].green = 0; ++ pPriv->colors[SOURCE_COLOR].blue = 0; ++ pPriv->colors[MASK_COLOR].red = 0; ++ pPriv->colors[MASK_COLOR].green = 0; ++ pPriv->colors[MASK_COLOR].blue = 0; ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr = (pointer) pPriv; ++ pScreen->CloseScreen = rfbSpriteCloseScreen; ++ pScreen->GetImage = rfbSpriteGetImage; ++ pScreen->GetSpans = rfbSpriteGetSpans; ++ pScreen->SourceValidate = rfbSpriteSourceValidate; ++ pScreen->CreateGC = rfbSpriteCreateGC; ++#if 0 ++ pScreen->BlockHandler = rfbSpriteBlockHandler; ++#endif ++ pScreen->InstallColormap = rfbSpriteInstallColormap; ++ pScreen->StoreColors = rfbSpriteStoreColors; ++ ++ pScreen->PaintWindowBackground = rfbSpritePaintWindowBackground; ++ pScreen->PaintWindowBorder = rfbSpritePaintWindowBorder; ++ pScreen->CopyWindow = rfbSpriteCopyWindow; ++ pScreen->ClearToBackground = rfbSpriteClearToBackground; ++ ++ pScreen->SaveDoomedAreas = rfbSpriteSaveDoomedAreas; ++ pScreen->RestoreAreas = rfbSpriteRestoreAreas; ++ ++ pScreen->DisplayCursor = rfbDisplayCursor; ++#ifdef RENDER ++ if (ps) ++ { ++ ps->Composite = rfbSpriteComposite; ++ ps->Glyphs = rfbSpriteGlyphs; ++ } ++#endif ++ ++ return TRUE; ++} ++ ++/* ++ * Screen wrappers ++ */ ++ ++/* ++ * CloseScreen wrapper -- unwrap everything, free the private data ++ * and call the wrapped function ++ */ ++ ++static Bool ++rfbSpriteCloseScreen (i, pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++#ifdef RENDER ++ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); ++#endif ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ pScreen->CloseScreen = pScreenPriv->CloseScreen; ++ pScreen->GetImage = pScreenPriv->GetImage; ++ pScreen->GetSpans = pScreenPriv->GetSpans; ++ pScreen->SourceValidate = pScreenPriv->SourceValidate; ++ pScreen->CreateGC = pScreenPriv->CreateGC; ++#if 0 ++ pScreen->BlockHandler = pScreenPriv->BlockHandler; ++#endif ++ pScreen->InstallColormap = pScreenPriv->InstallColormap; ++ pScreen->StoreColors = pScreenPriv->StoreColors; ++ ++ pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground; ++ pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder; ++ pScreen->CopyWindow = pScreenPriv->CopyWindow; ++ pScreen->ClearToBackground = pScreenPriv->ClearToBackground; ++ ++ pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas; ++ pScreen->RestoreAreas = pScreenPriv->RestoreAreas; ++#ifdef RENDER ++ if (ps) ++ { ++ ps->Composite = pScreenPriv->Composite; ++ ps->Glyphs = pScreenPriv->Glyphs; ++ } ++#endif ++ ++ xfree ((pointer) pScreenPriv); ++ ++ return (*pScreen->CloseScreen) (i, pScreen); ++} ++ ++static void ++rfbSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine) ++ DrawablePtr pDrawable; ++ int sx, sy, w, h; ++ unsigned int format; ++ unsigned long planemask; ++ char *pdstLine; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, GetImage); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ if (pDrawable->type == DRAWABLE_WINDOW && ++ pVNC->cursorIsDrawn && ++ ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->GetImage) (pDrawable, sx, sy, w, h, ++ format, planemask, pdstLine); ++ ++ SCREEN_EPILOGUE (pScreen, GetImage, rfbSpriteGetImage); ++} ++ ++static void ++rfbSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart) ++ DrawablePtr pDrawable; ++ int wMax; ++ DDXPointPtr ppt; ++ int *pwidth; ++ int nspans; ++ char *pdstStart; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, GetSpans); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn) ++ { ++ register DDXPointPtr pts; ++ register int *widths; ++ register int nPts; ++ register int xorg, ++ yorg; ++ ++ xorg = pDrawable->x; ++ yorg = pDrawable->y; ++ ++ for (pts = ppt, widths = pwidth, nPts = nspans; ++ nPts--; ++ pts++, widths++) ++ { ++ if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg, ++ pts->x+xorg,*widths)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ break; ++ } ++ } ++ } ++ ++ (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); ++ ++ SCREEN_EPILOGUE (pScreen, GetSpans, rfbSpriteGetSpans); ++} ++ ++static void ++rfbSpriteSourceValidate (pDrawable, x, y, width, height) ++ DrawablePtr pDrawable; ++ int x, y, width, height; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, SourceValidate); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ if (pDrawable->type == DRAWABLE_WINDOW && pVNC->cursorIsDrawn && ++ ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y, ++ x, y, width, height)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ if (pScreen->SourceValidate) ++ (*pScreen->SourceValidate) (pDrawable, x, y, width, height); ++ ++ SCREEN_EPILOGUE (pScreen, SourceValidate, rfbSpriteSourceValidate); ++} ++ ++static Bool ++rfbSpriteCreateGC (pGC) ++ GCPtr pGC; ++{ ++ ScreenPtr pScreen = pGC->pScreen; ++ Bool ret; ++ rfbSpriteGCPtr pPriv; ++ ++ SCREEN_PROLOGUE (pScreen, CreateGC); ++ ++ pPriv = (rfbSpriteGCPtr)pGC->devPrivates[rfbSpriteGCIndex].ptr; ++ ++ ret = (*pScreen->CreateGC) (pGC); ++ ++ pPriv->wrapOps = NULL; ++ pPriv->wrapFuncs = pGC->funcs; ++ pGC->funcs = &rfbSpriteGCFuncs; ++ ++ SCREEN_EPILOGUE (pScreen, CreateGC, rfbSpriteCreateGC); ++ ++ return ret; ++} ++ ++static void ++rfbSpriteBlockHandler (i, blockData, pTimeout, pReadmask) ++ int i; ++ pointer blockData; ++ pointer pTimeout; ++ pointer pReadmask; ++{ ++ ScreenPtr pScreen = screenInfo.screens[i]; ++ rfbSpriteScreenPtr pPriv; ++ VNCSCREENPTR(pScreen); ++ ++ pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ SCREEN_PROLOGUE(pScreen, BlockHandler); ++ ++ (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); ++ ++ SCREEN_EPILOGUE(pScreen, BlockHandler, rfbSpriteBlockHandler); ++ ++ if (!pVNC->cursorIsDrawn && pPriv->shouldBeUp) ++ rfbSpriteRestoreCursor (pScreen); ++} ++ ++static void ++rfbSpriteInstallColormap (pMap) ++ ColormapPtr pMap; ++{ ++ ScreenPtr pScreen = pMap->pScreen; ++ rfbSpriteScreenPtr pPriv; ++ VNCSCREENPTR(pScreen); ++ ++ pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ SCREEN_PROLOGUE(pScreen, InstallColormap); ++ ++ (*pScreen->InstallColormap) (pMap); ++ ++ SCREEN_EPILOGUE(pScreen, InstallColormap, rfbSpriteInstallColormap); ++ ++ pPriv->pInstalledMap = pMap; ++ if (pPriv->pColormap != pMap) ++ { ++ pPriv->checkPixels = TRUE; ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++} ++ ++static void ++rfbSpriteStoreColors (pMap, ndef, pdef) ++ ColormapPtr pMap; ++ int ndef; ++ xColorItem *pdef; ++{ ++ ScreenPtr pScreen = pMap->pScreen; ++ rfbSpriteScreenPtr pPriv; ++ int i; ++ int updated; ++ VisualPtr pVisual; ++ VNCSCREENPTR(pScreen); ++ ++ pPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ SCREEN_PROLOGUE(pScreen, StoreColors); ++ ++ (*pScreen->StoreColors) (pMap, ndef, pdef); ++ ++ SCREEN_EPILOGUE(pScreen, StoreColors, rfbSpriteStoreColors); ++ ++ if (pPriv->pColormap == pMap) ++ { ++ updated = 0; ++ pVisual = pMap->pVisual; ++ if (pVisual->class == DirectColor) ++ { ++ /* Direct color - match on any of the subfields */ ++ ++#define MaskMatch(a,b,mask) ((a) & ((pVisual->mask) == (b)) & (pVisual->mask)) ++ ++#define UpdateDAC(plane,dac,mask) {\ ++ if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\ ++ pPriv->colors[plane].dac = pdef[i].dac; \ ++ updated = 1; \ ++ } \ ++} ++ ++#define CheckDirect(plane) \ ++ UpdateDAC(plane,red,redMask) \ ++ UpdateDAC(plane,green,greenMask) \ ++ UpdateDAC(plane,blue,blueMask) ++ ++ for (i = 0; i < ndef; i++) ++ { ++ CheckDirect (SOURCE_COLOR) ++ CheckDirect (MASK_COLOR) ++ } ++ } ++ else ++ { ++ /* PseudoColor/GrayScale - match on exact pixel */ ++ for (i = 0; i < ndef; i++) ++ { ++ if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) ++ { ++ pPriv->colors[SOURCE_COLOR] = pdef[i]; ++ if (++updated == 2) ++ break; ++ } ++ if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) ++ { ++ pPriv->colors[MASK_COLOR] = pdef[i]; ++ if (++updated == 2) ++ break; ++ } ++ } ++ } ++ if (updated) ++ { ++ pPriv->checkPixels = TRUE; ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++} ++ ++static void ++rfbSpriteFindColors (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr) ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ CursorPtr pCursor; ++ xColorItem *sourceColor, *maskColor; ++ ++ pCursor = pScreenPriv->pCursor; ++ sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; ++ maskColor = &pScreenPriv->colors[MASK_COLOR]; ++ if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || ++ !(pCursor->foreRed == sourceColor->red && ++ pCursor->foreGreen == sourceColor->green && ++ pCursor->foreBlue == sourceColor->blue && ++ pCursor->backRed == maskColor->red && ++ pCursor->backGreen == maskColor->green && ++ pCursor->backBlue == maskColor->blue)) ++ { ++ pScreenPriv->pColormap = pScreenPriv->pInstalledMap; ++ sourceColor->red = pCursor->foreRed; ++ sourceColor->green = pCursor->foreGreen; ++ sourceColor->blue = pCursor->foreBlue; ++ FakeAllocColor (pScreenPriv->pColormap, sourceColor); ++ maskColor->red = pCursor->backRed; ++ maskColor->green = pCursor->backGreen; ++ maskColor->blue = pCursor->backBlue; ++ FakeAllocColor (pScreenPriv->pColormap, maskColor); ++ /* "free" the pixels right away, don't let this confuse you */ ++ FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); ++ FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); ++ } ++ pScreenPriv->checkPixels = FALSE; ++} ++ ++/* ++ * BackingStore wrappers ++ */ ++ ++static void ++rfbSpriteSaveDoomedAreas (pWin, pObscured, dx, dy) ++ WindowPtr pWin; ++ RegionPtr pObscured; ++ int dx, dy; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ BoxRec cursorBox; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, SaveDoomedAreas); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ cursorBox = pScreenPriv->saved; ++ ++ if (dx || dy) ++ { ++ cursorBox.x1 += dx; ++ cursorBox.y1 += dy; ++ cursorBox.x2 += dx; ++ cursorBox.y2 += dy; ++ } ++ if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy); ++ ++ SCREEN_EPILOGUE (pScreen, SaveDoomedAreas, rfbSpriteSaveDoomedAreas); ++} ++ ++static RegionPtr ++rfbSpriteRestoreAreas (pWin, prgnExposed) ++ WindowPtr pWin; ++ RegionPtr prgnExposed; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ RegionPtr result; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, RestoreAreas); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ if (RECT_IN_REGION( pScreen, prgnExposed, &pScreenPriv->saved) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ result = (*pScreen->RestoreAreas) (pWin, prgnExposed); ++ ++ SCREEN_EPILOGUE (pScreen, RestoreAreas, rfbSpriteRestoreAreas); ++ ++ return result; ++} ++ ++/* ++ * Window wrappers ++ */ ++ ++static void ++rfbSpritePaintWindowBackground (pWin, pRegion, what) ++ WindowPtr pWin; ++ RegionPtr pRegion; ++ int what; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, PaintWindowBackground); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ /* ++ * If the cursor is on the same screen as the window, check the ++ * region to paint for the cursor and remove it as necessary ++ */ ++ if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->PaintWindowBackground) (pWin, pRegion, what); ++ ++ SCREEN_EPILOGUE (pScreen, PaintWindowBackground, rfbSpritePaintWindowBackground); ++} ++ ++static void ++rfbSpritePaintWindowBorder (pWin, pRegion, what) ++ WindowPtr pWin; ++ RegionPtr pRegion; ++ int what; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, PaintWindowBorder); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ /* ++ * If the cursor is on the same screen as the window, check the ++ * region to paint for the cursor and remove it as necessary ++ */ ++ if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->PaintWindowBorder) (pWin, pRegion, what); ++ ++ SCREEN_EPILOGUE (pScreen, PaintWindowBorder, rfbSpritePaintWindowBorder); ++} ++ ++static void ++rfbSpriteCopyWindow (pWin, ptOldOrg, pRegion) ++ WindowPtr pWin; ++ DDXPointRec ptOldOrg; ++ RegionPtr pRegion; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ BoxRec cursorBox; ++ int dx, dy; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, CopyWindow); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pVNC->cursorIsDrawn) ++ { ++ /* ++ * check both the source and the destination areas. The given ++ * region is source relative, so offset the cursor box by ++ * the delta position ++ */ ++ cursorBox = pScreenPriv->saved; ++ dx = pWin->drawable.x - ptOldOrg.x; ++ dy = pWin->drawable.y - ptOldOrg.y; ++ cursorBox.x1 -= dx; ++ cursorBox.x2 -= dx; ++ cursorBox.y1 -= dy; ++ cursorBox.y2 -= dy; ++ if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT || ++ RECT_IN_REGION( pScreen, pRegion, &cursorBox) != rgnOUT) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ ++ (*pScreen->CopyWindow) (pWin, ptOldOrg, pRegion); ++ ++ SCREEN_EPILOGUE (pScreen, CopyWindow, rfbSpriteCopyWindow); ++} ++ ++static void ++rfbSpriteClearToBackground (pWin, x, y, w, h, generateExposures) ++ WindowPtr pWin; ++ short x,y; ++ unsigned short w,h; ++ Bool generateExposures; ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ rfbSpriteScreenPtr pScreenPriv; ++ int realw, realh; ++ VNCSCREENPTR(pScreen); ++ ++ SCREEN_PROLOGUE (pScreen, ClearToBackground); ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (GC_CHECK(pWin)) ++ { ++ if (!(realw = w)) ++ realw = (int) pWin->drawable.width - x; ++ if (!(realh = h)) ++ realh = (int) pWin->drawable.height - y; ++ if (ORG_OVERLAP(&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y, ++ x, y, realw, realh)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++ ++ (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); ++ ++ SCREEN_EPILOGUE (pScreen, ClearToBackground, rfbSpriteClearToBackground); ++} ++ ++/* ++ * GC Func wrappers ++ */ ++ ++static void ++rfbSpriteValidateGC (pGC, changes, pDrawable) ++ GCPtr pGC; ++ unsigned long changes; ++ DrawablePtr pDrawable; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); ++ ++ pGCPriv->wrapOps = NULL; ++ if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDrawable)->viewable) ++ { ++ WindowPtr pWin; ++ RegionPtr pRegion; ++ ++ pWin = (WindowPtr) pDrawable; ++ pRegion = &pWin->clipList; ++ if (pGC->subWindowMode == IncludeInferiors) ++ pRegion = &pWin->borderClip; ++ if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) ++ pGCPriv->wrapOps = pGC->ops; ++ } ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteChangeGC (pGC, mask) ++ GCPtr pGC; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->ChangeGC) (pGC, mask); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteCopyGC (pGCSrc, mask, pGCDst) ++ GCPtr pGCSrc, pGCDst; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE (pGCDst); ++ ++ (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); ++ ++ GC_FUNC_EPILOGUE (pGCDst); ++} ++ ++static void ++rfbSpriteDestroyGC (pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->DestroyGC) (pGC); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteChangeClip (pGC, type, pvalue, nrects) ++ GCPtr pGC; ++ int type; ++ pointer pvalue; ++ int nrects; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteCopyClip(pgcDst, pgcSrc) ++ GCPtr pgcDst, pgcSrc; ++{ ++ GC_FUNC_PROLOGUE (pgcDst); ++ ++ (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); ++ ++ GC_FUNC_EPILOGUE (pgcDst); ++} ++ ++static void ++rfbSpriteDestroyClip(pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE (pGC); ++ ++ (* pGC->funcs->DestroyClip)(pGC); ++ ++ GC_FUNC_EPILOGUE (pGC); ++} ++ ++/* ++ * GC Op wrappers ++ */ ++ ++static void ++rfbSpriteFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nInit; /* number of spans to fill */ ++ DDXPointPtr pptInit; /* pointer to list of start points */ ++ int *pwidthInit; /* pointer to list of n widths */ ++ int fSorted; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register DDXPointPtr pts; ++ register int *widths; ++ register int nPts; ++ ++ for (pts = pptInit, widths = pwidthInit, nPts = nInit; ++ nPts--; ++ pts++, widths++) ++ { ++ if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ char *psrc; ++ register DDXPointPtr ppt; ++ int *pwidth; ++ int nspans; ++ int fSorted; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register DDXPointPtr pts; ++ register int *widths; ++ register int nPts; ++ ++ for (pts = ppt, widths = pwidth, nPts = nspans; ++ nPts--; ++ pts++, widths++) ++ { ++ if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths)) ++ { ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int depth; ++ int x; ++ int y; ++ int w; ++ int h; ++ int format; ++ char *pBits; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ if (ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, ++ x,y,w,h)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static RegionPtr ++rfbSpriteCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ GCPtr pGC; ++ int srcx; ++ int srcy; ++ int w; ++ int h; ++ int dstx; ++ int dsty; ++{ ++ RegionPtr rgn; ++ ScreenPtr pScreen = pGC->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDst, pGC); ++ ++ /* check destination/source overlap. */ ++ if (GC_CHECK((WindowPtr) pDst) && ++ (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) || ++ ((pDst == pSrc) && ++ ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h)))) ++ { ++ rfbSpriteRemoveCursor (pDst->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty); ++ ++ GC_OP_EPILOGUE (pGC); ++ ++ return rgn; ++} ++ ++static RegionPtr ++rfbSpriteCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ register GCPtr pGC; ++ int srcx, ++ srcy; ++ int w, ++ h; ++ int dstx, ++ dsty; ++ unsigned long plane; ++{ ++ RegionPtr rgn; ++ ScreenPtr pScreen = pGC->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDst, pGC); ++ ++ /* ++ * check destination/source for overlap. ++ */ ++ if (GC_CHECK((WindowPtr) pDst) && ++ (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) || ++ ((pDst == pSrc) && ++ ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h)))) ++ { ++ rfbSpriteRemoveCursor (pDst->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty, plane); ++ ++ GC_OP_EPILOGUE (pGC); ++ ++ return rgn; ++} ++ ++static void ++rfbSpritePolyPoint (pDrawable, pGC, mode, npt, pptInit) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; /* Origin or Previous */ ++ int npt; ++ xPoint *pptInit; ++{ ++ xPoint t; ++ int n; ++ BoxRec cursor; ++ register xPoint *pts; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (npt && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ cursor.x1 = pScreenPriv->saved.x1 - pDrawable->x; ++ cursor.y1 = pScreenPriv->saved.y1 - pDrawable->y; ++ cursor.x2 = pScreenPriv->saved.x2 - pDrawable->x; ++ cursor.y2 = pScreenPriv->saved.y2 - pDrawable->y; ++ ++ if (mode == CoordModePrevious) ++ { ++ t.x = 0; ++ t.y = 0; ++ for (pts = pptInit, n = npt; n--; pts++) ++ { ++ t.x += pts->x; ++ t.y += pts->y; ++ if (cursor.x1 <= t.x && t.x <= cursor.x2 && ++ cursor.y1 <= t.y && t.y <= cursor.y2) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ else ++ { ++ for (pts = pptInit, n = npt; n--; pts++) ++ { ++ if (cursor.x1 <= pts->x && pts->x <= cursor.x2 && ++ cursor.y1 <= pts->y && pts->y <= cursor.y2) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolylines (pDrawable, pGC, mode, npt, pptInit) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; ++ int npt; ++ DDXPointPtr pptInit; ++{ ++ BoxPtr cursor; ++ register DDXPointPtr pts; ++ int n; ++ int x, y, x1, y1, x2, y2; ++ int lw; ++ int extra; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (npt && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ cursor = &pScreenPriv->saved; ++ lw = pGC->lineWidth; ++ x = pptInit->x + pDrawable->x; ++ y = pptInit->y + pDrawable->y; ++ ++ if (npt == 1) ++ { ++ extra = lw >> 1; ++ if (LINE_OVERLAP(cursor, x, y, x, y, extra)) ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ else ++ { ++ extra = lw >> 1; ++ /* ++ * mitered joins can project quite a way from ++ * the line end; the 11 degree miter limit limits ++ * this extension to 10.43 * lw / 2, rounded up ++ * and converted to int yields 6 * lw ++ */ ++ if (pGC->joinStyle == JoinMiter) ++ extra = 6 * lw; ++ else if (pGC->capStyle == CapProjecting) ++ extra = lw; ++ for (pts = pptInit + 1, n = npt - 1; n--; pts++) ++ { ++ x1 = x; ++ y1 = y; ++ if (mode == CoordModeOrigin) ++ { ++ x2 = pDrawable->x + pts->x; ++ y2 = pDrawable->y + pts->y; ++ } ++ else ++ { ++ x2 = x + pts->x; ++ y2 = y + pts->y; ++ } ++ x = x2; ++ y = y2; ++ LINE_SORT(x1, y1, x2, y2); ++ if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ } ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, pptInit); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolySegment(pDrawable, pGC, nseg, pSegs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nseg; ++ xSegment *pSegs; ++{ ++ int n; ++ register xSegment *segs; ++ BoxPtr cursor; ++ int x1, y1, x2, y2; ++ int extra; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (nseg && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ cursor = &pScreenPriv->saved; ++ extra = pGC->lineWidth >> 1; ++ if (pGC->capStyle == CapProjecting) ++ extra = pGC->lineWidth; ++ for (segs = pSegs, n = nseg; n--; segs++) ++ { ++ x1 = segs->x1 + pDrawable->x; ++ y1 = segs->y1 + pDrawable->y; ++ x2 = segs->x2 + pDrawable->x; ++ y2 = segs->y2 + pDrawable->y; ++ LINE_SORT(x1, y1, x2, y2); ++ if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, pSegs); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyRectangle(pDrawable, pGC, nrects, pRects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *pRects; ++{ ++ register xRectangle *rects; ++ BoxPtr cursor; ++ int lw; ++ int n; ++ int x1, y1, x2, y2; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ lw = pGC->lineWidth >> 1; ++ cursor = &pScreenPriv->saved; ++ for (rects = pRects, n = nrects; n--; rects++) ++ { ++ x1 = rects->x + pDrawable->x; ++ y1 = rects->y + pDrawable->y; ++ x2 = x1 + (int)rects->width; ++ y2 = y1 + (int)rects->height; ++ if (LINE_OVERLAP(cursor, x1, y1, x2, y1, lw) || ++ LINE_OVERLAP(cursor, x2, y1, x2, y2, lw) || ++ LINE_OVERLAP(cursor, x1, y2, x2, y2, lw) || ++ LINE_OVERLAP(cursor, x1, y1, x1, y2, lw)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, pRects); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyArc(pDrawable, pGC, narcs, parcs) ++ DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int narcs; ++ xArc *parcs; ++{ ++ BoxPtr cursor; ++ int lw; ++ int n; ++ register xArc *arcs; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ lw = pGC->lineWidth >> 1; ++ cursor = &pScreenPriv->saved; ++ for (arcs = parcs, n = narcs; n--; arcs++) ++ { ++ if (ORG_OVERLAP (cursor, pDrawable->x, pDrawable->y, ++ arcs->x - lw, arcs->y - lw, ++ (int) arcs->width + pGC->lineWidth, ++ (int) arcs->height + pGC->lineWidth)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, parcs); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteFillPolygon(pDrawable, pGC, shape, mode, count, pPts) ++ register DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int shape, mode; ++ int count; ++ DDXPointPtr pPts; ++{ ++ int x, y, minx, miny, maxx, maxy; ++ register DDXPointPtr pts; ++ int n; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ if (count && GC_CHECK((WindowPtr) pDrawable)) ++ { ++ x = pDrawable->x; ++ y = pDrawable->y; ++ pts = pPts; ++ minx = maxx = pts->x; ++ miny = maxy = pts->y; ++ pts++; ++ n = count - 1; ++ ++ if (mode == CoordModeOrigin) ++ { ++ for (; n--; pts++) ++ { ++ if (pts->x < minx) ++ minx = pts->x; ++ else if (pts->x > maxx) ++ maxx = pts->x; ++ if (pts->y < miny) ++ miny = pts->y; ++ else if (pts->y > maxy) ++ maxy = pts->y; ++ } ++ minx += x; ++ miny += y; ++ maxx += x; ++ maxy += y; ++ } ++ else ++ { ++ x += minx; ++ y += miny; ++ minx = maxx = x; ++ miny = maxy = y; ++ for (; n--; pts++) ++ { ++ x += pts->x; ++ y += pts->y; ++ if (x < minx) ++ minx = x; ++ else if (x > maxx) ++ maxx = x; ++ if (y < miny) ++ miny = y; ++ else if (y > maxy) ++ maxy = y; ++ } ++ } ++ if (BOX_OVERLAP(&pScreenPriv->saved,minx,miny,maxx,maxy)) ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pPts); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyFillRect(pDrawable, pGC, nrectFill, prectInit) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrectFill; /* number of rectangles to fill */ ++ xRectangle *prectInit; /* Pointer to first rectangle to fill */ ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register int nRect; ++ register xRectangle *pRect; ++ register int xorg, yorg; ++ ++ xorg = pDrawable->x; ++ yorg = pDrawable->y; ++ ++ for (nRect = nrectFill, pRect = prectInit; nRect--; pRect++) { ++ if (ORGRECT_OVERLAP(&pScreenPriv->saved,xorg,yorg,pRect)){ ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrectFill, prectInit); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyFillArc(pDrawable, pGC, narcs, parcs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int narcs; ++ xArc *parcs; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ { ++ register int n; ++ BoxPtr cursor; ++ register xArc *arcs; ++ ++ cursor = &pScreenPriv->saved; ++ ++ for (arcs = parcs, n = narcs; n--; arcs++) ++ { ++ if (ORG_OVERLAP(cursor, pDrawable->x, pDrawable->y, ++ arcs->x, arcs->y, ++ (int) arcs->width, (int) arcs->height)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ break; ++ } ++ } ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, parcs); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++/* ++ * general Poly/Image text function. Extract glyph information, ++ * compute bounding box and remove cursor if it is overlapped. ++ */ ++ ++static Bool ++rfbSpriteTextOverlap (pDraw, font, x, y, n, charinfo, imageblt, w, cursorBox) ++ DrawablePtr pDraw; ++ FontPtr font; ++ int x, y; ++ unsigned int n; ++ CharInfoPtr *charinfo; ++ Bool imageblt; ++ unsigned int w; ++ BoxPtr cursorBox; ++{ ++ ExtentInfoRec extents; ++ ++ x += pDraw->x; ++ y += pDraw->y; ++ ++ if (FONTMINBOUNDS(font,characterWidth) >= 0) ++ { ++ /* compute an approximate (but covering) bounding box */ ++ if (!imageblt || (charinfo[0]->metrics.leftSideBearing < 0)) ++ extents.overallLeft = charinfo[0]->metrics.leftSideBearing; ++ else ++ extents.overallLeft = 0; ++ if (w) ++ extents.overallRight = w - charinfo[n-1]->metrics.characterWidth; ++ else ++ extents.overallRight = FONTMAXBOUNDS(font,characterWidth) ++ * (n - 1); ++ if (imageblt && (charinfo[n-1]->metrics.characterWidth > ++ charinfo[n-1]->metrics.rightSideBearing)) ++ extents.overallRight += charinfo[n-1]->metrics.characterWidth; ++ else ++ extents.overallRight += charinfo[n-1]->metrics.rightSideBearing; ++ if (imageblt && FONTASCENT(font) > FONTMAXBOUNDS(font,ascent)) ++ extents.overallAscent = FONTASCENT(font); ++ else ++ extents.overallAscent = FONTMAXBOUNDS(font, ascent); ++ if (imageblt && FONTDESCENT(font) > FONTMAXBOUNDS(font,descent)) ++ extents.overallDescent = FONTDESCENT(font); ++ else ++ extents.overallDescent = FONTMAXBOUNDS(font,descent); ++ if (!BOX_OVERLAP(cursorBox, ++ x + extents.overallLeft, ++ y - extents.overallAscent, ++ x + extents.overallRight, ++ y + extents.overallDescent)) ++ return FALSE; ++ else if (imageblt && w) ++ return TRUE; ++ /* if it does overlap, fall through and compute exactly, because ++ * taking down the cursor is expensive enough to make this worth it ++ */ ++ } ++ QueryGlyphExtents(font, charinfo, n, &extents); ++ if (imageblt) ++ { ++ if (extents.overallWidth > extents.overallRight) ++ extents.overallRight = extents.overallWidth; ++ if (extents.overallWidth < extents.overallLeft) ++ extents.overallLeft = extents.overallWidth; ++ if (extents.overallLeft > 0) ++ extents.overallLeft = 0; ++ if (extents.fontAscent > extents.overallAscent) ++ extents.overallAscent = extents.fontAscent; ++ if (extents.fontDescent > extents.overallDescent) ++ extents.overallDescent = extents.fontDescent; ++ } ++ return (BOX_OVERLAP(cursorBox, ++ x + extents.overallLeft, ++ y - extents.overallAscent, ++ x + extents.overallRight, ++ y + extents.overallDescent)); ++} ++ ++/* ++ * values for textType: ++ */ ++#define TT_POLY8 0 ++#define TT_IMAGE8 1 ++#define TT_POLY16 2 ++#define TT_IMAGE16 3 ++ ++static int ++rfbSpriteText (pDraw, pGC, x, y, count, chars, fontEncoding, textType, cursorBox) ++ DrawablePtr pDraw; ++ GCPtr pGC; ++ int x, ++ y; ++ unsigned long count; ++ char *chars; ++ FontEncoding fontEncoding; ++ Bool textType; ++ BoxPtr cursorBox; ++{ ++ CharInfoPtr *charinfo; ++ register CharInfoPtr *info; ++ unsigned long i; ++ unsigned int n; ++ int w; ++ void (*drawFunc)() = NULL; ++ ++ Bool imageblt; ++ ++ imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); ++ ++ charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr)); ++ if (!charinfo) ++ return x; ++ ++ GetGlyphs(pGC->font, count, (unsigned char *)chars, ++ fontEncoding, &i, charinfo); ++ n = (unsigned int)i; ++ w = 0; ++ if (!imageblt) ++ for (info = charinfo; i--; info++) ++ w += (*info)->metrics.characterWidth; ++ ++ if (n != 0) { ++ if (rfbSpriteTextOverlap(pDraw, pGC->font, x, y, n, charinfo, imageblt, w, cursorBox)) ++ rfbSpriteRemoveCursor(pDraw->pScreen); ++ ++#ifdef AVOID_GLYPHBLT ++ /* ++ * On displays like Apollos, which do not optimize the GlyphBlt functions because they ++ * convert fonts to their internal form in RealizeFont and optimize text directly, we ++ * want to invoke the text functions here, not the GlyphBlt functions. ++ */ ++ switch (textType) ++ { ++ case TT_POLY8: ++ drawFunc = (void (*)())pGC->ops->PolyText8; ++ break; ++ case TT_IMAGE8: ++ drawFunc = pGC->ops->ImageText8; ++ break; ++ case TT_POLY16: ++ drawFunc = (void (*)())pGC->ops->PolyText16; ++ break; ++ case TT_IMAGE16: ++ drawFunc = pGC->ops->ImageText16; ++ break; ++ } ++ (*drawFunc) (pDraw, pGC, x, y, (int) count, chars); ++#else /* don't AVOID_GLYPHBLT */ ++ /* ++ * On the other hand, if the device does use GlyphBlt ultimately to do text, we ++ * don't want to slow it down by invoking the text functions and having them call ++ * GetGlyphs all over again, so we go directly to the GlyphBlt functions here. ++ */ ++ drawFunc = imageblt ? pGC->ops->ImageGlyphBlt : pGC->ops->PolyGlyphBlt; ++ (*drawFunc) (pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); ++#endif /* AVOID_GLYPHBLT */ ++ } ++ DEALLOCATE_LOCAL(charinfo); ++ return x + w; ++} ++ ++static int ++rfbSpritePolyText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ int ret; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, chars, ++ Linear8Bit, TT_POLY8, &pScreenPriv->saved); ++ else ++ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++ return ret; ++} ++ ++static int ++rfbSpritePolyText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ int ret; ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ ret = rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, ++ (char *)chars, ++ FONTLASTROW(pGC->font) == 0 ? ++ Linear16Bit : TwoD16Bit, TT_POLY16, &pScreenPriv->saved); ++ else ++ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++ return ret; ++} ++ ++static void ++rfbSpriteImageText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ (void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, ++ chars, Linear8Bit, TT_IMAGE8, &pScreenPriv->saved); ++ else ++ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteImageText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable)) ++ (void) rfbSpriteText (pDrawable, pGC, x, y, (unsigned long)count, ++ (char *)chars, ++ FONTLASTROW(pGC->font) == 0 ? ++ Linear16Bit : TwoD16Bit, TT_IMAGE16, &pScreenPriv->saved); ++ else ++ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpriteImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP(pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable) && ++ rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, TRUE, 0, &pScreenPriv->saved)) ++ { ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ } ++ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ ScreenPtr pScreen = pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ ++ GC_SETUP (pDrawable, pGC); ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable) && ++ rfbSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, FALSE, 0, &pScreenPriv->saved)) ++ { ++ rfbSpriteRemoveCursor(pDrawable->pScreen); ++ } ++ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++static void ++rfbSpritePushPixels(pGC, pBitMap, pDrawable, w, h, x, y) ++ GCPtr pGC; ++ PixmapPtr pBitMap; ++ DrawablePtr pDrawable; ++ int w, h, x, y; ++{ ++ VNCSCREENPTR(pScreen); ++ GC_SETUP(pDrawable, pGC); ++ ++ if (GC_CHECK((WindowPtr) pDrawable) && ++ ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,x,y,w,h)) ++ { ++ rfbSpriteRemoveCursor (pDrawable->pScreen); ++ } ++ ++ GC_OP_PROLOGUE (pGC); ++ ++ (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); ++ ++ GC_OP_EPILOGUE (pGC); ++} ++ ++#ifdef NEED_LINEHELPER ++/* ++ * I don't expect this routine will ever be called, as the GC ++ * will have been unwrapped for the line drawing ++ */ ++ ++static void ++rfbSpriteLineHelper() ++{ ++ FatalError("rfbSpriteLineHelper called\n"); ++} ++#endif ++ ++#ifdef RENDER ++ ++# define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) ++ ++static void ++rfbSpritePictureOverlap (PicturePtr pPict, ++ INT16 x, ++ INT16 y, ++ CARD16 w, ++ CARD16 h) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if (pPict->pDrawable->type == DRAWABLE_WINDOW) ++ { ++ WindowPtr pWin = (WindowPtr) (pPict->pDrawable); ++ rfbSpriteScreenPtr pScreenPriv = (rfbSpriteScreenPtr) ++ pPict->pDrawable->pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (GC_CHECK(pWin)) ++ { ++ if (pPict->repeat) ++ { ++ x = mod(x,pWin->drawable.width); ++ y = mod(y,pWin->drawable.height); ++ } ++ if (ORG_OVERLAP (&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y, ++ x, y, w, h)) ++ rfbSpriteRemoveCursor (pWin->drawable.pScreen); ++ } ++ } ++} ++ ++#define PICTURE_PROLOGUE(ps, pScreenPriv, field) \ ++ ps->field = pScreenPriv->field ++ ++#define PICTURE_EPILOGUE(ps, field, wrap) \ ++ ps->field = wrap ++ ++static void ++rfbSpriteComposite(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height) ++{ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ PICTURE_PROLOGUE(ps, pScreenPriv, Composite); ++ rfbSpritePictureOverlap (pSrc, xSrc, ySrc, width, height); ++ if (pMask) ++ rfbSpritePictureOverlap (pMask, xMask, yMask, width, height); ++ rfbSpritePictureOverlap (pDst, xDst, yDst, width, height); ++ ++ (*ps->Composite) (op, ++ pSrc, ++ pMask, ++ pDst, ++ xSrc, ++ ySrc, ++ xMask, ++ yMask, ++ xDst, ++ yDst, ++ width, ++ height); ++ ++ PICTURE_EPILOGUE(ps, Composite, rfbSpriteComposite); ++} ++ ++static void ++rfbSpriteGlyphs(CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlist, ++ GlyphListPtr list, ++ GlyphPtr *glyphs) ++{ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ PICTURE_PROLOGUE(ps, pScreenPriv, Glyphs); ++ if (pSrc->pDrawable->type == DRAWABLE_WINDOW) ++ { ++ WindowPtr pSrcWin = (WindowPtr) (pSrc->pDrawable); ++ ++ if (GC_CHECK(pSrcWin)) ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ if (pDst->pDrawable->type == DRAWABLE_WINDOW) ++ { ++ WindowPtr pDstWin = (WindowPtr) (pDst->pDrawable); ++ ++ if (GC_CHECK(pDstWin)) ++ { ++ BoxRec extents; ++ ++ miGlyphExtents (nlist, list, glyphs, &extents); ++ if (BOX_OVERLAP(&pScreenPriv->saved, ++ extents.x1 + pDstWin->drawable.x, ++ extents.y1 + pDstWin->drawable.y, ++ extents.x2 + pDstWin->drawable.x, ++ extents.y2 + pDstWin->drawable.y)) ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++ } ++ ++ (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); ++ ++ PICTURE_EPILOGUE (ps, Glyphs, rfbSpriteGlyphs); ++} ++#endif ++ ++/* ++ * miPointer interface routines ++ */ ++ ++#define SPRITE_PAD 8 ++ ++static Bool ++rfbSpriteRealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (pCursor == pScreenPriv->pCursor) ++ pScreenPriv->checkPixels = TRUE; ++ return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor); ++} ++ ++static Bool ++rfbSpriteUnrealizeCursor (pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor); ++} ++ ++static void ++rfbSpriteSetCursor (pScreen, pCursor, x, y) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ rfbClientPtr cl, nextCl; ++ VNCSCREENPTR(pScreen); ++ ++ pScreenPriv ++ = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ if (!pCursor) ++ { ++ pScreenPriv->shouldBeUp = FALSE; ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ pScreenPriv->pCursor = 0; ++ return; ++ } ++ pScreenPriv->shouldBeUp = TRUE; ++ if (pScreenPriv->x == x && ++ pScreenPriv->y == y && ++ pScreenPriv->pCursor == pCursor && ++ !pScreenPriv->checkPixels) ++ { ++ return; ++ } ++ pScreenPriv->x = x; ++ pScreenPriv->y = y; ++ pScreenPriv->pCacheWin = NullWindow; ++ if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor) ++ { ++ pScreenPriv->pCursor = pCursor; ++ rfbSpriteFindColors (pScreen); ++ } ++ if (pVNC->cursorIsDrawn) { ++ int sx, sy; ++ /* ++ * check to see if the old saved region ++ * encloses the new sprite, in which case we use ++ * the flicker-free MoveCursor primitive. ++ */ ++ sx = pScreenPriv->x - (int)pCursor->bits->xhot; ++ sy = pScreenPriv->y - (int)pCursor->bits->yhot; ++ if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 && ++ sx < pScreenPriv->saved.x2 && ++ sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 && ++ sy < pScreenPriv->saved.y2 && ++ (int) pCursor->bits->width + (2 * SPRITE_PAD) == ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1 && ++ (int) pCursor->bits->height + (2 * SPRITE_PAD) == ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1 ++ ) ++ { ++ pVNC->cursorIsDrawn = FALSE; ++ if (!(sx >= pScreenPriv->saved.x1 && ++ sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 && ++ sy >= pScreenPriv->saved.y1 && ++ sy + (int)pCursor->bits->height < pScreenPriv->saved.y2)) ++ { ++ int oldx1, oldy1, dx, dy; ++ ++ oldx1 = pScreenPriv->saved.x1; ++ oldy1 = pScreenPriv->saved.y1; ++ dx = oldx1 - (sx - SPRITE_PAD); ++ dy = oldy1 - (sy - SPRITE_PAD); ++ pScreenPriv->saved.x1 -= dx; ++ pScreenPriv->saved.y1 -= dy; ++ pScreenPriv->saved.x2 -= dx; ++ pScreenPriv->saved.y2 -= dy; ++ (void) (*pScreenPriv->funcs->ChangeSave) (pScreen, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1, ++ dx, dy); ++ } ++ (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1, ++ sx - pScreenPriv->saved.x1, ++ sy - pScreenPriv->saved.y1, ++ pScreenPriv->colors[SOURCE_COLOR].pixel, ++ pScreenPriv->colors[MASK_COLOR].pixel); ++ pVNC->cursorIsDrawn = TRUE; ++ } ++ else ++ { ++ rfbSpriteRemoveCursor (pScreen); ++ } ++ } ++#if 0 ++ if (!pVNC->cursorIsDrawn && pScreenPriv->pCursor) ++ rfbSpriteRestoreCursor (pScreen); ++#endif ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor (pScreen); ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (cl->enableCursorPosUpdates) { ++ if (x == cl->cursorX && y == cl->cursorY) { ++ cl->cursorWasMoved = FALSE; ++ continue; ++ } ++ cl->cursorWasMoved = TRUE; ++ } ++ if (REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) { ++ /* cursorIsDrawn is guaranteed to be FALSE here, so we definitely ++ want to send a screen update to the client, even if that's only ++ putting up the cursor */ ++ rfbSendFramebufferUpdate(pScreen, cl); ++ } ++ } ++} ++ ++static void ++rfbSpriteMoveCursor (pScreen, x, y) ++ ScreenPtr pScreen; ++ int x, y; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ rfbSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y); ++} ++ ++/* ++ * undraw/draw cursor ++ */ ++ ++void ++rfbSpriteRemoveCursor (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ VNCSCREENPTR(pScreen); ++ ++ if (!pVNC->cursorIsDrawn) ++ return; ++ ++ pScreenPriv ++ = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ pVNC->dontSendFramebufferUpdate = TRUE; ++ pVNC->cursorIsDrawn = FALSE; ++ pScreenPriv->pCacheWin = NullWindow; ++ if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) ++ { ++ pVNC->cursorIsDrawn = TRUE; ++ } ++ pVNC->dontSendFramebufferUpdate = FALSE; ++} ++ ++ ++void ++rfbSpriteRestoreCursor (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ int x, y; ++ CursorPtr pCursor; ++ VNCSCREENPTR(pScreen); ++ ++ pScreenPriv ++ = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ pCursor = pScreenPriv->pCursor; ++ ++ if (pVNC->cursorIsDrawn || !pCursor) ++ return; ++ ++ pVNC->dontSendFramebufferUpdate = TRUE; ++ ++ rfbSpriteComputeSaved (pScreen); ++ ++ x = pScreenPriv->x - (int)pCursor->bits->xhot; ++ y = pScreenPriv->y - (int)pCursor->bits->yhot; ++ if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen, ++ pScreenPriv->saved.x1, ++ pScreenPriv->saved.y1, ++ pScreenPriv->saved.x2 - pScreenPriv->saved.x1, ++ pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) ++ { ++ if (pScreenPriv->checkPixels) ++ rfbSpriteFindColors (pScreen); ++ if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y, ++ pScreenPriv->colors[SOURCE_COLOR].pixel, ++ pScreenPriv->colors[MASK_COLOR].pixel)) ++ pVNC->cursorIsDrawn = TRUE; ++ } ++ ++ pVNC->dontSendFramebufferUpdate = FALSE; ++} ++ ++/* ++ * compute the desired area of the screen to save ++ */ ++ ++static void ++rfbSpriteComputeSaved (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ int x, y, w, h; ++ int wpad, hpad; ++ CursorPtr pCursor; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ pCursor = pScreenPriv->pCursor; ++ x = pScreenPriv->x - (int)pCursor->bits->xhot; ++ y = pScreenPriv->y - (int)pCursor->bits->yhot; ++ w = pCursor->bits->width; ++ h = pCursor->bits->height; ++ wpad = SPRITE_PAD; ++ hpad = SPRITE_PAD; ++ pScreenPriv->saved.x1 = x - wpad; ++ pScreenPriv->saved.y1 = y - hpad; ++ pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2; ++ pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2; ++} ++ ++ ++/* ++ * this function is called when the cursor shape is being changed ++ */ ++ ++static Bool ++rfbDisplayCursor(pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ rfbClientPtr cl; ++ rfbSpriteScreenPtr pPriv; ++ ++ for (cl = rfbClientHead; cl ; cl = cl->next) { ++ if (cl->enableCursorShapeUpdates) ++ cl->cursorWasChanged = TRUE; ++ } ++ ++ pPriv = (rfbSpriteScreenPtr)pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ return (*pPriv->DisplayCursor)(pScreen, pCursor); ++} ++ ++ ++/* ++ * obtain current cursor pointer ++ */ ++ ++CursorPtr ++rfbSpriteGetCursorPtr (pScreen) ++ ScreenPtr pScreen; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ return pScreenPriv->pCursor; ++} ++ ++/* ++ * obtain current cursor position ++ */ ++ ++void ++rfbSpriteGetCursorPos (pScreen, px, py) ++ ScreenPtr pScreen; ++ int *px, *py; ++{ ++ rfbSpriteScreenPtr pScreenPriv; ++ ++ pScreenPriv = (rfbSpriteScreenPtr) ++ pScreen->devPrivates[rfbSpriteScreenIndex].ptr; ++ ++ *px = pScreenPriv->x; ++ *py = pScreenPriv->y; ++} ++ +diff --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 ++ */ ++ ++/* ++ * 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 ++ */ ++ ++/* ++ * 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..53017ee +--- /dev/null ++++ b/hw/vnc/stats.c +@@ -0,0 +1,113 @@ ++/* ++ * stats.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#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/tableinitcmtemplate.c b/hw/vnc/tableinitcmtemplate.c +new file mode 100644 +index 0000000..8a757e5 +--- /dev/null ++++ b/hw/vnc/tableinitcmtemplate.c +@@ -0,0 +1,89 @@ ++/* ++ * tableinitcmtemplate.c - template for initialising lookup tables for ++ * translation from a colour map to true colour. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with a different definition of the macro OUT. ++ * For each value of OUT, this file defines a function which allocates an ++ * appropriately sized lookup table and initialises it. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define OUT_T CONCAT2E(CARD,OUT) ++#define SwapOUT(x) CONCAT2E(Swap,OUT(x)) ++#define rfbInitColourMapSingleTableOUT \ ++ CONCAT2E(rfbInitColourMapSingleTable,OUT) ++ ++static void ++rfbInitColourMapSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ VNCSCREENPTR(pScreen); ++ int i, r, g, b; ++ OUT_T *t; ++ EntryPtr pent; ++ int nEntries = 1 << in->bitsPerPixel; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc(nEntries * sizeof(OUT_T)); ++ t = (OUT_T *)*table; ++ ++#if XFREE86VNC ++ pent = (EntryPtr)&miInstalledMaps[pScreen->myNum]->red[0]; ++#else ++ pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[0]; ++#endif ++ ++ for (i = 0; i < nEntries; i++) { ++ if (pent->fShared) { ++ r = pent->co.shco.red->color; ++ g = pent->co.shco.green->color; ++ b = pent->co.shco.blue->color; ++ } else { ++ r = pent->co.local.red; ++ g = pent->co.local.green; ++ b = pent->co.local.blue; ++ } ++ t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) | ++ (((g * out->greenMax + 32767) / 65535) << out->greenShift) | ++ (((b * out->blueMax + 32767) / 65535) << out->blueShift)); ++#if (OUT != 8) ++ if (out->bigEndian != in->bigEndian) { ++ t[i] = SwapOUT(t[i]); ++ } ++#endif ++ pent++; ++ } ++} ++ ++#undef OUT_T ++#undef SwapOUT ++#undef rfbInitColourMapSingleTableOUT +diff --git a/hw/vnc/tableinittctemplate.c b/hw/vnc/tableinittctemplate.c +new file mode 100644 +index 0000000..da8ae01 +--- /dev/null ++++ b/hw/vnc/tableinittctemplate.c +@@ -0,0 +1,142 @@ ++/* ++ * tableinittctemplate.c - template for initialising lookup tables for ++ * truecolour to truecolour translation. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with a different definition of the macro OUT. ++ * For each value of OUT, this file defines two functions for initialising ++ * lookup tables. One is for truecolour translation using a single lookup ++ * table, the other is for truecolour translation using three separate ++ * lookup tables for the red, green and blue values. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define OUT_T CONCAT2E(CARD,OUT) ++#define SwapOUT(x) CONCAT2E(Swap,OUT(x)) ++#define rfbInitTrueColourSingleTableOUT \ ++ CONCAT2E(rfbInitTrueColourSingleTable,OUT) ++#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT) ++#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT) ++ ++static void ++rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift, ++ int swap); ++ ++ ++/* ++ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour ++ * translation. ++ */ ++ ++static void ++rfbInitTrueColourSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ int i; ++ int inRed, inGreen, inBlue, outRed, outGreen, outBlue; ++ OUT_T *t; ++ int nEntries = 1 << in->bitsPerPixel; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc(nEntries * sizeof(OUT_T)); ++ t = (OUT_T *)*table; ++ ++ for (i = 0; i < nEntries; i++) { ++ inRed = (i >> in->redShift) & in->redMax; ++ inGreen = (i >> in->greenShift) & in->greenMax; ++ inBlue = (i >> in->blueShift) & in->blueMax; ++ ++ outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax; ++ outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax; ++ outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax; ++ ++ t[i] = ((outRed << out->redShift) | ++ (outGreen << out->greenShift) | ++ (outBlue << out->blueShift)); ++#if (OUT != 8) ++ if (out->bigEndian != in->bigEndian) { ++ t[i] = SwapOUT(t[i]); ++ } ++#endif ++ } ++} ++ ++ ++/* ++ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the ++ * red, green and blue values. ++ */ ++ ++static void ++rfbInitTrueColourRGBTablesOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ OUT_T *redTable; ++ OUT_T *greenTable; ++ OUT_T *blueTable; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3) ++ * sizeof(OUT_T)); ++ redTable = (OUT_T *)*table; ++ greenTable = redTable + in->redMax + 1; ++ blueTable = greenTable + in->greenMax + 1; ++ ++ rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax, ++ out->redShift, (out->bigEndian != in->bigEndian)); ++ rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax, ++ out->greenShift, (out->bigEndian != in->bigEndian)); ++ rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax, ++ out->blueShift, (out->bigEndian != in->bigEndian)); ++} ++ ++static void ++rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift, ++ int swap) ++{ ++ int i; ++ int nEntries = inMax + 1; ++ ++ for (i = 0; i < nEntries; i++) { ++ table[i] = ((i * outMax + inMax / 2) / inMax) << outShift; ++#if (OUT != 8) ++ if (swap) { ++ table[i] = SwapOUT(table[i]); ++ } ++#endif ++ } ++} ++ ++#undef OUT_T ++#undef SwapOUT ++#undef rfbInitTrueColourSingleTableOUT ++#undef rfbInitTrueColourRGBTablesOUT ++#undef rfbInitOneRGBTableOUT +diff --git a/hw/vnc/tabletranstemplate.c b/hw/vnc/tabletranstemplate.c +new file mode 100644 +index 0000000..87cfcba +--- /dev/null ++++ b/hw/vnc/tabletranstemplate.c +@@ -0,0 +1,119 @@ ++/* ++ * tabletranstemplate.c - template for translation using lookup tables. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with different definitions of the macros IN and OUT. ++ * ++ * For each pair of values IN and OUT, this file defines two functions for ++ * translating a given rectangle of pixel data. One uses a single lookup ++ * table, and the other uses three separate lookup tables for the red, green ++ * and blue values. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(IN) || !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define IN_T CONCAT2E(CARD,IN) ++#define OUT_T CONCAT2E(CARD,OUT) ++#define rfbTranslateWithSingleTableINtoOUT \ ++ CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT) ++#define rfbTranslateWithRGBTablesINtoOUT \ ++ CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT) ++ ++/* ++ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data ++ * using a single lookup table. ++ */ ++ ++static void ++rfbTranslateWithSingleTableINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y) ++{ ++ IN_T *ip = (IN_T *)iptr; ++ OUT_T *op = (OUT_T *)optr; ++ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width; ++ OUT_T *opLineEnd; ++ OUT_T *t = (OUT_T *)table; ++ ++ while (height > 0) { ++ opLineEnd = op + width; ++ ++ while (op < opLineEnd) { ++ *(op++) = t[*(ip++)]; ++ } ++ ++ ip += ipextra; ++ height--; ++ } ++} ++ ++ ++/* ++ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data ++ * using three separate lookup tables for the red, green and blue values. ++ */ ++ ++static void ++rfbTranslateWithRGBTablesINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y) ++{ ++ IN_T *ip = (IN_T *)iptr; ++ OUT_T *op = (OUT_T *)optr; ++ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width; ++ OUT_T *opLineEnd; ++ OUT_T *redTable = (OUT_T *)table; ++ OUT_T *greenTable = redTable + in->redMax + 1; ++ OUT_T *blueTable = greenTable + in->greenMax + 1; ++ ++ while (height > 0) { ++ opLineEnd = op + width; ++ ++ while (op < opLineEnd) { ++ *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] | ++ greenTable[(*ip >> in->greenShift) & in->greenMax] | ++ blueTable[(*ip >> in->blueShift) & in->blueMax]); ++ ip++; ++ } ++ ip += ipextra; ++ height--; ++ } ++} ++ ++#undef IN_T ++#undef OUT_T ++#undef rfbTranslateWithSingleTableINtoOUT ++#undef rfbTranslateWithRGBTablesINtoOUT +diff --git a/hw/vnc/tight.c b/hw/vnc/tight.c +new file mode 100644 +index 0000000..d14b2ce +--- /dev/null ++++ b/hw/vnc/tight.c +@@ -0,0 +1,1824 @@ ++/* ++ * tight.c ++ * ++ * Routines to implement Tight Encoding ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++#include ++ ++ ++/* Note: The following constant should not be changed. */ ++#define TIGHT_MIN_TO_COMPRESS 12 ++ ++/* The parameters below may be adjusted. */ ++#define MIN_SPLIT_RECT_SIZE 4096 ++#define MIN_SOLID_SUBRECT_SIZE 2048 ++#define MAX_SPLIT_TILE_SIZE 16 ++ ++/* May be set to TRUE with "-lazytight" Xvnc option. */ ++Bool rfbTightDisableGradient = FALSE; ++ ++/* This variable is set on every rfbSendRectEncodingTight() call. */ ++static Bool usePixelFormat24; ++ ++ ++/* Compression level stuff. The following array contains various ++ encoder parameters for each of 10 compression levels (0..9). ++ Last three parameters correspond to JPEG quality levels (0..9). */ ++ ++typedef struct TIGHT_CONF_s { ++ int maxRectSize, maxRectWidth; ++ int monoMinRectSize, gradientMinRectSize; ++ int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel; ++ int gradientThreshold, gradientThreshold24; ++ int idxMaxColorsDivisor; ++ int jpegQuality, jpegThreshold, jpegThreshold24; ++} TIGHT_CONF; ++ ++static TIGHT_CONF tightConf[10] = { ++ { 512, 32, 6, 65536, 0, 0, 0, 0, 0, 0, 4, 5, 10000, 23000 }, ++ { 2048, 128, 6, 65536, 1, 1, 1, 0, 0, 0, 8, 10, 8000, 18000 }, ++ { 6144, 256, 8, 65536, 3, 3, 2, 0, 0, 0, 24, 15, 6500, 15000 }, ++ { 10240, 1024, 12, 65536, 5, 5, 3, 0, 0, 0, 32, 25, 5000, 12000 }, ++ { 16384, 2048, 12, 65536, 6, 6, 4, 0, 0, 0, 32, 37, 4000, 10000 }, ++ { 32768, 2048, 12, 4096, 7, 7, 5, 4, 150, 380, 32, 50, 3000, 8000 }, ++ { 65536, 2048, 16, 4096, 7, 7, 6, 4, 170, 420, 48, 60, 2000, 5000 }, ++ { 65536, 2048, 16, 4096, 8, 8, 7, 5, 180, 450, 64, 70, 1000, 2500 }, ++ { 65536, 2048, 32, 8192, 9, 9, 8, 6, 190, 475, 64, 75, 500, 1200 }, ++ { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } ++}; ++ ++/* Stuff dealing with palettes. */ ++ ++typedef struct COLOR_LIST_s { ++ struct COLOR_LIST_s *next; ++ int idx; ++ CARD32 rgb; ++} COLOR_LIST; ++ ++typedef struct PALETTE_ENTRY_s { ++ COLOR_LIST *listNode; ++ int numPixels; ++} PALETTE_ENTRY; ++ ++typedef struct PALETTE_s { ++ PALETTE_ENTRY entry[256]; ++ COLOR_LIST *hash[256]; ++ COLOR_LIST list[256]; ++} PALETTE; ++ ++static int paletteNumColors, paletteMaxColors; ++static CARD32 monoBackground, monoForeground; ++static PALETTE palette; ++ ++/* Pointers to dynamically-allocated buffers. */ ++ ++static int tightBeforeBufSize = 0; ++static char *tightBeforeBuf = NULL; ++ ++static int tightAfterBufSize = 0; ++static char *tightAfterBuf = NULL; ++ ++static int *prevRowBuf = NULL; ++ ++ ++/* Prototypes for static functions. */ ++ ++static void FindBestSolidArea (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 colorValue, int *w_ptr, int *h_ptr); ++static void ExtendSolidArea (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 colorValue, ++ int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr); ++static Bool CheckSolidTile (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile8 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile16 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile32 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++ ++static Bool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h); ++static Bool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h); ++static Bool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h); ++ ++static Bool SendSolidRect (rfbClientPtr cl); ++static Bool SendMonoRect (rfbClientPtr cl, int w, int h); ++static Bool SendIndexedRect (rfbClientPtr cl, int w, int h); ++static Bool SendFullColorRect (rfbClientPtr cl, int w, int h); ++static Bool SendGradientRect (rfbClientPtr cl, int w, int h); ++ ++static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen, ++ int zlibLevel, int zlibStrategy); ++static Bool SendCompressedData(rfbClientPtr cl, int compressedLen); ++ ++static void FillPalette8(int count); ++static void FillPalette16(int count); ++static void FillPalette32(int count); ++ ++static void PaletteReset(void); ++static int PaletteInsert(CARD32 rgb, int numPixels, int bpp); ++ ++static void Pack24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int count); ++ ++static void EncodeIndexedRect16(CARD8 *buf, int count); ++static void EncodeIndexedRect32(CARD8 *buf, int count); ++ ++static void EncodeMonoRect8(CARD8 *buf, int w, int h); ++static void EncodeMonoRect16(CARD8 *buf, int w, int h); ++static void EncodeMonoRect32(CARD8 *buf, int w, int h); ++ ++static void FilterGradient24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int w, int h); ++static void FilterGradient16(ScreenPtr pScreen, CARD16 *buf, rfbPixelFormat *fmt, int w, int h); ++static void FilterGradient32(ScreenPtr pScreen, CARD32 *buf, rfbPixelFormat *fmt, int w, int h); ++ ++static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++ ++static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, ++ int quality); ++static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++ ++static void JpegInitDestination(j_compress_ptr cinfo); ++static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo); ++static void JpegTermDestination(j_compress_ptr cinfo); ++static void JpegSetDstManager(j_compress_ptr cinfo); ++ ++ ++/* ++ * Tight encoding implementation. ++ */ ++ ++int ++rfbNumCodedRectsTight(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ int maxRectSize, maxRectWidth; ++ int subrectMaxWidth, subrectMaxHeight; ++ ++ /* No matter how many rectangles we will send if LastRect markers ++ are used to terminate rectangle stream. */ ++ if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE) ++ return 0; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ ++ if (w > maxRectWidth || w * h > maxRectSize) { ++ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ subrectMaxHeight = maxRectSize / subrectMaxWidth; ++ return (((w - 1) / maxRectWidth + 1) * ++ ((h - 1) / subrectMaxHeight + 1)); ++ } else { ++ return 1; ++ } ++} ++ ++Bool ++rfbSendRectEncodingTight(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int nMaxRows; ++ CARD32 colorValue; ++ int dx, dy, dw, dh; ++ int x_best, y_best, w_best, h_best; ++ unsigned char *fbptr; ++ ++ if ( cl->format.depth == 24 && cl->format.redMax == 0xFF && ++ cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) { ++ usePixelFormat24 = TRUE; ++ } else { ++ usePixelFormat24 = FALSE; ++ } ++ ++ if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE) ++ return SendRectSimple(cl, x, y, w, h); ++ ++ /* Make sure we can write at least one pixel into tightBeforeBuf. */ ++ ++ if (tightBeforeBufSize < 4) { ++ tightBeforeBufSize = 4; ++ if (tightBeforeBuf == NULL) ++ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); ++ else ++ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, ++ tightBeforeBufSize); ++ } ++ ++ /* Calculate maximum number of rows in one non-solid rectangle. */ ++ ++ { ++ int maxRectSize, maxRectWidth, nMaxWidth; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ nMaxRows = maxRectSize / nMaxWidth; ++ } ++ ++ /* Try to find large solid-color areas and send them separately. */ ++ ++ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { ++ ++ /* If a rectangle becomes too large, send its upper part now. */ ++ ++ if (dy - y >= nMaxRows) { ++ if (!SendRectSimple(cl, x, y, w, nMaxRows)) ++ return 0; ++ y += nMaxRows; ++ h -= nMaxRows; ++ } ++ ++ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? ++ MAX_SPLIT_TILE_SIZE : (y + h - dy); ++ ++ for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) { ++ ++ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ? ++ MAX_SPLIT_TILE_SIZE : (x + w - dx); ++ ++ if (CheckSolidTile(cl->pScreen, dx, dy, dw, dh, &colorValue, FALSE)) { ++ ++ /* Get dimensions of solid-color area. */ ++ ++ FindBestSolidArea(cl->pScreen, dx, dy, w - (dx - x), h - (dy - y), ++ colorValue, &w_best, &h_best); ++ ++ /* Make sure a solid rectangle is large enough ++ (or the whole rectangle is of the same color). */ ++ ++ if ( w_best * h_best != w * h && ++ w_best * h_best < MIN_SOLID_SUBRECT_SIZE ) ++ continue; ++ ++ /* Try to extend solid rectangle to maximum size. */ ++ ++ x_best = dx; y_best = dy; ++ ExtendSolidArea(cl->pScreen, x, y, w, h, colorValue, ++ &x_best, &y_best, &w_best, &h_best); ++ ++ /* Send rectangles at top and left to solid-color area. */ ++ ++ if ( y_best != y && ++ !SendRectSimple(cl, x, y, w, y_best-y) ) ++ return FALSE; ++ if ( x_best != x && ++ !rfbSendRectEncodingTight(cl, x, y_best, ++ x_best-x, h_best) ) ++ return FALSE; ++ ++ /* Send solid-color rectangle. */ ++ ++ if (!SendTightHeader(cl, x_best, y_best, w_best, h_best)) ++ return FALSE; ++ ++ fbptr = (pVNC->pfbMemory + ++ (pVNC->paddedWidthInBytes * y_best) + ++ (x_best * (pVNC->bitsPerPixel / 8))); ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, tightBeforeBuf, ++ pVNC->paddedWidthInBytes, 1, 1, ++ x_best, y_best); ++ ++ if (!SendSolidRect(cl)) ++ return FALSE; ++ ++ /* Send remaining rectangles (at right and bottom). */ ++ ++ if ( x_best + w_best != x + w && ++ !rfbSendRectEncodingTight(cl, x_best+w_best, y_best, ++ w-(x_best-x)-w_best, h_best) ) ++ return FALSE; ++ if ( y_best + h_best != y + h && ++ !rfbSendRectEncodingTight(cl, x, y_best+h_best, ++ w, h-(y_best-y)-h_best) ) ++ return FALSE; ++ ++ /* Return after all recursive calls are done. */ ++ ++ return TRUE; ++ } ++ ++ } ++ ++ } ++ ++ /* No suitable solid-color rectangles found. */ ++ ++ return SendRectSimple(cl, x, y, w, h); ++} ++ ++static void ++FindBestSolidArea(pScreen, x, y, w, h, colorValue, w_ptr, h_ptr) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 colorValue; ++ int *w_ptr, *h_ptr; ++{ ++ int dx, dy, dw, dh; ++ int w_prev; ++ int w_best = 0, h_best = 0; ++ ++ w_prev = w; ++ ++ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { ++ ++ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? ++ MAX_SPLIT_TILE_SIZE : (y + h - dy); ++ dw = (w_prev > MAX_SPLIT_TILE_SIZE) ? ++ MAX_SPLIT_TILE_SIZE : w_prev; ++ ++ if (!CheckSolidTile(pScreen, x, dy, dw, dh, &colorValue, TRUE)) ++ break; ++ ++ for (dx = x + dw; dx < x + w_prev;) { ++ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ? ++ MAX_SPLIT_TILE_SIZE : (x + w_prev - dx); ++ if (!CheckSolidTile(pScreen, dx, dy, dw, dh, &colorValue, TRUE)) ++ break; ++ dx += dw; ++ } ++ ++ w_prev = dx - x; ++ if (w_prev * (dy + dh - y) > w_best * h_best) { ++ w_best = w_prev; ++ h_best = dy + dh - y; ++ } ++ } ++ ++ *w_ptr = w_best; ++ *h_ptr = h_best; ++} ++ ++static void ++ExtendSolidArea(pScreen, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 colorValue; ++ int *x_ptr, *y_ptr, *w_ptr, *h_ptr; ++{ ++ int cx, cy; ++ ++ /* Try to extend the area upwards. */ ++ for ( cy = *y_ptr - 1; ++ cy >= y && CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); ++ cy-- ); ++ *h_ptr += *y_ptr - (cy + 1); ++ *y_ptr = cy + 1; ++ ++ /* ... downwards. */ ++ for ( cy = *y_ptr + *h_ptr; ++ cy < y + h && ++ CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); ++ cy++ ); ++ *h_ptr += cy - (*y_ptr + *h_ptr); ++ ++ /* ... to the left. */ ++ for ( cx = *x_ptr - 1; ++ cx >= x && CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); ++ cx-- ); ++ *w_ptr += *x_ptr - (cx + 1); ++ *x_ptr = cx + 1; ++ ++ /* ... to the right. */ ++ for ( cx = *x_ptr + *w_ptr; ++ cx < x + w && ++ CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); ++ cx++ ); ++ *w_ptr += cx - (*x_ptr + *w_ptr); ++} ++ ++/* ++ * Check if a rectangle is all of the same color. If needSameColor is ++ * set to non-zero, then also check that its color equals to the ++ * *colorPtr value. The result is 1 if the test is successfull, and in ++ * that case new color will be stored in *colorPtr. ++ */ ++ ++static Bool ++CheckSolidTile(pScreen, x, y, w, h, colorPtr, needSameColor) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 *colorPtr; ++ Bool needSameColor; ++{ ++ VNCSCREENPTR(pScreen); ++ switch(pVNC->rfbServerFormat.bitsPerPixel) { ++ case 32: ++ return CheckSolidTile32(pScreen, x, y, w, h, colorPtr, needSameColor); ++ case 16: ++ return CheckSolidTile16(pScreen, x, y, w, h, colorPtr, needSameColor); ++ default: ++ return CheckSolidTile8(pScreen, x, y, w, h, colorPtr, needSameColor); ++ } ++} ++ ++#define DEFINE_CHECK_SOLID_FUNCTION(bpp) \ ++ \ ++static Bool \ ++CheckSolidTile##bpp(pScreen, x, y, w, h, colorPtr, needSameColor) \ ++ ScreenPtr pScreen; \ ++ int x, y; \ ++ CARD32 *colorPtr; \ ++ Bool needSameColor; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp *fbptr; \ ++ CARD##bpp colorValue; \ ++ int dx, dy; \ ++ \ ++ fbptr = (CARD##bpp *) \ ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * (bpp/8)]; \ ++ \ ++ colorValue = *fbptr; \ ++ if (needSameColor && (CARD32)colorValue != *colorPtr) \ ++ return FALSE; \ ++ \ ++ for (dy = 0; dy < h; dy++) { \ ++ for (dx = 0; dx < w; dx++) { \ ++ if (colorValue != fbptr[dx]) \ ++ return FALSE; \ ++ } \ ++ fbptr = (CARD##bpp *)((CARD8 *)fbptr + pVNC->paddedWidthInBytes); \ ++ } \ ++ \ ++ *colorPtr = (CARD32)colorValue; \ ++ return TRUE; \ ++} ++ ++DEFINE_CHECK_SOLID_FUNCTION(8) ++DEFINE_CHECK_SOLID_FUNCTION(16) ++DEFINE_CHECK_SOLID_FUNCTION(32) ++ ++static Bool ++SendRectSimple(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ int maxBeforeSize, maxAfterSize; ++ int maxRectSize, maxRectWidth; ++ int subrectMaxWidth, subrectMaxHeight; ++ int dx, dy; ++ int rw, rh; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ ++ maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8); ++ maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; ++ ++ if (tightBeforeBufSize < maxBeforeSize) { ++ tightBeforeBufSize = maxBeforeSize; ++ if (tightBeforeBuf == NULL) ++ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); ++ else ++ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, ++ tightBeforeBufSize); ++ } ++ ++ if (tightAfterBufSize < maxAfterSize) { ++ tightAfterBufSize = maxAfterSize; ++ if (tightAfterBuf == NULL) ++ tightAfterBuf = (char *)xalloc(tightAfterBufSize); ++ else ++ tightAfterBuf = (char *)xrealloc(tightAfterBuf, ++ tightAfterBufSize); ++ } ++ ++ if (w > maxRectWidth || w * h > maxRectSize) { ++ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ subrectMaxHeight = maxRectSize / subrectMaxWidth; ++ ++ for (dy = 0; dy < h; dy += subrectMaxHeight) { ++ for (dx = 0; dx < w; dx += maxRectWidth) { ++ rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx; ++ rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy; ++ if (!SendSubrect(cl, x+dx, y+dy, rw, rh)) ++ return FALSE; ++ } ++ } ++ } else { ++ if (!SendSubrect(cl, x, y, w, h)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static Bool ++SendSubrect(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ unsigned char *fbptr; ++ Bool success = FALSE; ++ ++ /* Send pending data if there is more than 128 bytes. */ ++ if (pVNC->ublen > 128) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if (!SendTightHeader(cl, x, y, w, h)) ++ return FALSE; ++ ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat, ++ &cl->format, fbptr, tightBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ paletteMaxColors = w * h / tightConf[cl->tightCompressLevel].idxMaxColorsDivisor; ++ if ( paletteMaxColors < 2 && ++ w * h >= tightConf[cl->tightCompressLevel].monoMinRectSize ) { ++ paletteMaxColors = 2; ++ } ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ FillPalette8(w * h); ++ break; ++ case 16: ++ FillPalette16(w * h); ++ break; ++ default: ++ FillPalette32(w * h); ++ } ++ ++ switch (paletteNumColors) { ++ case 0: ++ /* Truecolor image */ ++ if (DetectSmoothImage(cl, &cl->format, w, h)) { ++ if (cl->tightQualityLevel != -1) { ++ success = SendJpegRect(cl, x, y, w, h, ++ tightConf[cl->tightQualityLevel].jpegQuality); ++ } else { ++ success = SendGradientRect(cl, w, h); ++ } ++ } else { ++ success = SendFullColorRect(cl, w, h); ++ } ++ break; ++ case 1: ++ /* Solid rectangle */ ++ success = SendSolidRect(cl); ++ break; ++ case 2: ++ /* Two-color rectangle */ ++ success = SendMonoRect(cl, w, h); ++ break; ++ default: ++ /* Up to 256 different colors */ ++ if ( paletteNumColors > 96 && ++ cl->tightQualityLevel != -1 && cl->tightQualityLevel <= 3 && ++ DetectSmoothImage(cl, &cl->format, w, h) ) { ++ success = SendJpegRect(cl, x, y, w, h, ++ tightConf[cl->tightQualityLevel].jpegQuality); ++ } else { ++ success = SendIndexedRect(cl, w, h); ++ } ++ } ++ return success; ++} ++ ++static Bool ++SendTightHeader(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingTight); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingTight]++; ++ cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader; ++ ++ return TRUE; ++} ++ ++/* ++ * Subencoding implementations. ++ */ ++ ++static Bool ++SendSolidRect(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int len; ++ ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightBeforeBuf, &cl->format, 1); ++ len = 3; ++ } else ++ len = cl->format.bitsPerPixel / 8; ++ ++ if (pVNC->ublen + 1 + len > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightFill << 4); ++ memcpy (&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, len); ++ pVNC->ublen += len; ++ ++ cl->rfbBytesSent[rfbEncodingTight] += len + 1; ++ ++ return TRUE; ++} ++ ++static Bool ++SendMonoRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 1; ++ int paletteLen, dataLen; ++ ++ if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 + ++ 2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ /* Prepare tight encoding header. */ ++ dataLen = (w + 7) / 8; ++ dataLen *= h; ++ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette; ++ pVNC->updateBuf[pVNC->ublen++] = 1; ++ ++ /* Prepare palette, convert image. */ ++ switch (cl->format.bitsPerPixel) { ++ ++ case 32: ++ EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h); ++ ++ ((CARD32 *)tightAfterBuf)[0] = monoBackground; ++ ((CARD32 *)tightAfterBuf)[1] = monoForeground; ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightAfterBuf, &cl->format, 2); ++ paletteLen = 6; ++ } else ++ paletteLen = 8; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteLen); ++ pVNC->ublen += paletteLen; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen; ++ break; ++ ++ case 16: ++ EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h); ++ ++ ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground; ++ ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, 4); ++ pVNC->ublen += 4; ++ cl->rfbBytesSent[rfbEncodingTight] += 7; ++ break; ++ ++ default: ++ EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h); ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)monoBackground; ++ pVNC->updateBuf[pVNC->ublen++] = (char)monoForeground; ++ cl->rfbBytesSent[rfbEncodingTight] += 5; ++ } ++ ++ return CompressData(cl, streamId, dataLen, ++ tightConf[cl->tightCompressLevel].monoZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendIndexedRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 2; ++ int i, entryLen; ++ ++ if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 + ++ paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ /* Prepare tight encoding header. */ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette; ++ pVNC->updateBuf[pVNC->ublen++] = (char)(paletteNumColors - 1); ++ ++ /* Prepare palette, convert image. */ ++ switch (cl->format.bitsPerPixel) { ++ ++ case 32: ++ EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h); ++ ++ for (i = 0; i < paletteNumColors; i++) { ++ ((CARD32 *)tightAfterBuf)[i] = ++ palette.entry[i].listNode->rgb; ++ } ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightAfterBuf, &cl->format, paletteNumColors); ++ entryLen = 3; ++ } else ++ entryLen = 4; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * entryLen); ++ pVNC->ublen += paletteNumColors * entryLen; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen; ++ break; ++ ++ case 16: ++ EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h); ++ ++ for (i = 0; i < paletteNumColors; i++) { ++ ((CARD16 *)tightAfterBuf)[i] = ++ (CARD16)palette.entry[i].listNode->rgb; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * 2); ++ pVNC->ublen += paletteNumColors * 2; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2; ++ break; ++ ++ default: ++ return FALSE; /* Should never happen. */ ++ } ++ ++ return CompressData(cl, streamId, w * h, ++ tightConf[cl->tightCompressLevel].idxZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendFullColorRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 0; ++ int len; ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */ ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightBeforeBuf, &cl->format, w * h); ++ len = 3; ++ } else ++ len = cl->format.bitsPerPixel / 8; ++ ++ return CompressData(cl, streamId, w * h * len, ++ tightConf[cl->tightCompressLevel].rawZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendGradientRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 3; ++ int len; ++ ++ if (cl->format.bitsPerPixel == 8) ++ return SendFullColorRect(cl, w, h); ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if (prevRowBuf == NULL) ++ prevRowBuf = (int *)xalloc(2048 * 3 * sizeof(int)); ++ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterGradient; ++ cl->rfbBytesSent[rfbEncodingTight] += 2; ++ ++ if (usePixelFormat24) { ++ FilterGradient24(cl->pScreen, tightBeforeBuf, &cl->format, w, h); ++ len = 3; ++ } else if (cl->format.bitsPerPixel == 32) { ++ FilterGradient32(cl->pScreen, (CARD32 *)tightBeforeBuf, &cl->format, w, h); ++ len = 4; ++ } else { ++ FilterGradient16(cl->pScreen, (CARD16 *)tightBeforeBuf, &cl->format, w, h); ++ len = 2; ++ } ++ ++ return CompressData(cl, streamId, w * h * len, ++ tightConf[cl->tightCompressLevel].gradientZlibLevel, ++ Z_FILTERED); ++} ++ ++static Bool ++CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy) ++ rfbClientPtr cl; ++ int streamId, dataLen, zlibLevel, zlibStrategy; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ z_streamp pz; ++ int err; ++ ++ if (dataLen < TIGHT_MIN_TO_COMPRESS) { ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, dataLen); ++ pVNC->ublen += dataLen; ++ cl->rfbBytesSent[rfbEncodingTight] += dataLen; ++ return TRUE; ++ } ++ ++ pz = &cl->zsStruct[streamId]; ++ ++ /* Initialize compression stream if needed. */ ++ if (!cl->zsActive[streamId]) { ++ pz->zalloc = Z_NULL; ++ pz->zfree = Z_NULL; ++ pz->opaque = Z_NULL; ++ ++ err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS, ++ MAX_MEM_LEVEL, zlibStrategy); ++ if (err != Z_OK) ++ return FALSE; ++ ++ cl->zsActive[streamId] = TRUE; ++ cl->zsLevel[streamId] = zlibLevel; ++ } ++ ++ /* Prepare buffer pointers. */ ++ pz->next_in = (Bytef *)tightBeforeBuf; ++ pz->avail_in = dataLen; ++ pz->next_out = (Bytef *)tightAfterBuf; ++ pz->avail_out = tightAfterBufSize; ++ ++ /* Change compression parameters if needed. */ ++ if (zlibLevel != cl->zsLevel[streamId]) { ++ if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) { ++ return FALSE; ++ } ++ cl->zsLevel[streamId] = zlibLevel; ++ } ++ ++ /* Actual compression. */ ++ if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK || ++ pz->avail_in != 0 || pz->avail_out == 0 ) { ++ return FALSE; ++ } ++ ++ return SendCompressedData(cl, tightAfterBufSize - pz->avail_out); ++} ++ ++static Bool SendCompressedData(cl, compressedLen) ++ rfbClientPtr cl; ++ int compressedLen; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int i, portionLen; ++ ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen & 0x7F; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ if (compressedLen > 0x7F) { ++ pVNC->updateBuf[pVNC->ublen-1] |= 0x80; ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 7 & 0x7F; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ if (compressedLen > 0x3FFF) { ++ pVNC->updateBuf[pVNC->ublen-1] |= 0x80; ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 14 & 0xFF; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ } ++ } ++ ++ portionLen = UPDATE_BUF_SIZE; ++ for (i = 0; i < compressedLen; i += portionLen) { ++ if (i + portionLen > compressedLen) { ++ portionLen = compressedLen - i; ++ } ++ if (pVNC->ublen + portionLen > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &tightAfterBuf[i], portionLen); ++ pVNC->ublen += portionLen; ++ } ++ cl->rfbBytesSent[rfbEncodingTight] += compressedLen; ++ return TRUE; ++} ++ ++/* ++ * Code to determine how many different colors used in rectangle. ++ */ ++ ++static void ++FillPalette8(count) ++ int count; ++{ ++ CARD8 *data = (CARD8 *)tightBeforeBuf; ++ CARD8 c0, c1; ++ int i, n0, n1; ++ ++ paletteNumColors = 0; ++ ++ c0 = data[0]; ++ for (i = 1; i < count && data[i] == c0; i++); ++ if (i == count) { ++ paletteNumColors = 1; ++ return; /* Solid rectangle */ ++ } ++ ++ if (paletteMaxColors < 2) ++ return; ++ ++ n0 = i; ++ c1 = data[i]; ++ n1 = 0; ++ for (i++; i < count; i++) { ++ if (data[i] == c0) { ++ n0++; ++ } else if (data[i] == c1) { ++ n1++; ++ } else ++ break; ++ } ++ if (i == count) { ++ if (n0 > n1) { ++ monoBackground = (CARD32)c0; ++ monoForeground = (CARD32)c1; ++ } else { ++ monoBackground = (CARD32)c1; ++ monoForeground = (CARD32)c0; ++ } ++ paletteNumColors = 2; /* Two colors */ ++ } ++} ++ ++#define DEFINE_FILL_PALETTE_FUNCTION(bpp) \ ++ \ ++static void \ ++FillPalette##bpp(count) \ ++ int count; \ ++{ \ ++ CARD##bpp *data = (CARD##bpp *)tightBeforeBuf; \ ++ CARD##bpp c0, c1, ci = 0; \ ++ int i, n0, n1, ni; \ ++ \ ++ c0 = data[0]; \ ++ for (i = 1; i < count && data[i] == c0; i++); \ ++ if (i >= count) { \ ++ paletteNumColors = 1; /* Solid rectangle */ \ ++ return; \ ++ } \ ++ \ ++ if (paletteMaxColors < 2) { \ ++ paletteNumColors = 0; /* Full-color encoding preferred */ \ ++ return; \ ++ } \ ++ \ ++ n0 = i; \ ++ c1 = data[i]; \ ++ n1 = 0; \ ++ for (i++; i < count; i++) { \ ++ ci = data[i]; \ ++ if (ci == c0) { \ ++ n0++; \ ++ } else if (ci == c1) { \ ++ n1++; \ ++ } else \ ++ break; \ ++ } \ ++ if (i >= count) { \ ++ if (n0 > n1) { \ ++ monoBackground = (CARD32)c0; \ ++ monoForeground = (CARD32)c1; \ ++ } else { \ ++ monoBackground = (CARD32)c1; \ ++ monoForeground = (CARD32)c0; \ ++ } \ ++ paletteNumColors = 2; /* Two colors */ \ ++ return; \ ++ } \ ++ \ ++ PaletteReset(); \ ++ PaletteInsert (c0, (CARD32)n0, bpp); \ ++ PaletteInsert (c1, (CARD32)n1, bpp); \ ++ \ ++ ni = 1; \ ++ for (i++; i < count; i++) { \ ++ if (data[i] == ci) { \ ++ ni++; \ ++ } else { \ ++ if (!PaletteInsert (ci, (CARD32)ni, bpp)) \ ++ return; \ ++ ci = data[i]; \ ++ ni = 1; \ ++ } \ ++ } \ ++ PaletteInsert (ci, (CARD32)ni, bpp); \ ++} ++ ++DEFINE_FILL_PALETTE_FUNCTION(16) ++DEFINE_FILL_PALETTE_FUNCTION(32) ++ ++ ++/* ++ * Functions to operate with palette structures. ++ */ ++ ++#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF)) ++#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF)) ++ ++static void ++PaletteReset(void) ++{ ++ paletteNumColors = 0; ++ memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *)); ++} ++ ++static int ++PaletteInsert(CARD32 rgb, int numPixels, int bpp) ++{ ++ COLOR_LIST *pnode; ++ COLOR_LIST *prev_pnode = NULL; ++ int hash_key, idx, new_idx, count; ++ ++ hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb); ++ ++ pnode = palette.hash[hash_key]; ++ ++ while (pnode != NULL) { ++ if (pnode->rgb == rgb) { ++ /* Such palette entry already exists. */ ++ new_idx = idx = pnode->idx; ++ count = palette.entry[idx].numPixels + numPixels; ++ if (new_idx && palette.entry[new_idx-1].numPixels < count) { ++ do { ++ palette.entry[new_idx] = palette.entry[new_idx-1]; ++ palette.entry[new_idx].listNode->idx = new_idx; ++ new_idx--; ++ } ++ while (new_idx && palette.entry[new_idx-1].numPixels < count); ++ palette.entry[new_idx].listNode = pnode; ++ pnode->idx = new_idx; ++ } ++ palette.entry[new_idx].numPixels = count; ++ return paletteNumColors; ++ } ++ prev_pnode = pnode; ++ pnode = pnode->next; ++ } ++ ++ /* Check if palette is full. */ ++ if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) { ++ paletteNumColors = 0; ++ return 0; ++ } ++ ++ /* Move palette entries with lesser pixel counts. */ ++ for ( idx = paletteNumColors; ++ idx > 0 && palette.entry[idx-1].numPixels < numPixels; ++ idx-- ) { ++ palette.entry[idx] = palette.entry[idx-1]; ++ palette.entry[idx].listNode->idx = idx; ++ } ++ ++ /* Add new palette entry into the freed slot. */ ++ pnode = &palette.list[paletteNumColors]; ++ if (prev_pnode != NULL) { ++ prev_pnode->next = pnode; ++ } else { ++ palette.hash[hash_key] = pnode; ++ } ++ pnode->next = NULL; ++ pnode->idx = idx; ++ pnode->rgb = rgb; ++ palette.entry[idx].listNode = pnode; ++ palette.entry[idx].numPixels = numPixels; ++ ++ return (++paletteNumColors); ++} ++ ++ ++/* ++ * Converting 32-bit color samples into 24-bit colors. ++ * Should be called only when redMax, greenMax and blueMax are 255. ++ * Color components assumed to be byte-aligned. ++ */ ++ ++static void Pack24(pScreen, buf, fmt, count) ++ ScreenPtr pScreen; ++ char *buf; ++ rfbPixelFormat *fmt; ++ int count; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *buf32; ++ CARD32 pix; ++ int r_shift, g_shift, b_shift; ++ ++ buf32 = (CARD32 *)buf; ++ ++ if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) { ++ r_shift = fmt->redShift; ++ g_shift = fmt->greenShift; ++ b_shift = fmt->blueShift; ++ } else { ++ r_shift = 24 - fmt->redShift; ++ g_shift = 24 - fmt->greenShift; ++ b_shift = 24 - fmt->blueShift; ++ } ++ ++ while (count--) { ++ pix = *buf32++; ++ *buf++ = (char)(pix >> r_shift); ++ *buf++ = (char)(pix >> g_shift); ++ *buf++ = (char)(pix >> b_shift); ++ } ++} ++ ++ ++/* ++ * Converting truecolor samples into palette indices. ++ */ ++ ++#define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ ++ \ ++static void \ ++EncodeIndexedRect##bpp(buf, count) \ ++ CARD8 *buf; \ ++ int count; \ ++{ \ ++ COLOR_LIST *pnode; \ ++ CARD##bpp *src; \ ++ CARD##bpp rgb; \ ++ int rep = 0; \ ++ \ ++ src = (CARD##bpp *) buf; \ ++ \ ++ while (count--) { \ ++ rgb = *src++; \ ++ while (count && *src == rgb) { \ ++ rep++, src++, count--; \ ++ } \ ++ pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \ ++ while (pnode != NULL) { \ ++ if ((CARD##bpp)pnode->rgb == rgb) { \ ++ *buf++ = (CARD8)pnode->idx; \ ++ while (rep) { \ ++ *buf++ = (CARD8)pnode->idx; \ ++ rep--; \ ++ } \ ++ break; \ ++ } \ ++ pnode = pnode->next; \ ++ } \ ++ } \ ++} ++ ++DEFINE_IDX_ENCODE_FUNCTION(16) ++DEFINE_IDX_ENCODE_FUNCTION(32) ++ ++#define DEFINE_MONO_ENCODE_FUNCTION(bpp) \ ++ \ ++static void \ ++EncodeMonoRect##bpp(buf, w, h) \ ++ CARD8 *buf; \ ++ int w, h; \ ++{ \ ++ CARD##bpp *ptr; \ ++ CARD##bpp bg; \ ++ unsigned int value, mask; \ ++ int aligned_width; \ ++ int x, y, bg_bits; \ ++ \ ++ ptr = (CARD##bpp *) buf; \ ++ bg = (CARD##bpp) monoBackground; \ ++ aligned_width = w - w % 8; \ ++ \ ++ for (y = 0; y < h; y++) { \ ++ for (x = 0; x < aligned_width; x += 8) { \ ++ for (bg_bits = 0; bg_bits < 8; bg_bits++) { \ ++ if (*ptr++ != bg) \ ++ break; \ ++ } \ ++ if (bg_bits == 8) { \ ++ *buf++ = 0; \ ++ continue; \ ++ } \ ++ mask = 0x80 >> bg_bits; \ ++ value = mask; \ ++ for (bg_bits++; bg_bits < 8; bg_bits++) { \ ++ mask >>= 1; \ ++ if (*ptr++ != bg) { \ ++ value |= mask; \ ++ } \ ++ } \ ++ *buf++ = (CARD8)value; \ ++ } \ ++ \ ++ mask = 0x80; \ ++ value = 0; \ ++ if (x >= w) \ ++ continue; \ ++ \ ++ for (; x < w; x++) { \ ++ if (*ptr++ != bg) { \ ++ value |= mask; \ ++ } \ ++ mask >>= 1; \ ++ } \ ++ *buf++ = (CARD8)value; \ ++ } \ ++} ++ ++DEFINE_MONO_ENCODE_FUNCTION(8) ++DEFINE_MONO_ENCODE_FUNCTION(16) ++DEFINE_MONO_ENCODE_FUNCTION(32) ++ ++ ++/* ++ * ``Gradient'' filter for 24-bit color samples. ++ * Should be called only when redMax, greenMax and blueMax are 255. ++ * Color components assumed to be byte-aligned. ++ */ ++ ++static void ++FilterGradient24(pScreen, buf, fmt, w, h) ++ ScreenPtr pScreen; ++ char *buf; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *buf32; ++ CARD32 pix32; ++ int *prevRowPtr; ++ int shiftBits[3]; ++ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; ++ int prediction; ++ int x, y, c; ++ ++ buf32 = (CARD32 *)buf; ++ memset (prevRowBuf, 0, w * 3 * sizeof(int)); ++ ++ if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) { ++ shiftBits[0] = fmt->redShift; ++ shiftBits[1] = fmt->greenShift; ++ shiftBits[2] = fmt->blueShift; ++ } else { ++ shiftBits[0] = 24 - fmt->redShift; ++ shiftBits[1] = 24 - fmt->greenShift; ++ shiftBits[2] = 24 - fmt->blueShift; ++ } ++ ++ for (y = 0; y < h; y++) { ++ for (c = 0; c < 3; c++) { ++ pixUpper[c] = 0; ++ pixHere[c] = 0; ++ } ++ prevRowPtr = prevRowBuf; ++ for (x = 0; x < w; x++) { ++ pix32 = *buf32++; ++ for (c = 0; c < 3; c++) { ++ pixUpperLeft[c] = pixUpper[c]; ++ pixLeft[c] = pixHere[c]; ++ pixUpper[c] = *prevRowPtr; ++ pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF); ++ *prevRowPtr++ = pixHere[c]; ++ ++ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; ++ if (prediction < 0) { ++ prediction = 0; ++ } else if (prediction > 0xFF) { ++ prediction = 0xFF; ++ } ++ *buf++ = (char)(pixHere[c] - prediction); ++ } ++ } ++ } ++} ++ ++ ++/* ++ * ``Gradient'' filter for other color depths. ++ */ ++ ++#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \ ++ \ ++static void \ ++FilterGradient##bpp(pScreen, buf, fmt, w, h) \ ++ ScreenPtr pScreen; \ ++ CARD##bpp *buf; \ ++ rfbPixelFormat *fmt; \ ++ int w, h; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp pix, diff; \ ++ Bool endianMismatch; \ ++ int *prevRowPtr; \ ++ int maxColor[3], shiftBits[3]; \ ++ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; \ ++ int prediction; \ ++ int x, y, c; \ ++ \ ++ memset (prevRowBuf, 0, w * 3 * sizeof(int)); \ ++ \ ++ endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian); \ ++ \ ++ maxColor[0] = fmt->redMax; \ ++ maxColor[1] = fmt->greenMax; \ ++ maxColor[2] = fmt->blueMax; \ ++ shiftBits[0] = fmt->redShift; \ ++ shiftBits[1] = fmt->greenShift; \ ++ shiftBits[2] = fmt->blueShift; \ ++ \ ++ for (y = 0; y < h; y++) { \ ++ for (c = 0; c < 3; c++) { \ ++ pixUpper[c] = 0; \ ++ pixHere[c] = 0; \ ++ } \ ++ prevRowPtr = prevRowBuf; \ ++ for (x = 0; x < w; x++) { \ ++ pix = *buf; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ diff = 0; \ ++ for (c = 0; c < 3; c++) { \ ++ pixUpperLeft[c] = pixUpper[c]; \ ++ pixLeft[c] = pixHere[c]; \ ++ pixUpper[c] = *prevRowPtr; \ ++ pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ *prevRowPtr++ = pixHere[c]; \ ++ \ ++ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \ ++ if (prediction < 0) { \ ++ prediction = 0; \ ++ } else if (prediction > maxColor[c]) { \ ++ prediction = maxColor[c]; \ ++ } \ ++ diff |= ((pixHere[c] - prediction) & maxColor[c]) \ ++ << shiftBits[c]; \ ++ } \ ++ if (endianMismatch) { \ ++ diff = Swap##bpp(diff); \ ++ } \ ++ *buf++ = diff; \ ++ } \ ++ } \ ++} ++ ++DEFINE_GRADIENT_FILTER_FUNCTION(16) ++DEFINE_GRADIENT_FILTER_FUNCTION(32) ++ ++ ++/* ++ * Code to guess if given rectangle is suitable for smooth image ++ * compression (by applying "gradient" filter or JPEG coder). ++ */ ++ ++#define JPEG_MIN_RECT_SIZE 4096 ++ ++#define DETECT_SUBROW_WIDTH 7 ++#define DETECT_MIN_WIDTH 8 ++#define DETECT_MIN_HEIGHT 8 ++ ++static int ++DetectSmoothImage (cl, fmt, w, h) ++ rfbClientPtr cl; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ unsigned long avgError; ++ ++ if ( pVNC->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 || ++ w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) { ++ return 0; ++ } ++ ++ if (cl->tightQualityLevel != -1) { ++ if (w * h < JPEG_MIN_RECT_SIZE) { ++ return 0; ++ } ++ } else { ++ if ( rfbTightDisableGradient || ++ w * h < tightConf[cl->tightCompressLevel].gradientMinRectSize ) { ++ return 0; ++ } ++ } ++ ++ if (fmt->bitsPerPixel == 32) { ++ if (usePixelFormat24) { ++ avgError = DetectSmoothImage24(cl, fmt, w, h); ++ if (cl->tightQualityLevel != -1) { ++ return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold24); ++ } ++ return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold24); ++ } else { ++ avgError = DetectSmoothImage32(cl, fmt, w, h); ++ } ++ } else { ++ avgError = DetectSmoothImage16(cl, fmt, w, h); ++ } ++ if (cl->tightQualityLevel != -1) { ++ return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold); ++ } ++ return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold); ++} ++ ++static unsigned long ++DetectSmoothImage24 (cl, fmt, w, h) ++ rfbClientPtr cl; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ int off; ++ int x, y, d, dx, c; ++ int diffStat[256]; ++ int pixelCount = 0; ++ int pix, left[3]; ++ unsigned long avgError; ++ ++ /* If client is big-endian, color samples begin from the second ++ byte (offset 1) of a 32-bit pixel value. */ ++ off = (fmt->bigEndian != 0); ++ ++ memset(diffStat, 0, 256*sizeof(int)); ++ ++ y = 0, x = 0; ++ while (y < h && x < w) { ++ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { ++ for (c = 0; c < 3; c++) { ++ left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF; ++ } ++ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { ++ for (c = 0; c < 3; c++) { ++ pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF; ++ diffStat[abs(pix - left[c])]++; ++ left[c] = pix; ++ } ++ pixelCount++; ++ } ++ } ++ if (w > h) { ++ x += h; ++ y = 0; ++ } else { ++ x = 0; ++ y += w; ++ } ++ } ++ ++ if (diffStat[0] * 33 / pixelCount >= 95) ++ return 0; ++ ++ avgError = 0; ++ for (c = 1; c < 8; c++) { ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); ++ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) ++ return 0; ++ } ++ for (; c < 256; c++) { ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); ++ } ++ avgError /= (pixelCount * 3 - diffStat[0]); ++ ++ return avgError; ++} ++ ++#define DEFINE_DETECT_FUNCTION(bpp) \ ++ \ ++static unsigned long \ ++DetectSmoothImage##bpp (cl, fmt, w, h) \ ++ rfbClientPtr cl; \ ++ rfbPixelFormat *fmt; \ ++ int w, h; \ ++{ \ ++ VNCSCREENPTR(cl->pScreen); \ ++ Bool endianMismatch; \ ++ CARD##bpp pix; \ ++ int maxColor[3], shiftBits[3]; \ ++ int x, y, d, dx, c; \ ++ int diffStat[256]; \ ++ int pixelCount = 0; \ ++ int sample, sum, left[3]; \ ++ unsigned long avgError; \ ++ \ ++ endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian); \ ++ \ ++ maxColor[0] = fmt->redMax; \ ++ maxColor[1] = fmt->greenMax; \ ++ maxColor[2] = fmt->blueMax; \ ++ shiftBits[0] = fmt->redShift; \ ++ shiftBits[1] = fmt->greenShift; \ ++ shiftBits[2] = fmt->blueShift; \ ++ \ ++ memset(diffStat, 0, 256*sizeof(int)); \ ++ \ ++ y = 0, x = 0; \ ++ while (y < h && x < w) { \ ++ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { \ ++ pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d]; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ for (c = 0; c < 3; c++) { \ ++ left[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ } \ ++ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { \ ++ pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d+dx]; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ sum = 0; \ ++ for (c = 0; c < 3; c++) { \ ++ sample = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ sum += abs(sample - left[c]); \ ++ left[c] = sample; \ ++ } \ ++ if (sum > 255) \ ++ sum = 255; \ ++ diffStat[sum]++; \ ++ pixelCount++; \ ++ } \ ++ } \ ++ if (w > h) { \ ++ x += h; \ ++ y = 0; \ ++ } else { \ ++ x = 0; \ ++ y += w; \ ++ } \ ++ } \ ++ \ ++ if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90) \ ++ return 0; \ ++ \ ++ avgError = 0; \ ++ for (c = 1; c < 8; c++) { \ ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \ ++ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) \ ++ return 0; \ ++ } \ ++ for (; c < 256; c++) { \ ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \ ++ } \ ++ avgError /= (pixelCount - diffStat[0]); \ ++ \ ++ return avgError; \ ++} ++ ++DEFINE_DETECT_FUNCTION(16) ++DEFINE_DETECT_FUNCTION(32) ++ ++ ++/* ++ * JPEG compression stuff. ++ */ ++ ++static struct jpeg_destination_mgr jpegDstManager; ++static Bool jpegError; ++static int jpegDstDataLen; ++ ++static Bool ++SendJpegRect(cl, x, y, w, h, quality) ++ rfbClientPtr cl; ++ int x, y, w, h; ++ int quality; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ struct jpeg_compress_struct cinfo; ++ struct jpeg_error_mgr jerr; ++ CARD8 *srcBuf; ++ JSAMPROW rowPointer[1]; ++ int dy; ++ ++ if (pVNC->rfbServerFormat.bitsPerPixel == 8) ++ return SendFullColorRect(cl, w, h); ++ ++ srcBuf = (CARD8 *)xalloc(w * 3); ++ if (srcBuf == NULL) { ++ return SendFullColorRect(cl, w, h); ++ } ++ rowPointer[0] = srcBuf; ++ ++ cinfo.err = jpeg_std_error(&jerr); ++ jpeg_create_compress(&cinfo); ++ ++ cinfo.image_width = w; ++ cinfo.image_height = h; ++ cinfo.input_components = 3; ++ cinfo.in_color_space = JCS_RGB; ++ ++ jpeg_set_defaults(&cinfo); ++ jpeg_set_quality(&cinfo, quality, TRUE); ++ ++ JpegSetDstManager (&cinfo); ++ ++ jpeg_start_compress(&cinfo, TRUE); ++ ++ for (dy = 0; dy < h; dy++) { ++ PrepareRowForJpeg(cl->pScreen, srcBuf, x, y + dy, w); ++ jpeg_write_scanlines(&cinfo, rowPointer, 1); ++ if (jpegError) ++ break; ++ } ++ ++ if (!jpegError) ++ jpeg_finish_compress(&cinfo); ++ ++ jpeg_destroy_compress(&cinfo); ++ xfree((char *)srcBuf); ++ ++ if (jpegError) ++ return SendFullColorRect(cl, w, h); ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightJpeg << 4); ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ ++ return SendCompressedData(cl, jpegDstDataLen); ++} ++ ++static void ++PrepareRowForJpeg(pScreen, dst, x, y, count) ++ ScreenPtr pScreen; ++ CARD8 *dst; ++ int x, y, count; ++{ ++ VNCSCREENPTR(pScreen); ++ if (pVNC->rfbServerFormat.bitsPerPixel == 32) { ++ if ( pVNC->rfbServerFormat.redMax == 0xFF && ++ pVNC->rfbServerFormat.greenMax == 0xFF && ++ pVNC->rfbServerFormat.blueMax == 0xFF ) { ++ PrepareRowForJpeg24(pScreen, dst, x, y, count); ++ } else { ++ PrepareRowForJpeg32(pScreen, dst, x, y, count); ++ } ++ } else { ++ /* 16 bpp assumed. */ ++ PrepareRowForJpeg16(pScreen, dst, x, y, count); ++ } ++} ++ ++static void ++PrepareRowForJpeg24(pScreen, dst, x, y, count) ++ ScreenPtr pScreen; ++ CARD8 *dst; ++ int x, y, count; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *fbptr; ++ CARD32 pix; ++ ++ fbptr = (CARD32 *) ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * 4]; ++ ++ while (count--) { ++ pix = *fbptr++; ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift); ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift); ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift); ++ } ++} ++ ++#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \ ++ \ ++static void \ ++PrepareRowForJpeg##bpp(pScreen, dst, x, y, count) \ ++ ScreenPtr pScreen; \ ++ CARD8 *dst; \ ++ int x, y, count; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp *fbptr; \ ++ CARD##bpp pix; \ ++ int inRed, inGreen, inBlue; \ ++ \ ++ fbptr = (CARD##bpp *) \ ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + \ ++ x * (bpp / 8)]; \ ++ \ ++ while (count--) { \ ++ pix = *fbptr++; \ ++ \ ++ inRed = (int) \ ++ (pix >> pVNC->rfbServerFormat.redShift & pVNC->rfbServerFormat.redMax); \ ++ inGreen = (int) \ ++ (pix >> pVNC->rfbServerFormat.greenShift & pVNC->rfbServerFormat.greenMax); \ ++ inBlue = (int) \ ++ (pix >> pVNC->rfbServerFormat.blueShift & pVNC->rfbServerFormat.blueMax); \ ++ \ ++ *dst++ = (CARD8)((inRed * 255 + pVNC->rfbServerFormat.redMax / 2) / \ ++ pVNC->rfbServerFormat.redMax); \ ++ *dst++ = (CARD8)((inGreen * 255 + pVNC->rfbServerFormat.greenMax / 2) / \ ++ pVNC->rfbServerFormat.greenMax); \ ++ *dst++ = (CARD8)((inBlue * 255 + pVNC->rfbServerFormat.blueMax / 2) / \ ++ pVNC->rfbServerFormat.blueMax); \ ++ } \ ++} ++ ++DEFINE_JPEG_GET_ROW_FUNCTION(16) ++DEFINE_JPEG_GET_ROW_FUNCTION(32) ++ ++/* ++ * Destination manager implementation for JPEG library. ++ */ ++ ++static void ++JpegInitDestination(j_compress_ptr cinfo) ++{ ++ jpegError = FALSE; ++ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf; ++ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize; ++} ++ ++static boolean ++JpegEmptyOutputBuffer(j_compress_ptr cinfo) ++{ ++ jpegError = TRUE; ++ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf; ++ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize; ++ ++ return TRUE; ++} ++ ++static void ++JpegTermDestination(j_compress_ptr cinfo) ++{ ++ jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer; ++} ++ ++static void ++JpegSetDstManager(j_compress_ptr cinfo) ++{ ++ jpegDstManager.init_destination = JpegInitDestination; ++ jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer; ++ jpegDstManager.term_destination = JpegTermDestination; ++ cinfo->dest = &jpegDstManager; ++} ++ +diff --git a/hw/vnc/translate.c b/hw/vnc/translate.c +new file mode 100644 +index 0000000..eb9bcb0 +--- /dev/null ++++ b/hw/vnc/translate.c +@@ -0,0 +1,496 @@ ++/* ++ * translate.c - translate between different pixel formats ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++#if XFREE86VNC ++#include ++#endif ++ ++static void PrintPixelFormat(rfbPixelFormat *pf); ++static Bool rfbSetClientColourMapBGR233(); ++ ++Bool rfbEconomicTranslate = FALSE; ++ ++/* ++ * Some standard pixel formats. ++ */ ++ ++static const rfbPixelFormat BGR233Format = { ++ 8, 8, 0, 1, 7, 7, 3, 0, 3, 6 ++}; ++ ++ ++/* ++ * Macro to compare pixel formats. ++ */ ++ ++#define PF_EQ(x,y) \ ++ ((x.bitsPerPixel == y.bitsPerPixel) && \ ++ (x.depth == y.depth) && \ ++ ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \ ++ (x.trueColour == y.trueColour) && \ ++ (!x.trueColour || ((x.redMax == y.redMax) && \ ++ (x.greenMax == y.greenMax) && \ ++ (x.blueMax == y.blueMax) && \ ++ (x.redShift == y.redShift) && \ ++ (x.greenShift == y.greenShift) && \ ++ (x.blueShift == y.blueShift)))) ++ ++#define CONCAT2(a,b) a##b ++#define CONCAT2E(a,b) CONCAT2(a,b) ++#define CONCAT4(a,b,c,d) a##b##c##d ++#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d) ++ ++#define OUT 8 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++#define OUT 16 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++#define OUT 32 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++typedef void (*rfbInitTableFnType)(ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out); ++ ++rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = { ++ rfbInitTrueColourSingleTable8, ++ rfbInitTrueColourSingleTable16, ++ rfbInitTrueColourSingleTable32 ++}; ++ ++rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = { ++ rfbInitColourMapSingleTable8, ++ rfbInitColourMapSingleTable16, ++ rfbInitColourMapSingleTable32 ++}; ++ ++rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = { ++ rfbInitTrueColourRGBTables8, ++ rfbInitTrueColourRGBTables16, ++ rfbInitTrueColourRGBTables32 ++}; ++ ++rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = { ++ { rfbTranslateWithSingleTable8to8, ++ rfbTranslateWithSingleTable8to16, ++ rfbTranslateWithSingleTable8to32 }, ++ { rfbTranslateWithSingleTable16to8, ++ rfbTranslateWithSingleTable16to16, ++ rfbTranslateWithSingleTable16to32 }, ++ { rfbTranslateWithSingleTable32to8, ++ rfbTranslateWithSingleTable32to16, ++ rfbTranslateWithSingleTable32to32 } ++}; ++ ++rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = { ++ { rfbTranslateWithRGBTables8to8, ++ rfbTranslateWithRGBTables8to16, ++ rfbTranslateWithRGBTables8to32 }, ++ { rfbTranslateWithRGBTables16to8, ++ rfbTranslateWithRGBTables16to16, ++ rfbTranslateWithRGBTables16to32 }, ++ { rfbTranslateWithRGBTables32to8, ++ rfbTranslateWithRGBTables32to16, ++ rfbTranslateWithRGBTables32to32 } ++}; ++ ++ ++ ++/* ++ * rfbTranslateNone is used when no translation is required. ++ */ ++ ++void ++rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, int bytesBetweenInputLines, ++ int width, int height, int x, int y) ++{ ++ VNCSCREENPTR(pScreen); ++ int bytesPerOutputLine = width * (out->bitsPerPixel / 8); ++ ++ if (pVNC->useGetImage) { ++ DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum]; ++ ++ /* catch all for other TranslateNone cases - hextile, corre, rre, etc.*/ ++ (*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, optr); ++ } else { ++ while (height > 0) { ++ memcpy(optr, iptr, bytesPerOutputLine); ++ iptr += bytesBetweenInputLines; ++ optr += bytesPerOutputLine; ++ height--; ++ } ++ } ++} ++ ++ ++/* ++ * rfbSetTranslateFunction sets the translation function. ++ */ ++ ++Bool ++rfbSetTranslateFunction(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbLog("Pixel format for client %s:\n",cl->host); ++ PrintPixelFormat(&cl->format); ++ ++ /* ++ * Check that bits per pixel values are valid ++ */ ++ ++ if ((pVNC->rfbServerFormat.bitsPerPixel != 8) && ++ (pVNC->rfbServerFormat.bitsPerPixel != 16) && ++ (pVNC->rfbServerFormat.bitsPerPixel != 32)) ++ { ++ rfbLog("%s: server bits per pixel not 8, 16 or 32\n", ++ "rfbSetTranslateFunction"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if ((cl->format.bitsPerPixel != 8) && ++ (cl->format.bitsPerPixel != 16) && ++ (cl->format.bitsPerPixel != 32)) ++ { ++ rfbLog("%s: client bits per pixel not 8, 16 or 32\n", ++ "rfbSetTranslateFunction"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if (!pVNC->rfbServerFormat.trueColour && ++ (pVNC->rfbServerFormat.bitsPerPixel != 8) && ++#if XFREE86VNC ++ (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) { ++#else ++ (pVNC->rfbInstalledColormap->class == PseudoColor)) { ++#endif ++ rfbLog("rfbSetTranslateFunction: server has colour map " ++ "but %d-bit - can only cope with 8-bit colour maps\n", ++ pVNC->rfbServerFormat.bitsPerPixel); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if (!cl->format.trueColour && ++ (cl->format.bitsPerPixel != 8) && ++#if XFREE86VNC ++ (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) { ++#else ++ (pVNC->rfbInstalledColormap->class == PseudoColor) ) { ++#endif ++ rfbLog("rfbSetTranslateFunction: client has colour map " ++ "but %d-bit - can only cope with 8-bit colour maps\n", ++ cl->format.bitsPerPixel); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ /* ++ * bpp is valid, now work out how to translate ++ */ ++ ++ if (!cl->format.trueColour) { ++ ++ /* ? -> colour map */ ++ ++ if (!pVNC->rfbServerFormat.trueColour) { ++ ++ /* colour map -> colour map */ ++ ++#if XFREE86VNC ++ if (miInstalledMaps[cl->pScreen->myNum]->class == DirectColor) { ++#else ++ if (pVNC->rfbInstalledColormap->class == DirectColor) { ++#endif ++ rfbLog("rfbSetTranslateFunction: client is %d-bit DirectColor," ++ " client has colour map\n",cl->format.bitsPerPixel); ++ ++ cl->translateFn = rfbTranslateWithRGBTablesFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16]) ++ (cl->pScreen, &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ return rfbSetClientColourMap(cl, 0, 0); ++ ++ /* PseudoColor colormap */ ++ ++ } else { ++ rfbLog("rfbSetTranslateFunction: both 8-bit colour map: " ++ "no translation needed\n"); ++ cl->translateFn = rfbTranslateNone; ++ return rfbSetClientColourMap(cl, 0, 0); ++ } ++ } ++ ++ /* ++ * truecolour -> colour map ++ * ++ * Set client's colour map to BGR233, then effectively it's ++ * truecolour as well ++ */ ++ ++ if (!rfbSetClientColourMapBGR233(cl)) ++ return FALSE; ++ ++ cl->format = BGR233Format; ++ } ++ ++ /* ? -> truecolour */ ++ ++ if (!pVNC->rfbServerFormat.trueColour) { ++ ++ /* colour map -> truecolour */ ++ ++ rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour," ++ " server has colour map\n",cl->format.bitsPerPixel); ++ ++ cl->translateFn = rfbTranslateWithSingleTableFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ return rfbSetClientColourMap(cl, 0, 0); ++ } ++ ++ /* truecolour -> truecolour */ ++ ++ if (PF_EQ(cl->format,pVNC->rfbServerFormat)) { ++ ++ /* client & server the same */ ++ ++ rfbLog(" no translation needed\n"); ++ cl->translateFn = rfbTranslateNone; ++ return TRUE; ++ } ++ ++ if ((pVNC->rfbServerFormat.bitsPerPixel < 16) || ++ (!rfbEconomicTranslate && (pVNC->rfbServerFormat.bitsPerPixel == 16))) { ++ ++ /* we can use a single lookup table for <= 16 bpp */ ++ ++ cl->translateFn = rfbTranslateWithSingleTableFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourSingleTableFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ } else { ++ ++ /* otherwise we use three separate tables for red, green and blue */ ++ ++ cl->translateFn = rfbTranslateWithRGBTablesFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourRGBTablesFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's ++ * just like an 8-bit BGR233 true colour client. ++ */ ++ ++static Bool ++rfbSetClientColourMapBGR233(cl) ++ rfbClientPtr cl; ++{ ++ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; ++ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; ++ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); ++ int i, len; ++ int r, g, b; ++ ++ if (cl->format.bitsPerPixel != 8) { ++ rfbLog("%s: client not 8 bits per pixel\n", ++ "rfbSetClientColourMapBGR233"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ scme->type = rfbSetColourMapEntries; ++ ++ scme->firstColour = Swap16IfLE(0); ++ scme->nColours = Swap16IfLE(256); ++ ++ len = sz_rfbSetColourMapEntriesMsg; ++ ++ i = 0; ++ ++ for (b = 0; b < 4; b++) { ++ for (g = 0; g < 8; g++) { ++ for (r = 0; r < 8; r++) { ++ rgb[i++] = Swap16IfLE(r * 65535 / 7); ++ rgb[i++] = Swap16IfLE(g * 65535 / 7); ++ rgb[i++] = Swap16IfLE(b * 65535 / 3); ++ } ++ } ++ } ++ ++ len += 256 * 3 * 2; ++ ++ if (WriteExact(cl->sock, buf, len) < 0) { ++ rfbLogPerror("rfbSetClientColourMapBGR233: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* ++ * rfbSetClientColourMap is called to set the client's colour map. If the ++ * client is a true colour client, we simply update our own translation table ++ * and mark the whole screen as having been modified. ++ */ ++ ++Bool ++rfbSetClientColourMap(cl, firstColour, nColours) ++ rfbClientPtr cl; ++ int firstColour; ++ int nColours; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ BoxRec box; ++ ++ if (nColours == 0) { ++#if XFREE86VNC ++ nColours = miInstalledMaps[cl->pScreen->myNum]->pVisual->ColormapEntries; ++#else ++ nColours = pVNC->rfbInstalledColormap->pVisual->ColormapEntries; ++#endif ++ } ++ ++ if (pVNC->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) { ++ return TRUE; ++ } ++ ++ if (cl->format.trueColour) { ++ (*rfbInitColourMapSingleTableFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ REGION_UNINIT(cl->pScreen,&cl->modifiedRegion); ++ box.x1 = box.y1 = 0; ++ box.x2 = pVNC->width; ++ box.y2 = pVNC->height; ++ REGION_INIT(cl->pScreen,&cl->modifiedRegion,&box,0); ++ ++ return TRUE; ++ } ++ ++ return rfbSendSetColourMapEntries(cl, firstColour, nColours); ++} ++ ++ ++/* ++ * rfbSetClientColourMaps sets the colour map for each RFB client. ++ */ ++ ++void ++rfbSetClientColourMaps(firstColour, nColours) ++ int firstColour; ++ int nColours; ++{ ++ rfbClientPtr cl, nextCl; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ rfbSetClientColourMap(cl, firstColour, nColours); ++ } ++} ++ ++ ++static void ++PrintPixelFormat(pf) ++ rfbPixelFormat *pf; ++{ ++ if (pf->bitsPerPixel == 1) { ++ rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n", ++ (pf->bigEndian ? "most" : "least")); ++ } else { ++ rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth, ++ ((pf->bitsPerPixel == 8) ? "" ++ : (pf->bigEndian ? ", big endian" : ", little endian"))); ++ if (pf->trueColour) { ++ rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n", ++ pf->redMax, pf->greenMax, pf->blueMax, ++ pf->redShift, pf->greenShift, pf->blueShift); ++ } else { ++ rfbLog(" uses a colour map (not true colour).\n"); ++ } ++ } ++} +diff --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..a823253 +--- /dev/null ++++ b/hw/vnc/vncext.c +@@ -0,0 +1,794 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include "rfb.h" ++ ++#include "extnsionst.h" ++#define _VNC_SERVER ++#include ++#ifdef XFree86LOADER ++#include "xf86Module.h" ++#endif ++ ++#include ++#include ++#include ++#include ++ ++int VncSelectNotify(ClientPtr client, BOOL onoff); ++void VncExtensionInit(void); ++ ++static int VncErrorBase; /* first vnc error number */ ++static int VncEventBase; /* first vnc event number */ ++ ++#define USE_ORIG_RES_CODE 0 ++ ++#if USE_ORIG_RES_CODE ++unsigned long VncResourceGeneration = 0; ++ ++static RESTYPE VncNotifyList; ++ ++static XID faked; ++ ++typedef struct _VncNotifyListRec { ++ struct _VncNotifyListRec *next; ++ ClientPtr client; ++} VncNotifyListRec, *VncNotifyListPtr; ++#endif ++ ++ ++/** ++ * Each X client that uses libVnc to talk to this extension will get ++ * recorded by one of these records. ++ */ ++typedef struct _VncClientRec { ++ ClientPtr client; ++ struct _VncClientRec *next; ++ XID fakeID; ++ RESTYPE res; ++} VncClientRec, *VncClientRecPtr; ++ ++static VncClientRecPtr ClientsList = NULL; ++ ++ ++/** ++ * Remove client record from list ++ */ ++static void ++VncRemoveClientRecord(ClientPtr client) ++{ ++ /* XXX need 'deleteresource' flag? */ ++ VncClientRecPtr p = ClientsList, prev = NULL; ++ rfbLog("%s client %p\n", __func__, (void *) client); ++ while (p) { ++ if (p->client == client) { ++ /* remove this one */ ++ if (prev) ++ prev->next = p->next; ++ else ++ ClientsList = p->next; ++ xfree(p); ++ return; ++ } ++ prev = p; ++ p = p->next; ++ } ++} ++ ++ ++/** ++ * This callback will be called by X's resource manager to delete the ++ * given resource. We create one resource for each client. When X ++ * deletes the resource, we know the client is going away. ++ */ ++static int ++VncDestroyClientResourceCallback(pointer pn, XID id) ++{ ++ VncClientRecPtr rec = (VncClientRecPtr) pn; ++ VncRemoveClientRecord(rec->client); ++ return Success; ++} ++ ++ ++/** ++ * Add a client record to the list of clients (unless already in list). ++ * We'll create a new, unique resource for this client. This is used ++ * to detect when an X client goes away. ++ */ ++static void ++VncSaveClientRecord(ClientPtr client) ++{ ++ VncClientRecPtr rec = ClientsList; ++ ++ rfbLog("%s saving client %p\n", __func__, (void *) client); ++ ++ /* look if already in list */ ++ while (rec) { ++ if (rec->client == client) { ++ return; /* already in list */ ++ } ++ rec = rec->next; ++ } ++ ++ /* allocate new client record */ ++ rec = (VncClientRecPtr) xalloc(sizeof(VncClientRec)); ++ if (rec) { ++ rec->client = client; ++ rec->fakeID = FakeClientID(client->index); ++ rec->res = CreateNewResourceType(VncDestroyClientResourceCallback); ++ if (!AddResource(rec->fakeID, rec->res, rec)) { ++ xfree(rec); ++ } ++ ++ /* insert at head of list */ ++ rec->next = ClientsList; ++ ClientsList = rec; ++ } ++} ++ ++ ++ ++static int ++ProcVncQueryVersion(ClientPtr client) ++{ ++ xVncQueryVersionReply rep; ++ ++ REQUEST_SIZE_MATCH(xVncQueryVersionReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ rep.majorVersion = VNC_MAJOR_VERSION; ++ rep.minorVersion = VNC_MINOR_VERSION; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.majorVersion, n); ++ swaps(&rep.minorVersion, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncQueryVersionReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncQueryVersion */ ++ ++static int ++ProcVncConnection(ClientPtr client) ++{ ++ REQUEST(xVncConnectionReq); ++ xVncConnectionReply rep; ++ ++ rfbUserAllow( stuff->sock, stuff->accept ); ++ ++ REQUEST_SIZE_MATCH(xVncConnectionReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ rep.sock = 0; ++ rep.accept = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.sock, n); ++ swaps(&rep.accept, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncConnectionReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncConnection */ ++ ++static int ++ProcVncSelectNotify(ClientPtr client) ++{ ++ REQUEST(xVncSelectNotifyReq); ++ xVncSelectNotifyReply rep; ++ ++ VncSelectNotify(client, stuff->onoff); ++ ++ REQUEST_SIZE_MATCH(xVncSelectNotifyReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncSelectNotifyReply), ++ (char *)&rep); ++ return (client->noClientException); ++ ++} ++ ++static int ++ProcVncListConnections(ClientPtr client) ++{ ++ xVncListConnectionsReply rep; ++ rfbClientPtr cl; ++ int count = 0; ++ struct in_addr ipaddress; ++ xVncConnectionListInfo Info; ++ ++ /* count connections */ ++ for (cl = rfbClientHead; cl; cl = cl->next) ++#ifdef CHROMIUM ++ /* ++ * Fix this, as it should be generic, but we're only using it ++ * for Chromium at the moment, so we only list the connections ++ * that have a valid chromium encoding. We should be able to list ++ * any type requested. FIXME! XXXX ++ * See furthur down this function too!!! ++ */ ++ if (cl->enableChromiumEncoding) ++#endif ++ count++; ++ ++ REQUEST_SIZE_MATCH(xVncListConnectionsReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.count = count; ++ rep.length = count * sizeof(xVncConnectionListInfo) >> 2; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.count, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncListConnectionsReply), ++ (char *)&rep); ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++#ifdef CHROMIUM ++ /* ++ * Fix this, as it should be generic, but we're only using it ++ * for Chromium at the moment, so we only list the connections ++ * that have a valid chromium encoding. We should be able to list ++ * any type requested. FIXME! XXXX ++ */ ++ if (!cl->enableChromiumEncoding) ++ continue; ++#endif ++ inet_aton(cl->host, &ipaddress); ++ memcpy(&Info, &ipaddress, sizeof(struct in_addr)); ++ WriteToClient(client, SIZEOF(xVncConnectionListInfo), (char*)&Info); ++ } ++ ++ return (client->noClientException); ++} /* ProcVncListConnections */ ++ ++#ifdef CHROMIUM ++static int ++ProcVncChromiumStart(ClientPtr client) ++{ ++ REQUEST(xVncChromiumStartReq); ++ xVncChromiumStartReply rep; ++ ++ rfbSendChromiumStart(stuff->ipaddress, stuff->crServerPort, stuff->mothershipPort); ++ ++ REQUEST_SIZE_MATCH(xVncChromiumStartReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncChromiumStartReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncChromiumStart */ ++ ++static int ++ProcVncChromiumMonitor(ClientPtr client) ++{ ++ REQUEST(xVncChromiumMonitorReq); ++ xVncChromiumMonitorReply rep; ++ ++ rfbChromiumMonitorWindowID(stuff->cr_windowid, stuff->windowid); ++ ++ REQUEST_SIZE_MATCH(xVncChromiumMonitorReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncChromiumMonitorReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncChromiumMonitor */ ++#endif /* CHROMIUM */ ++ ++static int ++ProcVncDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ ++ switch (stuff->data) ++ { ++ case X_VncQueryVersion: ++ return ProcVncQueryVersion(client); ++ case X_VncSelectNotify: ++ return ProcVncSelectNotify(client); ++ case X_VncConnection: ++ return ProcVncConnection(client); ++ case X_VncListConnections: ++ return ProcVncListConnections(client); ++#ifdef CHROMIUM ++ case X_VncChromiumStart: ++ return ProcVncChromiumStart(client); ++ case X_VncChromiumMonitor: ++ return ProcVncChromiumMonitor(client); ++#endif ++ default: ++ return BadRequest; ++ } ++} /* ProcVncDispatch */ ++ ++static int ++SProcVncQueryVersion(ClientPtr client) ++{ ++ REQUEST(xVncQueryVersionReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncQueryVersionReq); ++ swaps(&stuff->majorVersion, n); ++ swaps(&stuff->minorVersion,n); ++ return ProcVncQueryVersion(client); ++} /* SProcVncQueryVersion */ ++ ++static int ++SProcVncSelectNotify(ClientPtr client) ++{ ++ REQUEST(xVncSelectNotifyReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncSelectNotifyReq); ++ return ProcVncSelectNotify(client); ++} /* SProcVncSelectNotify */ ++ ++static int ++SProcVncListConnections(ClientPtr client) ++{ ++ REQUEST(xVncListConnectionsReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncListConnectionsReq); ++ return ProcVncListConnections(client); ++} /* SProcVncListConnections */ ++ ++#ifdef CHROMIUM ++static int ++SProcVncChromiumStart(ClientPtr client) ++{ ++ REQUEST(xVncChromiumStartReq); ++ register char n; ++ ++ swaps(&stuff->ipaddress, n); ++ swaps(&stuff->crServerPort, n); ++ swaps(&stuff->mothershipPort, n); ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncChromiumStartReq); ++ return ProcVncChromiumStart(client); ++} /* SProcVncChromiumStart */ ++ ++static int ++SProcVncChromiumMonitor(ClientPtr client) ++{ ++ REQUEST(xVncChromiumMonitorReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ swaps(&stuff->windowid, n); ++ swaps(&stuff->cr_windowid, n); ++ REQUEST_SIZE_MATCH(xVncChromiumMonitorReq); ++ return ProcVncChromiumMonitor(client); ++} /* SProcVncChromiumMonitor */ ++#endif /* CHROMIUM */ ++ ++static int ++SProcVncConnection(ClientPtr client) ++{ ++ REQUEST(xVncConnectionReq); ++ register char n; ++ ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncConnectionReq); ++ swaps(&stuff->sock, n); ++ swaps(&stuff->accept,n); ++ return ProcVncConnection(client); ++} /* SProcVncConnection */ ++ ++static int ++SProcVncDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ ++ switch (stuff->data) ++ { ++ case X_VncQueryVersion: ++ return SProcVncQueryVersion(client); ++ case X_VncSelectNotify: ++ return SProcVncSelectNotify(client); ++ case X_VncConnection: ++ return SProcVncConnection(client); ++ case X_VncListConnections: ++ return SProcVncListConnections(client); ++#ifdef CHROMIUM ++ case X_VncChromiumStart: ++ return SProcVncChromiumStart(client); ++ case X_VncChromiumMonitor: ++ return SProcVncChromiumMonitor(client); ++#endif ++ default: ++ return BadRequest; ++ } ++} /* SProcVncDispatch */ ++ ++static void ++SwapVncConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++ ++#ifdef CHROMIUM ++static void ++SwapVncChromiumConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++#endif ++ ++static void ++SwapVncDisconnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++ ++int ++GenerateVncConnectedEvent(int sock) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++#else ++ VncClientRecPtr pn = ClientsList; ++#endif ++ ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncConnectedEvent conn; ++ SOCKLEN_T peer_len; ++ struct sockaddr_in peer; ++ ++ conn.type = VncEventBase + XVncConnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ ++ peer_len = sizeof(peer); ++ if (getpeername(sock, (struct sockaddr *) &peer, &peer_len) == -1) ++ conn.ipaddress = 0; ++ else ++ conn.ipaddress = (CARD32)peer.sin_addr.s_addr; ++ ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++ ++ ++ ++#ifdef CHROMIUM ++int ++GenerateVncChromiumConnectedEvent(int sock) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr pn; ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++#else ++ VncClientRecPtr pn = ClientsList; ++#endif ++ rfbLog("Enter GenerateVncChromiumConnectedEvent\n"); ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncConnectedEvent conn; ++ SOCKLEN_T peer_len; ++ struct sockaddr_in peer; ++ ++ rfbLog("Sending XVncChromiumConnected to client %p\n", ++ (void *) pn->client); ++ ++ conn.type = VncEventBase + XVncChromiumConnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ ++ peer_len = sizeof(peer); ++ if (getpeername(sock, (struct sockaddr *)&peer, &peer_len) == -1) ++ conn.ipaddress = 0; ++ else ++ conn.ipaddress = (CARD32)peer.sin_addr.s_addr; ++ ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ return 1; ++} ++#endif /* CHROMIUM */ ++ ++ ++int ++GenerateVncDisconnectedEvent(int sock) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++#else ++ VncClientRecPtr pn = ClientsList; ++#endif ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncDisconnectedEvent conn; ++ conn.type = VncEventBase + XVncDisconnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++ ++static void ++VncResetProc(ExtensionEntry *extEntry) ++{ ++} /* VncResetProc */ ++ ++ ++ ++/** ++ * When the app calls libVnc's XVncSelectNotify() we wind up here. ++ * Either add or remove 'client' from the VncNotifyList depending on 'onoff'. ++ */ ++int ++VncSelectNotify(ClientPtr client, BOOL onoff) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr head, newRec, tmp, freeRec = NULL; ++ ++ rfbLog("%s client %p onoff=%d\n", __func__, (void *) client, (int) onoff); ++ if (!faked) ++ faked = FakeClientID(client->index); ++#else ++ /* ignore onoff param */ ++ VncSaveClientRecord(client); ++#endif ++ ++#if USE_ORIG_RES_CODE ++ /* Get the first VncNotifyListPtr */ ++ head = (VncNotifyListPtr) LookupIDByType(faked, VncNotifyList); ++ ++ /* search list for this client */ ++ tmp = head; ++ while (tmp) { ++ if (tmp->client == client) { ++ /* found client! */ ++ if (!onoff) ++ tmp->client = NULL; ++ return Success; ++ } ++ if (!tmp->client) ++ freeRec = tmp; /* save ptr to free record */ ++ tmp = tmp->next; ++ } ++ ++ /* if we get here, we didn't find client in the list */ ++ ++ if (!onoff) { ++ /* if turning off non-existing client, just return */ ++ return Success; ++ } ++ ++ /* OK, add new client to list now */ ++ ++ if (freeRec) { ++ /* re-using a free spot */ ++ freeRec->client = client; ++ return Success; ++ } ++ ++ /* need to allocate new node */ ++ if (!(newRec = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec)))) ++ return BadAlloc; ++ /* insert at head, just as AddResource() does!!! */ ++ newRec->next = head; ++ newRec->client = client; ++ if (!AddResource(faked, VncNotifyList, newRec)) { ++ xfree(newRec); ++ return BadAlloc; ++ } ++#endif ++ return Success; ++} ++ ++ ++#if USE_ORIG_RES_CODE ++static int ++VncDestroyNotifyList(pointer pn, XID id) ++{ ++ VncNotifyListPtr cpn = (VncNotifyListPtr) pn; ++ rfbLog("%s client %p\n", __func__, (void *) cpn->client); ++ cpn->client = NULL; ++ return Success; ++} ++#endif ++ ++static Bool ++CreateResourceTypes(void) ++{ ++#if USE_ORIG_RES_CODE ++ if (VncResourceGeneration == serverGeneration) ++ return TRUE; ++ ++ VncResourceGeneration = serverGeneration; ++ ++ if (!(VncNotifyList = CreateNewResourceType(VncDestroyNotifyList))) { ++ ErrorF("CreateResourceTypes: failed to allocate vnc notify list resource.\n"); ++ return FALSE; ++ } ++#endif ++ return TRUE; ++} ++ ++ ++ ++#if XFREE86VNC ++static unsigned long vncCreateScreenResourcesIndex; ++static unsigned long vncExtGeneration = 0; ++extern Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart); ++ ++/* copied from miscrinit.c */ ++typedef struct ++{ ++ pointer pbits; /* pointer to framebuffer */ ++ int width; /* delta to add to a framebuffer addr to move one row down */ ++} miScreenInitParmsRec, *miScreenInitParmsPtr; ++ ++ ++static Bool ++vncCreateScreenResources(ScreenPtr pScreen) ++{ ++ int ret = TRUE; ++ CreateScreenResourcesProcPtr CreateScreenResources = ++ (CreateScreenResourcesProcPtr) ++ pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr; ++ miScreenInitParmsPtr pScrInitParms; ++ ++ pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; ++ ++ if ( pScreen->CreateScreenResources != vncCreateScreenResources ) { ++ /* Can't find hook we are hung on */ ++ xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, ++ "vncCreateScreenResources %p called when not in " ++ "pScreen->CreateScreenResources %p n", ++ (void *) vncCreateScreenResources, ++ (void *) pScreen->CreateScreenResources ); ++ } ++ ++ /* Now do our stuff */ ++ VNCInit(pScreen, pScrInitParms->pbits); ++ ++ /* Unhook this function ... */ ++ pScreen->CreateScreenResources = CreateScreenResources; ++ pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr = NULL; ++ ++ /* ... and call the previous CreateScreenResources fuction, if any */ ++ if (pScreen->CreateScreenResources) { ++ ret = (*pScreen->CreateScreenResources)(pScreen); ++ } ++ ++#ifdef DEBUG ++ ErrorF("vncCreateScreenResources() returns %d\n", ret); ++#endif ++ return ret; ++} ++#endif ++ ++ ++ ++void ++VncExtensionInit(void) ++{ ++ ExtensionEntry *extEntry; ++ ++#if XFREE86VNC ++ if (vncExtGeneration != serverGeneration) { ++ unsigned int i; ++ ++ vncExtGeneration = serverGeneration; ++ ++ if ( ((vncCreateScreenResourcesIndex = AllocateScreenPrivateIndex()) < 0) || ++ ((vncScreenPrivateIndex = AllocateScreenPrivateIndex()) < 0) || ++ ((rfbGCIndex = AllocateGCPrivateIndex()) < 0) ) ++ return; ++ ++ for (i = 0 ; i < screenInfo.numScreens; i++) ++ { ++ screenInfo.screens[i]->devPrivates[vncCreateScreenResourcesIndex].ptr ++ = (void*)(xf86Screens[i]->pScreen->CreateScreenResources); ++ xf86Screens[i]->pScreen->CreateScreenResources = vncCreateScreenResources; ++ } ++ ++ gethostname(rfbThisHost, 255); ++ } ++#endif ++ ++ if (!CreateResourceTypes()) ++ return; ++ ++ extEntry = AddExtension(VNC_EXTENSION_NAME, ++ XVncNumberEvents, XVncNumberErrors, ++ ProcVncDispatch, SProcVncDispatch, ++ VncResetProc, StandardMinorOpcode); ++ ++ VncErrorBase = extEntry->errorBase; ++ VncEventBase = extEntry->eventBase; ++ ++ EventSwapVector[VncEventBase + XVncConnected] = ++ (EventSwapPtr)SwapVncConnectedEvent; ++ EventSwapVector[VncEventBase + XVncDisconnected] = ++ (EventSwapPtr)SwapVncDisconnectedEvent; ++#ifdef CHROMIUM ++ EventSwapVector[VncEventBase + XVncChromiumConnected] = ++ (EventSwapPtr)SwapVncChromiumConnectedEvent; ++#endif ++} /* VncExtensionInit */ +diff --git a/hw/vnc/xistubs.c b/hw/vnc/xistubs.c +new file mode 100644 +index 0000000..be874f5 +--- /dev/null ++++ b/hw/vnc/xistubs.c +@@ -0,0 +1,319 @@ ++/* $Xorg: stubs.c,v 1.4 2001/02/09 02:04:35 xorgcvs Exp $ */ ++ ++/************************************************************ ++ ++Copyright 1989, 1998 The Open Group ++ ++Permission to use, copy, modify, distribute, and sell this software and its ++documentation for any purpose is hereby granted without fee, provided that ++the above copyright notice appear in all copies and that both that ++copyright notice and this permission notice appear in supporting ++documentation. ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of The Open Group shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from The Open Group. ++ ++Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. ++ ++ All Rights Reserved ++ ++Permission to use, copy, modify, and distribute this software and its ++documentation for any purpose and without fee is hereby granted, ++provided that the above copyright notice appear in all copies and that ++both that copyright notice and this permission notice appear in ++supporting documentation, and that the name of Hewlett-Packard not be ++used in advertising or publicity pertaining to distribution of the ++software without specific, written prior permission. ++ ++HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ++ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ++HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ++ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ++WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ++ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ++SOFTWARE. ++ ++********************************************************/ ++/* $XFree86: xc/programs/Xserver/Xi/stubs.c,v 3.3 2001/01/17 22:13:26 dawes Exp $ */ ++ ++/* ++ * stubs.c -- stub routines for the X server side of the XINPUT ++ * extension. This file is mainly to be used only as documentation. ++ * There is not much code here, and you can't get a working XINPUT ++ * server just using this. ++ * The Xvfb server uses this file so it will compile with the same ++ * object files as the real X server for a platform that has XINPUT. ++ * Xnest could do the same thing. ++ */ ++ ++#define NEED_EVENTS ++#include ++#include ++#include ++#include ++#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..2533a6b +--- /dev/null ++++ b/hw/vnc/zlib.c +@@ -0,0 +1,309 @@ ++/* ++ * zlib.c ++ * ++ * Routines to implement zlib based encoding (deflate). ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * For the latest source code, please check: ++ * ++ * http://www.developVNC.org/ ++ * ++ * or send email to feedback@developvnc.org. ++ */ ++ ++#include ++#include "rfb.h" ++ ++/* ++ * zlibBeforeBuf contains pixel data in the client's format. ++ * zlibAfterBuf contains the zlib (deflated) encoding version. ++ * If the zlib compressed/encoded version is ++ * larger than the raw data or if it exceeds zlibAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int zlibBeforeBufSize = 0; ++static char *zlibBeforeBuf = NULL; ++ ++static int zlibAfterBufSize = 0; ++static char *zlibAfterBuf = NULL; ++static int zlibAfterBufLen; ++ ++/* ++ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib ++ * rectangle encoding. ++ */ ++ ++Bool ++rfbSendOneRectEncodingZlib(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbZlibHeader hdr; ++ int deflateResult; ++ int previousOut; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize; ++ int maxCompSize; ++ ++ maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (zlibBeforeBufSize < maxRawSize) { ++ zlibBeforeBufSize = maxRawSize; ++ if (zlibBeforeBuf == NULL) ++ zlibBeforeBuf = (char *)xalloc(zlibBeforeBufSize); ++ else ++ zlibBeforeBuf = (char *)xrealloc(zlibBeforeBuf, zlibBeforeBufSize); ++ } ++ ++ /* zlib compression is not useful for very small data sets. ++ * So, we just send these raw without any compression. ++ */ ++ if (( w * h * (pVNC->bitsPerPixel / 8)) < ++ VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) { ++ ++ int result; ++ ++ /* The translation function (used also by the in raw encoding) ++ * requires 4/2/1 byte alignment in the output buffer (which is ++ * pVNC->updateBuf for the raw encoding) based on the bitsPerPixel of ++ * the viewer/client. This prevents SIGBUS errors on some ++ * architectures like SPARC, PARISC... ++ */ ++ if (( cl->format.bitsPerPixel > 8 ) && ++ ( pVNC->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ result = rfbSendRectEncodingRaw(cl, x, y, w, h); ++ ++ return result; ++ ++ } ++ ++ /* ++ * zlib requires output buffer to be slightly larger than the input ++ * buffer, in the worst case. ++ */ ++ maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12; ++ ++ if (zlibAfterBufSize < maxCompSize) { ++ zlibAfterBufSize = maxCompSize; ++ if (zlibAfterBuf == NULL) ++ zlibAfterBuf = (char *)xalloc(zlibAfterBufSize); ++ else ++ zlibAfterBuf = (char *)xrealloc(zlibAfterBuf, zlibAfterBufSize); ++ } ++ ++ /* ++ * Convert pixel data to client format. ++ */ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, zlibBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ cl->compStream.next_in = ( Bytef * )zlibBeforeBuf; ++ cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8); ++ cl->compStream.next_out = ( Bytef * )zlibAfterBuf; ++ cl->compStream.avail_out = maxCompSize; ++ cl->compStream.data_type = Z_BINARY; ++ ++ /* Initialize the deflation state. */ ++ if ( cl->compStreamInited == FALSE ) { ++ ++ cl->compStream.total_in = 0; ++ cl->compStream.total_out = 0; ++ cl->compStream.zalloc = Z_NULL; ++ cl->compStream.zfree = Z_NULL; ++ cl->compStream.opaque = Z_NULL; ++ ++ deflateInit2( &(cl->compStream), ++ cl->zlibCompressLevel, ++ Z_DEFLATED, ++ MAX_WBITS, ++ MAX_MEM_LEVEL, ++ Z_DEFAULT_STRATEGY ); ++ /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */ ++ /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */ ++ cl->compStreamInited = TRUE; ++ ++ } ++ ++ previousOut = cl->compStream.total_out; ++ ++ /* Perform the compression here. */ ++ deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH ); ++ ++ /* Find the total size of the resulting compressed data. */ ++ zlibAfterBufLen = cl->compStream.total_out - previousOut; ++ ++ if ( deflateResult != Z_OK ) { ++ rfbLog("zlib deflation error: %s\n", cl->compStream.msg); ++ return FALSE; ++ } ++ ++ /* Note that it is not possible to switch zlib parameters based on ++ * the results of the compression pass. The reason is ++ * that we rely on the compressor and decompressor states being ++ * in sync. Compressing and then discarding the results would ++ * cause lose of synchronization. ++ */ ++ ++ /* Update statics */ ++ cl->rfbRectanglesSent[rfbEncodingZlib]++; ++ cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbZlibHeader + zlibAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingZlib); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nBytes = Swap32IfLE(zlibAfterBufLen); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbZlibHeader); ++ pVNC->ublen += sz_rfbZlibHeader; ++ ++ for (i = 0; i < zlibAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > zlibAfterBufLen) { ++ bytesToCopy = zlibAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &zlibAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ ++} ++ ++ ++/* ++ * rfbSendRectEncodingZlib - send a given rectangle using one or more ++ * Zlib encoding rectangles. ++ */ ++ ++Bool ++rfbSendRectEncodingZlib(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int maxLines; ++ int linesRemaining; ++ rfbRectangle partialRect; ++ ++ partialRect.x = x; ++ partialRect.y = y; ++ partialRect.w = w; ++ partialRect.h = h; ++ ++ /* Determine maximum pixel/scan lines allowed per rectangle. */ ++ maxLines = ( ZLIB_MAX_SIZE(w) / w ); ++ ++ /* Initialize number of scan lines left to do. */ ++ linesRemaining = h; ++ ++ /* Loop until all work is done. */ ++ while ( linesRemaining > 0 ) { ++ ++ int linesToComp; ++ ++ if ( maxLines < linesRemaining ) ++ linesToComp = maxLines; ++ else ++ linesToComp = linesRemaining; ++ ++ partialRect.h = linesToComp; ++ ++ /* Encode (compress) and send the next rectangle. */ ++ if ( ! rfbSendOneRectEncodingZlib( cl, ++ partialRect.x, ++ partialRect.y, ++ partialRect.w, ++ partialRect.h )) { ++ ++ return FALSE; ++ } ++ ++ /* Technically, flushing the buffer here is not extrememly ++ * efficient. However, this improves the overall throughput ++ * of the system over very slow networks. By flushing ++ * the buffer with every maximum size zlib rectangle, we ++ * improve the pipelining usage of the server CPU, network, ++ * and viewer CPU components. Insuring that these components ++ * are working in parallel actually improves the performance ++ * seen by the user. ++ * Since, zlib is most useful for slow networks, this flush ++ * is appropriate for the desired behavior of the zlib encoding. ++ */ ++ if (( pVNC->ublen > 0 ) && ++ ( linesToComp == maxLines )) { ++ if (!rfbSendUpdateBuf(cl)) { ++ ++ return FALSE; ++ } ++ } ++ ++ /* Update remaining and incremental rectangle location. */ ++ linesRemaining -= linesToComp; ++ partialRect.y += linesToComp; ++ ++ } ++ ++ return TRUE; ++ ++} ++ ++ +diff --git a/hw/xfree86/Makefile.am b/hw/xfree86/Makefile.am +index 8665926..5ada381 100644 +--- a/hw/xfree86/Makefile.am ++++ b/hw/xfree86/Makefile.am +@@ -8,16 +8,20 @@ if DRI + XF86UTILS_SUBDIR = utils + endif + ++if XORG_VNC ++VNC_SUBDIR = vnc ++endif ++ + DOC_SUBDIR = doc + + SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support parser rac \ + ramdac shadowfb vbe vgahw xaa xf1bpp xf4bpp xf8_16bpp \ + xf8_32bpp loader scanpci dixmods exa \ +- $(DRI_SUBDIR) $(XF86UTILS_SUBDIR) $(DOC_SUBDIR) ++ $(DRI_SUBDIR) $(XF86UTILS_SUBDIR) $(VNC_SUBDIR) $(DOC_SUBDIR) + + DIST_SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support \ + parser rac ramdac shadowfb vbe vgahw xaa xf1bpp xf4bpp \ +- xf8_16bpp xf8_32bpp loader scanpci dixmods dri exa \ ++ xf8_16bpp xf8_32bpp loader scanpci dixmods dri vnc exa \ + utils doc + + bin_PROGRAMS = Xorg +diff --git a/hw/xfree86/dixmods/Makefile.am b/hw/xfree86/dixmods/Makefile.am +index 7b6afc4..dbc136e 100644 +--- a/hw/xfree86/dixmods/Makefile.am ++++ b/hw/xfree86/dixmods/Makefile.am +@@ -14,6 +14,10 @@ if XTRAP + DBEMOD = libdbe.la + endif + ++if XCLIPLIST ++XCLIPLISTMOD = libxcliplist.la ++endif ++ + module_LTLIBRARIES = libafb.la \ + libcfb.la \ + libcfb32.la \ +@@ -37,6 +41,7 @@ INCLUDES = @XORG_INCS@ \ + -I$(top_srcdir)/cfb \ + -I$(top_srcdir)/mfb \ + -I$(top_srcdir)/dbe \ ++ -I$(top_srcdir)/xcliplist \ + -I$(top_srcdir)/hw/xfree86/loader \ + -I$(top_srcdir)/miext/shadow \ + -I$(top_srcdir)/GL/glx +@@ -61,6 +66,10 @@ libdbe_la_LDFLAGS = -avoid-version + libdbe_la_LIBADD = $(top_builddir)/dbe/libdbe.la + libdbe_la_SOURCES = dbemodule.c + ++libxcliplist_la_LDFLAGS = -avoid-version ++libxcliplist_la_LIBADD = $(top_builddir)/xcliplist/libxcliplist.la ++libxcliplist_la_SOURCES = $(top_srcdir)/xcliplist/cliplistmod.c ++ + libfb_la_LDFLAGS = -avoid-version + libfb_la_LIBADD = $(top_builddir)/fb/libfb.la + libfb_la_SOURCES = $(top_builddir)/fb/fbcmap.c fbmodule.c +diff --git a/hw/xfree86/vnc/Makefile.am b/hw/xfree86/vnc/Makefile.am +new file mode 100644 +index 0000000..432e9b0 +--- /dev/null ++++ b/hw/xfree86/vnc/Makefile.am +@@ -0,0 +1,45 @@ ++libvnc_la_LTLIBRARIES = libvnc.la ++libvnc_la_CFLAGS = -I$(top_srcdir)/hw/xfree86/common \ ++ -I$(top_srcdir)/hw/xfree86/os-support \ ++ -I$(top_srcdir)/hw/xfree86/os-support/bus \ ++ -I$(top_srcdir)/hw/xfree86/ramdac \ ++ -I$(top_srcdir)/GL/glx \ ++ -I$(top_srcdir)/GL/include \ ++ -I$(top_builddir)/GL/include \ ++ -I@MESA_SOURCE@/include \ ++ -DHAVE_XORG_CONFIG_H \ ++ -DXFree86LOADER \ ++ -DXFREE86VNC=1 \ ++ -DCHROMIUM=1 \ ++ @LIBDRM_CFLAGS@ \ ++ @GL_CFLAGS@ ++ ++# @MODULE_DEFINES@ ++# @LOADER_DEFINES@ ++ ++libvnc_la_LDFLAGS = -module -avoid-version ++libvnc_ladir = $(moduledir)/extensions ++libvnc_la_SOURCES = \ ++ auth.c \ ++ cmap.c \ ++ corre.c \ ++ cursor.c \ ++ cutpaste.c \ ++ draw.c \ ++ hextile.c \ ++ httpd.c \ ++ kbdptr.c \ ++ loginauth.c \ ++ rfbkeyb.c \ ++ rfbmouse.c \ ++ rfbserver.c \ ++ rre.c \ ++ sockets.c \ ++ stats.c \ ++ tight.c \ ++ translate.c \ ++ vncext.c \ ++ vncInit.c \ ++ zlib.c ++ ++#sdk_HEADERS = vncint.h +diff --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/auth.c b/hw/xfree86/vnc/auth.c +new file mode 100644 +index 0000000..706db55 +--- /dev/null ++++ b/hw/xfree86/vnc/auth.c +@@ -0,0 +1,563 @@ ++/* ++ * auth.c - deal with authentication. ++ * ++ * This file implements authentication when setting up an RFB connection. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2003-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "rfb.h" ++#include "windowstr.h" ++ ++static void rfbSendSecurityType(rfbClientPtr cl, int securityType); ++static void rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType); ++static void rfbSendTunnelingCaps(rfbClientPtr cl); ++static void rfbSendAuthCaps(rfbClientPtr cl); ++static void rfbVncAuthSendChallenge(rfbClientPtr cl); ++ ++/* ++ * rfbAuthNewClient is called right after negotiating the protocol ++ * version. Depending on the protocol version, we send either a code ++ * for authentication scheme to be used (protocol 3.3), or a list of ++ * possible "security types" (protocol 3.7). ++ */ ++ ++void ++rfbAuthNewClient(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int securityType = rfbSecTypeInvalid; ++ ++ if ((!pVNC->rfbAuthPasswdFile && !pVNC->loginAuthEnabled) || cl->reverseConnection) { ++ securityType = rfbSecTypeNone; ++ } else { ++ if (rfbAuthIsBlocked(cl)) { ++ rfbLog("Too many authentication failures - client rejected\n"); ++ rfbClientConnFailed(cl, "Too many authentication failures"); ++ return; ++ } ++ if (pVNC->rfbAuthPasswdFile) ++ securityType = rfbSecTypeVncAuth; ++ } ++ ++ if (cl->protocol_minor_ver < 7) { ++ /* Make sure we use only RFB 3.3 compatible security types. */ ++ if (securityType == rfbSecTypeInvalid) { ++ rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n"); ++ rfbClientConnFailed(cl, "Your viewer cannot handle required " ++ "authentication methods"); ++ return; ++ } ++ rfbSendSecurityType(cl, securityType); ++ } else { ++ /* Here it's ok when securityType is set to rfbSecTypeInvalid. */ ++ rfbSendSecurityTypeList(cl, securityType); ++ } ++} ++ ++ ++/* ++ * Tell the client what security type will be used (protocol 3.3). ++ */ ++ ++static void ++rfbSendSecurityType(cl, securityType) ++ rfbClientPtr cl; ++ int securityType; ++{ ++ CARD32 value32; ++ ++ /* Send the value. */ ++ value32 = Swap32IfLE(securityType); ++ if (WriteExact(cl->sock, (char *)&value32, 4) < 0) { ++ rfbLogPerror("rfbSendSecurityType: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Decide what to do next. */ ++ switch (securityType) { ++ case rfbSecTypeNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbSecTypeVncAuth: ++ /* Begin the standard VNC authentication procedure. */ ++ rfbVncAuthSendChallenge(cl); ++ break; ++ default: ++ /* Impossible case (hopefully). */ ++ rfbLogPerror("rfbSendSecurityType: assertion failed"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Advertise our supported security types (protocol 3.7). The list ++ * will include one standard security type (if primaryType is not set ++ * to rfbSecTypeInvalid), and then one more value telling the client ++ * that we support TightVNC protocol extensions. Thus, currently, ++ * there will be either 1 or 2 items in the list. ++ */ ++ ++static void ++rfbSendSecurityTypeList(cl, primaryType) ++ rfbClientPtr cl; ++ int primaryType; ++{ ++ int count = 1; ++ ++ /* Fill in the list of security types in the client structure. */ ++ if (primaryType != rfbSecTypeInvalid) { ++ cl->securityTypes[count++] = (CARD8)primaryType; ++ } ++ cl->securityTypes[count] = (CARD8)rfbSecTypeTight; ++ cl->securityTypes[0] = (CARD8)count++; ++ ++ /* Send the list. */ ++ if (WriteExact(cl->sock, (char *)cl->securityTypes, count) < 0) { ++ rfbLogPerror("rfbSendSecurityTypeList: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientSecurityType. */ ++ cl->state = RFB_SECURITY_TYPE; ++} ++ ++ ++/* ++ * Read the security type chosen by the client (protocol 3.7). ++ */ ++ ++void ++rfbProcessClientSecurityType(cl) ++ rfbClientPtr cl; ++{ ++ int n, count, i; ++ CARD8 chosenType; ++ ++ /* Read the security type. */ ++ n = ReadExact(cl->sock, (char *)&chosenType, 1); ++ if (n <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientSecurityType: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientSecurityType: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Make sure it was present in the list sent by the server. */ ++ count = (int)cl->securityTypes[0]; ++ for (i = 1; i <= count; i++) { ++ if (chosenType == cl->securityTypes[i]) ++ break; ++ } ++ if (i > count) { ++ rfbLog("rfbProcessClientSecurityType: " ++ "wrong security type requested\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Now go to the proper authentication procedure. */ ++ switch (chosenType) { ++ case rfbSecTypeNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbSecTypeVncAuth: ++ /* Begin the standard VNC authentication procedure. */ ++ rfbVncAuthSendChallenge(cl); ++ break; ++ case rfbSecTypeTight: ++ /* We are lucky: the viewer supports TightVNC extensions. */ ++ rfbLog("Enabling TightVNC protocol extensions\n"); ++ /* Switch to the protocol 3.7t. */ ++ cl->protocol_tightvnc = TRUE; ++ /* Advertise our tunneling capabilities. */ ++ rfbSendTunnelingCaps(cl); ++ break; ++ default: ++ /* Impossible case (hopefully). */ ++ rfbLog("rfbProcessClientSecurityType: " ++ "unknown authentication scheme\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Send the list of our tunneling capabilities (protocol 3.7t). ++ */ ++ ++static void ++rfbSendTunnelingCaps(cl) ++ rfbClientPtr cl; ++{ ++ rfbTunnelingCapsMsg caps; ++ CARD32 nTypes = 0; /* we don't support tunneling yet */ ++ ++ caps.nTunnelTypes = Swap32IfLE(nTypes); ++ if (WriteExact(cl->sock, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) { ++ rfbLogPerror("rfbSendTunnelingCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (nTypes) { ++ /* Dispatch client input to rfbProcessClientTunnelingType(). */ ++ cl->state = RFB_TUNNELING_TYPE; ++ } else { ++ rfbSendAuthCaps(cl); ++ } ++} ++ ++ ++/* ++ * Read tunneling type requested by the client (protocol 3.7t). ++ * NOTE: Currently, we don't support tunneling, and this function ++ * can never be called. ++ */ ++ ++void ++rfbProcessClientTunnelingType(cl) ++ rfbClientPtr cl; ++{ ++ /* If we were called, then something's really wrong. */ ++ rfbLog("rfbProcessClientTunnelingType: not implemented\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++} ++ ++ ++/* ++ * Send the list of our authentication capabilities to the client ++ * (protocol 3.7t). ++ */ ++ ++static void ++rfbSendAuthCaps(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ Bool authRequired; ++ rfbAuthenticationCapsMsg caps; ++ rfbCapabilityInfo caplist[MAX_AUTH_CAPS]; ++ int count = 0; ++ ++ authRequired = ((pVNC->rfbAuthPasswdFile != NULL || pVNC->loginAuthEnabled) && ++ !cl->reverseConnection); ++ ++ if (authRequired) { ++ if (pVNC->loginAuthEnabled) { ++ SetCapInfo(&caplist[count], rfbAuthUnixLogin, rfbTightVncVendor); ++ cl->authCaps[count++] = rfbAuthUnixLogin; ++ } ++ if (pVNC->rfbAuthPasswdFile != NULL) { ++ SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor); ++ cl->authCaps[count++] = rfbAuthVNC; ++ } ++ if (count == 0) { ++ /* Should never happen. */ ++ rfbLog("rfbSendAuthCaps: assertion failed\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ ++ cl->nAuthCaps = count; ++ caps.nAuthTypes = Swap32IfLE((CARD32)count); ++ if (WriteExact(cl->sock, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) { ++ rfbLogPerror("rfbSendAuthCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (count) { ++ if (WriteExact(cl->sock, (char *)&caplist[0], ++ count * sz_rfbCapabilityInfo) < 0) { ++ rfbLogPerror("rfbSendAuthCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ /* Dispatch client input to rfbProcessClientAuthType. */ ++ cl->state = RFB_AUTH_TYPE; ++ } else { ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ } ++} ++ ++ ++/* ++ * Read client's preferred authentication type (protocol 3.7t). ++ */ ++ ++void ++rfbProcessClientAuthType(cl) ++ rfbClientPtr cl; ++{ ++ CARD32 auth_type; ++ int n, i; ++ ++ /* Read authentication type selected by the client. */ ++ n = ReadExact(cl->sock, (char *)&auth_type, sizeof(auth_type)); ++ if (n <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientAuthType: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientAuthType: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ auth_type = Swap32IfLE(auth_type); ++ ++ /* Make sure it was present in the list sent by the server. */ ++ for (i = 0; i < cl->nAuthCaps; i++) { ++ if (auth_type == cl->authCaps[i]) ++ break; ++ } ++ if (i >= cl->nAuthCaps) { ++ rfbLog("rfbProcessClientAuthType: " ++ "wrong authentication type requested\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ switch (auth_type) { ++ case rfbAuthNone: ++ /* Dispatch client input to rfbProcessClientInitMessage. */ ++ cl->state = RFB_INITIALISATION; ++ break; ++ case rfbAuthVNC: ++ rfbVncAuthSendChallenge(cl); ++ break; ++ case rfbAuthUnixLogin: ++ /* FIXME: Do (cl->state = RFB_LOGIN_AUTH) instead? */ ++ rfbLoginAuthProcessClientMessage(cl); ++ break; ++ default: ++ rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++} ++ ++ ++/* ++ * Send the authentication challenge. ++ */ ++ ++static void ++rfbVncAuthSendChallenge(cl) ++ rfbClientPtr cl; ++{ ++ vncRandomBytes(cl->authChallenge); ++ if (WriteExact(cl->sock, (char *)cl->authChallenge, CHALLENGESIZE) < 0) { ++ rfbLogPerror("rfbVncAuthSendChallenge: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbVncAuthProcessResponse. */ ++ cl->state = RFB_AUTHENTICATION; ++} ++ ++/* ++ * rfbVncAuthProcessResponse is called when the client sends its ++ * authentication response. ++ */ ++ ++void ++rfbVncAuthProcessResponse(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ char passwdFullControl[9]; ++ char passwdViewOnly[9]; ++ int numPasswords; ++ Bool ok; ++ int n; ++ CARD8 encryptedChallenge1[CHALLENGESIZE]; ++ CARD8 encryptedChallenge2[CHALLENGESIZE]; ++ CARD8 response[CHALLENGESIZE]; ++ CARD32 authResult; ++ ++ n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE); ++ if (n <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbVncAuthProcessResponse: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ numPasswords = vncDecryptPasswdFromFile2(pVNC->rfbAuthPasswdFile, ++ passwdFullControl, ++ passwdViewOnly); ++ if (numPasswords == 0) { ++ rfbLog("rfbVncAuthProcessResponse: could not get password from %s\n", ++ pVNC->rfbAuthPasswdFile); ++ ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ memcpy(encryptedChallenge1, cl->authChallenge, CHALLENGESIZE); ++ vncEncryptBytes(encryptedChallenge1, passwdFullControl); ++ memcpy(encryptedChallenge2, cl->authChallenge, CHALLENGESIZE); ++ vncEncryptBytes(encryptedChallenge2, ++ (numPasswords == 2) ? passwdViewOnly : passwdFullControl); ++ ++ /* Lose the passwords from memory */ ++ memset(passwdFullControl, 0, 9); ++ memset(passwdViewOnly, 0, 9); ++ ++ ok = FALSE; ++ if (memcmp(encryptedChallenge1, response, CHALLENGESIZE) == 0) { ++ rfbLog("Full-control authentication passed by %s\n", cl->host); ++ ok = TRUE; ++ cl->viewOnly = FALSE; ++ } else if (memcmp(encryptedChallenge2, response, CHALLENGESIZE) == 0) { ++ rfbLog("View-only authentication passed by %s\n", cl->host); ++ ok = TRUE; ++ cl->viewOnly = TRUE; ++ } ++ ++ if (!ok) { ++ rfbLog("rfbVncAuthProcessResponse: authentication failed from %s\n", ++ cl->host); ++ ++ if (rfbAuthConsiderBlocking(cl)) { ++ authResult = Swap32IfLE(rfbVncAuthTooMany); ++ } else { ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ } ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ rfbAuthUnblock(cl); ++ ++ authResult = Swap32IfLE(rfbVncAuthOK); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { ++ rfbLogPerror("rfbVncAuthProcessResponse: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientInitMessage(). */ ++ cl->state = RFB_INITIALISATION; ++} ++ ++ ++/* ++ * Functions to prevent too many successive authentication failures. ++ * FIXME: This should be performed separately per each client IP. ++ */ ++ ++/* Maximum authentication failures before blocking connections */ ++#define MAX_AUTH_TRIES 5 ++ ++/* Delay in ms, doubles for each failure over MAX_AUTH_TRIES */ ++#define AUTH_TOO_MANY_BASE_DELAY 10 * 1000 ++ ++/* ++ * This function should not be called directly, it is called by ++ * setting a timer in rfbAuthConsiderBlocking(). ++ */ ++ ++static CARD32 ++rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg) ++{ ++ rfbClientPtr cl = (rfbClientPtr) arg; ++ VNCSCREENPTR(cl->pScreen); ++ pVNC->rfbAuthTooManyTries = FALSE; ++ return 0; ++} ++ ++/* ++ * This function should be called after each authentication failure. ++ * The return value will be true if there was too many failures. ++ */ ++ ++Bool ++rfbAuthConsiderBlocking(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int i; ++ ++ pVNC->rfbAuthTries++; ++ ++ if (pVNC->rfbAuthTries >= MAX_AUTH_TRIES) { ++ CARD32 delay = AUTH_TOO_MANY_BASE_DELAY; ++ for (i = MAX_AUTH_TRIES; i < pVNC->rfbAuthTries; i++) ++ delay *= 2; ++ pVNC->timer = TimerSet(pVNC->timer, 0, delay, rfbAuthReenable, NULL); ++ pVNC->rfbAuthTooManyTries = TRUE; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function should be called after successful authentication. ++ * It resets the counter of authentication failures. Note that it's ++ * not necessary to clear the rfbAuthTooManyTries flag as it will be ++ * reset by the timer function. ++ */ ++ ++void ++rfbAuthUnblock(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ pVNC->rfbAuthTries = 0; ++} ++ ++/* ++ * This function should be called before authentication process. ++ * The return value will be true if there was too many authentication ++ * failures, and the server should not allow another try. ++ */ ++ ++Bool ++rfbAuthIsBlocked(rfbClientPtr cl) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ return pVNC->rfbAuthTooManyTries; ++} ++ +diff --git a/hw/xfree86/vnc/cmap.c b/hw/xfree86/vnc/cmap.c +new file mode 100644 +index 0000000..88aad12 +--- /dev/null ++++ b/hw/xfree86/vnc/cmap.c +@@ -0,0 +1,163 @@ ++/* ++ * cmap.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1993 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR ++OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall ++not be used in advertising or otherwise to promote the sale, use or ++other dealings in this Software without prior written authorization ++from the X Consortium. ++ ++*/ ++ ++#include "rfb.h" ++ ++int ++rfbListInstalledColormaps(pScreen, pmaps) ++ ScreenPtr pScreen; ++ Colormap *pmaps; ++{ ++ VNCSCREENPTR(pScreen); ++ /* By the time we are processing requests, we can guarantee that there ++ * is always a colormap installed */ ++ if (pVNC->rfbInstalledColormap) ++ *pmaps = pVNC->rfbInstalledColormap->mid; ++ ++#if XFREE86VNC ++ pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps; ++ (*pScreen->ListInstalledColormaps)(pScreen, pmaps); ++ pScreen->ListInstalledColormaps = rfbListInstalledColormaps; ++#endif ++ ++ return (1); ++} ++ ++ ++void ++rfbInstallColormap(pmap) ++ ColormapPtr pmap; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ ++ if (pmap != pVNC->rfbInstalledColormap) { ++ ++ if(pVNC->rfbInstalledColormap != (ColormapPtr)None) ++ WalkTree(pmap->pScreen, TellLostMap, ++ (char *)&pVNC->rfbInstalledColormap->mid); ++ /* Install pmap */ ++ pVNC->rfbInstalledColormap = pmap; ++ WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); ++ ++ rfbSetClientColourMaps(0, 0); ++ } ++#if XFREE86VNC ++ pmap->pScreen->InstallColormap = pVNC->InstallColormap; ++ (*pmap->pScreen->InstallColormap)(pmap); ++ pmap->pScreen->InstallColormap = rfbInstallColormap; ++#endif ++} ++ ++void ++rfbUninstallColormap(pmap) ++ ColormapPtr pmap; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ ++ if(pmap == pVNC->rfbInstalledColormap) ++ { ++ if (pmap->mid != pmap->pScreen->defColormap) ++ { ++ pVNC->rfbInstalledColormap = ++ (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, ++ RT_COLORMAP); ++ (*pmap->pScreen->InstallColormap)(pVNC->rfbInstalledColormap); ++ } ++ } ++#if XFREE86VNC ++ pmap->pScreen->UninstallColormap = pVNC->UninstallColormap; ++ (*pmap->pScreen->UninstallColormap)(pmap); ++ pmap->pScreen->UninstallColormap = rfbUninstallColormap; ++#endif ++} ++ ++ ++/* ++ * rfbStoreColors. We have a set of pixels but they may be in any order. ++ * If some of them happen to be in continuous ascending order then we can ++ * group them together into a single call to rfbSetClientColourMaps. ++ */ ++ ++void ++rfbStoreColors(pmap, ndef, pdefs) ++ ColormapPtr pmap; ++ int ndef; ++ xColorItem *pdefs; ++{ ++ VNCSCREENPTR(pmap->pScreen); ++ int i; ++ int first = -1; ++ int n = 0; ++ ++ if (pmap == pVNC->rfbInstalledColormap) { ++ for (i = 0; i < ndef; i++) { ++ if ((first != -1) && (first + n == pdefs[i].pixel)) { ++ n++; ++ } else { ++ if (first != -1) { ++ rfbSetClientColourMaps(first, n); ++ } ++ first = pdefs[i].pixel; ++ n = 1; ++ } ++ } ++ rfbSetClientColourMaps(first, n); ++ } ++#if XFREE86VNC ++ pmap->pScreen->StoreColors = pVNC->StoreColors; ++ (*pmap->pScreen->StoreColors)(pmap, ndef, pdefs); ++ pmap->pScreen->StoreColors = rfbStoreColors; ++#endif ++} +diff --git a/hw/xfree86/vnc/corre.c b/hw/xfree86/vnc/corre.c +new file mode 100644 +index 0000000..ec1c917 +--- /dev/null ++++ b/hw/xfree86/vnc/corre.c +@@ -0,0 +1,355 @@ ++/* ++ * corre.c ++ * ++ * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This ++ * code is based on krw's original javatel rfbserver. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include "rfb.h" ++ ++/* ++ * rreBeforeBuf contains pixel data in the client's format. ++ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is ++ * larger than the raw data or if it exceeds rreAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int rreBeforeBufSize = 0; ++static char *rreBeforeBuf = NULL; ++ ++static int rreAfterBufSize = 0; ++static char *rreAfterBuf = NULL; ++static int rreAfterBufLen; ++ ++static int subrectEncode8(CARD8 *data, int w, int h); ++static int subrectEncode16(CARD16 *data, int w, int h); ++static int subrectEncode32(CARD32 *data, int w, int h); ++static CARD32 getBgColour(char *data, int size, int bpp); ++static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y, ++ int w, int h); ++ ++ ++/* ++ * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE ++ * encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingCoRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ if (h > cl->correMaxHeight) { ++ return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) && ++ rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, ++ w, h - cl->correMaxHeight)); ++ } ++ ++ if (w > cl->correMaxWidth) { ++ return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) && ++ rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y, ++ w - cl->correMaxWidth, h)); ++ } ++ ++ return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h); ++} ++ ++ ++ ++/* ++ * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256) ++ * rectangle using CoRRE encoding. ++ */ ++ ++static Bool ++rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbRREHeader hdr; ++ int nSubrects; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (rreBeforeBufSize < maxRawSize) { ++ rreBeforeBufSize = maxRawSize; ++ if (rreBeforeBuf == NULL) ++ rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); ++ else ++ rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); ++ } ++ ++ if (rreAfterBufSize < maxRawSize) { ++ rreAfterBufSize = maxRawSize; ++ if (rreAfterBuf == NULL) ++ rreAfterBuf = (char *)xalloc(rreAfterBufSize); ++ else ++ rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); ++ } ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, rreBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); ++ break; ++ case 16: ++ nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); ++ break; ++ case 32: ++ nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); ++ break; ++ default: ++ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); ++ exit(1); ++ } ++ ++ if (nSubrects < 0) { ++ ++ /* RRE encoding was too large, use raw */ ++ ++ return rfbSendRectEncodingRaw(cl, x, y, w, h); ++ } ++ ++ cl->rfbRectanglesSent[rfbEncodingCoRRE]++; ++ cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbRREHeader + rreAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingCoRRE); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nSubrects = Swap32IfLE(nSubrects); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader); ++ pVNC->ublen += sz_rfbRREHeader; ++ ++ for (i = 0; i < rreAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > rreAfterBufLen) { ++ bytesToCopy = rreAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * subrectEncode() encodes the given multicoloured rectangle as a background ++ * colour overwritten by single-coloured rectangles. It returns the number ++ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't ++ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The ++ * single-colour rectangle partition is not optimal, but does find the biggest ++ * horizontal or vertical rectangle top-left anchored to each consecutive ++ * coordinate position. ++ * ++ * The coding scheme is simply [...] where each ++ * is []. ++ */ ++ ++#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 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) { ++ 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/xfree86/vnc/cursor.c b/hw/xfree86/vnc/cursor.c +new file mode 100644 +index 0000000..a79111d +--- /dev/null ++++ b/hw/xfree86/vnc/cursor.c +@@ -0,0 +1,405 @@ ++/* ++ * cursor.c - support for cursor shape updates. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include "rfb.h" ++#include "mipointer.h" ++#include "sprite.h" ++#include "cursorstr.h" ++#include "servermd.h" ++ ++ ++/* Copied from Xvnc/lib/font/util/utilbitmap.c */ ++static unsigned char _reverse_byte[0x100] = { ++ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, ++ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, ++ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, ++ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, ++ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, ++ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, ++ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, ++ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, ++ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, ++ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, ++ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, ++ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, ++ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, ++ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, ++ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, ++ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, ++ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, ++ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, ++ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, ++ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, ++ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, ++ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, ++ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, ++ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, ++ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, ++ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, ++ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, ++ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, ++ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, ++ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, ++ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, ++ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff ++}; ++ ++ ++static int EncodeRichCursorData8 (char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++static int EncodeRichCursorData16 (ScreenPtr pScreen, ++ char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++static int EncodeRichCursorData32 (ScreenPtr pScreen, ++ char *buf, rfbPixelFormat *fmt, ++ CursorPtr pCursor); ++ ++ ++/* ++ * Send cursor shape either in X-style format or in client pixel format. ++ */ ++ ++Bool ++rfbSendCursorShape(cl, pScreen) ++ rfbClientPtr cl; ++ ScreenPtr pScreen; ++{ ++ VNCSCREENPTR(pScreen); ++ CursorPtr pCursor; ++ rfbFramebufferUpdateRectHeader rect; ++ rfbXCursorColors colors; ++ int saved_ublen; ++ int bitmapRowBytes, paddedRowBytes, maskBytes, dataBytes; ++ int i, j; ++ CARD8 *bitmapData; ++ CARD8 bitmapByte; ++ ++ if (cl->useRichCursorEncoding) { ++ rect.encoding = Swap32IfLE(rfbEncodingRichCursor); ++ } else { ++ rect.encoding = Swap32IfLE(rfbEncodingXCursor); ++ } ++ ++#if XFREE86VNC ++ pCursor = pVNC->pCurs; ++#else ++ pCursor = rfbSpriteGetCursorPtr(pScreen); ++#endif ++ ++ /* If there is no cursor, send update with empty cursor data. */ ++ ++ if ( pCursor != NULL && ++ pCursor->bits->width == 1 && ++ pCursor->bits->height == 1 && ++ pCursor->bits->mask[0] == 0 ) { ++ pCursor = NULL; ++ } ++ ++ if (pCursor == NULL) { ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ rect.r.x = rect.r.y = 0; ++ rect.r.w = rect.r.h = 0; ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbCursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ cl->rfbCursorShapeUpdatesSent++; ++ ++ return TRUE; ++ } ++ ++ /* Calculate data sizes. */ ++ ++ bitmapRowBytes = (pCursor->bits->width + 7) / 8; ++ paddedRowBytes = PixmapBytePad(pCursor->bits->width, 1); ++ maskBytes = bitmapRowBytes * pCursor->bits->height; ++ dataBytes = (cl->useRichCursorEncoding) ? ++ (pCursor->bits->width * pCursor->bits->height * ++ (cl->format.bitsPerPixel / 8)) : maskBytes; ++ ++ /* Send buffer contents if needed. */ ++ ++ if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + ++ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if ( pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + ++ sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) { ++ return FALSE; /* FIXME. */ ++ } ++ ++ saved_ublen = pVNC->ublen; ++ ++ /* Prepare rectangle header. */ ++ ++ rect.r.x = Swap16IfLE(pCursor->bits->xhot); ++ rect.r.y = Swap16IfLE(pCursor->bits->yhot); ++ rect.r.w = Swap16IfLE(pCursor->bits->width); ++ rect.r.h = Swap16IfLE(pCursor->bits->height); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ /* Prepare actual cursor data (depends on encoding used). */ ++ ++ if (!cl->useRichCursorEncoding) { ++ /* XCursor encoding. */ ++ colors.foreRed = (char)(pCursor->foreRed >> 8); ++ colors.foreGreen = (char)(pCursor->foreGreen >> 8); ++ colors.foreBlue = (char)(pCursor->foreBlue >> 8); ++ colors.backRed = (char)(pCursor->backRed >> 8); ++ colors.backGreen = (char)(pCursor->backGreen >> 8); ++ colors.backBlue = (char)(pCursor->backBlue >> 8); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&colors, sz_rfbXCursorColors); ++ pVNC->ublen += sz_rfbXCursorColors; ++ ++ bitmapData = (CARD8 *)pCursor->bits->source; ++ ++ for (i = 0; i < pCursor->bits->height; i++) { ++ for (j = 0; j < bitmapRowBytes; j++) { ++ bitmapByte = bitmapData[i * paddedRowBytes + j]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte; ++ } ++ } ++ } else { ++ /* RichCursor encoding. */ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ pVNC->ublen += EncodeRichCursorData8(&pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ case 16: ++ pVNC->ublen += EncodeRichCursorData16(pScreen, &pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ case 32: ++ pVNC->ublen += EncodeRichCursorData32(pScreen, &pVNC->updateBuf[pVNC->ublen], ++ &cl->format, pCursor); ++ break; ++ default: ++ return FALSE; ++ } ++ } ++ ++ /* Prepare transparency mask. */ ++ ++ bitmapData = (CARD8 *)pCursor->bits->mask; ++ ++ for (i = 0; i < pCursor->bits->height; i++) { ++ for (j = 0; j < bitmapRowBytes; j++) { ++ bitmapByte = bitmapData[i * paddedRowBytes + j]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ pVNC->updateBuf[pVNC->ublen++] = (char)bitmapByte; ++ } ++ } ++ ++ /* Update statistics. */ ++ ++ cl->rfbCursorShapeBytesSent += (pVNC->ublen - saved_ublen); ++ cl->rfbCursorShapeUpdatesSent++; ++ ++ return TRUE; ++} ++ ++/* ++ * Send cursor position (PointerPos pseudo-encoding). ++ */ ++Bool ++rfbSendCursorPos(cl, pScreen) ++ rfbClientPtr cl; ++ ScreenPtr pScreen; ++{ ++ VNCSCREENPTR(pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++#if XFREE86VNC ++ ScreenPtr pCursorScreen = miPointerCurrentScreen(); ++#endif ++ int x, y; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++#if XFREE86VNC ++ if (pScreen == pCursorScreen) ++ miPointerPosition(&x, &y); ++#else ++ rfbSpriteGetCursorPos(pScreen, &x, &y); ++#endif ++ ++ rect.encoding = Swap32IfLE(rfbEncodingPointerPos); ++ rect.r.x = Swap16IfLE((CARD16)x); ++ rect.r.y = Swap16IfLE((CARD16)y); ++ rect.r.w = 0; ++ rect.r.h = 0; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbCursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ cl->rfbCursorPosUpdatesSent++; ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ cl->cursorX = x; ++ cl->cursorY = y; ++ ++ return TRUE; ++} ++ ++/* ++ * Code to convert cursor source bitmap to the desired pixel format. ++ */ ++ ++#define RGB48_TO_PIXEL(fmt,r,g,b) \ ++ (((CARD32)(r) * ((fmt)->redMax + 1) >> 16) << (fmt)->redShift | \ ++ ((CARD32)(g) * ((fmt)->greenMax + 1) >> 16) << (fmt)->greenShift | \ ++ ((CARD32)(b) * ((fmt)->blueMax + 1) >> 16) << (fmt)->blueShift) ++ ++static int ++EncodeRichCursorData8(buf, fmt, pCursor) ++ char *buf; ++ rfbPixelFormat *fmt; ++ CursorPtr pCursor; ++{ ++ int widthPixels, widthBytes; ++ int x, y, b; ++ CARD8 *src; ++ char pix[2]; ++ CARD8 bitmapByte; ++ ++ pix[0] = (char)RGB48_TO_PIXEL(fmt, pCursor->backRed, pCursor->backGreen, ++ pCursor->backBlue); ++ pix[1] = (char)RGB48_TO_PIXEL(fmt, pCursor->foreRed, pCursor->foreGreen, ++ pCursor->foreBlue); ++ ++ src = (CARD8 *)pCursor->bits->source; ++ widthPixels = pCursor->bits->width; ++ widthBytes = PixmapBytePad(widthPixels, 1); ++ ++ for (y = 0; y < pCursor->bits->height; y++) { ++ for (x = 0; x < widthPixels / 8; x++) { ++ bitmapByte = src[y * widthBytes + x]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ for (b = 7; b >= 0; b--) { ++ *buf++ = pix[bitmapByte >> b & 1]; ++ } ++ } ++ if (widthPixels % 8) { ++ bitmapByte = src[y * widthBytes + x]; ++ if (screenInfo.bitmapBitOrder == LSBFirst) { ++ bitmapByte = _reverse_byte[bitmapByte]; ++ } ++ for (b = 7; b > 7 - widthPixels % 8; b--) { ++ *buf++ = pix[bitmapByte >> b & 1]; ++ } ++ } ++ } ++ ++ return (widthPixels * pCursor->bits->height); ++} ++ ++#define DEFINE_RICH_ENCODE(bpp) \ ++ \ ++static int \ ++EncodeRichCursorData##bpp(pScreen, buf, fmt, pCursor) \ ++ ScreenPtr pScreen; \ ++ char *buf; \ ++ rfbPixelFormat *fmt; \ ++ CursorPtr pCursor; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ int widthPixels, widthBytes; \ ++ int x, y, b; \ ++ CARD8 *src; \ ++ CARD##bpp pix[2]; \ ++ CARD8 bitmapByte; \ ++ \ ++ pix[0] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->backRed, \ ++ pCursor->backGreen, \ ++ pCursor->backBlue); \ ++ pix[1] = (CARD##bpp)RGB48_TO_PIXEL(fmt, pCursor->foreRed, \ ++ pCursor->foreGreen, \ ++ pCursor->foreBlue); \ ++ if (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian) { \ ++ pix[0] = Swap##bpp(pix[0]); \ ++ pix[1] = Swap##bpp(pix[1]); \ ++ } \ ++ \ ++ src = (CARD8 *)pCursor->bits->source; \ ++ widthPixels = pCursor->bits->width; \ ++ widthBytes = PixmapBytePad(widthPixels, 1); \ ++ \ ++ for (y = 0; y < pCursor->bits->height; y++) { \ ++ for (x = 0; x < widthPixels / 8; x++) { \ ++ bitmapByte = src[y * widthBytes + x]; \ ++ if (screenInfo.bitmapBitOrder == LSBFirst) { \ ++ bitmapByte = _reverse_byte[bitmapByte]; \ ++ } \ ++ for (b = 7; b >= 0; b--) { \ ++ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ ++ sizeof(CARD##bpp)); \ ++ buf += sizeof(CARD##bpp); \ ++ } \ ++ } \ ++ if (widthPixels % 8) { \ ++ bitmapByte = src[y * widthBytes + x]; \ ++ if (screenInfo.bitmapBitOrder == LSBFirst) { \ ++ bitmapByte = _reverse_byte[bitmapByte]; \ ++ } \ ++ for (b = 7; b > 7 - widthPixels % 8; b--) { \ ++ memcpy (buf, (char *)&pix[bitmapByte >> b & 1], \ ++ sizeof(CARD##bpp)); \ ++ buf += sizeof(CARD##bpp); \ ++ } \ ++ } \ ++ } \ ++ \ ++ return (widthPixels * pCursor->bits->height * (bpp / 8)); \ ++} ++ ++DEFINE_RICH_ENCODE(16) ++DEFINE_RICH_ENCODE(32) ++ +diff --git a/hw/xfree86/vnc/cutpaste.c b/hw/xfree86/vnc/cutpaste.c +new file mode 100644 +index 0000000..13aebbb +--- /dev/null ++++ b/hw/xfree86/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 ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#define NEED_EVENTS ++#include ++#include ++#include ++#include "rfb.h" ++#include "selection.h" ++#include "input.h" ++ ++extern Selection *CurrentSelections; ++extern int NumCurrentSelections; ++ ++ ++static Bool inSetXCutText = FALSE; ++ ++/* ++ * rfbSetXCutText sets the cut buffer to be the given string. We also clear ++ * the primary selection. Ideally we'd like to set it to the same thing, but I ++ * can't work out how to do that without some kind of helper X client. ++ */ ++ ++void ++rfbSetXCutText(char *str, int len) ++{ ++ int i = 0; ++ ++ inSetXCutText = TRUE; ++ ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING, ++ 8, PropModeReplace, len, ++ (pointer)str, TRUE); ++ ++ while ((i < NumCurrentSelections) && ++ CurrentSelections[i].selection != XA_PRIMARY) ++ i++; ++ ++ if (i < NumCurrentSelections) { ++ xEvent event; ++ ++ if (CurrentSelections[i].client) { ++ event.u.u.type = SelectionClear; ++ event.u.selectionClear.time = GetTimeInMillis(); ++ event.u.selectionClear.window = CurrentSelections[i].window; ++ event.u.selectionClear.atom = CurrentSelections[i].selection; ++ (void) TryClientEvents (CurrentSelections[i].client, &event, 1, ++ NoEventMask, NoEventMask /* CantBeFiltered */, ++ NullGrab); ++ } ++ ++ CurrentSelections[i].window = None; ++ CurrentSelections[i].pWin = NULL; ++ CurrentSelections[i].client = NullClient; ++ } ++ ++ inSetXCutText = FALSE; ++} ++ ++ ++void rfbGotXCutText(char *str, int len) ++{ ++ if (!inSetXCutText) ++ rfbSendServerCutText(str, len); ++} +diff --git a/hw/xfree86/vnc/draw.c b/hw/xfree86/vnc/draw.c +new file mode 100644 +index 0000000..889db6f +--- /dev/null ++++ b/hw/xfree86/vnc/draw.c +@@ -0,0 +1,2108 @@ ++/* ++ * draw.c - drawing routines for the RFB X server. This is a set of ++ * wrappers around the standard MI/MFB/CFB drawing routines which work out ++ * to a fair approximation the region of the screen being modified by the ++ * drawing. If the RFB client is ready then the modified region of the screen ++ * is sent to the client, otherwise the modified region will simply grow with ++ * each drawing request until the client is ready. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ ++Copyright (c) 1989 X Consortium ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++Except as contained in this notice, the name of the X Consortium shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from the X Consortium. ++*/ ++ ++#include "rfb.h" ++ ++int rfbDeferUpdateTime = 40; /* ms */ ++ ++ ++/****************************************************************************/ ++/* ++ * Macro definitions ++ */ ++/****************************************************************************/ ++ ++#define TRC(x) /* (rfbLog x) */ ++ ++/* ADD_TO_MODIFIED_REGION adds the given region to the modified region for each ++ client */ ++ ++#define ADD_TO_MODIFIED_REGION(pScreen,reg) \ ++ { \ ++ rfbClientPtr cl; \ ++ for (cl = rfbClientHead; cl; cl = cl->next) { \ ++ REGION_UNION((pScreen),&cl->modifiedRegion,&cl->modifiedRegion,reg);\ ++ } \ ++ } ++ ++/* SCHEDULE_FB_UPDATE is used at the end of each drawing routine to schedule an ++ update to be sent to each client if there is one pending and the client is ++ ready for it. */ ++ ++#define SCHEDULE_FB_UPDATE(pScreen,pVNC) \ ++ if (!pVNC->dontSendFramebufferUpdate) { \ ++ rfbClientPtr cl, nextCl; \ ++ for (cl = rfbClientHead; cl; cl = nextCl) { \ ++ nextCl = cl->next; \ ++ if (!cl->deferredUpdateScheduled && FB_UPDATE_PENDING(cl) && \ ++ REGION_NOTEMPTY(pScreen,&cl->requestedRegion)) \ ++ { \ ++ rfbScheduleDeferredUpdate(pScreen, cl); \ ++ } \ ++ } \ ++ } ++ ++/* function prototypes */ ++ ++static void rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl); ++static void rfbCopyRegion(ScreenPtr pScreen, rfbClientPtr cl, ++ RegionPtr src, RegionPtr dst, int dx, int dy); ++#ifdef DEBUG ++static void PrintRegion(ScreenPtr pScreen, RegionPtr reg); ++#endif ++ ++/* GC funcs */ ++ ++static void rfbValidateGC(GCPtr, unsigned long /*changes*/, DrawablePtr); ++static void rfbChangeGC(GCPtr, unsigned long /*mask*/); ++static void rfbCopyGC(GCPtr /*src*/, unsigned long /*mask*/, GCPtr /*dst*/); ++static void rfbDestroyGC(GCPtr); ++static void rfbChangeClip(GCPtr, int /*type*/, pointer /*pValue*/, ++ int /*nrects*/); ++static void rfbDestroyClip(GCPtr); ++static void rfbCopyClip(GCPtr /*dst*/, GCPtr /*src*/); ++ ++/* GC ops */ ++ ++static void rfbFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted); ++static void rfbSetSpans(DrawablePtr pDrawable, ++ GCPtr pGC, ++ char *psrc, ++ register DDXPointPtr ppt, ++ int *pwidth, ++ int nspans, ++ int fSorted); ++static void rfbPutImage(); ++static RegionPtr rfbCopyArea(); ++static RegionPtr rfbCopyPlane(); ++static void rfbPolyPoint(); ++static void rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts); ++static void rfbPolySegment(); ++static void rfbPolyRectangle(); ++static void rfbPolyArc(); ++static void rfbFillPolygon(); ++static void rfbPolyFillRect(); ++static void rfbPolyFillArc(); ++static int rfbPolyText8(); ++static int rfbPolyText16(); ++static void rfbImageText8(); ++static void rfbImageText16(); ++static void rfbImageGlyphBlt(); ++static void rfbPolyGlyphBlt(); ++static void rfbPushPixels(); ++ ++ ++static GCFuncs rfbGCFuncs = { ++ rfbValidateGC, ++ rfbChangeGC, ++ rfbCopyGC, ++ rfbDestroyGC, ++ rfbChangeClip, ++ rfbDestroyClip, ++ rfbCopyClip, ++}; ++ ++ ++static GCOps rfbGCOps = { ++ rfbFillSpans, rfbSetSpans, rfbPutImage, ++ rfbCopyArea, rfbCopyPlane, rfbPolyPoint, ++ rfbPolylines, rfbPolySegment, rfbPolyRectangle, ++ rfbPolyArc, rfbFillPolygon, rfbPolyFillRect, ++ rfbPolyFillArc, rfbPolyText8, rfbPolyText16, ++ rfbImageText8, rfbImageText16, rfbImageGlyphBlt, ++ rfbPolyGlyphBlt, rfbPushPixels ++}; ++ ++ ++ ++/****************************************************************************/ ++/* ++ * Screen functions wrapper stuff ++ */ ++/****************************************************************************/ ++ ++#define SCREEN_PROLOGUE(scrn, field) \ ++ ScreenPtr pScreen = scrn; \ ++ VNCSCREENPTR(pScreen); \ ++ pScreen->field = pVNC->field; ++ ++#define SCREEN_EPILOGUE(field, wrapper) \ ++ pScreen->field = wrapper; ++ ++ ++/* ++ * CloseScreen wrapper -- unwrap everything, free the private data ++ * and call the wrapped CloseScreen function. ++ */ ++ ++Bool ++rfbCloseScreen (int i, ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++#if XFREE86VNC ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++#endif ++ int sock; ++ ++ for (sock = 0; sock <= pVNC->maxFd; sock++) { ++ if (FD_ISSET(sock, &pVNC->allFds)) ++ if (sock != pVNC->rfbListenSock && sock != pVNC->httpListenSock) { ++ rfbCloseSock(pScreen, sock); ++ } ++ } ++ ++ if (pVNC->rfbListenSock > 0) ++ if (close(pVNC->rfbListenSock)) ++ ErrorF("Close of port %d failed\n",pVNC->rfbPort); ++ ++ if (pVNC->httpListenSock > 0) ++ if (close(pVNC->httpListenSock)) ++ ErrorF("Close of port %d failed\n",pVNC->httpPort); ++ ++ pScreen->CloseScreen = pVNC->CloseScreen; ++ pScreen->CreateGC = pVNC->CreateGC; ++ pScreen->PaintWindowBackground = pVNC->PaintWindowBackground; ++ pScreen->PaintWindowBorder = pVNC->PaintWindowBorder; ++ pScreen->CopyWindow = pVNC->CopyWindow; ++ pScreen->ClearToBackground = pVNC->ClearToBackground; ++ pScreen->RestoreAreas = pVNC->RestoreAreas; ++ pScreen->WakeupHandler = pVNC->WakeupHandler; ++ ++#if XFREE86VNC ++ pScreen->InstallColormap = pVNC->InstallColormap; ++ pScreen->UninstallColormap = pVNC->UninstallColormap; ++ pScreen->ListInstalledColormaps = pVNC->ListInstalledColormaps; ++ pScreen->StoreColors = pVNC->StoreColors; ++ pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess; ++ ++ xfree(pVNC); ++#endif ++ ++ TRC((stderr,"Unwrapped screen functions\n")); ++ ++ return (*pScreen->CloseScreen) (i, pScreen); ++} ++ ++#if XFREE86VNC ++void ++rfbEnableDisableFBAccess (int index, Bool enable) ++{ ++ ScrnInfoPtr pScrn = xf86Screens[index]; ++ VNCSCREENPTR(pScrn->pScreen); ++ ++ /* ++ * Blank the screen for security while inputs are disabled. ++ * When VT switching is fixed, we might be able to allow ++ * control even when switched away. ++ */ ++ if (!enable) { ++ WindowPtr pWin = WindowTable[index]; ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ GCPtr pGC; ++ xRectangle rect; ++ ++ rect.x = 0; ++ rect.y = 0; ++ rect.width = pScrn->virtualX; ++ rect.height = pScrn->virtualY; ++ ++ if (!(pGC = GetScratchGC(pScreen->rootDepth, pScreen))) { ++ ErrorF("Couldn't blank screen"); ++ } else { ++ CARD32 attributes[2]; ++ attributes[0] = pScreen->whitePixel; ++ attributes[1] = pScreen->blackPixel; ++ (void)ChangeGC(pGC, GCForeground | GCBackground, attributes); ++ ++ ValidateGC((DrawablePtr)pWin, pGC); ++ ++ (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, 1, &rect); ++ ++ FreeScratchGC(pGC); ++ ++ /* Flush pending packets */ ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++ } ++ } ++ ++ pScrn->EnableDisableFBAccess = pVNC->EnableDisableFBAccess; ++ (*pScrn->EnableDisableFBAccess)(index, enable); ++ pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess; ++} ++#endif ++ ++/* ++ * CreateGC - wrap the GC funcs (the GC ops will be wrapped when the GC ++ * func "ValidateGC" is called). ++ */ ++ ++Bool ++rfbCreateGC (GCPtr pGC) ++{ ++ Bool ret; ++ rfbGCPtr pGCPriv; ++ ++ SCREEN_PROLOGUE(pGC->pScreen,CreateGC); ++ ++ pGCPriv = (rfbGCPtr)pGC->devPrivates[rfbGCIndex].ptr; ++ ++ ret = (*pScreen->CreateGC) (pGC); ++ ++ TRC((stderr,"rfbCreateGC called\n")); ++ ++ pGCPriv->wrapOps = NULL; ++ pGCPriv->wrapFuncs = pGC->funcs; ++ pGC->funcs = &rfbGCFuncs; ++ ++ SCREEN_EPILOGUE(CreateGC,rfbCreateGC); ++ ++ return ret; ++} ++ ++/* ++ * PaintWindowBackground - the region being modified is just the given region. ++ */ ++ ++void ++rfbPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what) ++{ ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBackground); ++ ++ TRC((stderr,"rfbPaintWindowBackground called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen,pRegion); ++ ++ (*pScreen->PaintWindowBackground) (pWin, pRegion, what); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(PaintWindowBackground,rfbPaintWindowBackground); ++} ++ ++/* ++ * PaintWindowBorder - the region being modified is just the given region. ++ */ ++ ++void ++rfbPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what) ++{ ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PaintWindowBorder); ++ ++ TRC((stderr,"rfbPaintWindowBorder called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen,pRegion); ++ ++ (*pScreen->PaintWindowBorder) (pWin, pRegion, what); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(PaintWindowBorder,rfbPaintWindowBorder); ++} ++ ++#ifdef CHROMIUM ++Bool ++rfbRealizeWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,RealizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 1); ++ } ++ } ++ ++ ret = (*pScreen->RealizeWindow)(pWin); ++ ++ SCREEN_EPILOGUE(RealizeWindow,rfbRealizeWindow); ++ ++ return ret; ++} ++ ++Bool ++rfbUnrealizeWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,UnrealizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 0); ++ } ++ } ++ ++ ret = (*pScreen->UnrealizeWindow)(pWin); ++ ++ SCREEN_EPILOGUE(UnrealizeWindow,rfbUnrealizeWindow); ++ ++ return ret; ++} ++ ++Bool ++rfbDestroyWindow(WindowPtr pWin) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ Bool ret; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,DestroyWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumWindowShow(wt->CRwinId, 0); ++ } ++ } ++ ++ ret = (*pScreen->DestroyWindow)(pWin); ++ ++ SCREEN_EPILOGUE(DestroyWindow,rfbDestroyWindow); ++ ++ return ret; ++} ++ ++void ++rfbResizeWindow(WindowPtr pWin, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib) ++{ ++ CRWindowTable *wt = NULL, *nextWt = NULL; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ResizeWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumMoveResizeWindow(wt->CRwinId, pWin->drawable.x, pWin->drawable.y, w, h); ++ } ++ } ++ ++ (*pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); ++ ++ SCREEN_EPILOGUE(ResizeWindow,rfbResizeWindow); ++} ++ ++Bool ++rfbPositionWindow(WindowPtr pWin, int x, int y) ++{ ++ Bool ret; ++ CRWindowTable *wt, *nextWt; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,PositionWindow); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ rfbSendChromiumMoveResizeWindow(wt->CRwinId, x, y, pWin->drawable.width, pWin->drawable.height); ++ } ++ } ++ ++ ret = (*pScreen->PositionWindow)(pWin, x, y); ++ ++ SCREEN_EPILOGUE(PositionWindow,rfbPositionWindow); ++ ++ return ret; ++} ++ ++void ++rfbClipNotify(WindowPtr pWin, int x, int y) ++{ ++ CRWindowTable *wt, *nextWt; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ClipNotify); ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == pWin->drawable.id) { ++ int numClipRects = REGION_NUM_RECTS(&pWin->clipList); ++ BoxPtr pClipRects = REGION_RECTS(&pWin->clipList); ++ ++ /* Possible optimization - has the cliplist really? changed */ ++ ++ rfbSendChromiumClipList(wt->CRwinId, pClipRects, numClipRects); ++ } ++ } ++ ++ if (*pScreen->ClipNotify) ++ (*pScreen->ClipNotify)(pWin, x, y); ++ ++ SCREEN_EPILOGUE(ClipNotify,rfbClipNotify); ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * CopyWindow - the region being modified is the translation of the old ++ * region, clipped to the border clip region of the window. Note that any ++ * parts of the window which have become newly-visible will not be affected by ++ * this call - a separate PaintWindowBackground/Border will be called to do ++ * that. If the client will accept CopyRect messages then use rfbCopyRegion to ++ * optimise the pending screen changes into a single "copy region" plus the ++ * ordinary modified region. ++ */ ++ ++void ++rfbCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) ++{ ++ rfbClientPtr cl; ++ RegionRec srcRegion, dstRegion; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,CopyWindow); ++ ++ TRC((stderr,"rfbCopyWindow called\n")); ++ ++ REGION_NULL(pScreen,&dstRegion); ++ REGION_COPY(pScreen,&dstRegion,pOldRegion); ++ REGION_TRANSLATE(pWin->drawable.pScreen, &dstRegion, ++ pWin->drawable.x - ptOldOrg.x, ++ pWin->drawable.y - ptOldOrg.y); ++ REGION_INTERSECT(pWin->drawable.pScreen, &dstRegion, &dstRegion, ++ &pWin->borderClip); ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->useCopyRect) { ++ REGION_NULL(pScreen,&srcRegion); ++ REGION_COPY(pScreen,&srcRegion,pOldRegion); ++ ++ rfbCopyRegion(pScreen, cl, &srcRegion, &dstRegion, ++ pWin->drawable.x - ptOldOrg.x, ++ pWin->drawable.y - ptOldOrg.y); ++ ++ REGION_UNINIT(pScreen, &srcRegion); ++ ++ } else { ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &dstRegion); ++ } ++ } ++ ++ REGION_UNINIT(pScreen, &dstRegion); ++ ++ (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(CopyWindow,rfbCopyWindow); ++} ++ ++/* ++ * ClearToBackground - when generateExposures is false, the region being ++ * modified is the given rectangle (clipped to the "window clip region"). ++ */ ++ ++void ++rfbClearToBackground (WindowPtr pWin, int x, int y, int w, int h, ++ Bool generateExposures) ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,ClearToBackground); ++ ++ TRC((stderr,"rfbClearToBackground called\n")); ++ ++ if (!generateExposures) { ++ box.x1 = x + pWin->drawable.x; ++ box.y1 = y + pWin->drawable.y; ++ box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width); ++ box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height); ++ ++ SAFE_REGION_INIT(pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pScreen, &tmpRegion, &tmpRegion, &pWin->clipList); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pScreen, &tmpRegion); ++ } ++ ++ (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); ++ ++ if (!generateExposures) { ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ } ++ ++ SCREEN_EPILOGUE(ClearToBackground,rfbClearToBackground); ++} ++ ++/* ++ * RestoreAreas - just be safe here - the region being modified is the whole ++ * exposed region. ++ */ ++ ++RegionPtr ++rfbRestoreAreas (WindowPtr pWin, RegionPtr prgnExposed) ++{ ++ RegionPtr result; ++ SCREEN_PROLOGUE(pWin->drawable.pScreen,RestoreAreas); ++ ++ TRC((stderr,"rfbRestoreAreas called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, prgnExposed); ++ ++ result = (*pScreen->RestoreAreas) (pWin, prgnExposed); ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ SCREEN_EPILOGUE(RestoreAreas,rfbRestoreAreas); ++ ++ return result; ++} ++ ++ ++ ++/****************************************************************************/ ++/* ++ * GC funcs wrapper stuff ++ * ++ * We only really want to wrap the GC ops, but to do this we need to wrap ++ * ValidateGC and so all the other GC funcs must be wrapped as well. ++ */ ++/****************************************************************************/ ++ ++#define GC_FUNC_PROLOGUE(pGC) \ ++ rfbGCPtr pGCPriv = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \ ++ (pGC)->funcs = pGCPriv->wrapFuncs; \ ++ if (pGCPriv->wrapOps) \ ++ (pGC)->ops = pGCPriv->wrapOps; ++ ++#define GC_FUNC_EPILOGUE(pGC) \ ++ pGCPriv->wrapFuncs = (pGC)->funcs; \ ++ (pGC)->funcs = &rfbGCFuncs; \ ++ if (pGCPriv->wrapOps) { \ ++ pGCPriv->wrapOps = (pGC)->ops; \ ++ (pGC)->ops = &rfbGCOps; \ ++ } ++ ++ ++/* ++ * ValidateGC - call the wrapped ValidateGC, then wrap the resulting GC ops if ++ * the drawing will be to a viewable window. ++ */ ++ ++static void ++rfbValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) ++{ ++ VNCSCREENPTR(pGC->pScreen); ++ GC_FUNC_PROLOGUE(pGC); ++ ++ TRC((stderr,"rfbValidateGC called\n")); ++ ++ (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); ++ ++ pGCPriv->wrapOps = NULL; ++ if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) ++ { ++ WindowPtr pWin = (WindowPtr) pDrawable; ++ RegionPtr pRegion = &pWin->clipList; ++ ++ if (pGC->subWindowMode == IncludeInferiors) ++ pRegion = &pWin->borderClip; ++ if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) { ++ pGCPriv->wrapOps = pGC->ops; ++ TRC((stderr,"rfbValidateGC: wrapped GC ops\n")); ++ } ++ } ++ ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++/* ++ * All other GC funcs simply unwrap the GC funcs and ops, call the wrapped ++ * function and then rewrap the funcs and ops. ++ */ ++ ++static void ++rfbChangeGC (pGC, mask) ++ GCPtr pGC; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->ChangeGC) (pGC, mask); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbCopyGC (pGCSrc, mask, pGCDst) ++ GCPtr pGCSrc, pGCDst; ++ unsigned long mask; ++{ ++ GC_FUNC_PROLOGUE(pGCDst); ++ (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); ++ GC_FUNC_EPILOGUE(pGCDst); ++} ++ ++static void ++rfbDestroyGC (pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->DestroyGC) (pGC); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbChangeClip (pGC, type, pvalue, nrects) ++ GCPtr pGC; ++ int type; ++ pointer pvalue; ++ int nrects; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbDestroyClip(pGC) ++ GCPtr pGC; ++{ ++ GC_FUNC_PROLOGUE(pGC); ++ (* pGC->funcs->DestroyClip)(pGC); ++ GC_FUNC_EPILOGUE(pGC); ++} ++ ++static void ++rfbCopyClip(pgcDst, pgcSrc) ++ GCPtr pgcDst, pgcSrc; ++{ ++ GC_FUNC_PROLOGUE(pgcDst); ++ (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); ++ GC_FUNC_EPILOGUE(pgcDst); ++} ++ ++ ++/****************************************************************************/ ++/* ++ * GC ops wrapper stuff ++ * ++ * Note that these routines will only have been wrapped for drawing to ++ * viewable windows so we don't need to check each time that the drawable ++ * is a viewable window. ++ */ ++/****************************************************************************/ ++ ++#define GC_OP_PROLOGUE(pDrawable,pGC) \ ++ ScreenPtr pScreen = pGC->pScreen; \ ++ VNCSCREENPTR(pScreen); \ ++ rfbGCPtr pGCPrivate = (rfbGCPtr) (pGC)->devPrivates[rfbGCIndex].ptr; \ ++ GCFuncs *oldFuncs = pGC->funcs; \ ++ (void) pScreen; /* silence compiler */ \ ++ (pGC)->funcs = pGCPrivate->wrapFuncs; \ ++ (pGC)->ops = pGCPrivate->wrapOps; ++ ++#define GC_OP_EPILOGUE(pGC) \ ++ pGCPrivate->wrapOps = (pGC)->ops; \ ++ (pGC)->funcs = oldFuncs; \ ++ (pGC)->ops = &rfbGCOps; ++ ++ ++/* ++ * FillSpans - being very safe - the region being modified is the border clip ++ * region of the window. ++ */ ++ ++static void ++rfbFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nInit; /* number of spans to fill */ ++ DDXPointPtr pptInit; /* pointer to list of start points */ ++ int *pwidthInit; /* pointer to list of n widths */ ++ int fSorted; ++{ ++ GC_OP_PROLOGUE(pDrawable,pGC); ++ ++ TRC((stderr,"rfbFillSpans called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, ++ &((WindowPtr)pDrawable)->borderClip); ++ ++ (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit,pwidthInit,fSorted); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * SetSpans - being very safe - the region being modified is the border clip ++ * region of the window. ++ */ ++ ++static void ++rfbSetSpans(DrawablePtr pDrawable, ++ GCPtr pGC, ++ char *psrc, ++ register DDXPointPtr ppt, ++ int *pwidth, ++ int nspans, ++ int fSorted) ++{ ++ GC_OP_PROLOGUE(pDrawable,pGC); ++ ++ TRC((stderr,"rfbSetSpans called\n")); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, ++ &((WindowPtr)pDrawable)->borderClip); ++ ++ (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PutImage - the region being modified is the rectangle of the ++ * PutImage (clipped to the window clip region). ++ */ ++ ++static void ++rfbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int depth; ++ int x; ++ int y; ++ int w; ++ int h; ++ int leftPad; ++ int format; ++ char *pBits; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPutImage called\n")); ++ ++ box.x1 = x + pDrawable->x; ++ box.y1 = y + pDrawable->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ ++ (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, ++ leftPad, format, pBits); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * CopyArea - the region being modified is the destination rectangle (clipped ++ * to the window clip region). ++ * If the client will accept CopyRect messages then use rfbCopyRegion ++ * to optimise the pending screen changes into a single "copy region" plus ++ * the ordinary modified region. ++ */ ++ ++static RegionPtr ++rfbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ GCPtr pGC; ++ int srcx; ++ int srcy; ++ int w; ++ int h; ++ int dstx; ++ int dsty; ++{ ++ rfbClientPtr cl; ++ RegionPtr rgn; ++ RegionRec srcRegion, dstRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDst, pGC); ++ ++ TRC((stderr,"rfbCopyArea called\n")); ++ ++ box.x1 = dstx + pDst->x; ++ box.y1 = dsty + pDst->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDst->pScreen, &dstRegion, &box, 0); ++ REGION_INTERSECT(pDst->pScreen, &dstRegion, &dstRegion, ++ pGC->pCompositeClip); ++ ++ if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pDst->pScreen)) { ++ box.x1 = srcx + pSrc->x; ++ box.y1 = srcy + pSrc->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->useCopyRect) { ++ SAFE_REGION_INIT(pSrc->pScreen, &srcRegion, &box, 0); ++ REGION_INTERSECT(pSrc->pScreen, &srcRegion, &srcRegion, ++ &((WindowPtr)pSrc)->clipList); ++ ++ rfbCopyRegion(pSrc->pScreen, cl, &srcRegion, &dstRegion, ++ dstx + pDst->x - srcx - pSrc->x, ++ dsty + pDst->y - srcy - pSrc->y); ++ ++ REGION_UNINIT(pSrc->pScreen, &srcRegion); ++ ++ } else { ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &dstRegion); ++ } ++ } ++ ++ } else { ++ ++ ADD_TO_MODIFIED_REGION(pDst->pScreen, &dstRegion); ++ } ++ ++ REGION_UNINIT(pDst->pScreen, &dstRegion); ++ ++ rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty); ++ ++ SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++ ++ return rgn; ++} ++ ++ ++/* ++ * CopyPlane - the region being modified is the destination rectangle (clipped ++ * to the window clip region). ++ */ ++ ++static RegionPtr ++rfbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) ++ DrawablePtr pSrc; ++ DrawablePtr pDst; ++ register GCPtr pGC; ++ int srcx, ++ srcy; ++ int w, ++ h; ++ int dstx, ++ dsty; ++ unsigned long plane; ++{ ++ RegionPtr rgn; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDst, pGC); ++ ++ TRC((stderr,"rfbCopyPlane called\n")); ++ ++ box.x1 = dstx + pDst->x; ++ box.y1 = dsty + pDst->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDst->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDst->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDst->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDst->pScreen, &tmpRegion); ++ ++ rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, ++ dstx, dsty, plane); ++ ++ SCHEDULE_FB_UPDATE(pDst->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++ ++ return rgn; ++} ++ ++/* ++ * PolyPoint - find the smallest rectangle which encloses the points drawn ++ * (and clip). ++ */ ++ ++static void ++rfbPolyPoint (pDrawable, pGC, mode, npt, pts) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int mode; /* Origin or Previous */ ++ int npt; ++ xPoint *pts; ++{ ++ int i; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyPoint called\n")); ++ ++ if (npt) { ++ int minX = pts[0].x, maxX = pts[0].x; ++ int minY = pts[0].y, maxY = pts[0].y; ++ ++ if (mode == CoordModePrevious) ++ { ++ int x = pts[0].x, y = pts[0].y; ++ ++ for (i = 1; i < npt; i++) { ++ x += pts[i].x; ++ y += pts[i].y; ++ if (x < minX) minX = x; ++ if (x > maxX) maxX = x; ++ if (y < minY) minY = y; ++ if (y > maxY) maxY = y; ++ } ++ } ++ else ++ { ++ for (i = 1; i < npt; i++) { ++ if (pts[i].x < minX) minX = pts[i].x; ++ if (pts[i].x > maxX) maxX = pts[i].x; ++ if (pts[i].y < minY) minY = pts[i].y; ++ if (pts[i].y > maxY) maxY = pts[i].y; ++ } ++ } ++ ++ box.x1 = minX + pDrawable->x; ++ box.y1 = minY + pDrawable->y; ++ box.x2 = maxX + 1 + pDrawable->x; ++ box.y2 = maxY + 1 + pDrawable->y; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts); ++ ++ if (npt) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyLines - take the union of bounding boxes around each line (and clip). ++ */ ++ ++static void ++rfbPolylines (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppts) ++{ ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ int i, extra, nlines, lw; ++ int x1, x2, y1, y2; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolylines called\n")); ++ ++ if (npt) { ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ if (npt == 1) ++ { ++ nlines = 1; ++ rects = (xRectangle *)xalloc(sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolylines: xalloc failed\n"); ++ } ++ ++ rects[0].x = ppts[0].x - lw + pDrawable->x; /* being safe here */ ++ rects[0].y = ppts[0].y - lw + pDrawable->y; ++ rects[0].width = 2*lw; ++ rects[0].height = 2*lw; ++ } ++ else ++ { ++ nlines = npt - 1; ++ rects = (xRectangle *)xalloc(nlines*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolylines: xalloc failed\n"); ++ } ++ ++ /* ++ * mitered joins can project quite a way from ++ * the line end; the 11 degree miter limit limits ++ * this extension to lw / (2 * tan(11/2)), rounded up ++ * and converted to int yields 6 * lw ++ */ ++ ++ if (pGC->joinStyle == JoinMiter) { ++ extra = 6 * lw; ++ } else { ++ extra = lw / 2; ++ } ++ ++ x1 = ppts[0].x + pDrawable->x; ++ y1 = ppts[0].y + pDrawable->y; ++ ++ for (i = 0; i < nlines; i++) { ++ if (mode == CoordModeOrigin) { ++ x2 = pDrawable->x + ppts[i+1].x; ++ y2 = pDrawable->y + ppts[i+1].y; ++ } else { ++ x2 = x1 + ppts[i+1].x; ++ y2 = y1 + ppts[i+1].y; ++ } ++ ++ if (x1 > x2) { ++ rects[i].x = x2 - extra; ++ rects[i].width = x1 - x2 + 1 + 2 * extra; ++ } else { ++ rects[i].x = x1 - extra; ++ rects[i].width = x2 - x1 + 1 + 2 * extra; ++ } ++ ++ if (y1 > y2) { ++ rects[i].y = y2 - extra; ++ rects[i].height = y1 - y2 + 1 + 2 * extra; ++ } else { ++ rects[i].y = y1 - extra; ++ rects[i].height = y2 - y1 + 1 + 2 * extra; ++ } ++ ++ x1 = x2; ++ y1 = y2; ++ } ++ } ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nlines, rects,CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts); ++ ++ if (npt) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolySegment - take the union of bounding boxes around each segment (and ++ * clip). ++ */ ++ ++static void ++rfbPolySegment(pDrawable, pGC, nseg, segs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nseg; ++ xSegment *segs; ++{ ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ int i, extra, lw; ++ ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolySegment called\n")); ++ ++ if (nseg) { ++ rects = (xRectangle *)xalloc(nseg*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolySegment: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < nseg; i++) ++ { ++ if (segs[i].x1 > segs[i].x2) { ++ rects[i].x = segs[i].x2 - extra + pDrawable->x; ++ rects[i].width = segs[i].x1 - segs[i].x2 + 1 + 2 * extra; ++ } else { ++ rects[i].x = segs[i].x1 - extra + pDrawable->x; ++ rects[i].width = segs[i].x2 - segs[i].x1 + 1 + 2 * extra; ++ } ++ ++ if (segs[i].y1 > segs[i].y2) { ++ rects[i].y = segs[i].y2 - extra + pDrawable->y; ++ rects[i].height = segs[i].y1 - segs[i].y2 + 1 + 2 * extra; ++ } else { ++ rects[i].y = segs[i].y1 - extra + pDrawable->y; ++ rects[i].height = segs[i].y2 - segs[i].y1 + 1 + 2 * extra; ++ } ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nseg, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs); ++ ++ if (nseg) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyRectangle (rectangle outlines) - take the union of bounding boxes ++ * around each line (and clip). ++ */ ++ ++static void ++rfbPolyRectangle(pDrawable, pGC, nrects, rects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *rects; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *regRects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyRectangle called\n")); ++ ++ if (nrects) { ++ regRects = (xRectangle *)xalloc(nrects*4*sizeof(xRectangle)); ++ if (!regRects) { ++ FatalError("rfbPolyRectangle: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < nrects; i++) ++ { ++ regRects[i*4].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4].width = rects[i].width + 1 + 2 * extra; ++ regRects[i*4].height = 1 + 2 * extra; ++ ++ regRects[i*4+1].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4+1].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4+1].width = 1 + 2 * extra; ++ regRects[i*4+1].height = rects[i].height + 1 + 2 * extra; ++ ++ regRects[i*4+2].x ++ = rects[i].x + rects[i].width - extra + pDrawable->x; ++ regRects[i*4+2].y = rects[i].y - extra + pDrawable->y; ++ regRects[i*4+2].width = 1 + 2 * extra; ++ regRects[i*4+2].height = rects[i].height + 1 + 2 * extra; ++ ++ regRects[i*4+3].x = rects[i].x - extra + pDrawable->x; ++ regRects[i*4+3].y ++ = rects[i].y + rects[i].height - extra + pDrawable->y; ++ regRects[i*4+3].width = rects[i].width + 1 + 2 * extra; ++ regRects[i*4+3].height = 1 + 2 * extra; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects*4, ++ regRects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)regRects); ++ } ++ ++ (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects); ++ ++ if (nrects) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyArc - take the union of bounding boxes around each arc (and clip). ++ * Bounding boxes assume each is a full circle / ellipse. ++ */ ++ ++static void ++rfbPolyArc(pDrawable, pGC, narcs, arcs) ++ DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int narcs; ++ xArc *arcs; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyArc called\n")); ++ ++ if (narcs) { ++ rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolyArc: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < narcs; i++) ++ { ++ rects[i].x = arcs[i].x - extra + pDrawable->x; ++ rects[i].y = arcs[i].y - extra + pDrawable->y; ++ rects[i].width = arcs[i].width + lw; ++ rects[i].height = arcs[i].height + lw; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs); ++ ++ if (narcs) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * FillPolygon - take bounding box around polygon (and clip). ++ */ ++ ++static void ++rfbFillPolygon(pDrawable, pGC, shape, mode, count, pts) ++ register DrawablePtr pDrawable; ++ register GCPtr pGC; ++ int shape, mode; ++ int count; ++ DDXPointPtr pts; ++{ ++ int i; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbFillPolygon called\n")); ++ ++ if (count) { ++ int minX = pts[0].x, maxX = pts[0].x; ++ int minY = pts[0].y, maxY = pts[0].y; ++ ++ if (mode == CoordModePrevious) ++ { ++ int x = pts[0].x, y = pts[0].y; ++ ++ for (i = 1; i < count; i++) { ++ x += pts[i].x; ++ y += pts[i].y; ++ if (x < minX) minX = x; ++ if (x > maxX) maxX = x; ++ if (y < minY) minY = y; ++ if (y > maxY) maxY = y; ++ } ++ } ++ else ++ { ++ for (i = 1; i < count; i++) { ++ if (pts[i].x < minX) minX = pts[i].x; ++ if (pts[i].x > maxX) maxX = pts[i].x; ++ if (pts[i].y < minY) minY = pts[i].y; ++ if (pts[i].y > maxY) maxY = pts[i].y; ++ } ++ } ++ ++ box.x1 = minX + pDrawable->x; ++ box.y1 = minY + pDrawable->y; ++ box.x2 = maxX + 1 + pDrawable->x; ++ box.y2 = maxY + 1 + pDrawable->y; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyFillRect - take the union of the given rectangles (and clip). ++ */ ++ ++static void ++rfbPolyFillRect(pDrawable, pGC, nrects, rects) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int nrects; ++ xRectangle *rects; ++{ ++ RegionPtr tmpRegion; ++ xRectangle *regRects; ++ int i; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyFillRect called\n")); ++ ++ if (nrects) { ++ regRects = (xRectangle *)xalloc(nrects*sizeof(xRectangle)); ++ if (!regRects) { ++ FatalError("rfbPolyFillRect: xalloc failed\n"); ++ } ++ ++ for (i = 0; i < nrects; i++) { ++ regRects[i].x = rects[i].x + pDrawable->x; ++ regRects[i].y = rects[i].y + pDrawable->y; ++ regRects[i].width = rects[i].width; ++ regRects[i].height = rects[i].height; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, nrects, regRects, ++ CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)regRects); ++ } ++ ++ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects); ++ ++ if (nrects) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyFillArc - take the union of bounding boxes around each arc (and clip). ++ * Bounding boxes assume each is a full circle / ellipse. ++ */ ++ ++static void ++rfbPolyFillArc(pDrawable, pGC, narcs, arcs) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int narcs; ++ xArc *arcs; ++{ ++ int i, extra, lw; ++ RegionPtr tmpRegion; ++ xRectangle *rects; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyFillArc called\n")); ++ ++ if (narcs) { ++ rects = (xRectangle *)xalloc(narcs*sizeof(xRectangle)); ++ if (!rects) { ++ FatalError("rfbPolyFillArc: xalloc failed\n"); ++ } ++ ++ lw = pGC->lineWidth; ++ if (lw == 0) ++ lw = 1; ++ ++ extra = lw / 2; ++ ++ for (i = 0; i < narcs; i++) ++ { ++ rects[i].x = arcs[i].x - extra + pDrawable->x; ++ rects[i].y = arcs[i].y - extra + pDrawable->y; ++ rects[i].width = arcs[i].width + lw; ++ rects[i].height = arcs[i].height + lw; ++ } ++ ++ tmpRegion = RECTS_TO_REGION(pDrawable->pScreen, narcs, rects, CT_NONE); ++ REGION_INTERSECT(pDrawable->pScreen, tmpRegion, tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, tmpRegion); ++ ++ REGION_DESTROY(pDrawable->pScreen, tmpRegion); ++ xfree((char *)rects); ++ } ++ ++ (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs); ++ ++ if (narcs) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * Get a rough bounding box around n characters of the given font. ++ */ ++ ++static void GetTextBoundingBox(pDrawable, font, x, y, n, pbox) ++ DrawablePtr pDrawable; ++ FontPtr font; ++ int x, y, n; ++ BoxPtr pbox; ++{ ++ int maxAscent, maxDescent, maxCharWidth; ++ ++ if (FONTASCENT(font) > FONTMAXBOUNDS(font,ascent)) ++ maxAscent = FONTASCENT(font); ++ else ++ maxAscent = FONTMAXBOUNDS(font,ascent); ++ ++ if (FONTDESCENT(font) > FONTMAXBOUNDS(font,descent)) ++ maxDescent = FONTDESCENT(font); ++ else ++ maxDescent = FONTMAXBOUNDS(font,descent); ++ ++ if (FONTMAXBOUNDS(font,rightSideBearing) > FONTMAXBOUNDS(font,characterWidth)) ++ maxCharWidth = FONTMAXBOUNDS(font,rightSideBearing); ++ else ++ maxCharWidth = FONTMAXBOUNDS(font,characterWidth); ++ ++ pbox->x1 = pDrawable->x + x; ++ pbox->y1 = pDrawable->y + y - maxAscent; ++ pbox->x2 = pbox->x1 + maxCharWidth * n; ++ pbox->y2 = pbox->y1 + maxAscent + maxDescent; ++ ++ if (FONTMINBOUNDS(font,leftSideBearing) < 0) { ++ pbox->x1 += FONTMINBOUNDS(font,leftSideBearing); ++ } ++} ++ ++ ++/* ++ * PolyText8 - use rough bounding box. ++ */ ++ ++static int ++rfbPolyText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ int ret; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyText8 called '%.*s'\n",count,chars)); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++ return ret; ++} ++ ++/* ++ * PolyText16 - use rough bounding box. ++ */ ++ ++static int ++rfbPolyText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ int ret; ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyText16 called\n")); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++ return ret; ++} ++ ++/* ++ * ImageText8 - use rough bounding box. ++ */ ++ ++static void ++rfbImageText8(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ char *chars; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageText8 called '%.*s'\n",count,chars)); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * ImageText16 - use rough bounding box. ++ */ ++ ++static void ++rfbImageText16(pDrawable, pGC, x, y, count, chars) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ int count; ++ unsigned short *chars; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageText16 called\n")); ++ ++ if (count) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); ++ ++ if (count) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * ImageGlyphBlt - use rough bounding box. ++ */ ++ ++static void ++rfbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbImageGlyphBlt called\n")); ++ ++ if (nglyph) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase); ++ ++ if (nglyph) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PolyGlyphBlt - use rough bounding box. ++ */ ++ ++static void ++rfbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) ++ DrawablePtr pDrawable; ++ GCPtr pGC; ++ int x, y; ++ unsigned int nglyph; ++ CharInfoPtr *ppci; /* array of character info */ ++ pointer pglyphBase; /* start of array of glyphs */ ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPolyGlyphBlt called\n")); ++ ++ if (nglyph) { ++ GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ } ++ ++ (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); ++ ++ if (nglyph) { ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ } ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++/* ++ * PushPixels - be fairly safe - region modified is intersection of the given ++ * rectangle with the window clip region. ++ */ ++ ++static void ++rfbPushPixels(pGC, pBitMap, pDrawable, w, h, x, y) ++ GCPtr pGC; ++ PixmapPtr pBitMap; ++ DrawablePtr pDrawable; ++ int w, h, x, y; ++{ ++ RegionRec tmpRegion; ++ BoxRec box; ++ GC_OP_PROLOGUE(pDrawable, pGC); ++ ++ TRC((stderr,"rfbPushPixels called\n")); ++ ++ box.x1 = x + pDrawable->x; ++ box.y1 = y + pDrawable->y; ++ box.x2 = box.x1 + w; ++ box.y2 = box.y1 + h; ++ ++ SAFE_REGION_INIT(pDrawable->pScreen, &tmpRegion, &box, 0); ++ ++ REGION_INTERSECT(pDrawable->pScreen, &tmpRegion, &tmpRegion, ++ pGC->pCompositeClip); ++ ++ ADD_TO_MODIFIED_REGION(pDrawable->pScreen, &tmpRegion); ++ ++ REGION_UNINIT(pDrawable->pScreen, &tmpRegion); ++ ++ (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); ++ ++ SCHEDULE_FB_UPDATE(pDrawable->pScreen, pVNC); ++ ++ GC_OP_EPILOGUE(pGC); ++} ++ ++#ifdef RENDER ++void ++rfbComposite( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height ++){ ++ ScreenPtr pScreen = pDst->pDrawable->pScreen; ++ VNCSCREENPTR(pScreen); ++ RegionRec tmpRegion; ++ BoxRec box; ++ PictureScreenPtr ps = GetPictureScreen(pScreen); ++ ++ box.x1 = pDst->pDrawable->x + xDst; ++ box.y1 = pDst->pDrawable->y + yDst; ++ box.x2 = box.x1 + width; ++ box.y2 = box.y1 + height; ++ ++ REGION_INIT(pScreen, &tmpRegion, &box, 0); ++ ++ ADD_TO_MODIFIED_REGION(pScreen, &tmpRegion); ++ ++ ps->Composite = pVNC->Composite; ++ (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc, ++ xMask, yMask, xDst, yDst, width, height); ++ ps->Composite = rfbComposite; ++ ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++ ++ REGION_UNINIT(pScreen, &tmpRegion); ++} ++#endif /* RENDER */ ++ ++/****************************************************************************/ ++/* ++ * Other functions ++ */ ++/****************************************************************************/ ++ ++/* ++ * rfbCopyRegion. Args are src and dst regions plus a translation (dx,dy). ++ * Takes these args together with the existing modified region and possibly an ++ * existing copy region and translation. Produces a combined modified region ++ * plus copy region and translation. Note that the copy region is the ++ * destination of the copy. ++ * ++ * First we trim parts of src which are invalid (ie in the modified region). ++ * Then we see if there is any overlap between the src and the existing copy ++ * region. If not then the two copies cannot be combined, so we choose ++ * whichever is bigger to form the basis of a new copy, while the other copy is ++ * just done the hard way by being added to the modified region. So if the ++ * existing copy is bigger then we simply add the destination of the new copy ++ * to the modified region and we're done. If the new copy is bigger, we add ++ * the old copy region to the modified region and behave as though there is no ++ * existing copy region. ++ * ++ * At this stage we now know that either the two copies can be combined, or ++ * that there is no existing copy. We temporarily add both the existing copy ++ * region and dst to the modified region (this is the entire area of the screen ++ * affected in any way). Finally we calculate the new copy region, and remove ++ * it from the modified region. ++ * ++ * Note: ++ * 1. The src region is modified by this routine. ++ * 2. When the copy region is empty, copyDX and copyDY MUST be set to zero. ++ */ ++ ++static void ++rfbCopyRegion(pScreen, cl, src, dst, dx, dy) ++ ScreenPtr pScreen; ++ rfbClientPtr cl; ++ RegionPtr src; ++ RegionPtr dst; ++ int dx, dy; ++{ ++ RegionRec tmp; ++ ++ /* src = src - modifiedRegion */ ++ ++ REGION_SUBTRACT(pScreen, src, src, &cl->modifiedRegion); ++ ++ if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ ++ REGION_NULL(pScreen, &tmp); ++ REGION_INTERSECT(pScreen, &tmp, src, &cl->copyRegion); ++ ++ if (REGION_NOTEMPTY(pScreen, &tmp)) { ++ ++ /* if src and copyRegion overlap: ++ src = src intersect copyRegion */ ++ ++ REGION_COPY(pScreen, src, &tmp); ++ ++ } else { ++ ++ /* if no overlap, find bigger region */ ++ ++ int newArea = (((REGION_EXTENTS(pScreen,src))->x2 ++ - (REGION_EXTENTS(pScreen,src))->x1) ++ * ((REGION_EXTENTS(pScreen,src))->y2 ++ - (REGION_EXTENTS(pScreen,src))->y1)); ++ ++ int oldArea = (((REGION_EXTENTS(pScreen,&cl->copyRegion))->x2 ++ - (REGION_EXTENTS(pScreen,&cl->copyRegion))->x1) ++ * ((REGION_EXTENTS(pScreen,&cl->copyRegion))->y2 ++ - (REGION_EXTENTS(pScreen,&cl->copyRegion))->y1)); ++ ++ if (oldArea > newArea) { ++ ++ /* existing copy is bigger: ++ modifiedRegion = modifiedRegion union dst ++ copyRegion = copyRegion - dst ++ return */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ dst); ++ REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion, ++ dst); ++ if (!REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ } ++ return; ++ } ++ ++ /* new copy is bigger: ++ modifiedRegion = modifiedRegion union copyRegion ++ copyRegion = empty */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ REGION_EMPTY(pScreen, &cl->copyRegion); ++ cl->copyDX = cl->copyDY = 0; ++ } ++ } ++ ++ ++ /* modifiedRegion = modifiedRegion union dst union copyRegion */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, dst); ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ ++ /* copyRegion = T(src) intersect dst */ ++ ++ REGION_TRANSLATE(pScreen, src, dx, dy); ++ REGION_INTERSECT(pScreen, &cl->copyRegion, src, dst); ++ ++ /* modifiedRegion = modifiedRegion - copyRegion */ ++ ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ ++ /* combine new translation T with existing translation */ ++ ++ if (REGION_NOTEMPTY(pScreen, &cl->copyRegion)) { ++ cl->copyDX += dx; ++ cl->copyDY += dy; ++ } else { ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ } ++} ++ ++ ++/* ++ * rfbDeferredUpdateCallback() is called when a client's deferredUpdateTimer ++ * goes off. ++ */ ++ ++static CARD32 ++rfbDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) ++{ ++ rfbClientPtr cl = (rfbClientPtr)arg; ++ ++ rfbSendFramebufferUpdate(cl->pScreen, cl); ++ ++ cl->deferredUpdateScheduled = FALSE; ++ return 0; ++} ++ ++ ++/* ++ * rfbScheduleDeferredUpdate() is called from the SCHEDULE_FB_UPDATE macro ++ * to schedule an update. ++ */ ++ ++static void ++rfbScheduleDeferredUpdate(ScreenPtr pScreen, rfbClientPtr cl) ++{ ++ if (rfbDeferUpdateTime != 0) { ++ cl->deferredUpdateTimer = TimerSet(cl->deferredUpdateTimer, 0, ++ rfbDeferUpdateTime, ++ rfbDeferredUpdateCallback, cl); ++ cl->deferredUpdateScheduled = TRUE; ++ } else { ++ rfbSendFramebufferUpdate(pScreen, cl); ++ } ++} ++ ++ ++/* ++ * PrintRegion is useful for debugging. ++ */ ++ ++#ifdef DEBUG ++static void ++PrintRegion(ScreenPtr pScreen, RegionPtr reg) ++{ ++ int nrects = REGION_NUM_RECTS(reg); ++ int i; ++ ++ ErrorF("Region num rects %d extents %d,%d %d,%d\n",nrects, ++ (REGION_EXTENTS(pScreen,reg))->x1, ++ (REGION_EXTENTS(pScreen,reg))->y1, ++ (REGION_EXTENTS(pScreen,reg))->x2, ++ (REGION_EXTENTS(pScreen,reg))->y2); ++ ++ for (i = 0; i < nrects; i++) { ++ ErrorF(" rect %d,%d %dx%d\n", ++ REGION_RECTS(reg)[i].x1, ++ REGION_RECTS(reg)[i].y1, ++ REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1, ++ REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1); ++ } ++} ++#endif ++ ++ ++/** ++ * Allow scheduling updates from other functions in other files. ++ */ ++void ++rfbScheduleUpdate(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ SCHEDULE_FB_UPDATE(pScreen, pVNC); ++} +diff --git a/hw/xfree86/vnc/hextile.c b/hw/xfree86/vnc/hextile.c +new file mode 100644 +index 0000000..6017489 +--- /dev/null ++++ b/hw/xfree86/vnc/hextile.c +@@ -0,0 +1,352 @@ ++/* ++ * hextile.c ++ * ++ * Routines to implement Hextile Encoding ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include "rfb.h" ++ ++static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h); ++static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h); ++static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h); ++ ++ ++/* ++ * rfbSendRectEncodingHextile - send a rectangle using hextile encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingHextile(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingHextile); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingHextile]++; ++ cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader; ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ return sendHextiles8(cl, x, y, w, h); ++ case 16: ++ return sendHextiles16(cl, x, y, w, h); ++ case 32: ++ return sendHextiles32(cl, x, y, w, h); ++ } ++ ++ rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel); ++ return FALSE; ++} ++ ++ ++#define PUT_PIXEL8(pix) (pVNC->updateBuf[pVNC->ublen++] = (pix)) ++ ++#define PUT_PIXEL16(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1]) ++ ++#define PUT_PIXEL32(pix) (pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[0], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[1], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[2], \ ++ pVNC->updateBuf[pVNC->ublen++] = ((char*)&(pix))[3]) ++ ++ ++#define DEFINE_SEND_HEXTILES(bpp) \ ++ \ ++ \ ++static Bool subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, \ ++ int h, CARD##bpp bg, \ ++ CARD##bpp fg, Bool mono); \ ++static void testColours##bpp(CARD##bpp *data, int size, Bool *mono, \ ++ Bool *solid, CARD##bpp *bg, CARD##bpp *fg); \ ++ \ ++ \ ++/* \ ++ * rfbSendHextiles \ ++ */ \ ++ \ ++static Bool \ ++sendHextiles##bpp(cl, rx, ry, rw, rh) \ ++ rfbClientPtr cl; \ ++ int rx, ry, rw, rh; \ ++{ \ ++ VNCSCREENPTR(cl->pScreen); \ ++ int x, y, w, h; \ ++ int startUblen; \ ++ unsigned char *fbptr; \ ++ CARD##bpp bg = 0, fg = 0, newBg, newFg; \ ++ Bool mono, solid; \ ++ Bool validBg = FALSE; \ ++ Bool validFg = FALSE; \ ++ CARD##bpp clientPixelData[16*16*(bpp/8)]; \ ++ \ ++ for (y = ry; y < ry+rh; y += 16) { \ ++ for (x = rx; x < rx+rw; x += 16) { \ ++ w = h = 16; \ ++ if (rx+rw - x < 16) \ ++ w = rx+rw - x; \ ++ if (ry+rh - y < 16) \ ++ h = ry+rh - y; \ ++ \ ++ if ((pVNC->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \ ++ if (!rfbSendUpdateBuf(cl)) \ ++ return FALSE; \ ++ } \ ++ \ ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) \ ++ + (x * (pVNC->bitsPerPixel / 8))); \ ++ \ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \ ++ &pVNC->rfbServerFormat, \ ++ &cl->format, fbptr, (char *)clientPixelData, \ ++ pVNC->paddedWidthInBytes, w, h, x, y); \ ++ \ ++ startUblen = pVNC->ublen; \ ++ pVNC->updateBuf[startUblen] = 0; \ ++ pVNC->ublen++; \ ++ \ ++ testColours##bpp(clientPixelData, w * h, \ ++ &mono, &solid, &newBg, &newFg); \ ++ \ ++ if (!validBg || (newBg != bg)) { \ ++ validBg = TRUE; \ ++ bg = newBg; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \ ++ PUT_PIXEL##bpp(bg); \ ++ } \ ++ \ ++ if (solid) { \ ++ cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \ ++ continue; \ ++ } \ ++ \ ++ pVNC->updateBuf[startUblen] |= rfbHextileAnySubrects; \ ++ \ ++ if (mono) { \ ++ if (!validFg || (newFg != fg)) { \ ++ validFg = TRUE; \ ++ fg = newFg; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \ ++ PUT_PIXEL##bpp(fg); \ ++ } \ ++ } else { \ ++ validFg = FALSE; \ ++ pVNC->updateBuf[startUblen] |= rfbHextileSubrectsColoured; \ ++ } \ ++ \ ++ if (!subrectEncode##bpp(cl->pScreen, clientPixelData, w, h, bg, fg, mono)) { \ ++ /* encoding was too large, use raw */ \ ++ validBg = FALSE; \ ++ validFg = FALSE; \ ++ pVNC->ublen = startUblen; \ ++ pVNC->updateBuf[pVNC->ublen++] = rfbHextileRaw; \ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, \ ++ &pVNC->rfbServerFormat, &cl->format, fbptr,\ ++ (char *)clientPixelData, \ ++ pVNC->paddedWidthInBytes, w, h, x, y); \ ++ \ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)clientPixelData,\ ++ w * h * (bpp/8)); \ ++ \ ++ pVNC->ublen += w * h * (bpp/8); \ ++ } \ ++ \ ++ cl->rfbBytesSent[rfbEncodingHextile] += pVNC->ublen - startUblen; \ ++ } \ ++ } \ ++ \ ++ return TRUE; \ ++} \ ++ \ ++ \ ++static Bool \ ++subrectEncode##bpp(ScreenPtr pScreen, CARD##bpp *data, int w, int h, \ ++ CARD##bpp bg, CARD##bpp fg, Bool mono) \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp clientdata; \ ++ int x,y; \ ++ int i,j; \ ++ int hx=0,hy,vx=0,vy; \ ++ int hyflag; \ ++ CARD##bpp *seg; \ ++ CARD##bpp *line; \ ++ int hw,hh,vw,vh; \ ++ int thex,they,thew,theh; \ ++ int numsubs = 0; \ ++ int newLen; \ ++ int nSubrectsUblen; \ ++ \ ++ nSubrectsUblen = pVNC->ublen; \ ++ pVNC->ublen++; \ ++ \ ++ for (y=0; y 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/xfree86/vnc/httpd.c b/hw/xfree86/vnc/httpd.c +new file mode 100644 +index 0000000..863543a +--- /dev/null ++++ b/hw/xfree86/vnc/httpd.c +@@ -0,0 +1,520 @@ ++/* ++ * httpd.c - a simple HTTP server ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef USE_LIBWRAP ++#define USE_LIBWRAP 0 ++#endif ++#if USE_LIBWRAP ++#include ++#endif ++ ++#include "rfb.h" ++ ++#define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\n\r\n" \ ++ "File Not Found\n" \ ++ "

File Not Found

\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 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(¶m_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, ++ "\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/xfree86/vnc/kbdptr.c b/hw/xfree86/vnc/kbdptr.c +new file mode 100644 +index 0000000..6fd0d73 +--- /dev/null ++++ b/hw/xfree86/vnc/kbdptr.c +@@ -0,0 +1,426 @@ ++/* ++ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ * ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "rfb.h" ++#include "X11/X.h" ++#define NEED_EVENTS ++#include "X11/Xproto.h" ++#include "inputstr.h" ++#define XK_CYRILLIC ++#include ++#include ++#include "mi.h" ++#include "mipointer.h" ++ ++#if XFREE86VNC ++#ifdef XINPUT ++# include "xf86Xinput.h" ++# define Enqueue(ev) xf86eqEnqueue(ev) ++#else ++# define Enqueue(ev) mieqEnqueue(ev) ++#endif ++#else ++#define Enqueue(ev) mieqEnqueue(ev) ++#endif ++ ++#define KEY_IS_PRESSED(keycode) \ ++ (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7))) ++ ++static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper); ++ ++DeviceIntPtr kbdDevice = NULL; ++ ++#include "keyboard.h" ++ ++/* ++ * Called when the rfbserver receives a rfbKeyEvent event from a client. ++ * Put an X keyboard event into the event queue. ++ */ ++void ++KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl) ++{ ++ xEvent ev, fake; ++ KeySymsPtr keySyms; ++ int i; ++ int keyCode = 0; ++ int freeIndex = -1; ++ unsigned long time; ++ Bool fakeShiftPress = FALSE; ++ Bool fakeShiftLRelease = FALSE; ++ Bool fakeShiftRRelease = FALSE; ++ Bool shiftMustBeReleased = FALSE; ++ Bool shiftMustBePressed = FALSE; ++ ++ if (!kbdDevice) return; ++ ++ keySyms = &kbdDevice->key->curKeySyms; ++ ++#ifdef CORBA ++ if (cl) { ++ CARD32 clientId = cl->sock; ++ ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, ++ 32, PropModeReplace, 1, (pointer)&clientId, TRUE); ++ } ++#endif ++ ++ if (down) { ++ ev.u.u.type = KeyPress; ++ } else { ++ ev.u.u.type = KeyRelease; ++ } ++ ++ /* NOTE: This is where it gets hairy for XFree86 servers. ++ * I think the best way to deal with this is invent a new protocol ++ * to send over the wire the remote keyboard type and correctly ++ * handle that as XINPUT extension device (we're part of the way ++ * there for that. ++ * ++ * Alan. ++ */ ++#if !XFREE86VNC ++ /* First check if it's one of our predefined keys. If so then we can make ++ some attempt at allowing an xmodmap inside a VNC desktop behave ++ something like you'd expect - e.g. if keys A & B are swapped over and ++ the VNC client sends an A, then map it to a B when generating the X ++ event. We don't attempt to do this for keycodes which we make up on the ++ fly because it's too hard... */ ++ ++ for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { ++ if (keySym == map[i]) { ++ keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY; ++ ++ if (map[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) { ++ ++ /* this keycode has more than one symbol associated with it, ++ so shift state is important */ ++ ++ if ((i % GLYPHS_PER_KEY) == 0) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ break; ++ } ++ } ++#endif ++ ++ if (!keyCode) { ++ ++ /* not one of our predefined keys - see if it's in the current keyboard ++ mapping (i.e. we've already allocated an extra keycode for it) */ ++ ++ if (keySyms->mapWidth < 2) { ++ ErrorF("KbdAddEvent: Sanity check failed - Keyboard mapping has " ++ "less than 2 keysyms per keycode (KeySym 0x%x)\n", ++ (unsigned) keySym); ++ return; ++ } ++ ++ for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) { ++ if (keySym == keySyms->map[i]) { ++ keyCode = MIN_KEY_CODE + i / keySyms->mapWidth; ++ ++ if (keySyms->map[(i / keySyms->mapWidth) ++ * keySyms->mapWidth + 1] != NoSymbol) { ++ ++ /* this keycode has more than one symbol associated with ++ it, so shift state is important */ ++ ++ if ((i % keySyms->mapWidth) == 0) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ break; ++ } ++ if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol) ++ && (i % keySyms->mapWidth) == 0) ++ { ++ freeIndex = i; ++ } ++ } ++ } ++ ++ if (!keyCode) { ++ KeySym lower, upper; ++ ++ /* we don't have an existing keycode - make one up on the fly and add ++ it to the keyboard mapping. Thanks to Vlad Harchev for pointing ++ out problems with non-ascii capitalisation. */ ++ ++ if (freeIndex == -1) { ++ ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n", ++ (unsigned) keySym); ++ return; ++ } ++ ++ keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth; ++ ++ XConvertCase(keySym, &lower, &upper); ++ ++ if (lower == upper) { ++ keySyms->map[freeIndex] = keySym; ++ ++ } else { ++ keySyms->map[freeIndex] = lower; ++ keySyms->map[freeIndex+1] = upper; ++ ++ if (keySym == lower) ++ shiftMustBeReleased = TRUE; ++ else ++ shiftMustBePressed = TRUE; ++ } ++ ++ SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient); ++ ++ ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n", ++ (unsigned) keySym, keyCode); ++ } ++ ++ time = GetTimeInMillis(); ++ ++ if (down) { ++ if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) { ++ fakeShiftPress = TRUE; ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) { ++ if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) { ++ fakeShiftLRelease = TRUE; ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) { ++ fakeShiftRRelease = TRUE; ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_R_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ } ++ } ++ ++ ev.u.u.detail = keyCode; ++ ev.u.keyButtonPointer.time = time; ++ Enqueue(&ev); ++ ++ if (fakeShiftPress) { ++ fake.u.u.type = KeyRelease; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (fakeShiftLRelease) { ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_L_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++ if (fakeShiftRRelease) { ++ fake.u.u.type = KeyPress; ++ fake.u.u.detail = SHIFT_R_KEY_CODE; ++ fake.u.keyButtonPointer.time = time; ++ Enqueue(&fake); ++ } ++} ++ ++/* ++ * Called when the rfbserver receives a rfbPointerEvent event from a client. ++ * Put an X mouse event into the event queue. ++ */ ++void ++PtrAddEvent(buttonMask, x, y, cl) ++ int buttonMask; ++ int x; ++ int y; ++ rfbClientPtr cl; ++{ ++ xEvent ev; ++ int i; ++ unsigned long time; ++ static int oldButtonMask = 0; ++ ++#ifdef CORBA ++ if (cl) { ++ CARD32 clientId = cl->sock; ++ ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER, ++ 32, PropModeReplace, 1, (pointer)&clientId, TRUE); ++ } ++#endif ++ ++ time = GetTimeInMillis(); ++ ++ miPointerAbsoluteCursor(x, y, time); ++ ++ for (i = 0; i < 5; i++) { ++ if ((buttonMask ^ oldButtonMask) & (1<key->down[i] != 0) { ++ for (j = 0; j < 8; j++) { ++ if (kbdDevice->key->down[i] & (1 << j)) { ++ ev.u.u.type = KeyRelease; ++ ev.u.u.detail = (i << 3) | j; ++ ev.u.keyButtonPointer.time = time; ++ Enqueue(&ev); ++ } ++ } ++ } ++ } ++} ++ ++ ++/* copied from Xlib source */ ++ ++static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper) ++{ ++ *lower = sym; ++ *upper = sym; ++ switch(sym >> 8) { ++ case 0: /* Latin 1 */ ++ if ((sym >= XK_A) && (sym <= XK_Z)) ++ *lower += (XK_a - XK_A); ++ else if ((sym >= XK_a) && (sym <= XK_z)) ++ *upper -= (XK_a - XK_A); ++ else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) ++ *lower += (XK_agrave - XK_Agrave); ++ else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) ++ *upper -= (XK_agrave - XK_Agrave); ++ else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) ++ *lower += (XK_oslash - XK_Ooblique); ++ else if ((sym >= XK_oslash) && (sym <= XK_thorn)) ++ *upper -= (XK_oslash - XK_Ooblique); ++ break; ++ case 1: /* Latin 2 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym == XK_Aogonek) ++ *lower = XK_aogonek; ++ else if (sym >= XK_Lstroke && sym <= XK_Sacute) ++ *lower += (XK_lstroke - XK_Lstroke); ++ else if (sym >= XK_Scaron && sym <= XK_Zacute) ++ *lower += (XK_scaron - XK_Scaron); ++ else if (sym >= XK_Zcaron && sym <= XK_Zabovedot) ++ *lower += (XK_zcaron - XK_Zcaron); ++ else if (sym == XK_aogonek) ++ *upper = XK_Aogonek; ++ else if (sym >= XK_lstroke && sym <= XK_sacute) ++ *upper -= (XK_lstroke - XK_Lstroke); ++ else if (sym >= XK_scaron && sym <= XK_zacute) ++ *upper -= (XK_scaron - XK_Scaron); ++ else if (sym >= XK_zcaron && sym <= XK_zabovedot) ++ *upper -= (XK_zcaron - XK_Zcaron); ++ else if (sym >= XK_Racute && sym <= XK_Tcedilla) ++ *lower += (XK_racute - XK_Racute); ++ else if (sym >= XK_racute && sym <= XK_tcedilla) ++ *upper -= (XK_racute - XK_Racute); ++ break; ++ case 2: /* Latin 3 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Hstroke && sym <= XK_Hcircumflex) ++ *lower += (XK_hstroke - XK_Hstroke); ++ else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex) ++ *lower += (XK_gbreve - XK_Gbreve); ++ else if (sym >= XK_hstroke && sym <= XK_hcircumflex) ++ *upper -= (XK_hstroke - XK_Hstroke); ++ else if (sym >= XK_gbreve && sym <= XK_jcircumflex) ++ *upper -= (XK_gbreve - XK_Gbreve); ++ else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex) ++ *lower += (XK_cabovedot - XK_Cabovedot); ++ else if (sym >= XK_cabovedot && sym <= XK_scircumflex) ++ *upper -= (XK_cabovedot - XK_Cabovedot); ++ break; ++ case 3: /* Latin 4 */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Rcedilla && sym <= XK_Tslash) ++ *lower += (XK_rcedilla - XK_Rcedilla); ++ else if (sym >= XK_rcedilla && sym <= XK_tslash) ++ *upper -= (XK_rcedilla - XK_Rcedilla); ++ else if (sym == XK_ENG) ++ *lower = XK_eng; ++ else if (sym == XK_eng) ++ *upper = XK_ENG; ++ else if (sym >= XK_Amacron && sym <= XK_Umacron) ++ *lower += (XK_amacron - XK_Amacron); ++ else if (sym >= XK_amacron && sym <= XK_umacron) ++ *upper -= (XK_amacron - XK_Amacron); ++ break; ++ case 6: /* Cyrillic */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE) ++ *lower -= (XK_Serbian_DJE - XK_Serbian_dje); ++ else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze) ++ *upper += (XK_Serbian_DJE - XK_Serbian_dje); ++ else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN) ++ *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu); ++ else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign) ++ *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu); ++ break; ++ case 7: /* Greek */ ++ /* Assume the KeySym is a legal value (ignore discontinuities) */ ++ if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent) ++ *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); ++ else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent && ++ sym != XK_Greek_iotaaccentdieresis && ++ sym != XK_Greek_upsilonaccentdieresis) ++ *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent); ++ else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA) ++ *lower += (XK_Greek_alpha - XK_Greek_ALPHA); ++ else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega && ++ sym != XK_Greek_finalsmallsigma) ++ *upper -= (XK_Greek_alpha - XK_Greek_ALPHA); ++ break; ++ } ++} +diff --git a/hw/xfree86/vnc/keyboard.h b/hw/xfree86/vnc/keyboard.h +new file mode 100644 +index 0000000..ab5b1b3 +--- /dev/null ++++ b/hw/xfree86/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 ++ */ ++ ++#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/xfree86/vnc/loginauth.c b/hw/xfree86/vnc/loginauth.c +new file mode 100644 +index 0000000..5041429 +--- /dev/null ++++ b/hw/xfree86/vnc/loginauth.c +@@ -0,0 +1,141 @@ ++/* ++ * loginauth.c - deal with login-style Unix authentication. ++ * ++ * This file implements the UnixLogin authentication protocol when setting up ++ * an RFB connection. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2003 Constantin Kaplinsky. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef linux ++#include /* XXX xserver has a shadow.h file too */ ++#endif ++#include ++#include ++#include ++#define _XOPEN_SOURCE ++#define __USE_XOPEN /* XXX shouldn't really need this */ ++#include ++#include ++#include ++#include "rfb.h" ++ ++void rfbLoginAuthProcessClientMessage(rfbClientPtr cl) ++{ ++ int n1 = 0, n2 = 0; ++ CARD32 loginLen, passwdLen, authResult; ++ char *loginBuf, *passwdBuf; ++ struct passwd *ps; ++ char *encPasswd1, *encPasswd2; ++ Bool ok; ++ ++ if ((n1 = ReadExact(cl->sock, (char *)&loginLen, ++ sizeof(loginLen))) <= 0 || ++ (n2 = ReadExact(cl->sock, (char *)&passwdLen, ++ sizeof(passwdLen))) <= 0) { ++ if (n1 != 0 || n2 != 0) ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ loginLen = Swap32IfLE(loginLen); ++ passwdLen = Swap32IfLE(passwdLen); ++ loginBuf = (char *)xalloc(loginLen + 1); ++ passwdBuf = (char *)xalloc(passwdLen + 1); ++ ++ n1 = n2 = 0; ++ if ((n1 = ReadExact(cl->sock, loginBuf, loginLen)) <= 0 || ++ (n2 = ReadExact(cl->sock, passwdBuf, passwdLen)) <= 0) { ++ if (n1 != 0 || n2 != 0) ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ loginBuf[loginLen] = '\0'; ++ passwdBuf[passwdLen] = '\0'; ++ ++ encPasswd1 = encPasswd2 = NULL; ++ ++ ps = getpwnam(loginBuf); ++ if (ps == NULL) { ++ rfbLog("rfbLoginAuthProcessClientMessage: " ++ "Cannot get password file entry for \"%s\"\n", loginBuf); ++ } else { ++ encPasswd1 = ps->pw_passwd; ++#ifdef linux ++ if (strlen(ps->pw_passwd) == 1) { ++ struct spwd *sps; ++ ++ sps = getspnam(loginBuf); ++ if (sps == NULL) { ++ rfbLog("rfbLoginAuthProcessClientMessage:" ++ " getspnam() failed for user \"%s\"\n", loginBuf); ++ } else { ++ encPasswd1 = sps->sp_pwdp; ++ } ++ } ++#endif ++ encPasswd2 = crypt(passwdBuf, encPasswd1); ++ memset(passwdBuf, 0, strlen(passwdBuf)); ++ } ++ ++ ok = FALSE; ++ if (encPasswd1 != NULL && encPasswd2 != NULL) { ++ if (strcmp(encPasswd1, encPasswd2) == 0) ++ ok = TRUE; ++ } ++ ++ if (!ok) { ++ rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n", ++ cl->host); ++ ++ if (rfbAuthConsiderBlocking(cl)) { ++ authResult = Swap32IfLE(rfbVncAuthTooMany); ++ } else { ++ authResult = Swap32IfLE(rfbVncAuthFailed); ++ } ++ ++ if (WriteExact(cl->sock, (char *)&authResult, ++ sizeof(authResult)) < 0) { ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: write"); ++ } ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ rfbAuthUnblock(cl); ++ ++ cl->login = strdup(loginBuf); ++ rfbLog("Login-style authentication passed for user %s at %s\n", ++ cl->login, cl->host); ++ ++ authResult = Swap32IfLE(rfbVncAuthOK); ++ ++ if (WriteExact(cl->sock, (char *)&authResult, sizeof(authResult)) < 0) { ++ rfbLogPerror("rfbLoginAuthProcessClientMessage: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ cl->state = RFB_INITIALISATION; ++} ++ +diff --git a/hw/xfree86/vnc/rfb.h b/hw/xfree86/vnc/rfb.h +new file mode 100644 +index 0000000..f22604b +--- /dev/null ++++ b/hw/xfree86/vnc/rfb.h +@@ -0,0 +1,726 @@ ++/* ++ * rfb.h - header file for RFB DDX implementation. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000-2004 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include ++#endif ++ ++#include ++#include "scrnintstr.h" ++#include "colormapst.h" ++#include "dixstruct.h" ++#include "gcstruct.h" ++#include "regionstr.h" ++#include "windowstr.h" ++#include "dixfontstr.h" ++#include "rfbproto.h" ++#include "vncauth.h" ++#include "picturestr.h" ++ ++#define _VNC_SERVER ++#include ++ ++ ++ ++#if defined(sun) || defined(hpux) ++#define SOCKLEN_T int ++#else ++#define SOCKLEN_T socklen_t ++#endif ++ ++/* It's a good idea to keep these values a bit greater than required. */ ++#define MAX_ENCODINGS 10 ++#define MAX_SECURITY_TYPES 4 ++#define MAX_TUNNELING_CAPS 16 ++#define MAX_AUTH_CAPS 16 ++ ++/* ++ * HTTP_BUF_SIZE for http transfers ++ */ ++#define HTTP_BUF_SIZE 32768 ++ ++/* ++ * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the ++ * framebuffer. So for a max screen width of say 2K with 32-bit pixels this ++ * means 8K minimum. ++ */ ++#define UPDATE_BUF_SIZE 30000 ++ ++#if XFREE86VNC ++#include "xf86.h" ++#include "vncint.h" ++#define VNCSCREENPTR(ptr) \ ++ vncScreenPtr pVNC = VNCPTR(ptr) ++#else ++bad! ++#define VNCSCREENPTR(ptr) \ ++/* Soon \ ++ rfbScreenInfoPtr pVNC = rfbScreen[ptr->myNum] \ ++*/ \ ++ rfbScreenInfoPtr pVNC = &rfbScreen ++#endif ++ ++/* ++ * Per-screen (framebuffer) structure. There is only one of these, since we ++ * don't allow the X server to have multiple screens. ++ */ ++ ++typedef struct ++{ ++ int rfbPort; ++ int rdpPort; ++ int udpPort; ++ int rfbListenSock; ++ int rdpListenSock; ++ int udpSock; ++ int httpPort; ++ int httpListenSock; ++ int httpSock; ++ char * httpDir; ++ char buf[HTTP_BUF_SIZE]; ++ Bool udpSockConnected; ++ char * rfbAuthPasswdFile; ++ size_t buf_filled; ++ int maxFd; ++ fd_set allFds; ++ Bool useGetImage; ++ Bool noCursor; ++ Bool rfbAlwaysShared; ++ Bool rfbNeverShared; ++ Bool rfbDontDisconnect; ++ Bool rfbUserAccept; ++ Bool rfbViewOnly; ++ ColormapPtr savedColormap; ++ ColormapPtr rfbInstalledColormap; ++ rfbPixelFormat rfbServerFormat; ++ Bool rfbAuthTooManyTries; ++ int rfbAuthTries; ++ Bool loginAuthEnabled; ++ struct in_addr interface; ++ OsTimerPtr timer; ++ char updateBuf[UPDATE_BUF_SIZE]; ++ int ublen; ++ int width; ++ int paddedWidthInBytes; ++ int height; ++ int depth; ++ int bitsPerPixel; ++ int sizeInBytes; ++ unsigned char *pfbMemory; ++ Pixel blackPixel; ++ Pixel whitePixel; ++ ++ /* The following two members are used to minimise the amount of unnecessary ++ drawing caused by cursor movement. Whenever any drawing affects the ++ part of the screen where the cursor is, the cursor is removed first and ++ then the drawing is done (this is what the sprite routines test for). ++ Afterwards, however, we do not replace the cursor, even when the cursor ++ is logically being moved across the screen. We only draw the cursor ++ again just as we are about to send the client a framebuffer update. ++ ++ We need to be careful when removing and drawing the cursor because of ++ their relationship with the normal drawing routines. The drawing ++ routines can invoke the cursor routines, but also the cursor routines ++ themselves end up invoking drawing routines. ++ ++ Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by ++ doing a CopyArea from a pixmap to the screen, where the pixmap contains ++ the saved contents of the screen under the cursor. Before doing this, ++ however, we set cursorIsDrawn to FALSE. Then, when CopyArea is called, ++ it sees that cursorIsDrawn is FALSE and so doesn't feel the need to ++ (recursively!) remove the cursor before doing it. ++ ++ Putting up the cursor (rfbSpriteRestoreCursor) involves a call to ++ PushPixels. While this is happening, cursorIsDrawn must be FALSE so ++ that PushPixels doesn't think it has to remove the cursor first. ++ Obviously cursorIsDrawn is set to TRUE afterwards. ++ ++ Another problem we face is that drawing routines sometimes cause a ++ framebuffer update to be sent to the RFB client. When the RFB client is ++ already waiting for a framebuffer update and some drawing to the ++ framebuffer then happens, the drawing routine sees that the client is ++ ready, so it calls rfbSendFramebufferUpdate. If the cursor is not drawn ++ at this stage, it must be put up, and so rfbSpriteRestoreCursor is ++ called. However, if the original drawing routine was actually called ++ from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't ++ want this to happen. So both the cursor routines set ++ dontSendFramebufferUpdate to TRUE, and all the drawing routines check ++ this before calling rfbSendFramebufferUpdate. */ ++ ++ Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ ++ Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the ++ cursor */ ++ ++ /* wrapped screen functions */ ++ ++ CloseScreenProcPtr CloseScreen; ++ CreateGCProcPtr CreateGC; ++ PaintWindowBackgroundProcPtr PaintWindowBackground; ++ PaintWindowBorderProcPtr PaintWindowBorder; ++ CopyWindowProcPtr CopyWindow; ++ ClearToBackgroundProcPtr ClearToBackground; ++ RestoreAreasProcPtr RestoreAreas; ++ ScreenWakeupHandlerProcPtr WakeupHandler; ++#ifdef CHROMIUM ++ RealizeWindowProcPtr RealizeWindow; ++ UnrealizeWindowProcPtr UnrealizeWindow; ++ DestroyWindowProcPtr DestroyWindow; ++ ResizeWindowProcPtr ResizeWindow; ++ PositionWindowProcPtr PositionWindow; ++ ClipNotifyProcPtr ClipNotify; ++#endif ++#ifdef RENDER ++ CompositeProcPtr Composite; ++#endif ++ ++} rfbScreenInfo, *rfbScreenInfoPtr; ++ ++ ++/* ++ * rfbTranslateFnType is the type of translation functions. ++ */ ++ ++struct rfbClientRec; ++typedef void (*rfbTranslateFnType)(ScreenPtr pScreen, ++ char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y); ++ ++ ++/* ++ * Per-client structure. ++ */ ++ ++typedef struct rfbClientRec { ++ int sock; ++ char *host; ++ char *login; ++ ++ int protocol_minor_ver; /* RFB protocol minor version in use. */ ++ Bool protocol_tightvnc; /* TightVNC protocol extensions enabled */ ++ ++ /* Possible client states: */ ++ ++ enum { ++ RFB_PROTOCOL_VERSION, /* establishing protocol version */ ++ RFB_SECURITY_TYPE, /* negotiating security (RFB v.3.7) */ ++ RFB_TUNNELING_TYPE, /* establishing tunneling (RFB v.3.7t) */ ++ RFB_AUTH_TYPE, /* negotiating authentication (RFB v.3.7t) */ ++ RFB_AUTHENTICATION, /* authenticating (VNC authentication) */ ++ RFB_INITIALISATION, /* sending initialisation messages */ ++ RFB_NORMAL /* normal protocol messages */ ++ } state; ++ ++ Bool viewOnly; /* Do not accept input from this client. */ ++ ++ Bool reverseConnection; ++ ++ Bool readyForSetColourMapEntries; ++ ++ Bool useCopyRect; ++ int preferredEncoding; ++ int correMaxWidth, correMaxHeight; ++ ++ /* The list of security types sent to this client (protocol 3.7). ++ Note that the first entry is the number of list items following. */ ++ ++ CARD8 securityTypes[MAX_SECURITY_TYPES + 1]; ++ ++ /* Lists of capability codes sent to clients. We remember these ++ lists to restrict clients from choosing those tunneling and ++ authentication types that were not advertised. */ ++ ++ int nAuthCaps; ++ CARD32 authCaps[MAX_AUTH_CAPS]; ++ ++ /* This is not useful while we don't support tunneling: ++ int nTunnelingCaps; ++ CARD32 tunnelingCaps[MAX_TUNNELING_CAPS]; */ ++ ++ /* The following member is only used during VNC authentication */ ++ ++ CARD8 authChallenge[CHALLENGESIZE]; ++ ++ /* The following members represent the update needed to get the client's ++ framebuffer from its present state to the current state of our ++ framebuffer. ++ ++ If the client does not accept CopyRect encoding then the update is ++ simply represented as the region of the screen which has been modified ++ (modifiedRegion). ++ ++ If the client does accept CopyRect encoding, then the update consists of ++ two parts. First we have a single copy from one region of the screen to ++ another (the destination of the copy is copyRegion), and second we have ++ the region of the screen which has been modified in some other way ++ (modifiedRegion). ++ ++ Although the copy is of a single region, this region may have many ++ rectangles. When sending an update, the copyRegion is always sent ++ before the modifiedRegion. This is because the modifiedRegion may ++ overlap parts of the screen which are in the source of the copy. ++ ++ In fact during normal processing, the modifiedRegion may even overlap ++ the destination copyRegion. Just before an update is sent we remove ++ from the copyRegion anything in the modifiedRegion. */ ++ ++ RegionRec copyRegion; /* the destination region of the copy */ ++ int copyDX, copyDY; /* the translation by which the copy happens */ ++ ++ RegionRec modifiedRegion; /* the region of the screen modified in any ++ other way */ ++ ++ /* As part of the FramebufferUpdateRequest, a client can express interest ++ in a subrectangle of the whole framebuffer. This is stored in the ++ requestedRegion member. In the normal case this is the whole ++ framebuffer if the client is ready, empty if it's not. */ ++ ++ RegionRec requestedRegion; ++ ++ /* The following members represent the state of the "deferred update" timer ++ - when the framebuffer is modified and the client is ready, in most ++ cases it is more efficient to defer sending the update by a few ++ milliseconds so that several changes to the framebuffer can be combined ++ into a single update. */ ++ ++ Bool deferredUpdateScheduled; ++ OsTimerPtr deferredUpdateTimer; ++ ++ /* translateFn points to the translation function which is used to copy ++ and translate a rectangle from the framebuffer to an output buffer. */ ++ ++ rfbTranslateFnType translateFn; ++ ++ char *translateLookupTable; ++ ++ rfbPixelFormat format; ++ ++ /* statistics */ ++ ++ int rfbBytesSent[MAX_ENCODINGS]; ++ int rfbRectanglesSent[MAX_ENCODINGS]; ++ int rfbLastRectMarkersSent; ++ int rfbLastRectBytesSent; ++ int rfbCursorShapeBytesSent; ++ int rfbCursorShapeUpdatesSent; ++ int rfbCursorPosBytesSent; ++ int rfbCursorPosUpdatesSent; ++ int rfbFramebufferUpdateMessagesSent; ++ int rfbRawBytesEquivalent; ++ int rfbKeyEventsRcvd; ++ int rfbPointerEventsRcvd; ++ ++ /* zlib encoding -- necessary compression state info per client */ ++ ++ struct z_stream_s compStream; ++ Bool compStreamInited; ++ ++ CARD32 zlibCompressLevel; ++ ++ /* tight encoding -- preserve zlib streams' state for each client */ ++ ++ z_stream zsStruct[4]; ++ Bool zsActive[4]; ++ int zsLevel[4]; ++ int tightCompressLevel; ++ int tightQualityLevel; ++ ++ Bool enableLastRectEncoding; /* client supports LastRect encoding */ ++ Bool enableCursorShapeUpdates; /* client supports cursor shape updates */ ++ Bool enableCursorPosUpdates; /* client supports PointerPos updates */ ++#ifdef CHROMIUM ++ Bool enableChromiumEncoding; /* client supports Chromium encoding */ ++#endif ++ Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */ ++ Bool cursorWasChanged; /* cursor shape update should be sent */ ++ Bool cursorWasMoved; /* cursor position update should be sent */ ++ ++ int cursorX, cursorY; /* client's cursor position */ ++ ++ struct rfbClientRec *next; ++ ++ ScreenPtr pScreen; ++ int userAccepted; ++ ++#ifdef CHROMIUM ++ unsigned int chromium_port; ++ unsigned int chromium_msport; ++#endif ++} rfbClientRec, *rfbClientPtr; ++ ++#ifdef CHROMIUM ++typedef struct CRWindowTable { ++ unsigned long CRwinId; ++ unsigned long XwinId; ++ BoxPtr clipRects; ++ int numRects; ++ struct CRWindowTable *next; ++} CRWindowTable, *CRWindowTablePtr; ++ ++extern struct CRWindowTable *windowTable; ++#endif ++ ++/* ++ * This macro is used to test whether there is a framebuffer update needing to ++ * be sent to the client. ++ */ ++ ++#define FB_UPDATE_PENDING(cl) \ ++ ((!(cl)->enableCursorShapeUpdates && !pVNC->cursorIsDrawn) || \ ++ ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \ ++ ((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) || \ ++ REGION_NOTEMPTY(((cl)->pScreen),&(cl)->copyRegion) || \ ++ REGION_NOTEMPTY(((cl)->pScreen),&(cl)->modifiedRegion)) ++ ++/* ++ * This macro creates an empty region (ie. a region with no areas) if it is ++ * given a rectangle with a width or height of zero. It appears that ++ * REGION_INTERSECT does not quite do the right thing with zero-width ++ * rectangles, but it should with completely empty regions. ++ */ ++ ++#define SAFE_REGION_INIT(pscreen, preg, rect, size) \ ++{ \ ++ if ( ( (rect) ) && \ ++ ( ( (rect)->x2 == (rect)->x1 ) || \ ++ ( (rect)->y2 == (rect)->y1 ) ) ) { \ ++ REGION_NULL( (pscreen), (preg) ); \ ++ } else { \ ++ REGION_INIT( (pscreen), (preg), (rect), (size) ); \ ++ } \ ++} ++ ++/* ++ * An rfbGCRec is where we store the pointers to the original GC funcs and ops ++ * which we wrap (NULL means not wrapped). ++ */ ++ ++typedef struct { ++ GCFuncs *wrapFuncs; ++ GCOps *wrapOps; ++} rfbGCRec, *rfbGCPtr; ++ ++ ++ ++/* ++ * Macros for endian swapping. ++ */ ++ ++#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) ++ ++#define Swap32(l) (((l) >> 24) | \ ++ (((l) & 0x00ff0000) >> 8) | \ ++ (((l) & 0x0000ff00) << 8) | \ ++ ((l) << 24)) ++ ++static const int rfbEndianTest = 1; ++ ++#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s)) ++ ++#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l)) ++ ++ ++/* ++ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.130). ++ * Normally, using macros is no good, but this macro saves us from ++ * writing constants twice -- it constructs signature names from codes. ++ * Note that "code_sym" argument should be a single symbol, not an expression. ++ */ ++ ++#define SetCapInfo(cap_ptr, code_sym, vendor) \ ++{ \ ++ rfbCapabilityInfo *pcap; \ ++ pcap = (cap_ptr); \ ++ pcap->code = Swap32IfLE(code_sym); \ ++ memcpy(pcap->vendorSignature, (vendor), \ ++ sz_rfbCapabilityInfoVendor); \ ++ memcpy(pcap->nameSignature, sig_##code_sym, \ ++ sz_rfbCapabilityInfoName); \ ++} ++ ++ ++/* init.c */ ++ ++extern char *desktopName; ++extern char rfbThisHost[]; ++extern Atom VNC_LAST_CLIENT_ID; ++ ++extern rfbScreenInfo rfbScreen; ++extern int rfbGCIndex; ++ ++extern int inetdSock; ++ ++extern int rfbBitsPerPixel(int depth); ++extern void rfbLog(char *format, ...); ++extern void rfbLogPerror(char *str); ++ ++ ++/* sockets.c */ ++ ++extern int rfbMaxClientWait; ++ ++extern Bool rfbInitSockets(ScreenPtr pScreen); ++extern void rfbDisconnectUDPSock(ScreenPtr pScreen); ++extern void rfbCloseSock(ScreenPtr pScreen, int sock); ++extern void rfbCheckFds(ScreenPtr pScreen); ++extern void rfbWaitForClient(int sock); ++extern int rfbConnect(ScreenPtr pScreen, char *host, int port); ++ ++extern int ReadExact(int sock, char *buf, int len); ++extern int WriteExact(int sock, char *buf, int len); ++extern int ListenOnTCPPort(ScreenPtr pScreen, int port); ++extern int ListenOnUDPPort(ScreenPtr pScreen, int port); ++extern int ConnectToTcpAddr(char *host, int port); ++ ++ ++/* cmap.c */ ++ ++ ++extern int rfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps); ++extern void rfbInstallColormap(ColormapPtr pmap); ++extern void rfbUninstallColormap(ColormapPtr pmap); ++extern void rfbStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs); ++ ++ ++/* draw.c */ ++ ++extern int rfbDeferUpdateTime; ++ ++extern void ++rfbComposite( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pMask, ++ PicturePtr pDst, ++ INT16 xSrc, ++ INT16 ySrc, ++ INT16 xMask, ++ INT16 yMask, ++ INT16 xDst, ++ INT16 yDst, ++ CARD16 width, ++ CARD16 height ++); ++ ++extern void rfbGlyphs( ++ CARD8 op, ++ PicturePtr pSrc, ++ PicturePtr pDst, ++ PictFormatPtr maskFormat, ++ INT16 xSrc, ++ INT16 ySrc, ++ int nlistInit, ++ GlyphListPtr listInit, ++ GlyphPtr *glyphsInit ++); ++extern Bool rfbCloseScreen(int,ScreenPtr); ++extern Bool rfbCreateGC(GCPtr); ++extern void rfbPaintWindowBackground(WindowPtr, RegionPtr, int what); ++extern void rfbPaintWindowBorder(WindowPtr, RegionPtr, int what); ++extern void rfbCopyWindow(WindowPtr, DDXPointRec, RegionPtr); ++#ifdef CHROMIUM ++extern Bool rfbRealizeWindow(WindowPtr); ++extern Bool rfbUnrealizeWindow(WindowPtr); ++extern Bool rfbDestroyWindow(WindowPtr); ++extern void rfbResizeWindow(WindowPtr, int x, int y, unsigned int w, unsigned int h, WindowPtr pSib); ++extern Bool rfbPositionWindow(WindowPtr, int x, int y); ++extern void rfbClipNotify(WindowPtr, int x, int y); ++#endif ++extern void rfbClearToBackground(WindowPtr, int x, int y, int w, ++ int h, Bool generateExposures); ++extern RegionPtr rfbRestoreAreas(WindowPtr, RegionPtr); ++extern void rfbScheduleUpdate(ScreenPtr pScreen); ++ ++ ++/* cutpaste.c */ ++ ++extern void rfbSetXCutText(char *str, int len); ++extern void rfbGotXCutText(char *str, int len); ++ ++ ++/* kbdptr.c */ ++ ++extern Bool compatibleKbd; ++extern unsigned char ptrAcceleration; ++ ++extern void PtrDeviceInit(void); ++extern void PtrDeviceOn(DeviceIntPtr pDev); ++extern void PtrDeviceOff(void); ++extern void PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl); ++extern void PtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl); ++ ++extern void KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap); ++extern void KbdDeviceOn(void); ++extern void KbdDeviceOff(void); ++extern void KbdAddEvent(Bool down, KeySym keySym, rfbClientPtr cl); ++extern void KbdReleaseAllKeys(void); ++ ++/* rfbmouse.c */ ++extern void vncInitMouse(void); ++ ++/* rfbkeyb.c */ ++extern void vncInitKeyb(void); ++ ++ ++/* rfbserver.c */ ++ ++ ++extern rfbClientPtr rfbClientHead; ++extern rfbClientPtr pointerClient; ++ ++extern void rfbNewClientConnection(ScreenPtr pScreen, int sock); ++extern rfbClientPtr rfbReverseConnection(ScreenPtr pScreen, char *host, int port); ++extern void rfbRootPropertyChange(ScreenPtr pScreen); ++extern void rfbClientConnectionGone(int sock); ++extern void rfbProcessClientMessage(ScreenPtr pScreen, int sock); ++extern void rfbClientConnFailed(rfbClientPtr cl, char *reason); ++extern void rfbNewUDPConnection(int sock); ++extern void rfbProcessUDPInput(ScreenPtr pScreen, int sock); ++extern Bool rfbSendFramebufferUpdate(ScreenPtr pScreen, rfbClientPtr cl); ++extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h); ++extern Bool rfbSendUpdateBuf(rfbClientPtr cl); ++extern Bool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, ++ int nColours); ++extern void rfbSendBell(void); ++extern void rfbSendServerCutText(char *str, int len); ++extern void rfbUserAllow(int sock, int accept); ++extern void rfbSetClip (WindowPtr pWin, BOOL enable); ++ ++extern int GenerateVncConnectedEvent(int sock); ++extern int GenerateVncDisconnectedEvent(int sock); ++ ++#ifdef CHROMIUM ++extern void rfbSendChromiumWindowShow(unsigned int winid, unsigned int show); ++extern void rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h); ++extern void rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects); ++#endif ++ ++/* translate.c */ ++ ++extern Bool rfbEconomicTranslate; ++ ++extern void rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y); ++extern Bool rfbSetTranslateFunction(rfbClientPtr cl); ++extern void rfbSetClientColourMaps(int firstColour, int nColours); ++extern Bool rfbSetClientColourMap(rfbClientPtr cl, int firstColour, ++ int nColours); ++ ++ ++/* httpd.c */ ++ ++extern Bool httpInitSockets(ScreenPtr pScreen); ++extern void httpCheckFds(ScreenPtr pScreen); ++ ++ ++/* vncext.c */ ++ ++#ifdef CHROMIUM ++extern void rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort, unsigned int mothershipPort); ++extern void rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long windowid); ++int GenerateVncChromiumConnectedEvent(int sock); ++#endif ++ ++ ++/* auth.c */ ++ ++extern void rfbAuthNewClient(rfbClientPtr cl); ++extern void rfbProcessClientSecurityType(rfbClientPtr cl); ++extern void rfbProcessClientTunnelingType(rfbClientPtr cl); ++extern void rfbProcessClientAuthType(rfbClientPtr cl); ++extern void rfbVncAuthProcessResponse(rfbClientPtr cl); ++ ++/* Functions to prevent too many successive authentication failures */ ++extern Bool rfbAuthConsiderBlocking(rfbClientPtr cl); ++extern void rfbAuthUnblock(rfbClientPtr cl); ++extern Bool rfbAuthIsBlocked(rfbClientPtr cl); ++ ++/* loginauth.c */ ++ ++extern void rfbLoginAuthProcessClientMessage(rfbClientPtr cl); ++ ++/* rre.c */ ++ ++extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* corre.c */ ++ ++extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* hextile.c */ ++ ++extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w, ++ int h); ++ ++ ++/* zlib.c */ ++ ++/* Minimum zlib rectangle size in bytes. Anything smaller will ++ * not compress well due to overhead. ++ */ ++#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17) ++ ++/* Set maximum zlib rectangle size in pixels. Always allow at least ++ * two scan lines. ++ */ ++#define ZLIB_MAX_RECT_SIZE (128*256) ++#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \ ++ ( min * 2 ) : ZLIB_MAX_RECT_SIZE ) ++ ++extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, ++ int h); ++ ++ ++/* tight.c */ ++ ++#define TIGHT_DEFAULT_COMPRESSION 6 ++ ++extern Bool rfbTightDisableGradient; ++ ++extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h); ++extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h); ++ ++ ++/* cursor.c */ ++ ++extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen); ++extern Bool rfbSendCursorPos(rfbClientPtr cl, ScreenPtr pScreen); ++ ++ ++/* stats.c */ ++ ++extern void rfbResetStats(rfbClientPtr cl); ++extern void rfbPrintStats(rfbClientPtr cl); +diff --git a/hw/xfree86/vnc/rfbkeyb.c b/hw/xfree86/vnc/rfbkeyb.c +new file mode 100644 +index 0000000..4a26781 +--- /dev/null ++++ b/hw/xfree86/vnc/rfbkeyb.c +@@ -0,0 +1,410 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include ++ ++#define XINPUT ++ ++#if XFREE86VNC ++ ++#include ++#include ++#include ++#include ++#include "xf86Xinput.h" ++#include ++#include ++ ++#else /* XFREE86VNC */ ++ ++#include ++#include ++#include ++ ++#endif /* XFREE86VNC */ ++ ++#include "rfb.h" ++ ++ ++extern Bool noXkbExtension; ++extern void rfbSendBell(void); ++extern DeviceIntPtr kbdDevice; ++ ++static const char *DEFAULTS[] = { ++ NULL ++}; ++ ++#include "keyboard.h" ++ ++#undef XKB ++#ifdef XKB ++#include ++#include ++#include ++ ++#if XFREE86VNC ++ /* ++ * would like to use an XkbComponentNamesRec here but can't without ++ * pulling in a bunch of header files. :-( ++ */ ++static char * xkbkeymap; ++static char * xkbkeycodes; ++static char * xkbtypes; ++static char * xkbcompat; ++static char * xkbsymbols; ++static char * xkbgeometry; ++static Bool xkbcomponents_specified; ++static char * xkbrules; ++static char * xkbmodel; ++static char * xkblayout; ++static char * xkbvariant; ++static char * xkboptions; ++#endif ++#endif ++ ++void ++KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap) ++{ ++ int i; ++ ++ kbdDevice = pDevice; ++ ++ for (i = 0; i < MAP_LENGTH; i++) ++ pModMap[i] = NoSymbol; ++ ++ pModMap[CONTROL_L_KEY_CODE] = ControlMask; ++ pModMap[CONTROL_R_KEY_CODE] = ControlMask; ++ pModMap[SHIFT_L_KEY_CODE] = ShiftMask; ++ pModMap[SHIFT_R_KEY_CODE] = ShiftMask; ++ pModMap[META_L_KEY_CODE] = Mod1Mask; ++ pModMap[META_R_KEY_CODE] = Mod1Mask; ++ pModMap[ALT_L_KEY_CODE] = Mod1Mask; ++ pModMap[ALT_R_KEY_CODE] = Mod1Mask; ++ ++ pKeySyms->minKeyCode = MIN_KEY_CODE; ++ pKeySyms->maxKeyCode = MAX_KEY_CODE; ++ pKeySyms->mapWidth = GLYPHS_PER_KEY; ++ ++ pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym) ++ * MAP_LENGTH * GLYPHS_PER_KEY); ++ ++ if (!pKeySyms->map) { ++ ErrorF("xalloc failed\n"); ++ exit(1); ++ } ++ ++ for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++) ++ pKeySyms->map[i] = NoSymbol; ++ ++ for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) { ++ pKeySyms->map[i] = map[i]; ++ } ++} ++ ++ ++void ++KbdDeviceOn(void) ++{ ++} ++ ++ ++void ++KbdDeviceOff(void) ++{ ++} ++ ++ ++#if XFREE86VNC ++static int ++xf86rfbKeybControlProc(DeviceIntPtr device, int onoff) ++{ ++ KeySymsRec keySyms; ++ CARD8 modMap[MAP_LENGTH]; ++ DevicePtr pDev = (DevicePtr)device; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ KbdDeviceInit(device, &keySyms, modMap); ++#ifdef XKB ++ if (noXkbExtension) { ++#endif ++ InitKeyboardDeviceStruct(pDev, &keySyms, modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++#ifdef XKB ++ } else { ++ XkbComponentNamesRec names; ++ if (XkbInitialMap) { ++ if ((xkbkeymap = strchr(XkbInitialMap, '/')) != NULL) ++ xkbkeymap++; ++ else ++ xkbkeymap = XkbInitialMap; ++ } ++ if (xkbkeymap) { ++ names.keymap = xkbkeymap; ++ names.keycodes = NULL; ++ names.types = NULL; ++ names.compat = NULL; ++ names.symbols = NULL; ++ names.geometry = NULL; ++ } else { ++ names.keymap = NULL; ++ names.keycodes = xkbkeycodes; ++ names.types = xkbtypes; ++ names.compat = xkbcompat; ++ names.symbols = xkbsymbols; ++ names.geometry = xkbgeometry; ++ } ++ if ((xkbkeymap || xkbcomponents_specified) ++ && (xkbmodel == NULL || xkblayout == NULL)) { ++ xkbrules = NULL; ++ } ++#if 0 ++ XkbSetRulesDflts(xkbrules, xkbmodel, ++ xkblayout, xkbvariant, ++ xkboptions); ++#endif ++ XkbInitKeyboardDeviceStruct(device, ++ &names, ++ &keySyms, ++ modMap, ++ (BellProcPtr)rfbSendBell, ++ (KbdCtrlProcPtr)NoopDDA); ++ } ++#endif /* XKB */ ++ break; ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ KbdDeviceOn(); ++ break; ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ KbdDeviceOff(); ++ break; ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ KbdDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static void ++xf86rfbKeybUninit(InputDriverPtr drv, ++ InputInfoPtr pInfo, ++ int flags) ++{ ++ xf86rfbKeybControlProc(pInfo->dev, DEVICE_OFF); ++} ++ ++static InputInfoPtr ++xf86rfbKeybInit(InputDriverPtr drv, ++ IDevPtr dev, ++ int flags) ++{ ++ InputInfoPtr pInfo; ++#ifdef XKB ++ char *s; ++ Bool from; ++#endif ++ if (!(pInfo = xf86AllocateInput(drv, 0))) ++ return NULL; ++ ++ /* Initialise the InputInfoRec. */ ++ pInfo->name = dev->identifier; ++ pInfo->type_name = "rfbKeyb"; ++ pInfo->flags = XI86_KEYBOARD_CAPABLE; ++ pInfo->device_control = xf86rfbKeybControlProc; ++ pInfo->read_input = NULL; ++ pInfo->motion_history_proc = NULL; ++ pInfo->history_size = 0; ++ pInfo->control_proc = NULL; ++ pInfo->close_proc = NULL; ++ pInfo->switch_mode = NULL; ++ pInfo->conversion_proc = NULL; ++ pInfo->reverse_conversion_proc = NULL; ++ pInfo->fd = -1; ++ pInfo->dev = NULL; ++ pInfo->private_flags = 0; ++ pInfo->always_core_feedback = 0; ++ pInfo->conf_idev = dev; ++ ++ /* Collect the options, and process the common options. */ ++ xf86CollectInputOptions(pInfo, DEFAULTS, NULL); ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ /* Mark the device configured */ ++ pInfo->flags |= XI86_CONFIGURED; ++ ++#ifdef XKB ++ from = X_DEFAULT; ++ if (noXkbExtension) ++ from = X_CMDLINE; ++ else if (xf86FindOption(dev->commonOptions, "XkbDisable")) { ++ noXkbExtension = ++ xf86SetBoolOption(dev->commonOptions, "XkbDisable", FALSE); ++ from = X_CONFIG; ++ } ++ if (noXkbExtension) ++ xf86Msg(from, "XKB: disabled\n"); ++ ++#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL)) ++ ++ if (!noXkbExtension && !XkbInitialMap) { ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeymap", NULL))) { ++ xkbkeymap = NULL_IF_EMPTY(s); ++ xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" " ++ "(overrides other XKB settings)\n", xkbkeymap); ++ } else { ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbCompat", NULL))) { ++ xkbcompat = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbTypes", NULL))) { ++ xkbtypes = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbKeycodes", NULL))) { ++ xkbkeycodes = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbGeometry", NULL))) { ++ xkbgeometry = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbSymbols", NULL))) { ++ xkbsymbols = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbRules", NULL))) { ++ xkbrules = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbModel", NULL))) { ++ xkbmodel = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbLayout", NULL))) { ++ xkblayout = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbVariant", NULL))) { ++ xkbvariant = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s); ++ } ++ ++ if ((s = xf86SetStrOption(dev->commonOptions, "XkbOptions", NULL))) { ++ xkboptions = NULL_IF_EMPTY(s); ++ xkbcomponents_specified = TRUE; ++ xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s); ++ } ++ } ++ } ++#undef NULL_IF_EMPTY ++#endif /* XKB */ ++ ++ /* Return the configured device */ ++ return (pInfo); ++} ++ ++#ifdef XFree86LOADER ++static ++#endif ++InputDriverRec RFBKEYB = { ++ 1, /* driver version */ ++ "rfbkeyb", /* driver name */ ++ NULL, /* identify */ ++ xf86rfbKeybInit, /* pre-init */ ++ xf86rfbKeybUninit, /* un-init */ ++ NULL, /* module */ ++ 0 /* ref count */ ++}; ++ ++/* ++ *************************************************************************** ++ * ++ * Dynamic loading functions ++ * ++ *************************************************************************** ++ */ ++#ifdef XFree86LOADER ++static void ++xf86rfbKeybUnplug(pointer p) ++{ ++} ++ ++static pointer ++xf86rfbKeybPlug(pointer module, ++ pointer options, ++ int *errmaj, ++ int *errmin) ++{ ++ xf86AddInputDriver(&RFBKEYB, module, 0); ++ ++ return module; ++} ++ ++void ++vncInitKeyb(void) ++{ ++ xf86AddInputDriver(&RFBKEYB, NULL, 0); ++} ++ ++static XF86ModuleVersionInfo xf86rfbKeybVersionRec = ++{ ++ "rfbkeyb", ++ "xf4vnc Project, see http://xf4vnc.sf.net", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XF86_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_XINPUT, ++ ABI_XINPUT_VERSION, ++ MOD_CLASS_XINPUT, ++ {0, 0, 0, 0} /* signature, to be patched into the file by */ ++ /* a tool */ ++}; ++ ++XF86ModuleData rfbkeybModuleData = {&xf86rfbKeybVersionRec, ++ xf86rfbKeybPlug, ++ xf86rfbKeybUnplug}; ++ ++#endif /* XFree86LOADER */ ++#endif /* XFREE86VNC */ ++ +diff --git a/hw/xfree86/vnc/rfbmouse.c b/hw/xfree86/vnc/rfbmouse.c +new file mode 100644 +index 0000000..342469b +--- /dev/null ++++ b/hw/xfree86/vnc/rfbmouse.c +@@ -0,0 +1,240 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include ++#endif ++ ++#ifndef XINPUT ++#define XINPUT ++#endif ++ ++#if XFREE86VNC ++ ++#include ++#include ++#include ++#include ++#include "xf86Xinput.h" ++ ++#ifdef XFree86LOADER ++#include ++#endif ++ ++static const char *DEFAULTS[] = { ++ NULL ++}; ++#else ++#include ++#include ++#include ++#endif ++ ++#include "rfb.h" ++ ++ ++unsigned char ptrAcceleration = 50; ++ ++void ++PtrDeviceOn(DeviceIntPtr pDev) ++{ ++#if 0 ++ ptrAcceleration = (unsigned char)pDev->ptrfeed->ctrl.num; ++#endif ++} ++ ++void ++PtrDeviceInit(void) ++{ ++} ++ ++void ++PtrDeviceOff(void) ++{ ++} ++ ++ ++void ++PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl) ++{ ++#if 0 ++ ptrAcceleration = (char)ctrl->num; ++ ++ if (udpSockConnected) { ++ if (write(udpSock, &ptrAcceleration, 1) <= 0) { ++ ErrorF("PtrDeviceControl: UDP input: write"); ++ rfbDisconnectUDPSock(); ++ } ++ } ++#endif ++} ++ ++#if XFREE86VNC ++static int ++xf86rfbMouseControlProc(DeviceIntPtr device, int onoff) ++{ ++ BYTE map[6]; ++ DevicePtr pDev = (DevicePtr)device; ++ ++ switch (onoff) ++ { ++ case DEVICE_INIT: ++ PtrDeviceInit(); ++ map[1] = 1; ++ map[2] = 2; ++ map[3] = 3; ++ map[4] = 4; ++ map[5] = 5; ++ InitPointerDeviceStruct(pDev, map, 5, miPointerGetMotionEvents, ++ PtrDeviceControl, ++ miPointerGetMotionBufferSize()); ++ break; ++ ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ PtrDeviceOn(device); ++ break; ++ ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ PtrDeviceOff(); ++ break; ++ ++ case DEVICE_CLOSE: ++ if (pDev->on) ++ PtrDeviceOff(); ++ break; ++ } ++ return Success; ++} ++ ++static void ++xf86rfbMouseUninit(InputDriverPtr drv, ++ InputInfoPtr pInfo, ++ int flags) ++{ ++ xf86rfbMouseControlProc(pInfo->dev, DEVICE_OFF); ++} ++ ++static InputInfoPtr ++xf86rfbMouseInit(InputDriverPtr drv, ++ IDevPtr dev, ++ int flags) ++{ ++ InputInfoPtr pInfo; ++ ++ if (!(pInfo = xf86AllocateInput(drv, 0))) ++ return NULL; ++ ++ /* Initialise the InputInfoRec. */ ++ pInfo->name = dev->identifier; ++ pInfo->type_name = "rfbMouse"; ++ pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; ++ pInfo->device_control = xf86rfbMouseControlProc; ++ pInfo->read_input = NULL; ++ pInfo->motion_history_proc = xf86GetMotionEvents; ++ pInfo->history_size = 0; ++ pInfo->control_proc = NULL; ++ pInfo->close_proc = NULL; ++ pInfo->switch_mode = NULL; ++ pInfo->conversion_proc = NULL; ++ pInfo->reverse_conversion_proc = NULL; ++ pInfo->fd = -1; ++ pInfo->dev = NULL; ++ pInfo->private_flags = 0; ++ pInfo->always_core_feedback = 0; ++ pInfo->conf_idev = dev; ++ ++ /* Collect the options, and process the common options. */ ++ xf86CollectInputOptions(pInfo, DEFAULTS, NULL); ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ /* Mark the device configured */ ++ pInfo->flags |= XI86_CONFIGURED; ++ ++ /* Return the configured device */ ++ return (pInfo); ++} ++ ++#ifdef XFree86LOADER ++static ++#endif ++InputDriverRec RFBMOUSE = { ++ 1, /* driver version */ ++ "rfbmouse", /* driver name */ ++ NULL, /* identify */ ++ xf86rfbMouseInit, /* pre-init */ ++ xf86rfbMouseUninit, /* un-init */ ++ NULL, /* module */ ++ 0 /* ref count */ ++}; ++ ++/* ++ *************************************************************************** ++ * ++ * Dynamic loading functions ++ * ++ *************************************************************************** ++ */ ++#ifdef XFree86LOADER ++static void ++xf86rfbMouseUnplug(pointer p) ++{ ++} ++ ++static pointer ++xf86rfbMousePlug(pointer module, ++ pointer options, ++ int *errmaj, ++ int *errmin) ++{ ++ xf86AddInputDriver(&RFBMOUSE, module, 0); ++ ++ return module; ++} ++ ++void ++vncInitMouse(void) ++{ ++ xf86AddInputDriver(&RFBMOUSE, NULL, 0); ++} ++ ++static XF86ModuleVersionInfo xf86rfbMouseVersionRec = ++{ ++ "rfbmouse", ++ "xf4vnc Project, see http://xf4vnc.sf.net", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XF86_VERSION_CURRENT, ++ 1, 0, 0, ++ ABI_CLASS_XINPUT, ++ ABI_XINPUT_VERSION, ++ MOD_CLASS_XINPUT, ++ {0, 0, 0, 0} /* signature, to be patched into the file by */ ++ /* a tool */ ++}; ++ ++XF86ModuleData rfbmouseModuleData = {&xf86rfbMouseVersionRec, ++ xf86rfbMousePlug, ++ xf86rfbMouseUnplug}; ++ ++#endif /* XFree86LOADER */ ++#endif +diff --git a/hw/xfree86/vnc/rfbproto.h b/hw/xfree86/vnc/rfbproto.h +new file mode 100644 +index 0000000..bbef703 +--- /dev/null ++++ b/hw/xfree86/vnc/rfbproto.h +@@ -0,0 +1,1347 @@ ++/* ++ * Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ * rfbproto.h - header file for the RFB protocol, versions 3.3, 3.7 and 3.7t ++ * (protocol 3.7t is effectively 3.7 with TightVNC extensions enabled) ++ * ++ * Uses types CARD for an n-bit unsigned integer, INT for an n-bit signed ++ * integer (for n = 8, 16 and 32). ++ * ++ * All multiple byte integers are in big endian (network) order (most ++ * significant byte first). Unless noted otherwise there is no special ++ * alignment of protocol structures. ++ * ++ * ++ * Once the initial handshaking is done, all messages start with a type byte, ++ * (usually) followed by message-specific data. The order of definitions in ++ * this file is as follows: ++ * ++ * (1) Structures used in several types of message. ++ * (2) Structures used in the initial handshaking. ++ * (3) Message types. ++ * (4) Encoding types. ++ * (5) For each message type, the form of the data following the type byte. ++ * Sometimes this is defined by a single structure but the more complex ++ * messages have to be explained by comments. ++ */ ++ ++ ++/***************************************************************************** ++ * ++ * Structures used in several messages ++ * ++ *****************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to specify a rectangle. This structure is a multiple of 4 ++ * bytes so that it can be interspersed with 32-bit pixel data without ++ * affecting alignment. ++ */ ++ ++typedef struct _rfbRectangle { ++ CARD16 x; ++ CARD16 y; ++ CARD16 w; ++ CARD16 h; ++} rfbRectangle; ++ ++#define sz_rfbRectangle 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to specify pixel format. ++ */ ++ ++typedef struct _rfbPixelFormat { ++ ++ CARD8 bitsPerPixel; /* 8,16,32 only */ ++ ++ CARD8 depth; /* 8 to 32 */ ++ ++ CARD8 bigEndian; /* True if multi-byte pixels are interpreted ++ as big endian, or if single-bit-per-pixel ++ has most significant bit of the byte ++ corresponding to first (leftmost) pixel. Of ++ course this is meaningless for 8 bits/pix */ ++ ++ CARD8 trueColour; /* If false then we need a "colour map" to ++ convert pixels to RGB. If true, xxxMax and ++ xxxShift specify bits used for red, green ++ and blue */ ++ ++ /* the following fields are only meaningful if trueColour is true */ ++ ++ CARD16 redMax; /* maximum red value (= 2^n - 1 where n is the ++ number of bits used for red). Note this ++ value is always in big endian order. */ ++ ++ CARD16 greenMax; /* similar for green */ ++ ++ CARD16 blueMax; /* and blue */ ++ ++ CARD8 redShift; /* number of shifts needed to get the red ++ value in a pixel to the least significant ++ bit. To find the red value from a given ++ pixel, do the following: ++ 1) Swap pixel value according to bigEndian ++ (e.g. if bigEndian is false and host byte ++ order is big endian, then swap). ++ 2) Shift right by redShift. ++ 3) AND with redMax (in host byte order). ++ 4) You now have the red value between 0 and ++ redMax. */ ++ ++ CARD8 greenShift; /* similar for green */ ++ ++ CARD8 blueShift; /* and blue */ ++ ++ CARD8 pad1; ++ CARD16 pad2; ++ ++} rfbPixelFormat; ++ ++#define sz_rfbPixelFormat 16 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Structure used to describe protocol options such as tunneling methods, ++ * authentication schemes and message types (protocol version 3.7t). ++ */ ++ ++typedef struct _rfbCapabilityInfo { ++ ++ CARD32 code; /* numeric identifier */ ++ CARD8 vendorSignature[4]; /* vendor identification */ ++ CARD8 nameSignature[8]; /* abbreviated option name */ ++ ++} rfbCapabilityInfo; ++ ++#define sz_rfbCapabilityInfoVendor 4 ++#define sz_rfbCapabilityInfoName 8 ++#define sz_rfbCapabilityInfo 16 ++ ++/* ++ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC. ++ */ ++ ++#define rfbStandardVendor "STDV" ++#define rfbTridiaVncVendor "TRDV" ++#define rfbTightVncVendor "TGHT" ++#define rfbTungstenGraphicsVendor "TGIV" ++ ++ ++/***************************************************************************** ++ * ++ * Initial handshaking messages ++ * ++ *****************************************************************************/ ++ ++/*----------------------------------------------------------------------------- ++ * Protocol Version ++ * ++ * The server always sends 12 bytes to start which identifies the latest RFB ++ * protocol version number which it supports. These bytes are interpreted ++ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where ++ * xxx and yyy are the major and minor version numbers (for version 3.7 ++ * this is "RFB 003.007\n"). ++ * ++ * The client then replies with a similar 12-byte message giving the version ++ * number of the protocol which should actually be used (which may be different ++ * to that quoted by the server). ++ * ++ * It is intended that both clients and servers may provide some level of ++ * backwards compatibility by this mechanism. Servers in particular should ++ * attempt to provide backwards compatibility, and even forwards compatibility ++ * to some extent. For example if a client demands version 3.1 of the ++ * protocol, a 3.0 server can probably assume that by ignoring requests for ++ * encoding types it doesn't understand, everything will still work OK. This ++ * will probably not be the case for changes in the major version number. ++ * ++ * The format string below can be used in sprintf or sscanf to generate or ++ * decode the version string respectively. ++ */ ++ ++#define rfbProtocolVersionFormat "RFB %03d.%03d\n" ++#define rfbProtocolMajorVersion 3 ++#define rfbProtocolMinorVersion 7 ++#define rfbProtocolFallbackMinorVersion 3 ++ ++typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */ ++ ++#define sz_rfbProtocolVersionMsg 12 ++ ++ ++/* ++ * Negotiation of the security type (protocol version 3.7) ++ * ++ * Once the protocol version has been decided, the server either sends a list ++ * of supported security types, or informs the client about an error (when the ++ * number of security types is 0). Security type rfbSecTypeTight is used to ++ * enable TightVNC-specific protocol extensions. The value rfbSecTypeVncAuth ++ * stands for classic VNC authentication. ++ * ++ * The client selects a particular security type from the list provided by the ++ * server. ++ */ ++ ++#define rfbSecTypeInvalid 0 ++#define rfbSecTypeNone 1 ++#define rfbSecTypeVncAuth 2 ++#define rfbSecTypeTight 16 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Negotiation of Tunneling Capabilities (protocol version 3.7t) ++ * ++ * If the chosen security type is rfbSecTypeTight, the server sends a list of ++ * supported tunneling methods ("tunneling" refers to any additional layer of ++ * data transformation, such as encryption or external compression.) ++ * ++ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures ++ * that list all supported tunneling methods in the order of preference. ++ * ++ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be ++ * used, and the client should not send a response requesting a tunneling ++ * method. ++ */ ++ ++typedef struct _rfbTunnelingCapsMsg { ++ CARD32 nTunnelTypes; ++ /* followed by nTunnelTypes * rfbCapabilityInfo structures */ ++} rfbTunnelingCapsMsg; ++ ++#define sz_rfbTunnelingCapsMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Tunneling Method Request (protocol version 3.7t) ++ * ++ * If the list of tunneling capabilities sent by the server was not empty, the ++ * client should reply with a 32-bit code specifying a particular tunneling ++ * method. The following code should be used for no tunneling. ++ */ ++ ++#define rfbNoTunneling 0 ++#define sig_rfbNoTunneling "NOTUNNEL" ++ ++ ++/*----------------------------------------------------------------------------- ++ * Negotiation of Authentication Capabilities (protocol version 3.7t) ++ * ++ * After setting up tunneling, the server sends a list of supported ++ * authentication schemes. ++ * ++ * nAuthTypes specifies the number of following rfbCapabilityInfo structures ++ * that list all supported authentication schemes in the order of preference. ++ * ++ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is ++ * necessary, and the client should not send a response requesting an ++ * authentication scheme. ++ */ ++ ++typedef struct _rfbAuthenticationCapsMsg { ++ CARD32 nAuthTypes; ++ /* followed by nAuthTypes * rfbCapabilityInfo structures */ ++} rfbAuthenticationCapsMsg; ++ ++#define sz_rfbAuthenticationCapsMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Authentication Scheme Request (protocol version 3.7t) ++ * ++ * If the list of authentication capabilities sent by the server was not empty, ++ * the client should reply with a 32-bit code specifying a particular ++ * authentication scheme. The following codes are supported. ++ */ ++ ++#define rfbAuthNone 1 ++#define rfbAuthVNC 2 ++#define rfbAuthUnixLogin 129 ++#define rfbAuthExternal 130 ++ ++#define sig_rfbAuthNone "NOAUTH__" ++#define sig_rfbAuthVNC "VNCAUTH_" ++#define sig_rfbAuthUnixLogin "ULGNAUTH" ++#define sig_rfbAuthExternal "XTRNAUTH" ++ ++ ++/*----------------------------------------------------------------------------- ++ * Standard VNC Authentication (all protocol versions) ++ * ++ * Standard authentication result codes are defined below. ++ */ ++ ++#define rfbVncAuthOK 0 ++#define rfbVncAuthFailed 1 ++#define rfbVncAuthTooMany 2 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Client Initialisation Message ++ * ++ * Once the client and server are sure that they're happy to talk to one ++ * another, the client sends an initialisation message. At present this ++ * message only consists of a boolean indicating whether the server should try ++ * to share the desktop by leaving other clients connected, or give exclusive ++ * access to this client by disconnecting all other clients. ++ */ ++ ++typedef struct _rfbClientInitMsg { ++ CARD8 shared; ++} rfbClientInitMsg; ++ ++#define sz_rfbClientInitMsg 1 ++ ++ ++/*----------------------------------------------------------------------------- ++ * Server Initialisation Message ++ * ++ * After the client initialisation message, the server sends one of its own. ++ * This tells the client the width and height of the server's framebuffer, ++ * its pixel format and the name associated with the desktop. ++ */ ++ ++typedef struct _rfbServerInitMsg { ++ CARD16 framebufferWidth; ++ CARD16 framebufferHeight; ++ rfbPixelFormat format; /* the server's preferred pixel format */ ++ CARD32 nameLength; ++ /* followed by char name[nameLength] */ ++} rfbServerInitMsg; ++ ++#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat) ++ ++ ++/*----------------------------------------------------------------------------- ++ * Server Interaction Capabilities Message (protocol version 3.7t) ++ * ++ * In the protocol version 3.7t, the server informs the client what message ++ * types it supports in addition to ones defined in the protocol version 3.7. ++ * Also, the server sends the list of all supported encodings (note that it's ++ * not necessary to advertise the "raw" encoding sinse it MUST be supported in ++ * RFB 3.x protocols). ++ * ++ * This data immediately follows the server initialisation message. ++ */ ++ ++typedef struct _rfbInteractionCapsMsg { ++ CARD16 nServerMessageTypes; ++ CARD16 nClientMessageTypes; ++ CARD16 nEncodingTypes; ++ CARD16 pad; /* reserved, must be 0 */ ++ /* followed by nServerMessageTypes * rfbCapabilityInfo structures */ ++ /* followed by nClientMessageTypes * rfbCapabilityInfo structures */ ++} rfbInteractionCapsMsg; ++ ++#define sz_rfbInteractionCapsMsg 8 ++ ++ ++/* ++ * Following the server initialisation message it's up to the client to send ++ * whichever protocol messages it wants. Typically it will send a ++ * SetPixelFormat message and a SetEncodings message, followed by a ++ * FramebufferUpdateRequest. From then on the server will send ++ * FramebufferUpdate messages in response to the client's ++ * FramebufferUpdateRequest messages. The client should send ++ * FramebufferUpdateRequest messages with incremental set to true when it has ++ * finished processing one FramebufferUpdate and is ready to process another. ++ * With a fast client, the rate at which FramebufferUpdateRequests are sent ++ * should be regulated to avoid hogging the network. ++ */ ++ ++ ++ ++/***************************************************************************** ++ * ++ * Message types ++ * ++ *****************************************************************************/ ++ ++/* server -> client */ ++ ++#define rfbFramebufferUpdate 0 ++#define rfbSetColourMapEntries 1 ++#define rfbBell 2 ++#define rfbServerCutText 3 ++/* Chromium extensions, use higher values */ ++#define rfbChromiumStart 50 ++#define rfbChromiumMoveResizeWindow 51 ++#define rfbChromiumClipList 52 ++#define rfbChromiumWindowShow 53 ++ ++#define rfbFileListData 130 ++#define rfbFileDownloadData 131 ++#define rfbFileUploadCancel 132 ++#define rfbFileDownloadFailed 133 ++ ++/* signatures for non-standard messages */ ++#define sig_rfbFileListData "FTS_LSDT" ++#define sig_rfbFileDownloadData "FTS_DNDT" ++#define sig_rfbFileUploadCancel "FTS_UPCN" ++#define sig_rfbFileDownloadFailed "FTS_DNFL" ++ ++ ++/* client -> server */ ++ ++#define rfbSetPixelFormat 0 ++#define rfbFixColourMapEntries 1 /* not currently supported */ ++#define rfbSetEncodings 2 ++#define rfbFramebufferUpdateRequest 3 ++#define rfbKeyEvent 4 ++#define rfbPointerEvent 5 ++#define rfbClientCutText 6 ++/* Chromium extensions, use higher values */ ++#define rfbChromiumStop 50 ++#define rfbChromiumExpose 51 ++ ++#define rfbFileListRequest 130 ++#define rfbFileDownloadRequest 131 ++#define rfbFileUploadRequest 132 ++#define rfbFileUploadData 133 ++#define rfbFileDownloadCancel 134 ++#define rfbFileUploadFailed 135 ++#define rfbFileCreateDirRequest 136 ++ ++/* signatures for non-standard messages */ ++#define sig_rfbFileListRequest "FTC_LSRQ" ++#define sig_rfbFileDownloadRequest "FTC_DNRQ" ++#define sig_rfbFileUploadRequest "FTC_UPRQ" ++#define sig_rfbFileUploadData "FTC_UPDT" ++#define sig_rfbFileDownloadCancel "FTC_DNCN" ++#define sig_rfbFileUploadFailed "FTC_UPFL" ++#define sig_rfbFileCreateDirRequest "FTC_FCDR" ++ ++/***************************************************************************** ++ * ++ * Encoding types ++ * ++ *****************************************************************************/ ++ ++#define rfbEncodingRaw 0 ++#define rfbEncodingCopyRect 1 ++#define rfbEncodingRRE 2 ++#define rfbEncodingCoRRE 4 ++#define rfbEncodingHextile 5 ++#define rfbEncodingZlib 6 ++#define rfbEncodingTight 7 ++#define rfbEncodingZlibHex 8 ++ ++/* signatures for basic encoding types */ ++#define sig_rfbEncodingRaw "RAW_____" ++#define sig_rfbEncodingCopyRect "COPYRECT" ++#define sig_rfbEncodingRRE "RRE_____" ++#define sig_rfbEncodingCoRRE "CORRE___" ++#define sig_rfbEncodingHextile "HEXTILE_" ++#define sig_rfbEncodingZlib "ZLIB____" ++#define sig_rfbEncodingTight "TIGHT___" ++#define sig_rfbEncodingZlibHex "ZLIBHEX_" ++#define sig_rfbEncodingChromium "CHROMIUM" ++ ++/* ++ * Special encoding numbers: ++ * 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels; ++ * 0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data; ++ * 0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions; ++ * 0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet; ++ * 0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor; ++ * 0xFFFFFFF0 .. 0xFFFFFFFF -- not allocated yet. ++ */ ++ ++#define rfbEncodingCompressLevel0 0xFFFFFF00 ++#define rfbEncodingCompressLevel1 0xFFFFFF01 ++#define rfbEncodingCompressLevel2 0xFFFFFF02 ++#define rfbEncodingCompressLevel3 0xFFFFFF03 ++#define rfbEncodingCompressLevel4 0xFFFFFF04 ++#define rfbEncodingCompressLevel5 0xFFFFFF05 ++#define rfbEncodingCompressLevel6 0xFFFFFF06 ++#define rfbEncodingCompressLevel7 0xFFFFFF07 ++#define rfbEncodingCompressLevel8 0xFFFFFF08 ++#define rfbEncodingCompressLevel9 0xFFFFFF09 ++ ++#define rfbEncodingXCursor 0xFFFFFF10 ++#define rfbEncodingRichCursor 0xFFFFFF11 ++#define rfbEncodingPointerPos 0xFFFFFF18 ++ ++#define rfbEncodingLastRect 0xFFFFFF20 ++#define rfbEncodingNewFBSize 0xFFFFFF21 ++#define rfbEncodingChromium 0xFFFFFF2F ++#define rfbEncodingChromium2 0xFFFFFF30 ++ ++#define rfbEncodingQualityLevel0 0xFFFFFFE0 ++#define rfbEncodingQualityLevel1 0xFFFFFFE1 ++#define rfbEncodingQualityLevel2 0xFFFFFFE2 ++#define rfbEncodingQualityLevel3 0xFFFFFFE3 ++#define rfbEncodingQualityLevel4 0xFFFFFFE4 ++#define rfbEncodingQualityLevel5 0xFFFFFFE5 ++#define rfbEncodingQualityLevel6 0xFFFFFFE6 ++#define rfbEncodingQualityLevel7 0xFFFFFFE7 ++#define rfbEncodingQualityLevel8 0xFFFFFFE8 ++#define rfbEncodingQualityLevel9 0xFFFFFFE9 ++ ++/* signatures for "fake" encoding types */ ++#define sig_rfbEncodingCompressLevel0 "COMPRLVL" ++#define sig_rfbEncodingXCursor "X11CURSR" ++#define sig_rfbEncodingRichCursor "RCHCURSR" ++#define sig_rfbEncodingPointerPos "POINTPOS" ++#define sig_rfbEncodingLastRect "LASTRECT" ++#define sig_rfbEncodingNewFBSize "NEWFBSIZ" ++#define sig_rfbEncodingQualityLevel0 "JPEGQLVL" ++ ++ ++/***************************************************************************** ++ * ++ * Server -> client message definitions ++ * ++ *****************************************************************************/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer. ++ * ++ * This message consists of a header giving the number of rectangles of pixel ++ * data followed by the rectangles themselves. The header is padded so that ++ * together with the type byte it is an exact multiple of 4 bytes (to help ++ * with alignment of 32-bit pixels): ++ */ ++ ++typedef struct _rfbFramebufferUpdateMsg { ++ CARD8 type; /* always rfbFramebufferUpdate */ ++ CARD8 pad; ++ CARD16 nRects; ++ /* followed by nRects rectangles */ ++} rfbFramebufferUpdateMsg; ++ ++#define sz_rfbFramebufferUpdateMsg 4 ++ ++/* ++ * Each rectangle of pixel data consists of a header describing the position ++ * and size of the rectangle and a type word describing the encoding of the ++ * pixel data, followed finally by the pixel data. Note that if the client has ++ * not sent a SetEncodings message then it will only receive raw pixel data. ++ * Also note again that this structure is a multiple of 4 bytes. ++ */ ++ ++typedef struct _rfbFramebufferUpdateRectHeader { ++ rfbRectangle r; ++ CARD32 encoding; /* one of the encoding types rfbEncoding... */ ++} rfbFramebufferUpdateRectHeader; ++ ++#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Raw Encoding. Pixels are sent in top-to-bottom scanline order, ++ * left-to-right within a scanline with no padding in between. ++ */ ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * CopyRect Encoding. The pixels are specified simply by the x and y position ++ * of the source rectangle. ++ */ ++ ++typedef struct _rfbCopyRect { ++ CARD16 srcX; ++ CARD16 srcY; ++} rfbCopyRect; ++ ++#define sz_rfbCopyRect 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * RRE - Rise-and-Run-length Encoding. We have an rfbRREHeader structure ++ * giving the number of subrectangles following. Finally the data follows in ++ * the form [...] where each is ++ * []. ++ */ ++ ++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 ++ * [...] where each is ++ * []. This means that ++ * the whole rectangle must be at most 255x255 pixels. ++ */ ++ ++typedef struct _rfbCoRRERectangle { ++ CARD8 x; ++ CARD8 y; ++ CARD8 w; ++ CARD8 h; ++} rfbCoRRERectangle; ++ ++#define sz_rfbCoRRERectangle 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Hextile Encoding. The rectangle is divided up into "tiles" of 16x16 pixels, ++ * starting at the top left going in left-to-right, top-to-bottom order. If ++ * the width of the rectangle is not an exact multiple of 16 then the width of ++ * the last tile in each row will be correspondingly smaller. Similarly if the ++ * height is not an exact multiple of 16 then the height of each tile in the ++ * final row will also be smaller. Each tile begins with a "subencoding" type ++ * byte, which is a mask made up of a number of bits. If the Raw bit is set ++ * then the other bits are irrelevant; w*h pixel values follow (where w and h ++ * are the width and height of the tile). Otherwise the tile is encoded in a ++ * similar way to RRE, except that the position and size of each subrectangle ++ * can be specified in just two bytes. The other bits in the mask are as ++ * follows: ++ * ++ * BackgroundSpecified - if set, a pixel value follows which specifies ++ * the background colour for this tile. The first non-raw tile in a ++ * rectangle must have this bit set. If this bit isn't set then the ++ * background is the same as the last tile. ++ * ++ * ForegroundSpecified - if set, a pixel value follows which specifies ++ * the foreground colour to be used for all subrectangles in this tile. ++ * If this bit is set then the SubrectsColoured bit must be zero. ++ * ++ * AnySubrects - if set, a single byte follows giving the number of ++ * subrectangles following. If not set, there are no subrectangles (i.e. ++ * the whole tile is just solid background colour). ++ * ++ * SubrectsColoured - if set then each subrectangle is preceded by a pixel ++ * value giving the colour of that subrectangle. If not set, all ++ * subrectangles are the same colour, the foreground colour; if the ++ * ForegroundSpecified bit wasn't set then the foreground is the same as ++ * the last tile. ++ * ++ * The position and size of each subrectangle is specified in two bytes. The ++ * Pack macros below can be used to generate the two bytes from x, y, w, h, ++ * and the Extract macros can be used to extract the x, y, w, h values from ++ * the two bytes. ++ */ ++ ++#define rfbHextileRaw (1 << 0) ++#define rfbHextileBackgroundSpecified (1 << 1) ++#define rfbHextileForegroundSpecified (1 << 2) ++#define rfbHextileAnySubrects (1 << 3) ++#define rfbHextileSubrectsColoured (1 << 4) ++ ++#define rfbHextilePackXY(x,y) (((x) << 4) | (y)) ++#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1)) ++#define rfbHextileExtractX(byte) ((byte) >> 4) ++#define rfbHextileExtractY(byte) ((byte) & 0xf) ++#define rfbHextileExtractW(byte) (((byte) >> 4) + 1) ++#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1) ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ZLIB - zlib compression Encoding. We have an rfbZlibHeader structure ++ * giving the number of bytes to follow. Finally the data follows in ++ * zlib compressed format. ++ */ ++ ++typedef struct _rfbZlibHeader { ++ CARD32 nBytes; ++} rfbZlibHeader; ++ ++#define sz_rfbZlibHeader 4 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * Tight Encoding. ++ * ++ *-- The first byte of each Tight-encoded rectangle is a "compression control ++ * byte". Its format is as follows (bit 0 is the least significant one): ++ * ++ * bit 0: if 1, then compression stream 0 should be reset; ++ * bit 1: if 1, then compression stream 1 should be reset; ++ * bit 2: if 1, then compression stream 2 should be reset; ++ * bit 3: if 1, then compression stream 3 should be reset; ++ * bits 7-4: if 1000 (0x08), then the compression type is "fill", ++ * if 1001 (0x09), then the compression type is "jpeg", ++ * if 0xxx, then the compression type is "basic", ++ * values greater than 1001 are not valid. ++ * ++ * If the compression type is "basic", then bits 6..4 of the ++ * compression control byte (those xxx in 0xxx) specify the following: ++ * ++ * bits 5-4: decimal representation is the index of a particular zlib ++ * stream which should be used for decompressing the data; ++ * bit 6: if 1, then a "filter id" byte is following this byte. ++ * ++ *-- The data that follows after the compression control byte described ++ * above depends on the compression type ("fill", "jpeg" or "basic"). ++ * ++ *-- If the compression type is "fill", then the only pixel value follows, in ++ * client pixel format (see NOTE 1). This value applies to all pixels of the ++ * rectangle. ++ * ++ *-- If the compression type is "jpeg", the following data stream looks like ++ * this: ++ * ++ * 1..3 bytes: data size (N) in compact representation; ++ * N bytes: JPEG image. ++ * ++ * Data size is compactly represented in one, two or three bytes, according ++ * to the following scheme: ++ * ++ * 0xxxxxxx (for values 0..127) ++ * 1xxxxxxx 0yyyyyyy (for values 128..16383) ++ * 1xxxxxxx 1yyyyyyy zzzzzzzz (for values 16384..4194303) ++ * ++ * Here each character denotes one bit, xxxxxxx are the least significant 7 ++ * bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the ++ * most significant 8 bits (bits 14-21). For example, decimal value 10000 ++ * should be represented as two bytes: binary 10010000 01001110, or ++ * hexadecimal 90 4E. ++ * ++ *-- If the compression type is "basic" and bit 6 of the compression control ++ * byte was set to 1, then the next (second) byte specifies "filter id" which ++ * tells the decoder what filter type was used by the encoder to pre-process ++ * pixel data before the compression. The "filter id" byte can be one of the ++ * following: ++ * ++ * 0: no filter ("copy" filter); ++ * 1: "palette" filter; ++ * 2: "gradient" filter. ++ * ++ *-- If bit 6 of the compression control byte is set to 0 (no "filter id" ++ * byte), or if the filter id is 0, then raw pixel values in the client ++ * format (see NOTE 1) will be compressed. See below details on the ++ * compression. ++ * ++ *-- The "gradient" filter pre-processes pixel data with a simple algorithm ++ * which converts each color component to a difference between a "predicted" ++ * intensity and the actual intensity. Such a technique does not affect ++ * uncompressed data size, but helps to compress photo-like images better. ++ * Pseudo-code for converting intensities to differences is the following: ++ * ++ * P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1]; ++ * if (P[i,j] < 0) then P[i,j] := 0; ++ * if (P[i,j] > MAX) then P[i,j] := MAX; ++ * D[i,j] := V[i,j] - P[i,j]; ++ * ++ * Here V[i,j] is the intensity of a color component for a pixel at ++ * coordinates (i,j). MAX is the maximum value of intensity for a color ++ * component. ++ * ++ *-- The "palette" filter converts true-color pixel data to indexed colors ++ * and a palette which can consist of 2..256 colors. If the number of colors ++ * is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to ++ * encode one pixel. 1-bit encoding is performed such way that the most ++ * significant bits correspond to the leftmost pixels, and each raw of pixels ++ * is aligned to the byte boundary. When "palette" filter is used, the ++ * palette is sent before the pixel data. The palette begins with an unsigned ++ * byte which value is the number of colors in the palette minus 1 (i.e. 1 ++ * means 2 colors, 255 means 256 colors in the palette). Then follows the ++ * palette itself which consist of pixel values in client pixel format (see ++ * NOTE 1). ++ * ++ *-- The pixel data is compressed using the zlib library. But if the data ++ * size after applying the filter but before the compression is less then 12, ++ * then the data is sent as is, uncompressed. Four separate zlib streams ++ * (0..3) can be used and the decoder should read the actual stream id from ++ * the compression control byte (see NOTE 2). ++ * ++ * If the compression is not used, then the pixel data is sent as is, ++ * otherwise the data stream looks like this: ++ * ++ * 1..3 bytes: data size (N) in compact representation; ++ * N bytes: zlib-compressed data. ++ * ++ * Data size is compactly represented in one, two or three bytes, just like ++ * in the "jpeg" compression method (see above). ++ * ++ *-- NOTE 1. If the color depth is 24, and all three color components are ++ * 8-bit wide, then one pixel in Tight encoding is always represented by ++ * three bytes, where the first byte is red component, the second byte is ++ * green component, and the third byte is blue component of the pixel color ++ * value. This applies to colors in palettes as well. ++ * ++ *-- NOTE 2. The decoder must reset compression streams' states before ++ * decoding the rectangle, if some of bits 0,1,2,3 in the compression control ++ * byte are set to 1. Note that the decoder must reset zlib streams even if ++ * the compression type is "fill" or "jpeg". ++ * ++ *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only ++ * when bits-per-pixel value is either 16 or 32, not 8. ++ * ++ *-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048 ++ * pixels. If a rectangle is wider, it must be split into several rectangles ++ * and each one should be encoded separately. ++ * ++ */ ++ ++#define rfbTightExplicitFilter 0x04 ++#define rfbTightFill 0x08 ++#define rfbTightJpeg 0x09 ++#define rfbTightMaxSubencoding 0x09 ++ ++/* Filters to improve compression efficiency */ ++#define rfbTightFilterCopy 0x00 ++#define rfbTightFilterPalette 0x01 ++#define rfbTightFilterGradient 0x02 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ZLIBHEX - zlib compressed Hextile Encoding. Essentially, this is the ++ * hextile encoding with zlib compression on the tiles that can not be ++ * efficiently encoded with one of the other hextile subencodings. The ++ * new zlib subencoding uses two bytes to specify the length of the ++ * compressed tile and then the compressed data follows. As with the ++ * raw sub-encoding, the zlib subencoding invalidates the other ++ * values, if they are also set. ++ */ ++ ++#define rfbHextileZlibRaw (1 << 5) ++#define rfbHextileZlibHex (1 << 6) ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * XCursor encoding. This is a special encoding used to transmit X-style ++ * cursor shapes from server to clients. Note that for this encoding, ++ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot ++ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB ++ * samples are sent after header in the rfbXCursorColors structure. They ++ * denote foreground and background colors of the cursor. If a client ++ * supports only black-and-white cursors, it should ignore these colors and ++ * assume that foreground is black and background is white. Next, two bitmaps ++ * (1 bits per pixel) follow: first one with actual data (value 0 denotes ++ * background color, value 1 denotes foreground color), second one with ++ * transparency data (bits with zero value mean that these pixels are ++ * transparent). Both bitmaps represent cursor data in a byte stream, from ++ * left to right, from top to bottom, and each row is byte-aligned. Most ++ * significant bits correspond to leftmost pixels. The number of bytes in ++ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor ++ * should be hidden (or default local cursor should be set by the client). ++ */ ++ ++typedef struct _rfbXCursorColors { ++ CARD8 foreRed; ++ CARD8 foreGreen; ++ CARD8 foreBlue; ++ CARD8 backRed; ++ CARD8 backGreen; ++ CARD8 backBlue; ++} rfbXCursorColors; ++ ++#define sz_rfbXCursorColors 6 ++ ++ ++/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * RichCursor encoding. This is a special encoding used to transmit cursor ++ * shapes from server to clients. It is similar to the XCursor encoding but ++ * uses client pixel format instead of two RGB colors to represent cursor ++ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader ++ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h). ++ * After header, two pixmaps follow: first one with cursor image in current ++ * client pixel format (like in raw encoding), second with transparency data ++ * (1 bit per pixel, exactly the same format as used for transparency bitmap ++ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or ++ * default local cursor should be set by the client). ++ */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetColourMapEntries - these messages are only sent if the pixel ++ * format uses a "colour map" (i.e. trueColour false) and the client has not ++ * fixed the entire colour map using FixColourMapEntries. In addition they ++ * will only start being sent after the client has sent its first ++ * FramebufferUpdateRequest. So if the client always tells the server to use ++ * trueColour then it never needs to process this type of message. ++ */ ++ ++typedef struct _rfbSetColourMapEntriesMsg { ++ CARD8 type; /* always rfbSetColourMapEntries */ ++ CARD8 redIndex; /* used to be pad, but used for DirectColor */ ++ CARD16 firstColour; ++ CARD16 nColours; ++ ++ /* Followed by nColours * 3 * CARD16 ++ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */ ++ ++} rfbSetColourMapEntriesMsg; ++ ++#define sz_rfbSetColourMapEntriesMsg 6 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Bell - ring a bell on the client if it has one. ++ */ ++ ++typedef struct _rfbBellMsg { ++ CARD8 type; /* always rfbBell */ ++} rfbBellMsg; ++ ++#define sz_rfbBellMsg 1 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * ServerCutText - the server has new text in its cut buffer. ++ */ ++ ++typedef struct _rfbServerCutTextMsg { ++ CARD8 type; /* always rfbServerCutText */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 length; ++ /* followed by char text[length] */ ++} rfbServerCutTextMsg; ++ ++#define sz_rfbServerCutTextMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumStart - a port number for the crserver ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumStart */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 crServerPort; ++ CARD32 mothershipPort; ++} rfbChromiumStartMsg; ++ ++#define sz_rfbChromiumStartMsg 12 ++ ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumMoveResizeWindow - move a chromium window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumMoveResizeWindow */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 x; ++ CARD32 y; ++ CARD32 w; ++ CARD32 h; ++} rfbChromiumMoveResizeWindowMsg; ++ ++#define sz_rfbChromiumMoveResizeWindowMsg 24 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumClipList - send clip list ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumClipList */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 length; ++} rfbChromiumClipListMsg; ++ ++#define sz_rfbChromiumClipListMsg 12 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumWindowShow - map or unmap a window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumWindowShow */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++ CARD32 show; ++} rfbChromiumWindowShowMsg; ++ ++#define sz_rfbChromiumWindowShowMsg 12 ++ ++/*----------------------------------------------------------------------------- ++ * FileListData ++ */ ++ ++typedef struct _rfbFileListDataMsg { ++ CARD8 type; ++ CARD8 flags; ++ CARD16 numFiles; ++ CARD16 dataSize; ++ CARD16 compressedSize; ++ /* Followed by SizeData[numFiles] */ ++ /* Followed by Filenames[compressedSize] */ ++} rfbFileListDataMsg; ++ ++#define sz_rfbFileListDataMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadData ++ */ ++ ++typedef struct _rfbFileDownloadDataMsg { ++ CARD8 type; ++ CARD8 compressLevel; ++ CARD16 realSize; ++ CARD16 compressedSize; ++ /* Followed by File[copressedSize] */ ++} rfbFileDownloadDataMsg; ++ ++#define sz_rfbFileDownloadDataMsg 6 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadCancel ++ */ ++ ++typedef struct _rfbFileUploadCancelMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileUploadCancelMsg; ++ ++#define sz_rfbFileUploadCancelMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadFailed ++ */ ++ ++typedef struct _rfbFileDownloadFailedMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileDownloadFailedMsg; ++ ++#define sz_rfbFileDownloadFailedMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * Union of all server->client messages. ++ */ ++ ++typedef union _rfbServerToClientMsg { ++ CARD8 type; ++ rfbFramebufferUpdateMsg fu; ++ rfbSetColourMapEntriesMsg scme; ++ rfbBellMsg b; ++ rfbServerCutTextMsg sct; ++ rfbFileListDataMsg fld; ++ rfbFileDownloadDataMsg fdd; ++ rfbFileUploadCancelMsg fuc; ++ rfbFileDownloadFailedMsg fdf; ++ rfbChromiumStartMsg scd; ++ rfbChromiumMoveResizeWindowMsg scm; ++ rfbChromiumClipListMsg sccl; ++ rfbChromiumWindowShowMsg scws; ++} rfbServerToClientMsg; ++ ++ ++ ++/***************************************************************************** ++ * ++ * Message definitions (client -> server) ++ * ++ *****************************************************************************/ ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetPixelFormat - tell the RFB server the format in which the client wants ++ * pixels sent. ++ */ ++ ++typedef struct _rfbSetPixelFormatMsg { ++ CARD8 type; /* always rfbSetPixelFormat */ ++ CARD8 pad1; ++ CARD16 pad2; ++ rfbPixelFormat format; ++} rfbSetPixelFormatMsg; ++ ++#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4) ++ ++ ++/*----------------------------------------------------------------------------- ++ * FixColourMapEntries - when the pixel format uses a "colour map", fix ++ * read-only colour map entries. ++ * ++ * ***************** NOT CURRENTLY SUPPORTED ***************** ++ */ ++ ++typedef struct _rfbFixColourMapEntriesMsg { ++ CARD8 type; /* always rfbFixColourMapEntries */ ++ CARD8 pad; ++ CARD16 firstColour; ++ CARD16 nColours; ++ ++ /* Followed by nColours * 3 * CARD16 ++ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */ ++ ++} rfbFixColourMapEntriesMsg; ++ ++#define sz_rfbFixColourMapEntriesMsg 6 ++ ++ ++/*----------------------------------------------------------------------------- ++ * SetEncodings - tell the RFB server which encoding types we accept. Put them ++ * in order of preference, if we have any. We may always receive raw ++ * encoding, even if we don't specify it here. ++ */ ++ ++typedef struct _rfbSetEncodingsMsg { ++ CARD8 type; /* always rfbSetEncodings */ ++ CARD8 pad; ++ CARD16 nEncodings; ++ /* followed by nEncodings * CARD32 encoding types */ ++} rfbSetEncodingsMsg; ++ ++#define sz_rfbSetEncodingsMsg 4 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FramebufferUpdateRequest - request for a framebuffer update. If incremental ++ * is true then the client just wants the changes since the last update. If ++ * false then it wants the whole of the specified rectangle. ++ */ ++ ++typedef struct _rfbFramebufferUpdateRequestMsg { ++ CARD8 type; /* always rfbFramebufferUpdateRequest */ ++ CARD8 incremental; ++ CARD16 x; ++ CARD16 y; ++ CARD16 w; ++ CARD16 h; ++} rfbFramebufferUpdateRequestMsg; ++ ++#define sz_rfbFramebufferUpdateRequestMsg 10 ++ ++ ++/*----------------------------------------------------------------------------- ++ * KeyEvent - key press or release ++ * ++ * Keys are specified using the "keysym" values defined by the X Window System. ++ * For most ordinary keys, the keysym is the same as the corresponding ASCII ++ * value. Other common keys are: ++ * ++ * BackSpace 0xff08 ++ * Tab 0xff09 ++ * Return or Enter 0xff0d ++ * Escape 0xff1b ++ * Insert 0xff63 ++ * Delete 0xffff ++ * Home 0xff50 ++ * End 0xff57 ++ * Page Up 0xff55 ++ * Page Down 0xff56 ++ * Left 0xff51 ++ * Up 0xff52 ++ * Right 0xff53 ++ * Down 0xff54 ++ * F1 0xffbe ++ * F2 0xffbf ++ * ... ... ++ * F12 0xffc9 ++ * Shift 0xffe1 ++ * Control 0xffe3 ++ * Meta 0xffe7 ++ * Alt 0xffe9 ++ */ ++ ++typedef struct _rfbKeyEventMsg { ++ CARD8 type; /* always rfbKeyEvent */ ++ CARD8 down; /* true if down (press), false if up */ ++ CARD16 pad; ++ CARD32 key; /* key is specified as an X keysym */ ++} rfbKeyEventMsg; ++ ++#define sz_rfbKeyEventMsg 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * PointerEvent - mouse/pen move and/or button press. ++ */ ++ ++typedef struct _rfbPointerEventMsg { ++ CARD8 type; /* always rfbPointerEvent */ ++ CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */ ++ CARD16 x; ++ CARD16 y; ++} rfbPointerEventMsg; ++ ++#define rfbButton1Mask 1 ++#define rfbButton2Mask 2 ++#define rfbButton3Mask 4 ++#define rfbButton4Mask 8 ++#define rfbButton5Mask 16 ++ ++#define sz_rfbPointerEventMsg 6 ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * ClientCutText - the client has new text in its cut buffer. ++ */ ++ ++typedef struct _rfbClientCutTextMsg { ++ CARD8 type; /* always rfbClientCutText */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 length; ++ /* followed by char text[length] */ ++} rfbClientCutTextMsg; ++ ++#define sz_rfbClientCutTextMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileListRequest ++ */ ++ ++typedef struct _rfbFileListRequestMsg { ++ CARD8 type; ++ CARD8 flags; ++ CARD16 dirNameSize; ++ /* Followed by char Dirname[dirNameSize] */ ++} rfbFileListRequestMsg; ++ ++#define sz_rfbFileListRequestMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadRequest ++ */ ++ ++typedef struct _rfbFileDownloadRequestMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 fNameSize; ++ CARD32 position; ++ /* Followed by char Filename[fNameSize] */ ++} rfbFileDownloadRequestMsg; ++ ++#define sz_rfbFileDownloadRequestMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadRequest ++ */ ++ ++typedef struct _rfbFileUploadRequestMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 fNameSize; ++ CARD32 position; ++ /* Followed by char Filename[fNameSize] */ ++} rfbFileUploadRequestMsg; ++ ++#define sz_rfbFileUploadRequestMsg 8 ++ ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadData ++ */ ++ ++typedef struct _rfbFileUploadDataMsg { ++ CARD8 type; ++ CARD8 compressedLevel; ++ CARD16 realSize; ++ CARD16 compressedSize; ++ /* Followed by File[compressedSize] */ ++} rfbFileUploadDataMsg; ++ ++#define sz_rfbFileUploadDataMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * FileDownloadCancel ++ */ ++ ++typedef struct _rfbFileDownloadCancelMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileDownloadCancelMsg; ++ ++#define sz_rfbFileDownloadCancelMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileUploadFailed ++ */ ++ ++typedef struct _rfbFileUploadFailedMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 reasonLen; ++ /* Followed by reason[reasonLen] */ ++} rfbFileUploadFailedMsg; ++ ++#define sz_rfbFileUploadFailedMsg 4 ++ ++/*----------------------------------------------------------------------------- ++ * FileCreateDirRequest ++ */ ++ ++typedef struct _rfbFileCreateDirRequestMsg { ++ CARD8 type; ++ CARD8 unused; ++ CARD16 dNameLen; ++ CARD32 dModTime; ++ /* Followed by dName[dNameLen] */ ++} rfbFileCreateDirRequestMsg; ++ ++#define sz_rfbFileCreateDirRequestMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumStop - the client has stopped the GL app. ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumStop */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 port; ++} rfbChromiumStopMsg; ++ ++#define sz_rfbChromiumStopMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * ChromiumExpose - redraw the window ++ */ ++ ++typedef struct { ++ CARD8 type; /* always rfbChromiumExpose */ ++ CARD8 pad1; ++ CARD16 pad2; ++ CARD32 winid; ++} rfbChromiumExposeMsg; ++ ++#define sz_rfbChromiumExposeMsg 8 ++ ++/*----------------------------------------------------------------------------- ++ * Union of all client->server messages. ++ */ ++ ++typedef union _rfbClientToServerMsg { ++ CARD8 type; ++ rfbSetPixelFormatMsg spf; ++ rfbFixColourMapEntriesMsg fcme; ++ rfbSetEncodingsMsg se; ++ rfbFramebufferUpdateRequestMsg fur; ++ rfbKeyEventMsg ke; ++ rfbPointerEventMsg pe; ++ rfbClientCutTextMsg cct; ++ rfbFileListRequestMsg flr; ++ rfbFileDownloadRequestMsg fdr; ++ rfbFileUploadRequestMsg fupr; ++ rfbFileUploadDataMsg fud; ++ rfbFileDownloadCancelMsg fdc; ++ rfbFileUploadFailedMsg fuf; ++ rfbFileCreateDirRequestMsg fcdr; ++ rfbChromiumStopMsg csd; ++ rfbChromiumExposeMsg cse; ++} rfbClientToServerMsg; +diff --git a/hw/xfree86/vnc/rfbserver.c b/hw/xfree86/vnc/rfbserver.c +new file mode 100644 +index 0000000..ee002ab +--- /dev/null ++++ b/hw/xfree86/vnc/rfbserver.c +@@ -0,0 +1,2278 @@ ++/* ++ * rfbserver.c - deal with server-side of the RFB protocol. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000-2004 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* Use ``#define CORBA'' to enable CORBA control interface */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "windowstr.h" ++#include "rfb.h" ++#include "input.h" ++#include "mipointer.h" ++#if XFREE86VNC ++#include ++#endif ++#ifdef CHROMIUM ++#include "mivalidate.h" ++#endif ++#include "sprite.h" ++#include "propertyst.h" ++#include ++#include ++ ++#ifdef CORBA ++#include ++#endif ++ ++#ifdef CHROMIUM ++struct CRWindowTable *windowTable = NULL; ++#endif ++ ++extern Atom VNC_CONNECT; ++ ++rfbClientPtr rfbClientHead = NULL; ++rfbClientPtr pointerClient = NULL; /* Mutex for pointer events */ ++ ++static rfbClientPtr rfbNewClient(ScreenPtr pScreen, int sock); ++static void rfbProcessClientProtocolVersion(rfbClientPtr cl); ++static void rfbProcessClientInitMessage(rfbClientPtr cl); ++static void rfbSendInteractionCaps(rfbClientPtr cl); ++static void rfbProcessClientNormalMessage(rfbClientPtr cl); ++static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy); ++static Bool rfbSendLastRectMarker(rfbClientPtr cl); ++ ++static char *text = NULL; ++ ++void ++rfbRootPropertyChange(ScreenPtr pScreen) ++{ ++ PropertyPtr pProp; ++ WindowPtr pWin = WindowTable[pScreen->myNum]; ++ ++ pProp = wUserProps (pWin); ++ ++ while (pProp) { ++ if ((pProp->propertyName == XA_CUT_BUFFER0) && ++ (pProp->type == XA_STRING) && ++ (pProp->format == 8)) ++ { ++ /* Ensure we don't keep re-sending cut buffer */ ++ ++ if ( (text && pProp->data && strncmp(text, pProp->data, pProp->size)) || !text) ++ rfbGotXCutText(pProp->data, pProp->size); ++ ++ if (text) xfree(text); ++ text = xalloc(1 + pProp->size); ++ if (! text) return; ++ if (pProp->data) memcpy(text, pProp->data, pProp->size); ++ text[pProp->size] = '\0'; ++ ++ return; ++ } ++ if ((pProp->propertyName == VNC_CONNECT) && (pProp->type == XA_STRING) ++ && (pProp->format == 8) && (pProp->size > 0)) ++ { ++ int i; ++ rfbClientPtr cl; ++ int port = 5500; ++ char *host = (char *)Xalloc(pProp->size+1); ++ memcpy(host, pProp->data, pProp->size); ++ host[pProp->size] = 0; ++ for (i = 0; i < pProp->size; i++) { ++ if (host[i] == ':') { ++ port = atoi(&host[i+1]); ++ host[i] = 0; ++ } ++ } ++ ++ cl = rfbReverseConnection(pScreen, host, port); ++ ++#ifdef CORBA ++ if (cl != NULL) ++ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1); ++#endif ++ ++ ChangeWindowProperty(pWin, ++ pProp->propertyName, pProp->type, ++ pProp->format, PropModeReplace, ++ 0, NULL, ++ FALSE ++ ); ++ ++ free(host); ++ } ++ pProp = pProp->next; ++ } ++} ++ ++int ++rfbBitsPerPixel(depth) ++ int depth; ++{ ++ if (depth == 1) return 1; ++ else if (depth <= 8) return 8; ++ else if (depth <= 16) return 16; ++ else return 32; ++} ++ ++void ++rfbUserAllow(int sock, int accept) ++{ ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (cl->sock == sock) { ++ cl->userAccepted = accept; ++ } ++ } ++} ++ ++/* ++ * rfbNewClientConnection is called from sockets.c when a new connection ++ * comes in. ++ */ ++ ++void ++rfbNewClientConnection(ScreenPtr pScreen, int sock) ++{ ++ rfbClientPtr cl; ++ ++ cl = rfbNewClient(pScreen, sock); ++ ++ GenerateVncConnectedEvent(sock); ++ ++#if XFREE86VNC ++ /* Someone is connected - disable VT switching */ ++ xf86EnableVTSwitch(FALSE); ++#endif ++ ++#ifdef CORBA ++ if (cl != NULL) ++ newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1); ++#endif ++} ++ ++ ++/* ++ * rfbReverseConnection is called by the CORBA stuff to make an outward ++ * connection to a "listening" RFB client. ++ */ ++ ++rfbClientPtr ++rfbReverseConnection(ScreenPtr pScreen, char *host, int port) ++{ ++ int sock; ++ rfbClientPtr cl; ++ ++ if ((sock = rfbConnect(pScreen, host, port)) < 0) ++ return (rfbClientPtr)NULL; ++ ++ cl = rfbNewClient(pScreen, sock); ++ ++ if (cl) { ++ cl->reverseConnection = TRUE; ++ } ++ ++ return cl; ++} ++ ++ ++#ifdef CHROMIUM ++/* ++ * rfbSetClip -- ++ * Generate expose event. ++ * This function is overkill and should be cleaned up, but it ++ * works for now. ++ */ ++ ++void ++rfbSetClip (WindowPtr pWin, BOOL enable) ++{ ++ ScreenPtr pScreen = pWin->drawable.pScreen; ++ WindowPtr pChild; ++ Bool WasViewable = (Bool)(pWin->viewable); ++ Bool anyMarked = FALSE; ++ RegionPtr pOldClip = NULL, bsExposed; ++#ifdef DO_SAVE_UNDERS ++ Bool dosave = FALSE; ++#endif ++ WindowPtr pLayerWin; ++ BoxRec box; ++ ++ if (WasViewable) ++ { ++ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) ++ { ++ (void) (*pScreen->MarkOverlappedWindows)(pChild, ++ pChild, ++ &pLayerWin); ++ } ++ (*pScreen->MarkWindow) (pWin); ++ anyMarked = TRUE; ++ if (pWin->valdata) ++ { ++ if (HasBorder (pWin)) ++ { ++ RegionPtr borderVisible; ++ ++ borderVisible = REGION_CREATE(pScreen, NullBox, 1); ++ REGION_SUBTRACT(pScreen, borderVisible, ++ &pWin->borderClip, &pWin->winSize); ++ pWin->valdata->before.borderVisible = borderVisible; ++ } ++ pWin->valdata->before.resized = TRUE; ++ } ++ } ++ ++ /* ++ * Use REGION_BREAK to avoid optimizations in ValidateTree ++ * that assume the root borderClip can't change well, normally ++ * it doesn't...) ++ */ ++ if (enable) ++ { ++ box.x1 = 0; ++ box.y1 = 0; ++ box.x2 = pScreen->width; ++ box.y2 = pScreen->height; ++ REGION_INIT (pScreen, &pWin->winSize, &box, 1); ++ REGION_INIT (pScreen, &pWin->borderSize, &box, 1); ++ if (WasViewable) ++ REGION_RESET(pScreen, &pWin->borderClip, &box); ++ pWin->drawable.width = pScreen->width; ++ pWin->drawable.height = pScreen->height; ++ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); ++ } ++ else ++ { ++ REGION_EMPTY(pScreen, &pWin->borderClip); ++ REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); ++ } ++ ++ ResizeChildrenWinSize (pWin, 0, 0, 0, 0); ++ ++ if (WasViewable) ++ { ++ if (pWin->backStorage) ++ { ++ pOldClip = REGION_CREATE(pScreen, NullBox, 1); ++ REGION_COPY(pScreen, pOldClip, &pWin->clipList); ++ } ++ ++ if (pWin->firstChild) ++ { ++ anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, ++ pWin->firstChild, ++ (WindowPtr *)NULL); ++ } ++ else ++ { ++ (*pScreen->MarkWindow) (pWin); ++ anyMarked = TRUE; ++ } ++ ++#ifdef DO_SAVE_UNDERS ++ if (DO_SAVE_UNDERS(pWin)) ++ { ++ dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin); ++ } ++#endif /* DO_SAVE_UNDERS */ ++ ++ if (anyMarked) ++ (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); ++ } ++ ++ if (pWin->backStorage && ++ ((pWin->backingStore == Always) || WasViewable)) ++ { ++ if (!WasViewable) ++ pOldClip = &pWin->clipList; /* a convenient empty region */ ++ bsExposed = (*pScreen->TranslateBackingStore) ++ (pWin, 0, 0, pOldClip, ++ pWin->drawable.x, pWin->drawable.y); ++ if (WasViewable) ++ REGION_DESTROY(pScreen, pOldClip); ++ if (bsExposed) ++ { ++ RegionPtr valExposed = NullRegion; ++ ++ if (pWin->valdata) ++ valExposed = &pWin->valdata->after.exposed; ++ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); ++ if (valExposed) ++ REGION_EMPTY(pScreen, valExposed); ++ REGION_DESTROY(pScreen, bsExposed); ++ } ++ } ++ if (WasViewable) ++ { ++ if (anyMarked) ++ (*pScreen->HandleExposures)(pWin); ++#ifdef DO_SAVE_UNDERS ++ if (dosave) ++ (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin); ++#endif /* DO_SAVE_UNDERS */ ++ if (anyMarked && pScreen->PostValidateTree) ++ (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); ++ } ++ if (pWin->realized) ++ WindowsRestructured (); ++ FlushAllOutput (); ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * rfbNewClient is called when a new connection has been made by whatever ++ * means. ++ */ ++ ++static rfbClientPtr ++rfbNewClient(ScreenPtr pScreen, int sock) ++{ ++ rfbProtocolVersionMsg pv; ++ rfbClientPtr cl; ++ BoxRec box; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(struct sockaddr_in); ++ VNCSCREENPTR(pScreen); ++ int i; ++ ++ if (rfbClientHead == NULL) { ++ /* no other clients - make sure we don't think any keys are pressed */ ++ KbdReleaseAllKeys(); ++ } else { ++ rfbLog(" (other clients"); ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ rfbLog(" %s",cl->host); ++ } ++ rfbLog(")\n"); ++ } ++ ++ cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec)); ++ ++#ifdef CHROMIUM ++ cl->chromium_port = 0; /* no GL application on this port, yet */ ++#endif ++ cl->userAccepted = 0; /* user hasn't even approached this yet .... */ ++ cl->sock = sock; ++ getpeername(sock, (struct sockaddr *)&addr, &addrlen); ++ cl->host = strdup(inet_ntoa(addr.sin_addr)); ++ cl->login = NULL; ++ ++ /* Dispatch client input to rfbProcessClientProtocolVersion(). */ ++ cl->state = RFB_PROTOCOL_VERSION; ++ ++ cl->viewOnly = FALSE; ++ cl->reverseConnection = FALSE; ++ cl->readyForSetColourMapEntries = FALSE; ++ cl->useCopyRect = FALSE; ++ cl->preferredEncoding = rfbEncodingRaw; ++ cl->correMaxWidth = 48; ++ cl->correMaxHeight = 48; ++ cl->pScreen = pScreen; ++ ++ REGION_NULL(pScreen,&cl->copyRegion); ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ ++ box.x1 = box.y1 = 0; ++ box.x2 = pVNC->width; ++ box.y2 = pVNC->height; ++ REGION_INIT(pScreen,&cl->modifiedRegion,&box,0); ++ ++ REGION_NULL(pScreen,&cl->requestedRegion); ++ ++ cl->deferredUpdateScheduled = FALSE; ++ cl->deferredUpdateTimer = NULL; ++ ++ cl->format = pVNC->rfbServerFormat; ++ cl->translateFn = rfbTranslateNone; ++ cl->translateLookupTable = NULL; ++ ++ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; ++ cl->tightQualityLevel = -1; ++ for (i = 0; i < 4; i++) ++ cl->zsActive[i] = FALSE; ++ ++ cl->enableCursorShapeUpdates = FALSE; ++ cl->enableCursorPosUpdates = FALSE; ++ cl->enableLastRectEncoding = FALSE; ++#ifdef CHROMIUM ++ cl->enableChromiumEncoding = FALSE; ++#endif ++ ++ cl->next = rfbClientHead; ++ rfbClientHead = cl; ++ ++ rfbResetStats(cl); ++ ++ cl->compStreamInited = FALSE; ++ cl->compStream.total_in = 0; ++ cl->compStream.total_out = 0; ++ cl->compStream.zalloc = Z_NULL; ++ cl->compStream.zfree = Z_NULL; ++ cl->compStream.opaque = Z_NULL; ++ ++ cl->zlibCompressLevel = 5; ++ ++ sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion, ++ rfbProtocolMinorVersion); ++ ++ if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) { ++ rfbLogPerror("rfbNewClient: write"); ++ rfbCloseSock(pScreen, sock); ++ return NULL; ++ } ++ ++ return cl; ++} ++ ++ ++/* ++ * rfbClientConnectionGone is called from sockets.c just after a connection ++ * has gone away. ++ */ ++ ++void ++rfbClientConnectionGone(sock) ++ int sock; ++{ ++ rfbClientPtr cl, prev; ++ int i; ++#if XFREE86VNC ++ int allowvt = TRUE; ++#endif ++ ++ for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) { ++ if (sock == cl->sock) ++ break; ++ } ++ ++ if (!cl) { ++ rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock); ++ return; ++ } ++ ++ if (cl->login != NULL) { ++ rfbLog("Client %s (%s) gone\n", cl->login, cl->host); ++ free(cl->login); ++ } else { ++ rfbLog("Client %s gone\n", cl->host); ++ } ++ free(cl->host); ++ ++ /* Release the compression state structures if any. */ ++ if ( cl->compStreamInited == TRUE ) { ++ deflateEnd( &(cl->compStream) ); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ if (cl->zsActive[i]) ++ deflateEnd(&cl->zsStruct[i]); ++ } ++ ++ if (pointerClient == cl) ++ pointerClient = NULL; ++ ++#ifdef CORBA ++ destroyConnection(cl); ++#endif ++ ++ if (prev) ++ prev->next = cl->next; ++ else ++ rfbClientHead = cl->next; ++ ++ REGION_UNINIT(cl->pScreen,&cl->copyRegion); ++ REGION_UNINIT(cl->pScreen,&cl->modifiedRegion); ++ TimerFree(cl->deferredUpdateTimer); ++ ++ rfbPrintStats(cl); ++ ++ if (cl->translateLookupTable) free(cl->translateLookupTable); ++ ++ xfree(cl); ++ ++ GenerateVncDisconnectedEvent(sock); ++ ++#if XFREE86VNC ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ /* still someone connected */ ++ allowvt = FALSE; ++ } ++ ++ xf86EnableVTSwitch(allowvt); ++#endif ++} ++ ++ ++/* ++ * rfbProcessClientMessage is called when there is data to read from a client. ++ */ ++ ++void ++rfbProcessClientMessage(ScreenPtr pScreen, int sock) ++{ ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++ if (sock == cl->sock) ++ break; ++ } ++ ++ if (!cl) { ++ rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock); ++ rfbCloseSock(pScreen, sock); ++ return; ++ } ++ ++#ifdef CORBA ++ if (isClosePending(cl)) { ++ rfbLog("Closing connection to client %s\n", cl->host); ++ rfbCloseSock(pScreen, sock); ++ return; ++ } ++#endif ++ ++ switch (cl->state) { ++ case RFB_PROTOCOL_VERSION: ++ rfbProcessClientProtocolVersion(cl); ++ break; ++ case RFB_SECURITY_TYPE: /* protocol 3.7 */ ++ rfbProcessClientSecurityType(cl); ++ break; ++ case RFB_TUNNELING_TYPE: /* protocol 3.7t */ ++ rfbProcessClientTunnelingType(cl); ++ break; ++ case RFB_AUTH_TYPE: /* protocol 3.7t */ ++ rfbProcessClientAuthType(cl); ++ break; ++ case RFB_AUTHENTICATION: ++ rfbVncAuthProcessResponse(cl); ++ break; ++ case RFB_INITIALISATION: ++ rfbProcessClientInitMessage(cl); ++ break; ++ default: ++ rfbProcessClientNormalMessage(cl); ++ } ++} ++ ++ ++/* ++ * rfbProcessClientProtocolVersion is called when the client sends its ++ * protocol version. ++ */ ++ ++static void ++rfbProcessClientProtocolVersion(cl) ++ rfbClientPtr cl; ++{ ++ rfbProtocolVersionMsg pv; ++ int n, major, minor; ++ ++ if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientProtocolVersion: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientProtocolVersion: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ pv[sz_rfbProtocolVersionMsg] = 0; ++ if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) { ++ rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ rfbLog("Using protocol version %d.%d\n", major, minor); ++ ++ if (major != rfbProtocolMajorVersion) { ++ rfbLog("RFB protocol version mismatch - server %d.%d, client %d.%d\n", ++ rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Always use one of the two standard versions of the RFB protocol. */ ++ cl->protocol_minor_ver = minor; ++ if (minor > rfbProtocolMinorVersion) { ++ cl->protocol_minor_ver = rfbProtocolMinorVersion; ++ } else if (minor < rfbProtocolMinorVersion) { ++ cl->protocol_minor_ver = rfbProtocolFallbackMinorVersion; ++ } ++ if (minor != rfbProtocolMinorVersion && ++ minor != rfbProtocolFallbackMinorVersion) { ++ rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n", ++ major, minor, rfbProtocolMajorVersion, cl->protocol_minor_ver); ++ } ++ ++ /* TightVNC protocol extensions are not enabled yet. */ ++ cl->protocol_tightvnc = FALSE; ++ ++ rfbAuthNewClient(cl); ++} ++ ++/* ++ * rfbClientConnFailed is called when a client connection has failed ++ * before the authentication stage. ++ */ ++ ++void ++rfbClientConnFailed(cl, reason) ++ rfbClientPtr cl; ++ char *reason; ++{ ++ int headerLen, reasonLen; ++ char buf[8]; ++ ++ headerLen = (cl->protocol_minor_ver >= 7) ? 1 : 4; ++ reasonLen = strlen(reason); ++ ((CARD32 *)buf)[0] = 0; ++ ((CARD32 *)buf)[1] = Swap32IfLE(reasonLen); ++ ++ if ( WriteExact(cl->sock, buf, headerLen) < 0 || ++ WriteExact(cl->sock, buf + 4, 4) < 0 || ++ WriteExact(cl->sock, reason, reasonLen) < 0 ) { ++ rfbLogPerror("rfbClientConnFailed: write"); ++ } ++ ++ rfbCloseSock(cl->pScreen, cl->sock); ++} ++ ++ ++/* ++ * rfbProcessClientInitMessage is called when the client sends its ++ * initialisation message. ++ */ ++ ++static void ++rfbProcessClientInitMessage(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbClientInitMsg ci; ++ char buf[256]; ++ rfbServerInitMsg *si = (rfbServerInitMsg *)buf; ++ struct passwd *user; ++ int len, n; ++ rfbClientPtr otherCl, nextCl; ++ ++ if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) { ++ if (n == 0) ++ rfbLog("rfbProcessClientInitMessage: client gone\n"); ++ else ++ rfbLogPerror("rfbProcessClientInitMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ si->framebufferWidth = Swap16IfLE(pVNC->width); ++ si->framebufferHeight = Swap16IfLE(pVNC->height); ++ si->format = pVNC->rfbServerFormat; ++ si->format.redMax = Swap16IfLE(si->format.redMax); ++ si->format.greenMax = Swap16IfLE(si->format.greenMax); ++ si->format.blueMax = Swap16IfLE(si->format.blueMax); ++ ++ user = getpwuid(getuid()); ++ ++ if (strlen(desktopName) > 128) /* sanity check on desktop name len */ ++ desktopName[128] = 0; ++ ++ if (user) { ++ sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)", ++ user->pw_name, desktopName, rfbThisHost, display); ++ } else { ++ sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)", ++ desktopName, rfbThisHost, display); ++ } ++ len = strlen(buf + sz_rfbServerInitMsg); ++ si->nameLength = Swap32IfLE(len); ++ ++ if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) { ++ rfbLogPerror("rfbProcessClientInitMessage: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ if (cl->protocol_tightvnc) ++ rfbSendInteractionCaps(cl); /* protocol 3.7t */ ++ ++ /* Dispatch client input to rfbProcessClientNormalMessage(). */ ++ cl->state = RFB_NORMAL; ++ ++ if (!cl->reverseConnection && ++ (pVNC->rfbNeverShared || (!pVNC->rfbAlwaysShared && !ci.shared))) { ++ ++ if (pVNC->rfbDontDisconnect) { ++ for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) { ++ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { ++ rfbLog("-dontdisconnect: Not shared & existing client\n"); ++ rfbLog(" refusing new client %s\n", cl->host); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ } else { ++ for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) { ++ nextCl = otherCl->next; ++ if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { ++ rfbLog("Not shared - closing connection to client %s\n", ++ otherCl->host); ++ rfbCloseSock(otherCl->pScreen, otherCl->sock); ++ } ++ } ++ } ++ } ++} ++ ++ ++/* ++ * rfbSendInteractionCaps is called after sending the server ++ * initialisation message, only if the protocol version is 3.130. ++ * In this function, we send the lists of supported protocol messages ++ * and encodings. ++ */ ++ ++/* Update these constants on changing capability lists below! */ ++#define N_SMSG_CAPS 0 ++#define N_CMSG_CAPS 0 ++#define N_ENC_CAPS 12 ++ ++void ++rfbSendInteractionCaps(cl) ++ rfbClientPtr cl; ++{ ++ rfbInteractionCapsMsg intr_caps; ++ rfbCapabilityInfo enc_list[N_ENC_CAPS]; ++ int i; ++ ++ /* Fill in the header structure sent prior to capability lists. */ ++ intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS); ++ intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS); ++ intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS); ++ intr_caps.pad = 0; ++ ++ /* Supported server->client message types. */ ++ /* For future file transfer support: ++ i = 0; ++ SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor); ++ SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor); ++ if (i != N_SMSG_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ */ ++ ++ /* Supported client->server message types. */ ++ /* For future file transfer support: ++ i = 0; ++ SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor); ++ SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor); ++ if (i != N_CMSG_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ */ ++ ++ /* Encoding types. */ ++ i = 0; ++ SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor); ++ SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor); ++ if (i != N_ENC_CAPS) { ++ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Send header and capability lists */ ++ if (WriteExact(cl->sock, (char *)&intr_caps, ++ sz_rfbInteractionCapsMsg) < 0 || ++ WriteExact(cl->sock, (char *)&enc_list[0], ++ sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) { ++ rfbLogPerror("rfbSendInteractionCaps: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* Dispatch client input to rfbProcessClientNormalMessage(). */ ++ cl->state = RFB_NORMAL; ++} ++ ++ ++/* ++ * rfbProcessClientNormalMessage is called when the client has sent a normal ++ * protocol message. ++ */ ++ ++static void ++rfbProcessClientNormalMessage(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int n; ++ rfbClientToServerMsg msg; ++ char *str; ++ ++ if (pVNC->rfbUserAccept) { ++ /* ++ * We've asked for another level of user authentication ++ * If the user has not validated this connected, don't ++ * process it. ++ */ ++ /* ++ * NOTE: we do it here, so the vncviewer knows it's ++ * connected, but waiting for the first screen update ++ */ ++ if (cl->userAccepted == VNC_USER_UNDEFINED) { ++ usleep(10); ++ return; ++ } ++ if (cl->userAccepted == VNC_USER_DISCONNECT) { ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ } ++ ++ if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ switch (msg.type) { ++ ++ case rfbSetPixelFormat: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbSetPixelFormatMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel; ++ cl->format.depth = msg.spf.format.depth; ++ cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0); ++ cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0); ++ cl->format.redMax = Swap16IfLE(msg.spf.format.redMax); ++ cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax); ++ cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax); ++ cl->format.redShift = msg.spf.format.redShift; ++ cl->format.greenShift = msg.spf.format.greenShift; ++ cl->format.blueShift = msg.spf.format.blueShift; ++ ++ cl->readyForSetColourMapEntries = TRUE; ++ ++ rfbSetTranslateFunction(cl); ++ return; ++ ++ ++ case rfbFixColourMapEntries: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbFixColourMapEntriesMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ rfbLog("rfbProcessClientNormalMessage: %s", ++ "FixColourMapEntries unsupported\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ ++ ++ case rfbSetEncodings: ++ { ++ int i; ++ CARD32 enc; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbSetEncodingsMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings); ++ ++ cl->preferredEncoding = -1; ++ cl->useCopyRect = FALSE; ++ cl->enableCursorShapeUpdates = FALSE; ++ cl->enableCursorPosUpdates = FALSE; ++ cl->enableLastRectEncoding = FALSE; ++#ifdef CHROMIUM ++ cl->enableChromiumEncoding = FALSE; ++#endif ++ cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; ++ cl->tightQualityLevel = -1; ++ ++ for (i = 0; i < msg.se.nEncodings; i++) { ++ if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ enc = Swap32IfLE(enc); ++ ++ switch (enc) { ++ ++ case rfbEncodingCopyRect: ++ cl->useCopyRect = TRUE; ++ rfbLog("Using copyrect encoding for client %s\n", ++ cl->host); ++ break; ++ case rfbEncodingRaw: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using raw encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingRRE: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using rre encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingCoRRE: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using CoRRE encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingHextile: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using hextile encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingZlib: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using zlib encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingTight: ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = enc; ++ rfbLog("Using tight encoding for client %s\n", ++ cl->host); ++ } ++ break; ++ case rfbEncodingXCursor: ++ rfbLog("Enabling X-style cursor updates for client %s\n", ++ cl->host); ++ cl->enableCursorShapeUpdates = TRUE; ++ cl->useRichCursorEncoding = FALSE; ++ cl->cursorWasChanged = TRUE; ++ break; ++ case rfbEncodingRichCursor: ++ if (!cl->enableCursorShapeUpdates) { ++ rfbLog("Enabling full-color cursor updates for client " ++ "%s\n", cl->host); ++ cl->enableCursorShapeUpdates = TRUE; ++ cl->useRichCursorEncoding = TRUE; ++ cl->cursorWasChanged = TRUE; ++ } ++ break; ++ case rfbEncodingPointerPos: ++ if (!cl->enableCursorPosUpdates) { ++ rfbLog("Enabling cursor position updates for client %s\n", ++ cl->host); ++ cl->enableCursorPosUpdates = TRUE; ++ cl->cursorWasMoved = TRUE; ++ cl->cursorX = -1; ++ cl->cursorY = -1; ++ } ++ break; ++ case rfbEncodingLastRect: ++ if (!cl->enableLastRectEncoding) { ++ rfbLog("Enabling LastRect protocol extension for client " ++ "%s\n", cl->host); ++ cl->enableLastRectEncoding = TRUE; ++ } ++ break; ++#ifdef CHROMIUM ++ case rfbEncodingChromium: ++ case rfbEncodingChromium2: ++ if (!cl->enableChromiumEncoding) { ++ cl->enableChromiumEncoding = TRUE; ++ /* This tells OpenGL apps/replicate SPUs that new viewer ++ * has attached. ++ */ ++ GenerateVncChromiumConnectedEvent(cl->sock); ++ if (enc == rfbEncodingChromium) { ++ /* Generate exposures for all windows */ ++ WindowPtr pWin = WindowTable[cl->pScreen->myNum]; ++ rfbSetClip(pWin, 1); ++ } ++ else { ++ /* don't generate exposures for Chromium2 because ++ * that confused DMX. ++ */ ++ } ++ } ++ break; ++#endif ++ default: ++ if ( enc >= (CARD32)rfbEncodingCompressLevel0 && ++ enc <= (CARD32)rfbEncodingCompressLevel9 ) { ++ cl->zlibCompressLevel = enc & 0x0F; ++ cl->tightCompressLevel = enc & 0x0F; ++ rfbLog("Using compression level %d for client %s\n", ++ cl->tightCompressLevel, cl->host); ++ } else if ( enc >= (CARD32)rfbEncodingQualityLevel0 && ++ enc <= (CARD32)rfbEncodingQualityLevel9 ) { ++ cl->tightQualityLevel = enc & 0x0F; ++ rfbLog("Using image quality level %d for client %s\n", ++ cl->tightQualityLevel, cl->host); ++ } else { ++ rfbLog("rfbProcessClientNormalMessage: ignoring unknown " ++ "encoding %d\n", (int)enc); ++ } ++ } ++ } ++ ++ if (cl->preferredEncoding == -1) { ++ cl->preferredEncoding = rfbEncodingRaw; ++ rfbLog("No encoding specified - using raw encoding for client %s\n", ++ cl->host); ++ } ++ ++ if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) { ++ rfbLog("Disabling cursor position updates for client %s\n", ++ cl->host); ++ cl->enableCursorPosUpdates = FALSE; ++ } ++ ++#if XFREE86VNC ++ /* ++ * With XFree86 and the hardware cursor's we need to put up the ++ * cursor again, and if we've detected a cursor shapeless client ++ * we need to disable hardware cursors. ++ */ ++ if (!cl->enableCursorShapeUpdates) ++ pVNC->SWCursor = (Bool *)TRUE; ++ else ++ pVNC->SWCursor = (Bool *)FALSE; ++ ++ { ++ int x, y; ++ miPointerPosition(&x, &y); ++ (*pVNC->spriteFuncs->SetCursor)(cl->pScreen, pVNC->pCurs, x, y); ++ } ++#endif ++ ++ return; ++ } ++ ++ ++ case rfbFramebufferUpdateRequest: ++ { ++ RegionRec tmpRegion; ++ BoxRec box; ++ ++#ifdef CORBA ++ addCapability(cl, DISPLAY_DEVICE); ++#endif ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ box.x1 = Swap16IfLE(msg.fur.x); ++ box.y1 = Swap16IfLE(msg.fur.y); ++ box.x2 = box.x1 + Swap16IfLE(msg.fur.w); ++ box.y2 = box.y1 + Swap16IfLE(msg.fur.h); ++ SAFE_REGION_INIT(cl->pScreen,&tmpRegion,&box,0); ++ ++ REGION_UNION(cl->pScreen, &cl->requestedRegion, &cl->requestedRegion, ++ &tmpRegion); ++ ++ if (!cl->readyForSetColourMapEntries) { ++ /* client hasn't sent a SetPixelFormat so is using server's */ ++ cl->readyForSetColourMapEntries = TRUE; ++ if (!cl->format.trueColour) { ++ if (!rfbSetClientColourMap(cl, 0, 0)) { ++ REGION_UNINIT(cl->pScreen,&tmpRegion); ++ return; ++ } ++ } ++ } ++ ++ if (!msg.fur.incremental) { ++ REGION_UNION(cl->pScreen,&cl->modifiedRegion,&cl->modifiedRegion, ++ &tmpRegion); ++ REGION_SUBTRACT(cl->pScreen,&cl->copyRegion,&cl->copyRegion, ++ &tmpRegion); ++ } ++ ++ if (FB_UPDATE_PENDING(cl)) { ++ rfbSendFramebufferUpdate(cl->pScreen, cl); ++ } ++ ++ REGION_UNINIT(cl->pScreen,&tmpRegion); ++ return; ++ } ++ ++ case rfbKeyEvent: ++ ++ cl->rfbKeyEventsRcvd++; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbKeyEventMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++#ifdef CORBA ++ addCapability(cl, KEYBOARD_DEVICE); ++ ++ if (!isKeyboardEnabled(cl)) ++ return; ++#endif ++ if (!pVNC->rfbViewOnly && !cl->viewOnly) { ++ KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl); ++ } ++ return; ++ ++ ++ case rfbPointerEvent: ++ ++ cl->rfbPointerEventsRcvd++; ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbPointerEventMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++#ifdef CORBA ++ addCapability(cl, POINTER_DEVICE); ++ ++ if (!isPointerEnabled(cl)) ++ return; ++#endif ++ ++ if (pointerClient && (pointerClient != cl)) ++ return; ++ ++ if (msg.pe.buttonMask == 0) ++ pointerClient = NULL; ++ else ++ pointerClient = cl; ++ ++ if (!pVNC->rfbViewOnly && !cl->viewOnly) { ++ cl->cursorX = (int)Swap16IfLE(msg.pe.x); ++ cl->cursorY = (int)Swap16IfLE(msg.pe.y); ++ PtrAddEvent(msg.pe.buttonMask, cl->cursorX, cl->cursorY, cl); ++ } ++ return; ++ ++ ++ case rfbClientCutText: ++ ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbClientCutTextMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ msg.cct.length = Swap32IfLE(msg.cct.length); ++ ++ str = (char *)xalloc(msg.cct.length); ++ ++ if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ xfree(str); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* NOTE: We do not accept cut text from a view-only client */ ++ if (!cl->viewOnly) ++ rfbSetXCutText(str, msg.cct.length); ++ ++ xfree(str); ++ return; ++ ++#ifdef CHROMIUM ++ case rfbChromiumStop: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbChromiumStopMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* would we use msg.csd.port ??? */ ++ ++ cl->chromium_port = 0; ++ ++ /* tear down window information */ ++ { ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ xfree(wt); ++ } ++ ++ windowTable = NULL; ++ } ++ ++ return; ++ ++ case rfbChromiumExpose: ++ if ((n = ReadExact(cl->sock, ((char *)&msg) + 1, ++ sz_rfbChromiumExposeMsg - 1)) <= 0) { ++ if (n != 0) ++ rfbLogPerror("rfbProcessClientNormalMessage: read"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++ ++ /* find the window and re-expose it */ ++ { ++ CRWindowTable *wt, *nextWt = NULL; ++ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->CRwinId == msg.cse.winid) { ++ WindowPtr pWin; ++ pWin = LookupIDByType(wt->XwinId, RT_WINDOW); ++ if (pWin) { ++ miSendExposures(pWin, &pWin->clipList, ++ pWin->drawable.x, ++ pWin->drawable.y); ++ FlushAllOutput(); ++ } ++ } ++ } ++ } ++ ++ return; ++#endif ++ ++ default: ++ ++ rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n", ++ msg.type); ++ rfbLog(" ... closing connection\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return; ++ } ++} ++ ++ ++ ++/* ++ * rfbSendFramebufferUpdate - send the currently pending framebuffer update to ++ * the RFB client. ++ */ ++ ++Bool ++rfbSendFramebufferUpdate(pScreen, cl) ++ ScreenPtr pScreen; ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(pScreen); ++ int i; ++ int nUpdateRegionRects; ++ rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)pVNC->updateBuf; ++ RegionRec updateRegion, updateCopyRegion; ++ int dx, dy; ++ Bool sendCursorShape = FALSE; ++ Bool sendCursorPos = FALSE; ++ ++ /* ++ * If this client understands cursor shape updates, cursor should be ++ * removed from the framebuffer. Otherwise, make sure it's put up. ++ */ ++ ++#if !XFREE86VNC ++ if (cl->enableCursorShapeUpdates) { ++ if (pVNC->cursorIsDrawn) ++ rfbSpriteRemoveCursor(pScreen); ++ if (!pVNC->cursorIsDrawn && cl->cursorWasChanged) ++ sendCursorShape = TRUE; ++ } else { ++ if (!pVNC->cursorIsDrawn) ++ rfbSpriteRestoreCursor(pScreen); ++ } ++#else ++ if (cl->enableCursorShapeUpdates) ++ if (cl->cursorWasChanged) ++ sendCursorShape = TRUE; ++#endif ++ ++ /* ++ * Do we plan to send cursor position update? ++ */ ++ ++ if (cl->enableCursorPosUpdates && cl->cursorWasMoved) ++ sendCursorPos = TRUE; ++ ++ /* ++ * The modifiedRegion may overlap the destination copyRegion. We remove ++ * any overlapping bits from the copyRegion (since they'd only be ++ * overwritten anyway). ++ */ ++ ++ REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion, ++ &cl->modifiedRegion); ++ ++ /* ++ * The client is interested in the region requestedRegion. The region ++ * which should be updated now is the intersection of requestedRegion ++ * and the union of modifiedRegion and copyRegion. If it's empty then ++ * no update is needed. ++ */ ++ ++ REGION_NULL(pScreen,&updateRegion); ++ REGION_UNION(pScreen, &updateRegion, &cl->copyRegion, ++ &cl->modifiedRegion); ++ REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion, ++ &updateRegion); ++ ++ if ( !REGION_NOTEMPTY(pScreen,&updateRegion) && ++ !sendCursorShape && !sendCursorPos ) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return TRUE; ++ } ++ ++ /* ++ * We assume that the client doesn't have any pixel data outside the ++ * requestedRegion. In other words, both the source and destination of a ++ * copy must lie within requestedRegion. So the region we can send as a ++ * copy is the intersection of the copyRegion with both the requestedRegion ++ * and the requestedRegion translated by the amount of the copy. We set ++ * updateCopyRegion to this. ++ */ ++ ++ REGION_NULL(pScreen,&updateCopyRegion); ++ REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion, ++ &cl->requestedRegion); ++ REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY); ++ REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion, ++ &cl->requestedRegion); ++ dx = cl->copyDX; ++ dy = cl->copyDY; ++ ++ /* ++ * Next we remove updateCopyRegion from updateRegion so that updateRegion ++ * is the part of this update which is sent as ordinary pixel data (i.e not ++ * a copy). ++ */ ++ ++ REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion); ++ ++ /* ++ * Finally we leave modifiedRegion to be the remainder (if any) of parts of ++ * the screen which are modified but outside the requestedRegion. We also ++ * empty both the requestedRegion and the copyRegion - note that we never ++ * carry over a copyRegion for a future update. ++ */ ++ ++ REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &cl->copyRegion); ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &updateRegion); ++ REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion, ++ &updateCopyRegion); ++ ++ REGION_EMPTY(pScreen, &cl->requestedRegion); ++ REGION_EMPTY(pScreen, &cl->copyRegion); ++ cl->copyDX = 0; ++ cl->copyDY = 0; ++ ++ /* ++ * Now send the update. ++ */ ++ ++ cl->rfbFramebufferUpdateMessagesSent++; ++ ++ if (cl->preferredEncoding == rfbEncodingCoRRE) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1) ++ * ((h-1) / cl->correMaxHeight + 1)); ++ } ++ } else if (cl->preferredEncoding == rfbEncodingZlib) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1); ++ } ++ } else if (cl->preferredEncoding == rfbEncodingTight) { ++ nUpdateRegionRects = 0; ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ int n = rfbNumCodedRectsTight(cl, x, y, w, h); ++ if (n == 0) { ++ nUpdateRegionRects = 0xFFFF; ++ break; ++ } ++ nUpdateRegionRects += n; ++ } ++ } else { ++ nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion); ++ } ++ ++ fu->type = rfbFramebufferUpdate; ++ if (nUpdateRegionRects != 0xFFFF) { ++ fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) + ++ nUpdateRegionRects + ++ !!sendCursorShape + !!sendCursorPos); ++ } else { ++ fu->nRects = 0xFFFF; ++ } ++ pVNC->ublen = sz_rfbFramebufferUpdateMsg; ++ ++ if (sendCursorShape) { ++ cl->cursorWasChanged = FALSE; ++ if (!rfbSendCursorShape(cl, pScreen)) ++ return FALSE; ++ } ++ ++ if (sendCursorPos) { ++ cl->cursorWasMoved = FALSE; ++ if (!rfbSendCursorPos(cl, pScreen)) ++ return FALSE; ++ } ++ ++ if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) { ++ if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ REGION_UNINIT(pScreen,&updateCopyRegion); ++ return FALSE; ++ } ++ } ++ ++ REGION_UNINIT(pScreen,&updateCopyRegion); ++ ++ for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) { ++ int x = REGION_RECTS(&updateRegion)[i].x1; ++ int y = REGION_RECTS(&updateRegion)[i].y1; ++ int w = REGION_RECTS(&updateRegion)[i].x2 - x; ++ int h = REGION_RECTS(&updateRegion)[i].y2 - y; ++ ++ cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader ++ + w * (cl->format.bitsPerPixel / 8) * h); ++ ++ switch (cl->preferredEncoding) { ++ case rfbEncodingRaw: ++ if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingRRE: ++ if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingCoRRE: ++ if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingHextile: ++ if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingZlib: ++ if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ case rfbEncodingTight: ++ if (!rfbSendRectEncodingTight(cl, x, y, w, h)) { ++ REGION_UNINIT(pScreen,&updateRegion); ++ return FALSE; ++ } ++ break; ++ } ++ } ++ ++ REGION_UNINIT(pScreen,&updateRegion); ++ ++ if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl)) ++ return FALSE; ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * Send the copy region as a string of CopyRect encoded rectangles. ++ * The only slightly tricky thing is that we should send the messages in ++ * the correct order so that an earlier CopyRect will not corrupt the source ++ * of a later one. ++ */ ++ ++static Bool ++rfbSendCopyRegion(cl, reg, dx, dy) ++ rfbClientPtr cl; ++ RegionPtr reg; ++ int dx, dy; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand; ++ int x, y, w, h; ++ rfbFramebufferUpdateRectHeader rect; ++ rfbCopyRect cr; ++ ++ nrects = REGION_NUM_RECTS(reg); ++ ++ if (dx <= 0) { ++ x_inc = 1; ++ } else { ++ x_inc = -1; ++ } ++ ++ if (dy <= 0) { ++ thisRect = 0; ++ y_inc = 1; ++ } else { ++ thisRect = nrects - 1; ++ y_inc = -1; ++ } ++ ++ while (nrects > 0) { ++ ++ firstInNextBand = thisRect; ++ nrectsInBand = 0; ++ ++ while ((nrects > 0) && ++ (REGION_RECTS(reg)[firstInNextBand].y1 ++ == REGION_RECTS(reg)[thisRect].y1)) ++ { ++ firstInNextBand += y_inc; ++ nrects--; ++ nrectsInBand++; ++ } ++ ++ if (x_inc != y_inc) { ++ thisRect = firstInNextBand - y_inc; ++ } ++ ++ while (nrectsInBand > 0) { ++ if ((pVNC->ublen + sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbCopyRect) > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ x = REGION_RECTS(reg)[thisRect].x1; ++ y = REGION_RECTS(reg)[thisRect].y1; ++ w = REGION_RECTS(reg)[thisRect].x2 - x; ++ h = REGION_RECTS(reg)[thisRect].y2 - y; ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingCopyRect); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cr.srcX = Swap16IfLE(x - dx); ++ cr.srcY = Swap16IfLE(y - dy); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&cr, sz_rfbCopyRect); ++ pVNC->ublen += sz_rfbCopyRect; ++ ++ cl->rfbRectanglesSent[rfbEncodingCopyRect]++; ++ cl->rfbBytesSent[rfbEncodingCopyRect] ++ += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect; ++ ++ thisRect += x_inc; ++ nrectsInBand--; ++ } ++ ++ thisRect = firstInNextBand; ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Send a given rectangle in raw encoding (rfbEncodingRaw). ++ */ ++ ++Bool ++rfbSendRectEncodingRaw(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ int nlines; ++ int bytesPerLine = w * (cl->format.bitsPerPixel / 8); ++ unsigned char *fbptr = NULL; ++ int newy = 0; ++ ++ if (pVNC->useGetImage) { ++ newy = y; ++ } else { ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ } ++ ++ /* Flush the buffer to guarantee correct alignment for translateFn(). */ ++ if (pVNC->ublen > 0) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingRaw); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingRaw]++; ++ cl->rfbBytesSent[rfbEncodingRaw] ++ += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h; ++ ++ nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine; ++ ++ while (TRUE) { ++ if (nlines > h) ++ nlines = h; ++ ++ if (pVNC->useGetImage) { ++ (*cl->pScreen->GetImage)((DrawablePtr)WindowTable[cl->pScreen->myNum], x, newy, w, nlines, ZPixmap, ~0, &pVNC->updateBuf[pVNC->ublen]); ++ newy += nlines; ++ } else { ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat, ++ &cl->format, fbptr, &pVNC->updateBuf[pVNC->ublen], ++ pVNC->paddedWidthInBytes, w, nlines, x, y); ++ } ++ ++ pVNC->ublen += nlines * bytesPerLine; ++ h -= nlines; ++ ++ if (h == 0) /* rect fitted in buffer, do next one */ ++ return TRUE; ++ ++ /* buffer full - flush partial rect and do another nlines */ ++ ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ ++ if (!pVNC->useGetImage) ++ fbptr += (pVNC->paddedWidthInBytes * nlines); ++ ++ nlines = (UPDATE_BUF_SIZE - pVNC->ublen) / bytesPerLine; ++ if (nlines == 0) { ++ rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d " ++ "bytes per line\n", bytesPerLine); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ } ++} ++ ++ ++/* ++ * Send an empty rectangle with encoding field set to value of ++ * rfbEncodingLastRect to notify client that this is the last ++ * rectangle in framebuffer update ("LastRect" extension of RFB ++ * protocol). ++ */ ++ ++static Bool ++rfbSendLastRectMarker(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.encoding = Swap32IfLE(rfbEncodingLastRect); ++ rect.r.x = 0; ++ rect.r.y = 0; ++ rect.r.w = 0; ++ rect.r.h = 0; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbLastRectMarkersSent++; ++ cl->rfbLastRectBytesSent += sz_rfbFramebufferUpdateRectHeader; ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Send the contents of pVNC->updateBuf. Returns 1 if successful, -1 if ++ * not (errno should be set). ++ */ ++ ++Bool ++rfbSendUpdateBuf(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ ++ /* ++ int i; ++ for (i = 0; i < pVNC->ublen; i++) { ++ rfbLog("%02x ",((unsigned char *)pVNC->updateBuf)[i]); ++ } ++ rfbLog("\n"); ++ */ ++ ++ if (pVNC->ublen > 0 && WriteExact(cl->sock, pVNC->updateBuf, pVNC->ublen) < 0) { ++ rfbLogPerror("rfbSendUpdateBuf: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ pVNC->ublen = 0; ++ return TRUE; ++} ++ ++ ++ ++/* ++ * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the ++ * client, using values from the currently installed colormap. ++ */ ++ ++Bool ++rfbSendSetColourMapEntries(cl, firstColour, nColours) ++ rfbClientPtr cl; ++ int firstColour; ++ int nColours; ++{ ++#if !XFREE86VNC ++ VNCSCREENPTR(cl->pScreen); ++#endif ++ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; ++ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; ++ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); ++ EntryPtr pent; ++ EntryPtr redEntry, greenEntry, blueEntry; ++ unsigned short redPart, greenPart, bluePart; ++ int i, len; ++ ++ scme->type = rfbSetColourMapEntries; ++ scme->nColours = Swap16IfLE(nColours); ++ ++ len = sz_rfbSetColourMapEntriesMsg; ++ ++ /* PseudoColor */ ++#if XFREE86VNC ++ if (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor) { ++#else ++ if (pVNC->rfbInstalledColormap->class == PseudoColor) { ++#endif ++ scme->firstColour = Swap16IfLE(firstColour); ++#if XFREE86VNC ++ pent = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[firstColour]; ++#else ++ pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[firstColour]; ++#endif ++ for (i = 0; i < nColours; i++) { ++ if (pent->fShared) { ++ rgb[i*3] = Swap16IfLE(pent->co.shco.red->color); ++ rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color); ++ rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color); ++ } else { ++ rgb[i*3] = Swap16IfLE(pent->co.local.red); ++ rgb[i*3+1] = Swap16IfLE(pent->co.local.green); ++ rgb[i*3+2] = Swap16IfLE(pent->co.local.blue); ++ } ++ pent++; ++ } ++ } ++ ++ else { ++ ++ /* Break the DirectColor pixel into its r/g/b components */ ++#if XFREE86VNC ++ redPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->redMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetRed; ++ greenPart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->greenMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetGreen; ++ bluePart = (firstColour & miInstalledMaps[cl->pScreen->myNum]->pVisual->blueMask) ++ >> miInstalledMaps[cl->pScreen->myNum]->pVisual->offsetBlue; ++#else ++ redPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->redMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetRed; ++ greenPart = (firstColour & pVNC->rfbInstalledColormap->pVisual->greenMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetGreen; ++ bluePart = (firstColour & pVNC->rfbInstalledColormap->pVisual->blueMask) ++ >> pVNC->rfbInstalledColormap->pVisual->offsetBlue; ++#endif ++ ++ /* ++ * The firstColour field is only 16 bits. To support 24-bit pixels we ++ * sneak the red component in the 8-bit padding field which we renamed ++ * to redIndex. Green and blue are in firstColour (MSB, LSB respectively). ++ */ ++ scme->redIndex = Swap16IfLE(redPart); ++ scme->firstColour = Swap16IfLE((greenPart << 8) | bluePart); ++ ++#if XFREE86VNC ++ redEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->red[redPart]; ++ greenEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->green[greenPart]; ++ blueEntry = (EntryPtr)&miInstalledMaps[cl->pScreen->myNum]->blue[bluePart]; ++#else ++ redEntry = (EntryPtr)&pVNC->rfbInstalledColormap->red[redPart]; ++ greenEntry = (EntryPtr)&pVNC->rfbInstalledColormap->green[greenPart]; ++ blueEntry = (EntryPtr)&pVNC->rfbInstalledColormap->blue[bluePart]; ++#endif ++ for (i = 0; i < nColours; i++) { ++ if (redEntry->fShared) ++ rgb[i*3] = Swap16IfLE(redEntry->co.shco.red->color); ++ else ++ rgb[i*3] = Swap16IfLE(redEntry->co.local.red); ++ ++ if (greenEntry->fShared) ++ rgb[i*3+1] = Swap16IfLE(greenEntry->co.shco.green->color); ++ else ++ rgb[i*3+1] = Swap16IfLE(greenEntry->co.local.green); ++ ++ if (blueEntry->fShared) ++ rgb[i*3+2] = Swap16IfLE(blueEntry->co.shco.blue->color); ++ else ++ rgb[i*3+2] = Swap16IfLE(blueEntry->co.local.blue); ++ ++ redEntry++; ++ greenEntry++; ++ blueEntry++; ++ } ++ } ++ ++ len += nColours * 3 * 2; ++ ++ if (WriteExact(cl->sock, buf, len) < 0) { ++ rfbLogPerror("rfbSendSetColourMapEntries: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* ++ * rfbSendBell sends a Bell message to all the clients. ++ */ ++ ++void ++rfbSendBell() ++{ ++ rfbClientPtr cl, nextCl; ++ rfbBellMsg b; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ b.type = rfbBell; ++ if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) { ++ rfbLogPerror("rfbSendBell: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ } ++} ++ ++#ifdef CHROMIUM ++#ifdef sun ++extern int inet_aton(const char *cp, struct in_addr *inp); ++#endif ++ ++void ++rfbSendChromiumStart(unsigned int ipaddress, unsigned int crServerPort, ++ unsigned int mothershipPort) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumStartMsg scd; ++ struct in_addr ip; ++ unsigned int vncipaddress; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ inet_aton(cl->host, &ip); ++ memcpy(&vncipaddress, &ip, sizeof(unsigned int)); ++ if (ipaddress == vncipaddress /***&& !cl->chromium_port***/) { ++ cl->chromium_port = crServerPort; ++ cl->chromium_msport = mothershipPort; ++ scd.type = rfbChromiumStart; ++ scd.crServerPort = crServerPort; ++ scd.mothershipPort = mothershipPort; ++ if (WriteExact(cl->sock, (char *)&scd, ++ sz_rfbChromiumStartMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumStart: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ /* We only start one client at at time, so break now! */ ++ break; ++ } ++ } ++} ++ ++ ++/** ++ * Begin monitoring the given X windowid. ++ * When we detect size/position/visibiliy changes we'll send a ++ * rfbChromiumMoveResizeWindow, rfbChromiumClipList, or rfbChromiumWindowShow ++ * message to the VNC viewer, passing the corresponding Chromium window id. ++ */ ++void ++rfbChromiumMonitorWindowID(unsigned int cr_windowid, unsigned long xwindowid) ++{ ++ CRWindowTable *newRec, *wt, *nextWt = NULL; ++ ++ if (xwindowid && !cr_windowid) { ++ /* stop monitoring the X window, remove from list */ ++ CRWindowTable *prev = NULL; ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (wt->XwinId == xwindowid) { ++ /* remove */ ++ if (prev) ++ prev->next = wt->next; ++ else ++ windowTable = wt->next; ++ xfree(wt); ++ } ++ else { ++ prev = wt; ++ } ++ } ++ return; ++ } ++ ++ /* See if we're already managing this window */ ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ /* and if so, update it's window ID */ ++ if (wt->CRwinId == cr_windowid) { ++ wt->XwinId = xwindowid; ++ return; ++ } ++ } ++ ++ /* o.k, new window so create new slot information */ ++ newRec = (CRWindowTable *)xalloc(sizeof(CRWindowTable)); ++ if (!newRec) { ++ rfbLog("Out of memory allocating CRWindowTable.\n"); ++ return; ++ } ++ ++ newRec->next = NULL; ++ newRec->CRwinId = cr_windowid; ++ newRec->XwinId = xwindowid; ++ newRec->clipRects = NULL; ++ newRec->numRects = 0; ++ ++ if (!windowTable) { ++ windowTable = newRec; ++ } ++ else { ++ for (wt = windowTable; wt; wt = nextWt) { ++ nextWt = wt->next; ++ if (!wt->next) /* found the next slot */ ++ wt->next = newRec; ++ } ++ } ++} ++ ++ ++void ++rfbSendChromiumMoveResizeWindow(unsigned int winid, int x, int y, unsigned int w, unsigned int h) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumMoveResizeWindowMsg scm; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ scm.type = rfbChromiumMoveResizeWindow; ++ scm.winid = winid; ++ scm.x = x; ++ scm.y = y; ++ scm.w = w; ++ scm.h = h; ++ if (WriteExact(cl->sock, (char *)&scm, ++ sz_rfbChromiumMoveResizeWindowMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumMoveResizeWindow: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++ ++void ++rfbSendChromiumClipList(unsigned int winid, BoxPtr pClipRects, int numClipRects) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumClipListMsg sccl; ++ int len = sizeof(BoxRec) * numClipRects; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ sccl.type = rfbChromiumClipList; ++ sccl.winid = winid; ++ sccl.length = Swap32IfLE(len); ++ if (WriteExact(cl->sock, (char *)&sccl, ++ sz_rfbChromiumClipListMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumClipList: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ if (WriteExact(cl->sock, (char *)pClipRects, len) < 0) { ++ rfbLogPerror("rfbSendChromiumClipList: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++ ++void ++rfbSendChromiumWindowShow(unsigned int winid, unsigned int show) ++{ ++ rfbClientPtr cl, nextCl; ++ rfbChromiumWindowShowMsg scws; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ if (!cl->enableChromiumEncoding) ++ continue; ++ if (cl->chromium_port) { ++ scws.type = rfbChromiumWindowShow; ++ scws.winid = winid; ++ scws.show = show; ++ if (WriteExact(cl->sock, (char *)&scws, ++ sz_rfbChromiumWindowShowMsg) < 0) { ++ rfbLogPerror("rfbSendChromiumWindowShow: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ } ++ } ++} ++#endif /* CHROMIUM */ ++ ++/* ++ * rfbSendServerCutText sends a ServerCutText message to all the clients. ++ */ ++ ++void ++rfbSendServerCutText(char *str, int len) ++{ ++ rfbClientPtr cl, nextCl = NULL; ++ rfbServerCutTextMsg sct; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ if (cl->state != RFB_NORMAL) continue; ++ nextCl = cl->next; ++ sct.type = rfbServerCutText; ++ sct.length = Swap32IfLE(len); ++ if (WriteExact(cl->sock, (char *)&sct, ++ sz_rfbServerCutTextMsg) < 0) { ++ rfbLogPerror("rfbSendServerCutText: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ continue; ++ } ++ if (WriteExact(cl->sock, str, len) < 0) { ++ rfbLogPerror("rfbSendServerCutText: write\n"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ } ++ } ++} ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * UDP can be used for keyboard and pointer events when the underlying ++ * network is highly reliable. This is really here to support ORL's ++ * videotile, whose TCP implementation doesn't like sending lots of small ++ * packets (such as 100s of pen readings per second!). ++ */ ++ ++void ++rfbNewUDPConnection(sock) ++ int sock; ++{ ++ if (write(sock, &ptrAcceleration, 1) < 0) { ++ rfbLogPerror("rfbNewUDPConnection: write"); ++ } ++} ++ ++/* ++ * Because UDP is a message based service, we can't read the first byte and ++ * then the rest of the packet separately like we do with TCP. We will always ++ * get a whole packet delivered in one go, so we ask read() for the maximum ++ * number of bytes we can possibly get. ++ */ ++ ++void ++rfbProcessUDPInput(ScreenPtr pScreen, int sock) ++{ ++ VNCSCREENPTR(pScreen); ++ int n; ++ rfbClientToServerMsg msg; ++ ++ if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) { ++ if (n < 0) { ++ rfbLogPerror("rfbProcessUDPInput: read"); ++ } ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ ++ switch (msg.type) { ++ ++ case rfbKeyEvent: ++ if (n != sz_rfbKeyEventMsg) { ++ rfbLog("rfbProcessUDPInput: key event incorrect length\n"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ if (!pVNC->rfbViewOnly) { ++ KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), 0); ++ } ++ break; ++ ++ case rfbPointerEvent: ++ if (n != sz_rfbPointerEventMsg) { ++ rfbLog("rfbProcessUDPInput: ptr event incorrect length\n"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ if (!pVNC->rfbViewOnly) { ++ PtrAddEvent(msg.pe.buttonMask, ++ Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), 0); ++ } ++ break; ++ ++ default: ++ rfbLog("rfbProcessUDPInput: unknown message type %d\n", ++ msg.type); ++ rfbDisconnectUDPSock(pScreen); ++ } ++} +diff --git a/hw/xfree86/vnc/rre.c b/hw/xfree86/vnc/rre.c +new file mode 100644 +index 0000000..9e63ed7 +--- /dev/null ++++ b/hw/xfree86/vnc/rre.c +@@ -0,0 +1,325 @@ ++/* ++ * rre.c ++ * ++ * Routines to implement Rise-and-Run-length Encoding (RRE). This ++ * code is based on krw's original javatel rfbserver. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include "rfb.h" ++ ++/* ++ * rreBeforeBuf contains pixel data in the client's format. ++ * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is ++ * larger than the raw data or if it exceeds rreAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int rreBeforeBufSize = 0; ++static char *rreBeforeBuf = NULL; ++ ++static int rreAfterBufSize = 0; ++static char *rreAfterBuf = NULL; ++static int rreAfterBufLen; ++ ++static int subrectEncode8(CARD8 *data, int w, int h); ++static int subrectEncode16(CARD16 *data, int w, int h); ++static int subrectEncode32(CARD32 *data, int w, int h); ++static CARD32 getBgColour(char *data, int size, int bpp); ++ ++ ++/* ++ * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding. ++ */ ++ ++Bool ++rfbSendRectEncodingRRE(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbRREHeader hdr; ++ int nSubrects; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (rreBeforeBufSize < maxRawSize) { ++ rreBeforeBufSize = maxRawSize; ++ if (rreBeforeBuf == NULL) ++ rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); ++ else ++ rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); ++ } ++ ++ if (rreAfterBufSize < maxRawSize) { ++ rreAfterBufSize = maxRawSize; ++ if (rreAfterBuf == NULL) ++ rreAfterBuf = (char *)xalloc(rreAfterBufSize); ++ else ++ rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); ++ } ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, rreBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); ++ break; ++ case 16: ++ nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); ++ break; ++ case 32: ++ nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); ++ break; ++ default: ++ rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); ++ exit(1); ++ } ++ ++ if (nSubrects < 0) { ++ ++ /* RRE encoding was too large, use raw */ ++ ++ return rfbSendRectEncodingRaw(cl, x, y, w, h); ++ } ++ ++ cl->rfbRectanglesSent[rfbEncodingRRE]++; ++ cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbRREHeader + rreAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingRRE); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nSubrects = Swap32IfLE(nSubrects); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbRREHeader); ++ pVNC->ublen += sz_rfbRREHeader; ++ ++ for (i = 0; i < rreAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > rreAfterBufLen) { ++ bytesToCopy = rreAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &rreAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * subrectEncode() encodes the given multicoloured rectangle as a background ++ * colour overwritten by single-coloured rectangles. It returns the number ++ * of subrectangles in the encoded buffer, or -1 if subrect encoding won't ++ * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The ++ * single-colour rectangle partition is not optimal, but does find the biggest ++ * horizontal or vertical rectangle top-left anchored to each consecutive ++ * coordinate position. ++ * ++ * The coding scheme is simply [...] where each ++ * is []. ++ */ ++ ++#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 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) { ++ 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/xfree86/vnc/sockets.c b/hw/xfree86/vnc/sockets.c +new file mode 100644 +index 0000000..e79ae42 +--- /dev/null ++++ b/hw/xfree86/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 ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "windowstr.h" ++ ++#ifndef USE_LIBWRAP ++#define USE_LIBWRAP 0 ++#endif ++#if USE_LIBWRAP ++#include ++#include ++int allow_severity = LOG_INFO; ++int deny_severity = LOG_WARNING; ++#endif ++ ++#include "rfb.h" ++ ++int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has ++ gone away - needed to stop us hanging */ ++ ++static struct sockaddr_in udpRemoteAddr; ++ ++/* ++ * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB ++ * connections. It does nothing if called again. ++ */ ++ ++Bool ++rfbInitSockets(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if (inetdSock != -1) { ++ const int one = 1; ++ ++ if (fcntl(inetdSock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("fcntl"); ++ return FALSE; ++ } ++ ++ if (setsockopt(inetdSock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("setsockopt"); ++ return FALSE; ++ } ++ ++ AddEnabledDevice(inetdSock); ++ FD_ZERO(&pVNC->allFds); ++ FD_SET(inetdSock, &pVNC->allFds); ++ pVNC->maxFd = inetdSock; ++ return TRUE; ++ } ++ ++ if (pVNC->rfbPort == 0) { ++ pVNC->rfbPort = 5900 + atoi(display) + pScreen->myNum; ++ } ++ ++ if ((pVNC->rfbListenSock = ListenOnTCPPort(pScreen, pVNC->rfbPort)) < 0) { ++ rfbLogPerror("ListenOnTCPPort"); ++ pVNC->rfbPort = 0; ++ return FALSE; ++ } ++ ++ rfbLog("Listening for VNC connections on TCP port %d\n", pVNC->rfbPort); ++ ++ AddEnabledDevice(pVNC->rfbListenSock); ++ ++ FD_ZERO(&pVNC->allFds); ++ FD_SET(pVNC->rfbListenSock, &pVNC->allFds); ++ pVNC->maxFd = pVNC->rfbListenSock; ++ ++ if (pVNC->udpPort != 0) { ++ rfbLog("rfbInitSockets: listening for input on UDP port %d\n",pVNC->udpPort); ++ ++ if ((pVNC->udpSock = ListenOnUDPPort(pScreen, pVNC->udpPort)) < 0) { ++ rfbLogPerror("ListenOnUDPPort"); ++ return FALSE; ++ } ++ AddEnabledDevice(pVNC->udpSock); ++ FD_SET(pVNC->udpSock, &pVNC->allFds); ++ pVNC->maxFd = max(pVNC->udpSock,pVNC->maxFd); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ * rfbCheckFds is called from ProcessInputEvents to check for input on the RFB ++ * socket(s). If there is input to process, the appropriate function in the ++ * RFB server code will be called (rfbNewClientConnection, ++ * rfbProcessClientMessage, etc). ++ */ ++ ++void ++rfbCheckFds(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++#if XFREE86VNC ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++#endif ++ int nfds; ++ fd_set fds; ++ struct timeval tv; ++ struct sockaddr_in addr; ++ SOCKLEN_T addrlen = sizeof(addr); ++ char buf[6]; ++ const int one = 1; ++ int sock; ++ static Bool inetdInitDone = FALSE; ++ ++ if (!inetdInitDone && inetdSock != -1) { ++ rfbNewClientConnection(pScreen, inetdSock); ++ inetdInitDone = TRUE; ++ } ++ ++ memcpy((char *)&fds, (char *)&pVNC->allFds, sizeof(fd_set)); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ nfds = select(pVNC->maxFd + 1, &fds, NULL, NULL, &tv); ++ if (nfds == 0) { ++ return; ++ } ++ if (nfds < 0) { ++ if (errno != EINTR) ++ rfbLogPerror("rfbCheckFds: select"); ++ return; ++ } ++ ++ if (pVNC->rfbListenSock != -1 && FD_ISSET(pVNC->rfbListenSock, &fds)) { ++ ++ if ((sock = accept(pVNC->rfbListenSock, ++ (struct sockaddr *)&addr, &addrlen)) < 0) { ++ rfbLogPerror("rfbCheckFds: accept"); ++ return; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("rfbCheckFds: fcntl"); ++ close(sock); ++ return; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("rfbCheckFds: setsockopt"); ++ close(sock); ++ return; ++ } ++ ++ rfbLog("\n"); ++ ++#if USE_LIBWRAP ++ if (!hosts_ctl("Xvnc", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), ++ STRING_UNKNOWN)) { ++ rfbLog("Rejected connection from client %s\n", ++ inet_ntoa(addr.sin_addr)); ++ close(sock); ++ return; ++ } ++#endif ++ ++ rfbLog("Got VNC connection from client %s\n", inet_ntoa(addr.sin_addr)); ++ ++ AddEnabledDevice(sock); ++ FD_SET(sock, &pVNC->allFds); ++ pVNC->maxFd = max(sock,pVNC->maxFd); ++ ++ rfbNewClientConnection(pScreen, sock); ++ ++ FD_CLR(pVNC->rfbListenSock, &fds); ++ if (--nfds == 0) ++ return; ++ } ++ ++ if ((pVNC->udpSock != -1) && FD_ISSET(pVNC->udpSock, &fds)) { ++ ++ if (recvfrom(pVNC->udpSock, buf, 1, MSG_PEEK, ++ (struct sockaddr *)&addr, &addrlen) < 0) { ++ ++ rfbLogPerror("rfbCheckFds: UDP: recvfrom"); ++ rfbDisconnectUDPSock(pScreen); ++ ++ } else { ++ ++ if (!pVNC->udpSockConnected || ++ (memcmp(&addr, &udpRemoteAddr, addrlen) != 0)) ++ { ++ /* new remote end */ ++ rfbLog("rfbCheckFds: UDP: got connection\n"); ++ ++ memcpy(&udpRemoteAddr, &addr, addrlen); ++ pVNC->udpSockConnected = TRUE; ++ ++ if (connect(pVNC->udpSock, ++ (struct sockaddr *)&addr, addrlen) < 0) { ++ rfbLogPerror("rfbCheckFds: UDP: connect"); ++ rfbDisconnectUDPSock(pScreen); ++ return; ++ } ++ ++ rfbNewUDPConnection(pVNC->udpSock); ++ } ++ ++ rfbProcessUDPInput(pScreen, pVNC->udpSock); ++ } ++ ++ FD_CLR(pVNC->udpSock, &fds); ++ if (--nfds == 0) ++ return; ++ } ++ ++ for (sock = 0; sock <= pVNC->maxFd; sock++) { ++ if (FD_ISSET(sock, &fds) && FD_ISSET(sock, &pVNC->allFds)) { ++#if XFREE86VNC ++ if (!pScrn->vtSema) ++ rfbCloseSock(pScreen, sock); ++ else ++#endif ++ rfbProcessClientMessage(pScreen, sock); ++ } ++ } ++} ++ ++ ++void ++rfbDisconnectUDPSock(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ pVNC->udpSockConnected = FALSE; ++} ++ ++ ++void ++rfbCloseSock(ScreenPtr pScreen, int sock) ++{ ++ VNCSCREENPTR(pScreen); ++ close(sock); ++ RemoveEnabledDevice(sock); ++ FD_CLR(sock, &pVNC->allFds); ++ rfbClientConnectionGone(sock); ++ if (sock == inetdSock) ++ GiveUp(0); ++} ++ ++#if 0 ++/* ++ * rfbWaitForClient can be called to wait for the RFB client to send us a ++ * message. When one is received it is processed by calling ++ * rfbProcessClientMessage(). ++ */ ++ ++void ++rfbWaitForClient(sock) ++ int sock; ++{ ++ int n; ++ fd_set fds; ++ struct timeval tv; ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = rfbMaxClientWait / 1000; ++ tv.tv_usec = (rfbMaxClientWait % 1000) * 1000; ++ n = select(sock+1, &fds, NULL, NULL, &tv); ++ if (n < 0) { ++ rfbLogPerror("rfbWaitForClient: select"); ++ exit(1); ++ } ++ if (n == 0) { ++ rfbCloseSock(sock); ++ return; ++ } ++ ++ rfbProcessClientMessage(sock); ++} ++#endif ++ ++/* ++ * rfbConnect is called to make a connection out to a given TCP address. ++ */ ++ ++int ++rfbConnect(ScreenPtr pScreen, char *host, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ int sock; ++ int one = 1; ++ ++ rfbLog("\n"); ++ rfbLog("Making connection to client on host %s port %d\n", ++ host,port); ++ ++ if ((sock = ConnectToTcpAddr(host, port)) < 0) { ++ rfbLogPerror("connection failed"); ++ return -1; ++ } ++ ++ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { ++ rfbLogPerror("fcntl failed"); ++ close(sock); ++ return -1; ++ } ++ ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, ++ (char *)&one, sizeof(one)) < 0) { ++ rfbLogPerror("setsockopt failed"); ++ close(sock); ++ return -1; ++ } ++ ++ AddEnabledDevice(sock); ++ FD_SET(sock, &pVNC->allFds); ++ pVNC->maxFd = max(sock,pVNC->maxFd); ++ ++ return sock; ++} ++ ++ ++ ++ ++/* ++ * ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if ++ * those bytes have been read, 0 if the other end has closed, or -1 if an error ++ * occurred (errno is set to ETIMEDOUT if it timed out). ++ */ ++ ++int ++ReadExact(sock, buf, len) ++ int sock; ++ char *buf; ++ int len; ++{ ++ int n; ++ fd_set fds; ++ int tries = 5; ++ struct timeval tv; ++ ++ while (len > 0) { ++ n = read(sock, buf, len); ++ ++ if (n > 0) { ++ ++ buf += n; ++ len -= n; ++ ++ } else if (n == 0) { ++ ++ return 0; ++ ++ } else { ++ if (errno != EWOULDBLOCK && errno != EAGAIN) { ++ return n; ++ } ++ ++ do { ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = rfbMaxClientWait / 1000; ++ tv.tv_usec = (rfbMaxClientWait % 1000) * 1000; ++ n = select(sock+1, &fds, NULL, NULL, &tv); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((n < 0 && errno == EINTR) && tries > 0); ++ ++ if (n < 0) { ++ rfbLogPerror("ReadExact: select"); ++ return n; ++ } ++ if (n == 0) { ++ errno = ETIMEDOUT; ++ return -1; ++ } ++ } ++ } ++ return 1; ++} ++ ++ ++ ++/* ++ * WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if ++ * those bytes have been written, or -1 if an error occurred (errno is set to ++ * ETIMEDOUT if it timed out). ++ */ ++ ++int ++WriteExact(sock, buf, len) ++ int sock; ++ char *buf; ++ int len; ++{ ++ int n; ++ fd_set fds; ++ struct timeval tv; ++ int totalTimeWaited = 0; ++ ++ while (len > 0) { ++ n = write(sock, buf, len); ++ ++ if (n > 0) { ++ ++ buf += n; ++ len -= n; ++ ++ } else if (n == 0) { ++ ++ rfbLog("WriteExact: write returned 0?\n"); ++ return -1; ++ ++ } else { ++ if (errno != EWOULDBLOCK && errno != EAGAIN) { ++ return n; ++ } ++ ++#if 0 ++ /* Retry every 5 seconds until we exceed rfbMaxClientWait. We ++ need to do this because select doesn't necessarily return ++ immediately when the other end has gone away */ ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = 5; ++ tv.tv_usec = 0; ++#else ++ /* We're in the WakeupHandler now, so don't wait */ ++ ++ FD_ZERO(&fds); ++ FD_SET(sock, &fds); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++#endif ++ n = select(sock+1, NULL, &fds, NULL, &tv); ++#if 0 ++ if (n < 0) { ++ rfbLogPerror("WriteExact: select"); ++ return n; ++ } ++ if (n == 0) { ++ totalTimeWaited += 5000; ++ if (totalTimeWaited >= rfbMaxClientWait) { ++ errno = ETIMEDOUT; ++ return -1; ++ } ++ } else { ++ totalTimeWaited = 0; ++ } ++#endif ++ } ++ } ++ return 1; ++} ++ ++ ++int ++ListenOnTCPPort(ScreenPtr pScreen, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ struct sockaddr_in addr; ++ int sock; ++ int one = 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = pVNC->interface.s_addr; ++ ++ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ return -1; ++ } ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { ++ close(sock); ++ return -1; ++ } ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ close(sock); ++ return -1; ++ } ++ if (listen(sock, 5) < 0) { ++ close(sock); ++ return -1; ++ } ++ ++ return sock; ++} ++ ++ ++int ++ConnectToTcpAddr(host, port) ++ char *host; ++ int port; ++{ ++ struct hostent *hp; ++ int sock, n; ++ struct sockaddr_in addr; ++ int tries = 5; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ ++ if ((addr.sin_addr.s_addr = inet_addr(host)) == -1) ++ { ++ if (!(hp = gethostbyname(host))) { ++ errno = EINVAL; ++ return -1; ++ } ++ addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr; ++ } ++ ++ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ return -1; ++ } ++ ++ do { ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((sock < 0 && errno == EINTR) && tries > 0); ++ ++ if (sock < 0) { ++ return -1; ++ } ++ ++ tries = 5; ++ ++ do { ++ n = connect(sock, (struct sockaddr *)&addr, (sizeof(addr))); ++ tries--; ++ ++ /* We really need to retry if we get EINTR, so spin */ ++ /* If after 5 attempts we're still broke, abort.... */ ++ ++ } while ((n < 0 && errno == EINTR) && tries > 0); ++ ++ if (n < 0) { ++ close(sock); ++ return -1; ++ } ++ ++ return sock; ++} ++ ++ ++int ++ListenOnUDPPort(ScreenPtr pScreen, int port) ++{ ++ VNCSCREENPTR(pScreen); ++ struct sockaddr_in addr; ++ int sock; ++ int one = 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = pVNC->interface.s_addr; ++ ++ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ++ return -1; ++ } ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { ++ return -1; ++ } ++ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { ++ return -1; ++ } ++ ++ return sock; ++} ++ ++#if 0 ++/* ++ * rdpInitSockets sets up the TCP for RDP ++ * connections. It does nothing if called again. ++ */ ++ ++Bool ++rdpInitSockets(ScreenPtr pScreen) ++{ ++ VNCSCREENPTR(pScreen); ++ ++ if ((pVNC->rdpListenSock = ListenOnTCPPort(pScreen, pVNC->rdpPort)) < 0) { ++ rfbLogPerror("ListenOnTCPPort"); ++ pVNC->rdpPort = 0; ++ return FALSE; ++ } ++ ++ rfbLog("Listening for RDP connections on TCP port %d\n", pVNC->rdpPort); ++ ++ AddEnabledDevice(pVNC->rdpListenSock); ++ ++ return TRUE; ++} ++#endif +diff --git a/hw/xfree86/vnc/sprite.h b/hw/xfree86/vnc/sprite.h +new file mode 100644 +index 0000000..ed34726 +--- /dev/null ++++ b/hw/xfree86/vnc/sprite.h +@@ -0,0 +1,141 @@ ++/* ++ * sprite.h ++ * ++ * software-sprite/sprite drawing - based on misprite ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * 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/xfree86/vnc/stats.c b/hw/xfree86/vnc/stats.c +new file mode 100644 +index 0000000..53017ee +--- /dev/null ++++ b/hw/xfree86/vnc/stats.c +@@ -0,0 +1,113 @@ ++/* ++ * stats.c ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#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/xfree86/vnc/tableinitcmtemplate.c b/hw/xfree86/vnc/tableinitcmtemplate.c +new file mode 100644 +index 0000000..8a757e5 +--- /dev/null ++++ b/hw/xfree86/vnc/tableinitcmtemplate.c +@@ -0,0 +1,89 @@ ++/* ++ * tableinitcmtemplate.c - template for initialising lookup tables for ++ * translation from a colour map to true colour. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with a different definition of the macro OUT. ++ * For each value of OUT, this file defines a function which allocates an ++ * appropriately sized lookup table and initialises it. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define OUT_T CONCAT2E(CARD,OUT) ++#define SwapOUT(x) CONCAT2E(Swap,OUT(x)) ++#define rfbInitColourMapSingleTableOUT \ ++ CONCAT2E(rfbInitColourMapSingleTable,OUT) ++ ++static void ++rfbInitColourMapSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ VNCSCREENPTR(pScreen); ++ int i, r, g, b; ++ OUT_T *t; ++ EntryPtr pent; ++ int nEntries = 1 << in->bitsPerPixel; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc(nEntries * sizeof(OUT_T)); ++ t = (OUT_T *)*table; ++ ++#if XFREE86VNC ++ pent = (EntryPtr)&miInstalledMaps[pScreen->myNum]->red[0]; ++#else ++ pent = (EntryPtr)&pVNC->rfbInstalledColormap->red[0]; ++#endif ++ ++ for (i = 0; i < nEntries; i++) { ++ if (pent->fShared) { ++ r = pent->co.shco.red->color; ++ g = pent->co.shco.green->color; ++ b = pent->co.shco.blue->color; ++ } else { ++ r = pent->co.local.red; ++ g = pent->co.local.green; ++ b = pent->co.local.blue; ++ } ++ t[i] = ((((r * out->redMax + 32767) / 65535) << out->redShift) | ++ (((g * out->greenMax + 32767) / 65535) << out->greenShift) | ++ (((b * out->blueMax + 32767) / 65535) << out->blueShift)); ++#if (OUT != 8) ++ if (out->bigEndian != in->bigEndian) { ++ t[i] = SwapOUT(t[i]); ++ } ++#endif ++ pent++; ++ } ++} ++ ++#undef OUT_T ++#undef SwapOUT ++#undef rfbInitColourMapSingleTableOUT +diff --git a/hw/xfree86/vnc/tableinittctemplate.c b/hw/xfree86/vnc/tableinittctemplate.c +new file mode 100644 +index 0000000..da8ae01 +--- /dev/null ++++ b/hw/xfree86/vnc/tableinittctemplate.c +@@ -0,0 +1,142 @@ ++/* ++ * tableinittctemplate.c - template for initialising lookup tables for ++ * truecolour to truecolour translation. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with a different definition of the macro OUT. ++ * For each value of OUT, this file defines two functions for initialising ++ * lookup tables. One is for truecolour translation using a single lookup ++ * table, the other is for truecolour translation using three separate ++ * lookup tables for the red, green and blue values. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define OUT_T CONCAT2E(CARD,OUT) ++#define SwapOUT(x) CONCAT2E(Swap,OUT(x)) ++#define rfbInitTrueColourSingleTableOUT \ ++ CONCAT2E(rfbInitTrueColourSingleTable,OUT) ++#define rfbInitTrueColourRGBTablesOUT CONCAT2E(rfbInitTrueColourRGBTables,OUT) ++#define rfbInitOneRGBTableOUT CONCAT2E(rfbInitOneRGBTable,OUT) ++ ++static void ++rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift, ++ int swap); ++ ++ ++/* ++ * rfbInitTrueColourSingleTable sets up a single lookup table for truecolour ++ * translation. ++ */ ++ ++static void ++rfbInitTrueColourSingleTableOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ int i; ++ int inRed, inGreen, inBlue, outRed, outGreen, outBlue; ++ OUT_T *t; ++ int nEntries = 1 << in->bitsPerPixel; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc(nEntries * sizeof(OUT_T)); ++ t = (OUT_T *)*table; ++ ++ for (i = 0; i < nEntries; i++) { ++ inRed = (i >> in->redShift) & in->redMax; ++ inGreen = (i >> in->greenShift) & in->greenMax; ++ inBlue = (i >> in->blueShift) & in->blueMax; ++ ++ outRed = (inRed * out->redMax + in->redMax / 2) / in->redMax; ++ outGreen = (inGreen * out->greenMax + in->greenMax / 2) / in->greenMax; ++ outBlue = (inBlue * out->blueMax + in->blueMax / 2) / in->blueMax; ++ ++ t[i] = ((outRed << out->redShift) | ++ (outGreen << out->greenShift) | ++ (outBlue << out->blueShift)); ++#if (OUT != 8) ++ if (out->bigEndian != in->bigEndian) { ++ t[i] = SwapOUT(t[i]); ++ } ++#endif ++ } ++} ++ ++ ++/* ++ * rfbInitTrueColourRGBTables sets up three separate lookup tables for the ++ * red, green and blue values. ++ */ ++ ++static void ++rfbInitTrueColourRGBTablesOUT (ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out) ++{ ++ OUT_T *redTable; ++ OUT_T *greenTable; ++ OUT_T *blueTable; ++ ++ if (*table) free(*table); ++ *table = (char *)malloc((in->redMax + in->greenMax + in->blueMax + 3) ++ * sizeof(OUT_T)); ++ redTable = (OUT_T *)*table; ++ greenTable = redTable + in->redMax + 1; ++ blueTable = greenTable + in->greenMax + 1; ++ ++ rfbInitOneRGBTableOUT (redTable, in->redMax, out->redMax, ++ out->redShift, (out->bigEndian != in->bigEndian)); ++ rfbInitOneRGBTableOUT (greenTable, in->greenMax, out->greenMax, ++ out->greenShift, (out->bigEndian != in->bigEndian)); ++ rfbInitOneRGBTableOUT (blueTable, in->blueMax, out->blueMax, ++ out->blueShift, (out->bigEndian != in->bigEndian)); ++} ++ ++static void ++rfbInitOneRGBTableOUT (OUT_T *table, int inMax, int outMax, int outShift, ++ int swap) ++{ ++ int i; ++ int nEntries = inMax + 1; ++ ++ for (i = 0; i < nEntries; i++) { ++ table[i] = ((i * outMax + inMax / 2) / inMax) << outShift; ++#if (OUT != 8) ++ if (swap) { ++ table[i] = SwapOUT(table[i]); ++ } ++#endif ++ } ++} ++ ++#undef OUT_T ++#undef SwapOUT ++#undef rfbInitTrueColourSingleTableOUT ++#undef rfbInitTrueColourRGBTablesOUT ++#undef rfbInitOneRGBTableOUT +diff --git a/hw/xfree86/vnc/tabletranstemplate.c b/hw/xfree86/vnc/tabletranstemplate.c +new file mode 100644 +index 0000000..87cfcba +--- /dev/null ++++ b/hw/xfree86/vnc/tabletranstemplate.c +@@ -0,0 +1,119 @@ ++/* ++ * tabletranstemplate.c - template for translation using lookup tables. ++ * ++ * This file shouldn't be compiled. It is included multiple times by ++ * translate.c, each time with different definitions of the macros IN and OUT. ++ * ++ * For each pair of values IN and OUT, this file defines two functions for ++ * translating a given rectangle of pixel data. One uses a single lookup ++ * table, and the other uses three separate lookup tables for the red, green ++ * and blue values. ++ * ++ * I know this code isn't nice to read because of all the macros, but ++ * efficiency is important here. ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#if !defined(IN) || !defined(OUT) ++#error "This file shouldn't be compiled." ++#error "It is included as part of translate.c" ++#endif ++ ++#define IN_T CONCAT2E(CARD,IN) ++#define OUT_T CONCAT2E(CARD,OUT) ++#define rfbTranslateWithSingleTableINtoOUT \ ++ CONCAT4E(rfbTranslateWithSingleTable,IN,to,OUT) ++#define rfbTranslateWithRGBTablesINtoOUT \ ++ CONCAT4E(rfbTranslateWithRGBTables,IN,to,OUT) ++ ++/* ++ * rfbTranslateWithSingleTableINtoOUT translates a rectangle of pixel data ++ * using a single lookup table. ++ */ ++ ++static void ++rfbTranslateWithSingleTableINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y) ++{ ++ IN_T *ip = (IN_T *)iptr; ++ OUT_T *op = (OUT_T *)optr; ++ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width; ++ OUT_T *opLineEnd; ++ OUT_T *t = (OUT_T *)table; ++ ++ while (height > 0) { ++ opLineEnd = op + width; ++ ++ while (op < opLineEnd) { ++ *(op++) = t[*(ip++)]; ++ } ++ ++ ip += ipextra; ++ height--; ++ } ++} ++ ++ ++/* ++ * rfbTranslateWithRGBTablesINtoOUT translates a rectangle of pixel data ++ * using three separate lookup tables for the red, green and blue values. ++ */ ++ ++static void ++rfbTranslateWithRGBTablesINtoOUT (ScreenPtr pScreen, char *table, rfbPixelFormat *in, ++ rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, ++ int bytesBetweenInputLines, ++ int width, int height, ++ int x, int y) ++{ ++ IN_T *ip = (IN_T *)iptr; ++ OUT_T *op = (OUT_T *)optr; ++ int ipextra = bytesBetweenInputLines / sizeof(IN_T) - width; ++ OUT_T *opLineEnd; ++ OUT_T *redTable = (OUT_T *)table; ++ OUT_T *greenTable = redTable + in->redMax + 1; ++ OUT_T *blueTable = greenTable + in->greenMax + 1; ++ ++ while (height > 0) { ++ opLineEnd = op + width; ++ ++ while (op < opLineEnd) { ++ *(op++) = (redTable[(*ip >> in->redShift) & in->redMax] | ++ greenTable[(*ip >> in->greenShift) & in->greenMax] | ++ blueTable[(*ip >> in->blueShift) & in->blueMax]); ++ ip++; ++ } ++ ip += ipextra; ++ height--; ++ } ++} ++ ++#undef IN_T ++#undef OUT_T ++#undef rfbTranslateWithSingleTableINtoOUT ++#undef rfbTranslateWithRGBTablesINtoOUT +diff --git a/hw/xfree86/vnc/tight.c b/hw/xfree86/vnc/tight.c +new file mode 100644 +index 0000000..d4b25ec +--- /dev/null ++++ b/hw/xfree86/vnc/tight.c +@@ -0,0 +1,1831 @@ ++/* ++ * tight.c ++ * ++ * Routines to implement Tight Encoding ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef HAVE_XORG_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include "rfb.h" ++#include ++ ++ ++/* Note: The following constant should not be changed. */ ++#define TIGHT_MIN_TO_COMPRESS 12 ++ ++/* The parameters below may be adjusted. */ ++#define MIN_SPLIT_RECT_SIZE 4096 ++#define MIN_SOLID_SUBRECT_SIZE 2048 ++#define MAX_SPLIT_TILE_SIZE 16 ++ ++/* May be set to TRUE with "-lazytight" Xvnc option. */ ++Bool rfbTightDisableGradient = FALSE; ++ ++/* This variable is set on every rfbSendRectEncodingTight() call. */ ++static Bool usePixelFormat24; ++ ++ ++/* Compression level stuff. The following array contains various ++ encoder parameters for each of 10 compression levels (0..9). ++ Last three parameters correspond to JPEG quality levels (0..9). */ ++ ++typedef struct TIGHT_CONF_s { ++ int maxRectSize, maxRectWidth; ++ int monoMinRectSize, gradientMinRectSize; ++ int idxZlibLevel, monoZlibLevel, rawZlibLevel, gradientZlibLevel; ++ int gradientThreshold, gradientThreshold24; ++ int idxMaxColorsDivisor; ++ int jpegQuality, jpegThreshold, jpegThreshold24; ++} TIGHT_CONF; ++ ++static TIGHT_CONF tightConf[10] = { ++ { 512, 32, 6, 65536, 0, 0, 0, 0, 0, 0, 4, 5, 10000, 23000 }, ++ { 2048, 128, 6, 65536, 1, 1, 1, 0, 0, 0, 8, 10, 8000, 18000 }, ++ { 6144, 256, 8, 65536, 3, 3, 2, 0, 0, 0, 24, 15, 6500, 15000 }, ++ { 10240, 1024, 12, 65536, 5, 5, 3, 0, 0, 0, 32, 25, 5000, 12000 }, ++ { 16384, 2048, 12, 65536, 6, 6, 4, 0, 0, 0, 32, 37, 4000, 10000 }, ++ { 32768, 2048, 12, 4096, 7, 7, 5, 4, 150, 380, 32, 50, 3000, 8000 }, ++ { 65536, 2048, 16, 4096, 7, 7, 6, 4, 170, 420, 48, 60, 2000, 5000 }, ++ { 65536, 2048, 16, 4096, 8, 8, 7, 5, 180, 450, 64, 70, 1000, 2500 }, ++ { 65536, 2048, 32, 8192, 9, 9, 8, 6, 190, 475, 64, 75, 500, 1200 }, ++ { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } ++}; ++ ++/* Stuff dealing with palettes. */ ++ ++typedef struct COLOR_LIST_s { ++ struct COLOR_LIST_s *next; ++ int idx; ++ CARD32 rgb; ++} COLOR_LIST; ++ ++typedef struct PALETTE_ENTRY_s { ++ COLOR_LIST *listNode; ++ int numPixels; ++} PALETTE_ENTRY; ++ ++typedef struct PALETTE_s { ++ PALETTE_ENTRY entry[256]; ++ COLOR_LIST *hash[256]; ++ COLOR_LIST list[256]; ++} PALETTE; ++ ++static int paletteNumColors, paletteMaxColors; ++static CARD32 monoBackground, monoForeground; ++static PALETTE palette; ++ ++/* Pointers to dynamically-allocated buffers. */ ++ ++static int tightBeforeBufSize = 0; ++static char *tightBeforeBuf = NULL; ++ ++static int tightAfterBufSize = 0; ++static char *tightAfterBuf = NULL; ++ ++static int *prevRowBuf = NULL; ++ ++ ++/* Prototypes for static functions. */ ++ ++static void FindBestSolidArea (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 colorValue, int *w_ptr, int *h_ptr); ++static void ExtendSolidArea (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 colorValue, ++ int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr); ++static Bool CheckSolidTile (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile8 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile16 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++static Bool CheckSolidTile32 (ScreenPtr pScreen, int x, int y, int w, int h, ++ CARD32 *colorPtr, Bool needSameColor); ++ ++static Bool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h); ++static Bool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h); ++static Bool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h); ++ ++static Bool SendSolidRect (rfbClientPtr cl); ++static Bool SendMonoRect (rfbClientPtr cl, int w, int h); ++static Bool SendIndexedRect (rfbClientPtr cl, int w, int h); ++static Bool SendFullColorRect (rfbClientPtr cl, int w, int h); ++static Bool SendGradientRect (rfbClientPtr cl, int w, int h); ++ ++static Bool CompressData(rfbClientPtr cl, int streamId, int dataLen, ++ int zlibLevel, int zlibStrategy); ++static Bool SendCompressedData(rfbClientPtr cl, int compressedLen); ++ ++static void FillPalette8(int count); ++static void FillPalette16(int count); ++static void FillPalette32(int count); ++ ++static void PaletteReset(void); ++static int PaletteInsert(CARD32 rgb, int numPixels, int bpp); ++ ++static void Pack24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int count); ++ ++static void EncodeIndexedRect16(CARD8 *buf, int count); ++static void EncodeIndexedRect32(CARD8 *buf, int count); ++ ++static void EncodeMonoRect8(CARD8 *buf, int w, int h); ++static void EncodeMonoRect16(CARD8 *buf, int w, int h); ++static void EncodeMonoRect32(CARD8 *buf, int w, int h); ++ ++static void FilterGradient24(ScreenPtr pScreen, char *buf, rfbPixelFormat *fmt, int w, int h); ++static void FilterGradient16(ScreenPtr pScreen, CARD16 *buf, rfbPixelFormat *fmt, int w, int h); ++static void FilterGradient32(ScreenPtr pScreen, CARD32 *buf, rfbPixelFormat *fmt, int w, int h); ++ ++static int DetectSmoothImage(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage24(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage16(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++static unsigned long DetectSmoothImage32(rfbClientPtr cl, rfbPixelFormat *fmt, int w, int h); ++ ++static Bool SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, ++ int quality); ++static void PrepareRowForJpeg(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg24(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg16(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++static void PrepareRowForJpeg32(ScreenPtr pScreen, CARD8 *dst, int x, int y, int count); ++ ++static void JpegInitDestination(j_compress_ptr cinfo); ++static boolean JpegEmptyOutputBuffer(j_compress_ptr cinfo); ++static void JpegTermDestination(j_compress_ptr cinfo); ++static void JpegSetDstManager(j_compress_ptr cinfo); ++ ++ ++/* ++ * Tight encoding implementation. ++ */ ++ ++int ++rfbNumCodedRectsTight(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ int maxRectSize, maxRectWidth; ++ int subrectMaxWidth, subrectMaxHeight; ++ ++ /* No matter how many rectangles we will send if LastRect markers ++ are used to terminate rectangle stream. */ ++ if (cl->enableLastRectEncoding && w * h >= MIN_SPLIT_RECT_SIZE) ++ return 0; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ ++ if (w > maxRectWidth || w * h > maxRectSize) { ++ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ subrectMaxHeight = maxRectSize / subrectMaxWidth; ++ return (((w - 1) / maxRectWidth + 1) * ++ ((h - 1) / subrectMaxHeight + 1)); ++ } else { ++ return 1; ++ } ++} ++ ++Bool ++rfbSendRectEncodingTight(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int nMaxRows; ++ CARD32 colorValue; ++ int dx, dy, dw, dh; ++ int x_best, y_best, w_best, h_best; ++ unsigned char *fbptr; ++ ++ if ( cl->format.depth == 24 && cl->format.redMax == 0xFF && ++ cl->format.greenMax == 0xFF && cl->format.blueMax == 0xFF ) { ++ usePixelFormat24 = TRUE; ++ } else { ++ usePixelFormat24 = FALSE; ++ } ++ ++ if (!cl->enableLastRectEncoding || w * h < MIN_SPLIT_RECT_SIZE) ++ return SendRectSimple(cl, x, y, w, h); ++ ++ /* Make sure we can write at least one pixel into tightBeforeBuf. */ ++ ++ if (tightBeforeBufSize < 4) { ++ tightBeforeBufSize = 4; ++ if (tightBeforeBuf == NULL) ++ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); ++ else ++ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, ++ tightBeforeBufSize); ++ } ++ ++ /* Calculate maximum number of rows in one non-solid rectangle. */ ++ ++ { ++ int maxRectSize, maxRectWidth, nMaxWidth; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ nMaxRows = maxRectSize / nMaxWidth; ++ } ++ ++ /* Try to find large solid-color areas and send them separately. */ ++ ++ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { ++ ++ /* If a rectangle becomes too large, send its upper part now. */ ++ ++ if (dy - y >= nMaxRows) { ++ if (!SendRectSimple(cl, x, y, w, nMaxRows)) ++ return 0; ++ y += nMaxRows; ++ h -= nMaxRows; ++ } ++ ++ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? ++ MAX_SPLIT_TILE_SIZE : (y + h - dy); ++ ++ for (dx = x; dx < x + w; dx += MAX_SPLIT_TILE_SIZE) { ++ ++ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w) ? ++ MAX_SPLIT_TILE_SIZE : (x + w - dx); ++ ++ if (CheckSolidTile(cl->pScreen, dx, dy, dw, dh, &colorValue, FALSE)) { ++ ++ /* Get dimensions of solid-color area. */ ++ ++ FindBestSolidArea(cl->pScreen, dx, dy, w - (dx - x), h - (dy - y), ++ colorValue, &w_best, &h_best); ++ ++ /* Make sure a solid rectangle is large enough ++ (or the whole rectangle is of the same color). */ ++ ++ if ( w_best * h_best != w * h && ++ w_best * h_best < MIN_SOLID_SUBRECT_SIZE ) ++ continue; ++ ++ /* Try to extend solid rectangle to maximum size. */ ++ ++ x_best = dx; y_best = dy; ++ ExtendSolidArea(cl->pScreen, x, y, w, h, colorValue, ++ &x_best, &y_best, &w_best, &h_best); ++ ++ /* Send rectangles at top and left to solid-color area. */ ++ ++ if ( y_best != y && ++ !SendRectSimple(cl, x, y, w, y_best-y) ) ++ return FALSE; ++ if ( x_best != x && ++ !rfbSendRectEncodingTight(cl, x, y_best, ++ x_best-x, h_best) ) ++ return FALSE; ++ ++ /* Send solid-color rectangle. */ ++ ++ if (!SendTightHeader(cl, x_best, y_best, w_best, h_best)) ++ return FALSE; ++ ++ fbptr = (pVNC->pfbMemory + ++ (pVNC->paddedWidthInBytes * y_best) + ++ (x_best * (pVNC->bitsPerPixel / 8))); ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, tightBeforeBuf, ++ pVNC->paddedWidthInBytes, 1, 1, ++ x_best, y_best); ++ ++ if (!SendSolidRect(cl)) ++ return FALSE; ++ ++ /* Send remaining rectangles (at right and bottom). */ ++ ++ if ( x_best + w_best != x + w && ++ !rfbSendRectEncodingTight(cl, x_best+w_best, y_best, ++ w-(x_best-x)-w_best, h_best) ) ++ return FALSE; ++ if ( y_best + h_best != y + h && ++ !rfbSendRectEncodingTight(cl, x, y_best+h_best, ++ w, h-(y_best-y)-h_best) ) ++ return FALSE; ++ ++ /* Return after all recursive calls are done. */ ++ ++ return TRUE; ++ } ++ ++ } ++ ++ } ++ ++ /* No suitable solid-color rectangles found. */ ++ ++ return SendRectSimple(cl, x, y, w, h); ++} ++ ++static void ++FindBestSolidArea(pScreen, x, y, w, h, colorValue, w_ptr, h_ptr) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 colorValue; ++ int *w_ptr, *h_ptr; ++{ ++ int dx, dy, dw, dh; ++ int w_prev; ++ int w_best = 0, h_best = 0; ++ ++ w_prev = w; ++ ++ for (dy = y; dy < y + h; dy += MAX_SPLIT_TILE_SIZE) { ++ ++ dh = (dy + MAX_SPLIT_TILE_SIZE <= y + h) ? ++ MAX_SPLIT_TILE_SIZE : (y + h - dy); ++ dw = (w_prev > MAX_SPLIT_TILE_SIZE) ? ++ MAX_SPLIT_TILE_SIZE : w_prev; ++ ++ if (!CheckSolidTile(pScreen, x, dy, dw, dh, &colorValue, TRUE)) ++ break; ++ ++ for (dx = x + dw; dx < x + w_prev;) { ++ dw = (dx + MAX_SPLIT_TILE_SIZE <= x + w_prev) ? ++ MAX_SPLIT_TILE_SIZE : (x + w_prev - dx); ++ if (!CheckSolidTile(pScreen, dx, dy, dw, dh, &colorValue, TRUE)) ++ break; ++ dx += dw; ++ } ++ ++ w_prev = dx - x; ++ if (w_prev * (dy + dh - y) > w_best * h_best) { ++ w_best = w_prev; ++ h_best = dy + dh - y; ++ } ++ } ++ ++ *w_ptr = w_best; ++ *h_ptr = h_best; ++} ++ ++static void ++ExtendSolidArea(pScreen, x, y, w, h, colorValue, x_ptr, y_ptr, w_ptr, h_ptr) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 colorValue; ++ int *x_ptr, *y_ptr, *w_ptr, *h_ptr; ++{ ++ int cx, cy; ++ ++ /* Try to extend the area upwards. */ ++ for ( cy = *y_ptr - 1; ++ cy >= y && CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); ++ cy-- ); ++ *h_ptr += *y_ptr - (cy + 1); ++ *y_ptr = cy + 1; ++ ++ /* ... downwards. */ ++ for ( cy = *y_ptr + *h_ptr; ++ cy < y + h && ++ CheckSolidTile(pScreen, *x_ptr, cy, *w_ptr, 1, &colorValue, TRUE); ++ cy++ ); ++ *h_ptr += cy - (*y_ptr + *h_ptr); ++ ++ /* ... to the left. */ ++ for ( cx = *x_ptr - 1; ++ cx >= x && CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); ++ cx-- ); ++ *w_ptr += *x_ptr - (cx + 1); ++ *x_ptr = cx + 1; ++ ++ /* ... to the right. */ ++ for ( cx = *x_ptr + *w_ptr; ++ cx < x + w && ++ CheckSolidTile(pScreen, cx, *y_ptr, 1, *h_ptr, &colorValue, TRUE); ++ cx++ ); ++ *w_ptr += cx - (*x_ptr + *w_ptr); ++} ++ ++/* ++ * Check if a rectangle is all of the same color. If needSameColor is ++ * set to non-zero, then also check that its color equals to the ++ * *colorPtr value. The result is 1 if the test is successfull, and in ++ * that case new color will be stored in *colorPtr. ++ */ ++ ++static Bool ++CheckSolidTile(pScreen, x, y, w, h, colorPtr, needSameColor) ++ ScreenPtr pScreen; ++ int x, y, w, h; ++ CARD32 *colorPtr; ++ Bool needSameColor; ++{ ++ VNCSCREENPTR(pScreen); ++ switch(pVNC->rfbServerFormat.bitsPerPixel) { ++ case 32: ++ return CheckSolidTile32(pScreen, x, y, w, h, colorPtr, needSameColor); ++ case 16: ++ return CheckSolidTile16(pScreen, x, y, w, h, colorPtr, needSameColor); ++ default: ++ return CheckSolidTile8(pScreen, x, y, w, h, colorPtr, needSameColor); ++ } ++} ++ ++#define DEFINE_CHECK_SOLID_FUNCTION(bpp) \ ++ \ ++static Bool \ ++CheckSolidTile##bpp(pScreen, x, y, w, h, colorPtr, needSameColor) \ ++ ScreenPtr pScreen; \ ++ int x, y; \ ++ CARD32 *colorPtr; \ ++ Bool needSameColor; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp *fbptr; \ ++ CARD##bpp colorValue; \ ++ int dx, dy; \ ++ \ ++ fbptr = (CARD##bpp *) \ ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * (bpp/8)]; \ ++ \ ++ colorValue = *fbptr; \ ++ if (needSameColor && (CARD32)colorValue != *colorPtr) \ ++ return FALSE; \ ++ \ ++ for (dy = 0; dy < h; dy++) { \ ++ for (dx = 0; dx < w; dx++) { \ ++ if (colorValue != fbptr[dx]) \ ++ return FALSE; \ ++ } \ ++ fbptr = (CARD##bpp *)((CARD8 *)fbptr + pVNC->paddedWidthInBytes); \ ++ } \ ++ \ ++ *colorPtr = (CARD32)colorValue; \ ++ return TRUE; \ ++} ++ ++DEFINE_CHECK_SOLID_FUNCTION(8) ++DEFINE_CHECK_SOLID_FUNCTION(16) ++DEFINE_CHECK_SOLID_FUNCTION(32) ++ ++static Bool ++SendRectSimple(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ int maxBeforeSize, maxAfterSize; ++ int maxRectSize, maxRectWidth; ++ int subrectMaxWidth, subrectMaxHeight; ++ int dx, dy; ++ int rw, rh; ++ ++ maxRectSize = tightConf[cl->tightCompressLevel].maxRectSize; ++ maxRectWidth = tightConf[cl->tightCompressLevel].maxRectWidth; ++ ++ maxBeforeSize = maxRectSize * (cl->format.bitsPerPixel / 8); ++ maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; ++ ++ if (tightBeforeBufSize < maxBeforeSize) { ++ tightBeforeBufSize = maxBeforeSize; ++ if (tightBeforeBuf == NULL) ++ tightBeforeBuf = (char *)xalloc(tightBeforeBufSize); ++ else ++ tightBeforeBuf = (char *)xrealloc(tightBeforeBuf, ++ tightBeforeBufSize); ++ } ++ ++ if (tightAfterBufSize < maxAfterSize) { ++ tightAfterBufSize = maxAfterSize; ++ if (tightAfterBuf == NULL) ++ tightAfterBuf = (char *)xalloc(tightAfterBufSize); ++ else ++ tightAfterBuf = (char *)xrealloc(tightAfterBuf, ++ tightAfterBufSize); ++ } ++ ++ if (w > maxRectWidth || w * h > maxRectSize) { ++ subrectMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; ++ subrectMaxHeight = maxRectSize / subrectMaxWidth; ++ ++ for (dy = 0; dy < h; dy += subrectMaxHeight) { ++ for (dx = 0; dx < w; dx += maxRectWidth) { ++ rw = (dx + maxRectWidth < w) ? maxRectWidth : w - dx; ++ rh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy; ++ if (!SendSubrect(cl, x+dx, y+dy, rw, rh)) ++ return FALSE; ++ } ++ } ++ } else { ++ if (!SendSubrect(cl, x, y, w, h)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static Bool ++SendSubrect(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ unsigned char *fbptr; ++ Bool success = FALSE; ++ ++ /* Send pending data if there is more than 128 bytes. */ ++ if (pVNC->ublen > 128) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if (!SendTightHeader(cl, x, y, w, h)) ++ return FALSE; ++ ++ fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, &pVNC->rfbServerFormat, ++ &cl->format, fbptr, tightBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ paletteMaxColors = w * h / tightConf[cl->tightCompressLevel].idxMaxColorsDivisor; ++ if ( paletteMaxColors < 2 && ++ w * h >= tightConf[cl->tightCompressLevel].monoMinRectSize ) { ++ paletteMaxColors = 2; ++ } ++ switch (cl->format.bitsPerPixel) { ++ case 8: ++ FillPalette8(w * h); ++ break; ++ case 16: ++ FillPalette16(w * h); ++ break; ++ default: ++ FillPalette32(w * h); ++ } ++ ++ switch (paletteNumColors) { ++ case 0: ++ /* Truecolor image */ ++ if (DetectSmoothImage(cl, &cl->format, w, h)) { ++ if (cl->tightQualityLevel != -1) { ++ success = SendJpegRect(cl, x, y, w, h, ++ tightConf[cl->tightQualityLevel].jpegQuality); ++ } else { ++ success = SendGradientRect(cl, w, h); ++ } ++ } else { ++ success = SendFullColorRect(cl, w, h); ++ } ++ break; ++ case 1: ++ /* Solid rectangle */ ++ success = SendSolidRect(cl); ++ break; ++ case 2: ++ /* Two-color rectangle */ ++ success = SendMonoRect(cl, w, h); ++ break; ++ default: ++ /* Up to 256 different colors */ ++ if ( paletteNumColors > 96 && ++ cl->tightQualityLevel != -1 && cl->tightQualityLevel <= 3 && ++ DetectSmoothImage(cl, &cl->format, w, h) ) { ++ success = SendJpegRect(cl, x, y, w, h, ++ tightConf[cl->tightQualityLevel].jpegQuality); ++ } else { ++ success = SendIndexedRect(cl, w, h); ++ } ++ } ++ return success; ++} ++ ++static Bool ++SendTightHeader(cl, x, y, w, h) ++ rfbClientPtr cl; ++ int x, y, w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingTight); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ cl->rfbRectanglesSent[rfbEncodingTight]++; ++ cl->rfbBytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader; ++ ++ return TRUE; ++} ++ ++/* ++ * Subencoding implementations. ++ */ ++ ++static Bool ++SendSolidRect(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int len; ++ ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightBeforeBuf, &cl->format, 1); ++ len = 3; ++ } else ++ len = cl->format.bitsPerPixel / 8; ++ ++ if (pVNC->ublen + 1 + len > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightFill << 4); ++ memcpy (&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, len); ++ pVNC->ublen += len; ++ ++ cl->rfbBytesSent[rfbEncodingTight] += len + 1; ++ ++ return TRUE; ++} ++ ++static Bool ++SendMonoRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 1; ++ int paletteLen, dataLen; ++ ++ if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 + ++ 2 * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ /* Prepare tight encoding header. */ ++ dataLen = (w + 7) / 8; ++ dataLen *= h; ++ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette; ++ pVNC->updateBuf[pVNC->ublen++] = 1; ++ ++ /* Prepare palette, convert image. */ ++ switch (cl->format.bitsPerPixel) { ++ ++ case 32: ++ EncodeMonoRect32((CARD8 *)tightBeforeBuf, w, h); ++ ++ ((CARD32 *)tightAfterBuf)[0] = monoBackground; ++ ((CARD32 *)tightAfterBuf)[1] = monoForeground; ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightAfterBuf, &cl->format, 2); ++ paletteLen = 6; ++ } else ++ paletteLen = 8; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteLen); ++ pVNC->ublen += paletteLen; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteLen; ++ break; ++ ++ case 16: ++ EncodeMonoRect16((CARD8 *)tightBeforeBuf, w, h); ++ ++ ((CARD16 *)tightAfterBuf)[0] = (CARD16)monoBackground; ++ ((CARD16 *)tightAfterBuf)[1] = (CARD16)monoForeground; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, 4); ++ pVNC->ublen += 4; ++ cl->rfbBytesSent[rfbEncodingTight] += 7; ++ break; ++ ++ default: ++ EncodeMonoRect8((CARD8 *)tightBeforeBuf, w, h); ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)monoBackground; ++ pVNC->updateBuf[pVNC->ublen++] = (char)monoForeground; ++ cl->rfbBytesSent[rfbEncodingTight] += 5; ++ } ++ ++ return CompressData(cl, streamId, dataLen, ++ tightConf[cl->tightCompressLevel].monoZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendIndexedRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 2; ++ int i, entryLen; ++ ++ if ( (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 6 + ++ paletteNumColors * cl->format.bitsPerPixel / 8) > UPDATE_BUF_SIZE ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ /* Prepare tight encoding header. */ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterPalette; ++ pVNC->updateBuf[pVNC->ublen++] = (char)(paletteNumColors - 1); ++ ++ /* Prepare palette, convert image. */ ++ switch (cl->format.bitsPerPixel) { ++ ++ case 32: ++ EncodeIndexedRect32((CARD8 *)tightBeforeBuf, w * h); ++ ++ for (i = 0; i < paletteNumColors; i++) { ++ ((CARD32 *)tightAfterBuf)[i] = ++ palette.entry[i].listNode->rgb; ++ } ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightAfterBuf, &cl->format, paletteNumColors); ++ entryLen = 3; ++ } else ++ entryLen = 4; ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * entryLen); ++ pVNC->ublen += paletteNumColors * entryLen; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen; ++ break; ++ ++ case 16: ++ EncodeIndexedRect16((CARD8 *)tightBeforeBuf, w * h); ++ ++ for (i = 0; i < paletteNumColors; i++) { ++ ((CARD16 *)tightAfterBuf)[i] = ++ (CARD16)palette.entry[i].listNode->rgb; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightAfterBuf, paletteNumColors * 2); ++ pVNC->ublen += paletteNumColors * 2; ++ cl->rfbBytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2; ++ break; ++ ++ default: ++ return FALSE; /* Should never happen. */ ++ } ++ ++ return CompressData(cl, streamId, w * h, ++ tightConf[cl->tightCompressLevel].idxZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendFullColorRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 0; ++ int len; ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */ ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ ++ if (usePixelFormat24) { ++ Pack24(cl->pScreen, tightBeforeBuf, &cl->format, w * h); ++ len = 3; ++ } else ++ len = cl->format.bitsPerPixel / 8; ++ ++ return CompressData(cl, streamId, w * h * len, ++ tightConf[cl->tightCompressLevel].rawZlibLevel, ++ Z_DEFAULT_STRATEGY); ++} ++ ++static Bool ++SendGradientRect(cl, w, h) ++ rfbClientPtr cl; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int streamId = 3; ++ int len; ++ ++ if (cl->format.bitsPerPixel == 8) ++ return SendFullColorRect(cl, w, h); ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 2 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ if (prevRowBuf == NULL) ++ prevRowBuf = (int *)xalloc(2048 * 3 * sizeof(int)); ++ ++ pVNC->updateBuf[pVNC->ublen++] = (streamId | rfbTightExplicitFilter) << 4; ++ pVNC->updateBuf[pVNC->ublen++] = rfbTightFilterGradient; ++ cl->rfbBytesSent[rfbEncodingTight] += 2; ++ ++ if (usePixelFormat24) { ++ FilterGradient24(cl->pScreen, tightBeforeBuf, &cl->format, w, h); ++ len = 3; ++ } else if (cl->format.bitsPerPixel == 32) { ++ FilterGradient32(cl->pScreen, (CARD32 *)tightBeforeBuf, &cl->format, w, h); ++ len = 4; ++ } else { ++ FilterGradient16(cl->pScreen, (CARD16 *)tightBeforeBuf, &cl->format, w, h); ++ len = 2; ++ } ++ ++ return CompressData(cl, streamId, w * h * len, ++ tightConf[cl->tightCompressLevel].gradientZlibLevel, ++ Z_FILTERED); ++} ++ ++static Bool ++CompressData(cl, streamId, dataLen, zlibLevel, zlibStrategy) ++ rfbClientPtr cl; ++ int streamId, dataLen, zlibLevel, zlibStrategy; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ z_streamp pz; ++ int err; ++ ++ if (dataLen < TIGHT_MIN_TO_COMPRESS) { ++ memcpy(&pVNC->updateBuf[pVNC->ublen], tightBeforeBuf, dataLen); ++ pVNC->ublen += dataLen; ++ cl->rfbBytesSent[rfbEncodingTight] += dataLen; ++ return TRUE; ++ } ++ ++ pz = &cl->zsStruct[streamId]; ++ ++ /* Initialize compression stream if needed. */ ++ if (!cl->zsActive[streamId]) { ++ pz->zalloc = Z_NULL; ++ pz->zfree = Z_NULL; ++ pz->opaque = Z_NULL; ++ ++ err = deflateInit2 (pz, zlibLevel, Z_DEFLATED, MAX_WBITS, ++ MAX_MEM_LEVEL, zlibStrategy); ++ if (err != Z_OK) ++ return FALSE; ++ ++ cl->zsActive[streamId] = TRUE; ++ cl->zsLevel[streamId] = zlibLevel; ++ } ++ ++ /* Prepare buffer pointers. */ ++ pz->next_in = (Bytef *)tightBeforeBuf; ++ pz->avail_in = dataLen; ++ pz->next_out = (Bytef *)tightAfterBuf; ++ pz->avail_out = tightAfterBufSize; ++ ++ /* Change compression parameters if needed. */ ++ if (zlibLevel != cl->zsLevel[streamId]) { ++ if (deflateParams (pz, zlibLevel, zlibStrategy) != Z_OK) { ++ return FALSE; ++ } ++ cl->zsLevel[streamId] = zlibLevel; ++ } ++ ++ /* Actual compression. */ ++ if ( deflate (pz, Z_SYNC_FLUSH) != Z_OK || ++ pz->avail_in != 0 || pz->avail_out == 0 ) { ++ return FALSE; ++ } ++ ++ return SendCompressedData(cl, tightAfterBufSize - pz->avail_out); ++} ++ ++static Bool SendCompressedData(cl, compressedLen) ++ rfbClientPtr cl; ++ int compressedLen; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int i, portionLen; ++ ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen & 0x7F; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ if (compressedLen > 0x7F) { ++ pVNC->updateBuf[pVNC->ublen-1] |= 0x80; ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 7 & 0x7F; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ if (compressedLen > 0x3FFF) { ++ pVNC->updateBuf[pVNC->ublen-1] |= 0x80; ++ pVNC->updateBuf[pVNC->ublen++] = compressedLen >> 14 & 0xFF; ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ } ++ } ++ ++ portionLen = UPDATE_BUF_SIZE; ++ for (i = 0; i < compressedLen; i += portionLen) { ++ if (i + portionLen > compressedLen) { ++ portionLen = compressedLen - i; ++ } ++ if (pVNC->ublen + portionLen > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &tightAfterBuf[i], portionLen); ++ pVNC->ublen += portionLen; ++ } ++ cl->rfbBytesSent[rfbEncodingTight] += compressedLen; ++ return TRUE; ++} ++ ++/* ++ * Code to determine how many different colors used in rectangle. ++ */ ++ ++static void ++FillPalette8(count) ++ int count; ++{ ++ CARD8 *data = (CARD8 *)tightBeforeBuf; ++ CARD8 c0, c1; ++ int i, n0, n1; ++ ++ paletteNumColors = 0; ++ ++ c0 = data[0]; ++ for (i = 1; i < count && data[i] == c0; i++); ++ if (i == count) { ++ paletteNumColors = 1; ++ return; /* Solid rectangle */ ++ } ++ ++ if (paletteMaxColors < 2) ++ return; ++ ++ n0 = i; ++ c1 = data[i]; ++ n1 = 0; ++ for (i++; i < count; i++) { ++ if (data[i] == c0) { ++ n0++; ++ } else if (data[i] == c1) { ++ n1++; ++ } else ++ break; ++ } ++ if (i == count) { ++ if (n0 > n1) { ++ monoBackground = (CARD32)c0; ++ monoForeground = (CARD32)c1; ++ } else { ++ monoBackground = (CARD32)c1; ++ monoForeground = (CARD32)c0; ++ } ++ paletteNumColors = 2; /* Two colors */ ++ } ++} ++ ++#define DEFINE_FILL_PALETTE_FUNCTION(bpp) \ ++ \ ++static void \ ++FillPalette##bpp(count) \ ++ int count; \ ++{ \ ++ CARD##bpp *data = (CARD##bpp *)tightBeforeBuf; \ ++ CARD##bpp c0, c1, ci = 0; \ ++ int i, n0, n1, ni; \ ++ \ ++ c0 = data[0]; \ ++ for (i = 1; i < count && data[i] == c0; i++); \ ++ if (i >= count) { \ ++ paletteNumColors = 1; /* Solid rectangle */ \ ++ return; \ ++ } \ ++ \ ++ if (paletteMaxColors < 2) { \ ++ paletteNumColors = 0; /* Full-color encoding preferred */ \ ++ return; \ ++ } \ ++ \ ++ n0 = i; \ ++ c1 = data[i]; \ ++ n1 = 0; \ ++ for (i++; i < count; i++) { \ ++ ci = data[i]; \ ++ if (ci == c0) { \ ++ n0++; \ ++ } else if (ci == c1) { \ ++ n1++; \ ++ } else \ ++ break; \ ++ } \ ++ if (i >= count) { \ ++ if (n0 > n1) { \ ++ monoBackground = (CARD32)c0; \ ++ monoForeground = (CARD32)c1; \ ++ } else { \ ++ monoBackground = (CARD32)c1; \ ++ monoForeground = (CARD32)c0; \ ++ } \ ++ paletteNumColors = 2; /* Two colors */ \ ++ return; \ ++ } \ ++ \ ++ PaletteReset(); \ ++ PaletteInsert (c0, (CARD32)n0, bpp); \ ++ PaletteInsert (c1, (CARD32)n1, bpp); \ ++ \ ++ ni = 1; \ ++ for (i++; i < count; i++) { \ ++ if (data[i] == ci) { \ ++ ni++; \ ++ } else { \ ++ if (!PaletteInsert (ci, (CARD32)ni, bpp)) \ ++ return; \ ++ ci = data[i]; \ ++ ni = 1; \ ++ } \ ++ } \ ++ PaletteInsert (ci, (CARD32)ni, bpp); \ ++} ++ ++DEFINE_FILL_PALETTE_FUNCTION(16) ++DEFINE_FILL_PALETTE_FUNCTION(32) ++ ++ ++/* ++ * Functions to operate with palette structures. ++ */ ++ ++#define HASH_FUNC16(rgb) ((int)((((rgb) >> 8) + (rgb)) & 0xFF)) ++#define HASH_FUNC32(rgb) ((int)((((rgb) >> 16) + ((rgb) >> 8)) & 0xFF)) ++ ++static void ++PaletteReset(void) ++{ ++ paletteNumColors = 0; ++ memset(palette.hash, 0, 256 * sizeof(COLOR_LIST *)); ++} ++ ++static int ++PaletteInsert(CARD32 rgb, int numPixels, int bpp) ++{ ++ COLOR_LIST *pnode; ++ COLOR_LIST *prev_pnode = NULL; ++ int hash_key, idx, new_idx, count; ++ ++ hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb); ++ ++ pnode = palette.hash[hash_key]; ++ ++ while (pnode != NULL) { ++ if (pnode->rgb == rgb) { ++ /* Such palette entry already exists. */ ++ new_idx = idx = pnode->idx; ++ count = palette.entry[idx].numPixels + numPixels; ++ if (new_idx && palette.entry[new_idx-1].numPixels < count) { ++ do { ++ palette.entry[new_idx] = palette.entry[new_idx-1]; ++ palette.entry[new_idx].listNode->idx = new_idx; ++ new_idx--; ++ } ++ while (new_idx && palette.entry[new_idx-1].numPixels < count); ++ palette.entry[new_idx].listNode = pnode; ++ pnode->idx = new_idx; ++ } ++ palette.entry[new_idx].numPixels = count; ++ return paletteNumColors; ++ } ++ prev_pnode = pnode; ++ pnode = pnode->next; ++ } ++ ++ /* Check if palette is full. */ ++ if (paletteNumColors == 256 || paletteNumColors == paletteMaxColors) { ++ paletteNumColors = 0; ++ return 0; ++ } ++ ++ /* Move palette entries with lesser pixel counts. */ ++ for ( idx = paletteNumColors; ++ idx > 0 && palette.entry[idx-1].numPixels < numPixels; ++ idx-- ) { ++ palette.entry[idx] = palette.entry[idx-1]; ++ palette.entry[idx].listNode->idx = idx; ++ } ++ ++ /* Add new palette entry into the freed slot. */ ++ pnode = &palette.list[paletteNumColors]; ++ if (prev_pnode != NULL) { ++ prev_pnode->next = pnode; ++ } else { ++ palette.hash[hash_key] = pnode; ++ } ++ pnode->next = NULL; ++ pnode->idx = idx; ++ pnode->rgb = rgb; ++ palette.entry[idx].listNode = pnode; ++ palette.entry[idx].numPixels = numPixels; ++ ++ return (++paletteNumColors); ++} ++ ++ ++/* ++ * Converting 32-bit color samples into 24-bit colors. ++ * Should be called only when redMax, greenMax and blueMax are 255. ++ * Color components assumed to be byte-aligned. ++ */ ++ ++static void Pack24(pScreen, buf, fmt, count) ++ ScreenPtr pScreen; ++ char *buf; ++ rfbPixelFormat *fmt; ++ int count; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *buf32; ++ CARD32 pix; ++ int r_shift, g_shift, b_shift; ++ ++ buf32 = (CARD32 *)buf; ++ ++ if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) { ++ r_shift = fmt->redShift; ++ g_shift = fmt->greenShift; ++ b_shift = fmt->blueShift; ++ } else { ++ r_shift = 24 - fmt->redShift; ++ g_shift = 24 - fmt->greenShift; ++ b_shift = 24 - fmt->blueShift; ++ } ++ ++ while (count--) { ++ pix = *buf32++; ++ *buf++ = (char)(pix >> r_shift); ++ *buf++ = (char)(pix >> g_shift); ++ *buf++ = (char)(pix >> b_shift); ++ } ++} ++ ++ ++/* ++ * Converting truecolor samples into palette indices. ++ */ ++ ++#define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ ++ \ ++static void \ ++EncodeIndexedRect##bpp(buf, count) \ ++ CARD8 *buf; \ ++ int count; \ ++{ \ ++ COLOR_LIST *pnode; \ ++ CARD##bpp *src; \ ++ CARD##bpp rgb; \ ++ int rep = 0; \ ++ \ ++ src = (CARD##bpp *) buf; \ ++ \ ++ while (count--) { \ ++ rgb = *src++; \ ++ while (count && *src == rgb) { \ ++ rep++, src++, count--; \ ++ } \ ++ pnode = palette.hash[HASH_FUNC##bpp(rgb)]; \ ++ while (pnode != NULL) { \ ++ if ((CARD##bpp)pnode->rgb == rgb) { \ ++ *buf++ = (CARD8)pnode->idx; \ ++ while (rep) { \ ++ *buf++ = (CARD8)pnode->idx; \ ++ rep--; \ ++ } \ ++ break; \ ++ } \ ++ pnode = pnode->next; \ ++ } \ ++ } \ ++} ++ ++DEFINE_IDX_ENCODE_FUNCTION(16) ++DEFINE_IDX_ENCODE_FUNCTION(32) ++ ++#define DEFINE_MONO_ENCODE_FUNCTION(bpp) \ ++ \ ++static void \ ++EncodeMonoRect##bpp(buf, w, h) \ ++ CARD8 *buf; \ ++ int w, h; \ ++{ \ ++ CARD##bpp *ptr; \ ++ CARD##bpp bg; \ ++ unsigned int value, mask; \ ++ int aligned_width; \ ++ int x, y, bg_bits; \ ++ \ ++ ptr = (CARD##bpp *) buf; \ ++ bg = (CARD##bpp) monoBackground; \ ++ aligned_width = w - w % 8; \ ++ \ ++ for (y = 0; y < h; y++) { \ ++ for (x = 0; x < aligned_width; x += 8) { \ ++ for (bg_bits = 0; bg_bits < 8; bg_bits++) { \ ++ if (*ptr++ != bg) \ ++ break; \ ++ } \ ++ if (bg_bits == 8) { \ ++ *buf++ = 0; \ ++ continue; \ ++ } \ ++ mask = 0x80 >> bg_bits; \ ++ value = mask; \ ++ for (bg_bits++; bg_bits < 8; bg_bits++) { \ ++ mask >>= 1; \ ++ if (*ptr++ != bg) { \ ++ value |= mask; \ ++ } \ ++ } \ ++ *buf++ = (CARD8)value; \ ++ } \ ++ \ ++ mask = 0x80; \ ++ value = 0; \ ++ if (x >= w) \ ++ continue; \ ++ \ ++ for (; x < w; x++) { \ ++ if (*ptr++ != bg) { \ ++ value |= mask; \ ++ } \ ++ mask >>= 1; \ ++ } \ ++ *buf++ = (CARD8)value; \ ++ } \ ++} ++ ++DEFINE_MONO_ENCODE_FUNCTION(8) ++DEFINE_MONO_ENCODE_FUNCTION(16) ++DEFINE_MONO_ENCODE_FUNCTION(32) ++ ++ ++/* ++ * ``Gradient'' filter for 24-bit color samples. ++ * Should be called only when redMax, greenMax and blueMax are 255. ++ * Color components assumed to be byte-aligned. ++ */ ++ ++static void ++FilterGradient24(pScreen, buf, fmt, w, h) ++ ScreenPtr pScreen; ++ char *buf; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *buf32; ++ CARD32 pix32; ++ int *prevRowPtr; ++ int shiftBits[3]; ++ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; ++ int prediction; ++ int x, y, c; ++ ++ buf32 = (CARD32 *)buf; ++ memset (prevRowBuf, 0, w * 3 * sizeof(int)); ++ ++ if (!pVNC->rfbServerFormat.bigEndian == !fmt->bigEndian) { ++ shiftBits[0] = fmt->redShift; ++ shiftBits[1] = fmt->greenShift; ++ shiftBits[2] = fmt->blueShift; ++ } else { ++ shiftBits[0] = 24 - fmt->redShift; ++ shiftBits[1] = 24 - fmt->greenShift; ++ shiftBits[2] = 24 - fmt->blueShift; ++ } ++ ++ for (y = 0; y < h; y++) { ++ for (c = 0; c < 3; c++) { ++ pixUpper[c] = 0; ++ pixHere[c] = 0; ++ } ++ prevRowPtr = prevRowBuf; ++ for (x = 0; x < w; x++) { ++ pix32 = *buf32++; ++ for (c = 0; c < 3; c++) { ++ pixUpperLeft[c] = pixUpper[c]; ++ pixLeft[c] = pixHere[c]; ++ pixUpper[c] = *prevRowPtr; ++ pixHere[c] = (int)(pix32 >> shiftBits[c] & 0xFF); ++ *prevRowPtr++ = pixHere[c]; ++ ++ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; ++ if (prediction < 0) { ++ prediction = 0; ++ } else if (prediction > 0xFF) { ++ prediction = 0xFF; ++ } ++ *buf++ = (char)(pixHere[c] - prediction); ++ } ++ } ++ } ++} ++ ++ ++/* ++ * ``Gradient'' filter for other color depths. ++ */ ++ ++#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \ ++ \ ++static void \ ++FilterGradient##bpp(pScreen, buf, fmt, w, h) \ ++ ScreenPtr pScreen; \ ++ CARD##bpp *buf; \ ++ rfbPixelFormat *fmt; \ ++ int w, h; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp pix, diff; \ ++ Bool endianMismatch; \ ++ int *prevRowPtr; \ ++ int maxColor[3], shiftBits[3]; \ ++ int pixHere[3], pixUpper[3], pixLeft[3], pixUpperLeft[3]; \ ++ int prediction; \ ++ int x, y, c; \ ++ \ ++ memset (prevRowBuf, 0, w * 3 * sizeof(int)); \ ++ \ ++ endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian); \ ++ \ ++ maxColor[0] = fmt->redMax; \ ++ maxColor[1] = fmt->greenMax; \ ++ maxColor[2] = fmt->blueMax; \ ++ shiftBits[0] = fmt->redShift; \ ++ shiftBits[1] = fmt->greenShift; \ ++ shiftBits[2] = fmt->blueShift; \ ++ \ ++ for (y = 0; y < h; y++) { \ ++ for (c = 0; c < 3; c++) { \ ++ pixUpper[c] = 0; \ ++ pixHere[c] = 0; \ ++ } \ ++ prevRowPtr = prevRowBuf; \ ++ for (x = 0; x < w; x++) { \ ++ pix = *buf; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ diff = 0; \ ++ for (c = 0; c < 3; c++) { \ ++ pixUpperLeft[c] = pixUpper[c]; \ ++ pixLeft[c] = pixHere[c]; \ ++ pixUpper[c] = *prevRowPtr; \ ++ pixHere[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ *prevRowPtr++ = pixHere[c]; \ ++ \ ++ prediction = pixLeft[c] + pixUpper[c] - pixUpperLeft[c]; \ ++ if (prediction < 0) { \ ++ prediction = 0; \ ++ } else if (prediction > maxColor[c]) { \ ++ prediction = maxColor[c]; \ ++ } \ ++ diff |= ((pixHere[c] - prediction) & maxColor[c]) \ ++ << shiftBits[c]; \ ++ } \ ++ if (endianMismatch) { \ ++ diff = Swap##bpp(diff); \ ++ } \ ++ *buf++ = diff; \ ++ } \ ++ } \ ++} ++ ++DEFINE_GRADIENT_FILTER_FUNCTION(16) ++DEFINE_GRADIENT_FILTER_FUNCTION(32) ++ ++ ++/* ++ * Code to guess if given rectangle is suitable for smooth image ++ * compression (by applying "gradient" filter or JPEG coder). ++ */ ++ ++#define JPEG_MIN_RECT_SIZE 4096 ++ ++#define DETECT_SUBROW_WIDTH 7 ++#define DETECT_MIN_WIDTH 8 ++#define DETECT_MIN_HEIGHT 8 ++ ++static int ++DetectSmoothImage (cl, fmt, w, h) ++ rfbClientPtr cl; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ unsigned long avgError; ++ ++ if ( pVNC->rfbServerFormat.bitsPerPixel == 8 || fmt->bitsPerPixel == 8 || ++ w < DETECT_MIN_WIDTH || h < DETECT_MIN_HEIGHT ) { ++ return 0; ++ } ++ ++ if (cl->tightQualityLevel != -1) { ++ if (w * h < JPEG_MIN_RECT_SIZE) { ++ return 0; ++ } ++ } else { ++ if ( rfbTightDisableGradient || ++ w * h < tightConf[cl->tightCompressLevel].gradientMinRectSize ) { ++ return 0; ++ } ++ } ++ ++ if (fmt->bitsPerPixel == 32) { ++ if (usePixelFormat24) { ++ avgError = DetectSmoothImage24(cl, fmt, w, h); ++ if (cl->tightQualityLevel != -1) { ++ return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold24); ++ } ++ return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold24); ++ } else { ++ avgError = DetectSmoothImage32(cl, fmt, w, h); ++ } ++ } else { ++ avgError = DetectSmoothImage16(cl, fmt, w, h); ++ } ++ if (cl->tightQualityLevel != -1) { ++ return (avgError < tightConf[cl->tightQualityLevel].jpegThreshold); ++ } ++ return (avgError < tightConf[cl->tightCompressLevel].gradientThreshold); ++} ++ ++static unsigned long ++DetectSmoothImage24 (cl, fmt, w, h) ++ rfbClientPtr cl; ++ rfbPixelFormat *fmt; ++ int w, h; ++{ ++ int off; ++ int x, y, d, dx, c; ++ int diffStat[256]; ++ int pixelCount = 0; ++ int pix, left[3]; ++ unsigned long avgError; ++ ++ /* If client is big-endian, color samples begin from the second ++ byte (offset 1) of a 32-bit pixel value. */ ++ off = (fmt->bigEndian != 0); ++ ++ memset(diffStat, 0, 256*sizeof(int)); ++ ++ y = 0, x = 0; ++ while (y < h && x < w) { ++ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { ++ for (c = 0; c < 3; c++) { ++ left[c] = (int)tightBeforeBuf[((y+d)*w+x+d)*4+off+c] & 0xFF; ++ } ++ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { ++ for (c = 0; c < 3; c++) { ++ pix = (int)tightBeforeBuf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF; ++ diffStat[abs(pix - left[c])]++; ++ left[c] = pix; ++ } ++ pixelCount++; ++ } ++ } ++ if (w > h) { ++ x += h; ++ y = 0; ++ } else { ++ x = 0; ++ y += w; ++ } ++ } ++ ++ if (diffStat[0] * 33 / pixelCount >= 95) ++ return 0; ++ ++ avgError = 0; ++ for (c = 1; c < 8; c++) { ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); ++ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) ++ return 0; ++ } ++ for (; c < 256; c++) { ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); ++ } ++ avgError /= (pixelCount * 3 - diffStat[0]); ++ ++ return avgError; ++} ++ ++#define DEFINE_DETECT_FUNCTION(bpp) \ ++ \ ++static unsigned long \ ++DetectSmoothImage##bpp (cl, fmt, w, h) \ ++ rfbClientPtr cl; \ ++ rfbPixelFormat *fmt; \ ++ int w, h; \ ++{ \ ++ VNCSCREENPTR(cl->pScreen); \ ++ Bool endianMismatch; \ ++ CARD##bpp pix; \ ++ int maxColor[3], shiftBits[3]; \ ++ int x, y, d, dx, c; \ ++ int diffStat[256]; \ ++ int pixelCount = 0; \ ++ int sample, sum, left[3]; \ ++ unsigned long avgError; \ ++ \ ++ endianMismatch = (!pVNC->rfbServerFormat.bigEndian != !fmt->bigEndian); \ ++ \ ++ maxColor[0] = fmt->redMax; \ ++ maxColor[1] = fmt->greenMax; \ ++ maxColor[2] = fmt->blueMax; \ ++ shiftBits[0] = fmt->redShift; \ ++ shiftBits[1] = fmt->greenShift; \ ++ shiftBits[2] = fmt->blueShift; \ ++ \ ++ memset(diffStat, 0, 256*sizeof(int)); \ ++ \ ++ y = 0, x = 0; \ ++ while (y < h && x < w) { \ ++ for (d = 0; d < h - y && d < w - x - DETECT_SUBROW_WIDTH; d++) { \ ++ pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d]; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ for (c = 0; c < 3; c++) { \ ++ left[c] = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ } \ ++ for (dx = 1; dx <= DETECT_SUBROW_WIDTH; dx++) { \ ++ pix = ((CARD##bpp *)tightBeforeBuf)[(y+d)*w+x+d+dx]; \ ++ if (endianMismatch) { \ ++ pix = Swap##bpp(pix); \ ++ } \ ++ sum = 0; \ ++ for (c = 0; c < 3; c++) { \ ++ sample = (int)(pix >> shiftBits[c] & maxColor[c]); \ ++ sum += abs(sample - left[c]); \ ++ left[c] = sample; \ ++ } \ ++ if (sum > 255) \ ++ sum = 255; \ ++ diffStat[sum]++; \ ++ pixelCount++; \ ++ } \ ++ } \ ++ if (w > h) { \ ++ x += h; \ ++ y = 0; \ ++ } else { \ ++ x = 0; \ ++ y += w; \ ++ } \ ++ } \ ++ \ ++ if ((diffStat[0] + diffStat[1]) * 100 / pixelCount >= 90) \ ++ return 0; \ ++ \ ++ avgError = 0; \ ++ for (c = 1; c < 8; c++) { \ ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \ ++ if (diffStat[c] == 0 || diffStat[c] > diffStat[c-1] * 2) \ ++ return 0; \ ++ } \ ++ for (; c < 256; c++) { \ ++ avgError += (unsigned long)diffStat[c] * (unsigned long)(c * c); \ ++ } \ ++ avgError /= (pixelCount - diffStat[0]); \ ++ \ ++ return avgError; \ ++} ++ ++DEFINE_DETECT_FUNCTION(16) ++DEFINE_DETECT_FUNCTION(32) ++ ++ ++/* ++ * JPEG compression stuff. ++ */ ++ ++static struct jpeg_destination_mgr jpegDstManager; ++static Bool jpegError; ++static int jpegDstDataLen; ++ ++static Bool ++SendJpegRect(cl, x, y, w, h, quality) ++ rfbClientPtr cl; ++ int x, y, w, h; ++ int quality; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ struct jpeg_compress_struct cinfo; ++ struct jpeg_error_mgr jerr; ++ CARD8 *srcBuf; ++ JSAMPROW rowPointer[1]; ++ int dy; ++ ++ if (pVNC->rfbServerFormat.bitsPerPixel == 8) ++ return SendFullColorRect(cl, w, h); ++ ++ srcBuf = (CARD8 *)xalloc(w * 3); ++ if (srcBuf == NULL) { ++ return SendFullColorRect(cl, w, h); ++ } ++ rowPointer[0] = srcBuf; ++ ++ cinfo.err = jpeg_std_error(&jerr); ++ jpeg_create_compress(&cinfo); ++ ++ cinfo.image_width = w; ++ cinfo.image_height = h; ++ cinfo.input_components = 3; ++ cinfo.in_color_space = JCS_RGB; ++ ++ jpeg_set_defaults(&cinfo); ++ jpeg_set_quality(&cinfo, quality, TRUE); ++ ++ JpegSetDstManager (&cinfo); ++ ++ jpeg_start_compress(&cinfo, TRUE); ++ ++ for (dy = 0; dy < h; dy++) { ++ PrepareRowForJpeg(cl->pScreen, srcBuf, x, y + dy, w); ++ jpeg_write_scanlines(&cinfo, rowPointer, 1); ++ if (jpegError) ++ break; ++ } ++ ++ if (!jpegError) ++ jpeg_finish_compress(&cinfo); ++ ++ jpeg_destroy_compress(&cinfo); ++ xfree((char *)srcBuf); ++ ++ if (jpegError) ++ return SendFullColorRect(cl, w, h); ++ ++ if (pVNC->ublen + TIGHT_MIN_TO_COMPRESS + 1 > UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ pVNC->updateBuf[pVNC->ublen++] = (char)(rfbTightJpeg << 4); ++ cl->rfbBytesSent[rfbEncodingTight]++; ++ ++ return SendCompressedData(cl, jpegDstDataLen); ++} ++ ++static void ++PrepareRowForJpeg(pScreen, dst, x, y, count) ++ ScreenPtr pScreen; ++ CARD8 *dst; ++ int x, y, count; ++{ ++ VNCSCREENPTR(pScreen); ++ if (pVNC->rfbServerFormat.bitsPerPixel == 32) { ++ if ( pVNC->rfbServerFormat.redMax == 0xFF && ++ pVNC->rfbServerFormat.greenMax == 0xFF && ++ pVNC->rfbServerFormat.blueMax == 0xFF ) { ++ PrepareRowForJpeg24(pScreen, dst, x, y, count); ++ } else { ++ PrepareRowForJpeg32(pScreen, dst, x, y, count); ++ } ++ } else { ++ /* 16 bpp assumed. */ ++ PrepareRowForJpeg16(pScreen, dst, x, y, count); ++ } ++} ++ ++static void ++PrepareRowForJpeg24(pScreen, dst, x, y, count) ++ ScreenPtr pScreen; ++ CARD8 *dst; ++ int x, y, count; ++{ ++ VNCSCREENPTR(pScreen); ++ CARD32 *fbptr; ++ CARD32 pix; ++ ++ fbptr = (CARD32 *) ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + x * 4]; ++ ++ while (count--) { ++ pix = *fbptr++; ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.redShift); ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.greenShift); ++ *dst++ = (CARD8)(pix >> pVNC->rfbServerFormat.blueShift); ++ } ++} ++ ++#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \ ++ \ ++static void \ ++PrepareRowForJpeg##bpp(pScreen, dst, x, y, count) \ ++ ScreenPtr pScreen; \ ++ CARD8 *dst; \ ++ int x, y, count; \ ++{ \ ++ VNCSCREENPTR(pScreen); \ ++ CARD##bpp *fbptr; \ ++ CARD##bpp pix; \ ++ int inRed, inGreen, inBlue; \ ++ \ ++ fbptr = (CARD##bpp *) \ ++ &pVNC->pfbMemory[y * pVNC->paddedWidthInBytes + \ ++ x * (bpp / 8)]; \ ++ \ ++ while (count--) { \ ++ pix = *fbptr++; \ ++ \ ++ inRed = (int) \ ++ (pix >> pVNC->rfbServerFormat.redShift & pVNC->rfbServerFormat.redMax); \ ++ inGreen = (int) \ ++ (pix >> pVNC->rfbServerFormat.greenShift & pVNC->rfbServerFormat.greenMax); \ ++ inBlue = (int) \ ++ (pix >> pVNC->rfbServerFormat.blueShift & pVNC->rfbServerFormat.blueMax); \ ++ \ ++ *dst++ = (CARD8)((inRed * 255 + pVNC->rfbServerFormat.redMax / 2) / \ ++ pVNC->rfbServerFormat.redMax); \ ++ *dst++ = (CARD8)((inGreen * 255 + pVNC->rfbServerFormat.greenMax / 2) / \ ++ pVNC->rfbServerFormat.greenMax); \ ++ *dst++ = (CARD8)((inBlue * 255 + pVNC->rfbServerFormat.blueMax / 2) / \ ++ pVNC->rfbServerFormat.blueMax); \ ++ } \ ++} ++ ++DEFINE_JPEG_GET_ROW_FUNCTION(16) ++DEFINE_JPEG_GET_ROW_FUNCTION(32) ++ ++/* ++ * Destination manager implementation for JPEG library. ++ */ ++ ++static void ++JpegInitDestination(j_compress_ptr cinfo) ++{ ++ jpegError = FALSE; ++ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf; ++ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize; ++} ++ ++static boolean ++JpegEmptyOutputBuffer(j_compress_ptr cinfo) ++{ ++ jpegError = TRUE; ++ jpegDstManager.next_output_byte = (JOCTET *)tightAfterBuf; ++ jpegDstManager.free_in_buffer = (size_t)tightAfterBufSize; ++ ++ return TRUE; ++} ++ ++static void ++JpegTermDestination(j_compress_ptr cinfo) ++{ ++ jpegDstDataLen = tightAfterBufSize - jpegDstManager.free_in_buffer; ++} ++ ++static void ++JpegSetDstManager(j_compress_ptr cinfo) ++{ ++ jpegDstManager.init_destination = JpegInitDestination; ++ jpegDstManager.empty_output_buffer = JpegEmptyOutputBuffer; ++ jpegDstManager.term_destination = JpegTermDestination; ++ cinfo->dest = &jpegDstManager; ++} ++ +diff --git a/hw/xfree86/vnc/translate.c b/hw/xfree86/vnc/translate.c +new file mode 100644 +index 0000000..5fdd602 +--- /dev/null ++++ b/hw/xfree86/vnc/translate.c +@@ -0,0 +1,497 @@ ++/* ++ * translate.c - translate between different pixel formats ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include "rfb.h" ++#if XFREE86VNC ++#include ++#endif ++ ++static void PrintPixelFormat(rfbPixelFormat *pf); ++static Bool rfbSetClientColourMapBGR233(rfbClientPtr cl); ++ ++Bool rfbEconomicTranslate = FALSE; ++ ++/* ++ * Some standard pixel formats. ++ */ ++ ++static const rfbPixelFormat BGR233Format = { ++ 8, 8, 0, 1, 7, 7, 3, 0, 3, 6 ++}; ++ ++ ++/* ++ * Macro to compare pixel formats. ++ */ ++ ++#define PF_EQ(x,y) \ ++ ((x.bitsPerPixel == y.bitsPerPixel) && \ ++ (x.depth == y.depth) && \ ++ ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \ ++ (x.trueColour == y.trueColour) && \ ++ (!x.trueColour || ((x.redMax == y.redMax) && \ ++ (x.greenMax == y.greenMax) && \ ++ (x.blueMax == y.blueMax) && \ ++ (x.redShift == y.redShift) && \ ++ (x.greenShift == y.greenShift) && \ ++ (x.blueShift == y.blueShift)))) ++ ++#define CONCAT2(a,b) a##b ++#define CONCAT2E(a,b) CONCAT2(a,b) ++#define CONCAT4(a,b,c,d) a##b##c##d ++#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d) ++ ++#define OUT 8 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++#define OUT 16 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++#define OUT 32 ++#include "tableinittctemplate.c" ++#include "tableinitcmtemplate.c" ++#define IN 8 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 16 ++#include "tabletranstemplate.c" ++#undef IN ++#define IN 32 ++#include "tabletranstemplate.c" ++#undef IN ++#undef OUT ++ ++typedef void (*rfbInitTableFnType)(ScreenPtr pScreen, char **table, rfbPixelFormat *in, ++ rfbPixelFormat *out); ++ ++rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = { ++ rfbInitTrueColourSingleTable8, ++ rfbInitTrueColourSingleTable16, ++ rfbInitTrueColourSingleTable32 ++}; ++ ++rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = { ++ rfbInitColourMapSingleTable8, ++ rfbInitColourMapSingleTable16, ++ rfbInitColourMapSingleTable32 ++}; ++ ++rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = { ++ rfbInitTrueColourRGBTables8, ++ rfbInitTrueColourRGBTables16, ++ rfbInitTrueColourRGBTables32 ++}; ++ ++rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = { ++ { rfbTranslateWithSingleTable8to8, ++ rfbTranslateWithSingleTable8to16, ++ rfbTranslateWithSingleTable8to32 }, ++ { rfbTranslateWithSingleTable16to8, ++ rfbTranslateWithSingleTable16to16, ++ rfbTranslateWithSingleTable16to32 }, ++ { rfbTranslateWithSingleTable32to8, ++ rfbTranslateWithSingleTable32to16, ++ rfbTranslateWithSingleTable32to32 } ++}; ++ ++rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = { ++ { rfbTranslateWithRGBTables8to8, ++ rfbTranslateWithRGBTables8to16, ++ rfbTranslateWithRGBTables8to32 }, ++ { rfbTranslateWithRGBTables16to8, ++ rfbTranslateWithRGBTables16to16, ++ rfbTranslateWithRGBTables16to32 }, ++ { rfbTranslateWithRGBTables32to8, ++ rfbTranslateWithRGBTables32to16, ++ rfbTranslateWithRGBTables32to32 } ++}; ++ ++ ++ ++/* ++ * rfbTranslateNone is used when no translation is required. ++ */ ++ ++void ++rfbTranslateNone(ScreenPtr pScreen, char *table, rfbPixelFormat *in, rfbPixelFormat *out, ++ unsigned char *iptr, char *optr, int bytesBetweenInputLines, ++ int width, int height, int x, int y) ++{ ++ VNCSCREENPTR(pScreen); ++ int bytesPerOutputLine = width * (out->bitsPerPixel / 8); ++ ++ if (pVNC->useGetImage) { ++ DrawablePtr pDraw = (DrawablePtr)WindowTable[pScreen->myNum]; ++ ++ /* catch all for other TranslateNone cases - hextile, corre, rre, etc.*/ ++ (*pScreen->GetImage)(pDraw, x, y, width, height, ZPixmap, ~0, optr); ++ } else { ++ while (height > 0) { ++ memcpy(optr, iptr, bytesPerOutputLine); ++ iptr += bytesBetweenInputLines; ++ optr += bytesPerOutputLine; ++ height--; ++ } ++ } ++} ++ ++ ++/* ++ * rfbSetTranslateFunction sets the translation function. ++ */ ++ ++Bool ++rfbSetTranslateFunction(cl) ++ rfbClientPtr cl; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbLog("Pixel format for client %s:\n",cl->host); ++ PrintPixelFormat(&cl->format); ++ ++ /* ++ * Check that bits per pixel values are valid ++ */ ++ ++ if ((pVNC->rfbServerFormat.bitsPerPixel != 8) && ++ (pVNC->rfbServerFormat.bitsPerPixel != 16) && ++ (pVNC->rfbServerFormat.bitsPerPixel != 32)) ++ { ++ rfbLog("%s: server bits per pixel not 8, 16 or 32\n", ++ "rfbSetTranslateFunction"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if ((cl->format.bitsPerPixel != 8) && ++ (cl->format.bitsPerPixel != 16) && ++ (cl->format.bitsPerPixel != 32)) ++ { ++ rfbLog("%s: client bits per pixel not 8, 16 or 32\n", ++ "rfbSetTranslateFunction"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if (!pVNC->rfbServerFormat.trueColour && ++ (pVNC->rfbServerFormat.bitsPerPixel != 8) && ++#if XFREE86VNC ++ (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) { ++#else ++ (pVNC->rfbInstalledColormap->class == PseudoColor)) { ++#endif ++ rfbLog("rfbSetTranslateFunction: server has colour map " ++ "but %d-bit - can only cope with 8-bit colour maps\n", ++ pVNC->rfbServerFormat.bitsPerPixel); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ if (!cl->format.trueColour && ++ (cl->format.bitsPerPixel != 8) && ++#if XFREE86VNC ++ (miInstalledMaps[cl->pScreen->myNum]->class == PseudoColor)) { ++#else ++ (pVNC->rfbInstalledColormap->class == PseudoColor) ) { ++#endif ++ rfbLog("rfbSetTranslateFunction: client has colour map " ++ "but %d-bit - can only cope with 8-bit colour maps\n", ++ cl->format.bitsPerPixel); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ /* ++ * bpp is valid, now work out how to translate ++ */ ++ ++ if (!cl->format.trueColour) { ++ ++ /* ? -> colour map */ ++ ++ if (!pVNC->rfbServerFormat.trueColour) { ++ ++ /* colour map -> colour map */ ++ ++#if XFREE86VNC ++ if (miInstalledMaps[cl->pScreen->myNum]->class == DirectColor) { ++#else ++ if (pVNC->rfbInstalledColormap->class == DirectColor) { ++#endif ++ rfbLog("rfbSetTranslateFunction: client is %d-bit DirectColor," ++ " client has colour map\n",cl->format.bitsPerPixel); ++ ++ cl->translateFn = rfbTranslateWithRGBTablesFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16]) ++ (cl->pScreen, &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ return rfbSetClientColourMap(cl, 0, 0); ++ ++ /* PseudoColor colormap */ ++ ++ } else { ++ rfbLog("rfbSetTranslateFunction: both 8-bit colour map: " ++ "no translation needed\n"); ++ cl->translateFn = rfbTranslateNone; ++ return rfbSetClientColourMap(cl, 0, 0); ++ } ++ } ++ ++ /* ++ * truecolour -> colour map ++ * ++ * Set client's colour map to BGR233, then effectively it's ++ * truecolour as well ++ */ ++ ++ if (!rfbSetClientColourMapBGR233(cl)) ++ return FALSE; ++ ++ cl->format = BGR233Format; ++ } ++ ++ /* ? -> truecolour */ ++ ++ if (!pVNC->rfbServerFormat.trueColour) { ++ ++ /* colour map -> truecolour */ ++ ++ rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour," ++ " server has colour map\n",cl->format.bitsPerPixel); ++ ++ cl->translateFn = rfbTranslateWithSingleTableFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ return rfbSetClientColourMap(cl, 0, 0); ++ } ++ ++ /* truecolour -> truecolour */ ++ ++ if (PF_EQ(cl->format,pVNC->rfbServerFormat)) { ++ ++ /* client & server the same */ ++ ++ rfbLog(" no translation needed\n"); ++ cl->translateFn = rfbTranslateNone; ++ return TRUE; ++ } ++ ++ if ((pVNC->rfbServerFormat.bitsPerPixel < 16) || ++ (!rfbEconomicTranslate && (pVNC->rfbServerFormat.bitsPerPixel == 16))) { ++ ++ /* we can use a single lookup table for <= 16 bpp */ ++ ++ cl->translateFn = rfbTranslateWithSingleTableFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourSingleTableFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ } else { ++ ++ /* otherwise we use three separate tables for red, green and blue */ ++ ++ cl->translateFn = rfbTranslateWithRGBTablesFns ++ [pVNC->rfbServerFormat.bitsPerPixel / 16] ++ [cl->format.bitsPerPixel / 16]; ++ ++ (*rfbInitTrueColourRGBTablesFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++/* ++ * rfbSetClientColourMapBGR233 sets the client's colour map so that it's ++ * just like an 8-bit BGR233 true colour client. ++ */ ++ ++static Bool ++rfbSetClientColourMapBGR233(rfbClientPtr cl) ++{ ++ char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; ++ rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; ++ CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); ++ int i, len; ++ int r, g, b; ++ ++ if (cl->format.bitsPerPixel != 8) { ++ rfbLog("%s: client not 8 bits per pixel\n", ++ "rfbSetClientColourMapBGR233"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ ++ scme->type = rfbSetColourMapEntries; ++ ++ scme->firstColour = Swap16IfLE(0); ++ scme->nColours = Swap16IfLE(256); ++ ++ len = sz_rfbSetColourMapEntriesMsg; ++ ++ i = 0; ++ ++ for (b = 0; b < 4; b++) { ++ for (g = 0; g < 8; g++) { ++ for (r = 0; r < 8; r++) { ++ rgb[i++] = Swap16IfLE(r * 65535 / 7); ++ rgb[i++] = Swap16IfLE(g * 65535 / 7); ++ rgb[i++] = Swap16IfLE(b * 65535 / 3); ++ } ++ } ++ } ++ ++ len += 256 * 3 * 2; ++ ++ if (WriteExact(cl->sock, buf, len) < 0) { ++ rfbLogPerror("rfbSetClientColourMapBGR233: write"); ++ rfbCloseSock(cl->pScreen, cl->sock); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++ ++/* ++ * rfbSetClientColourMap is called to set the client's colour map. If the ++ * client is a true colour client, we simply update our own translation table ++ * and mark the whole screen as having been modified. ++ */ ++ ++Bool ++rfbSetClientColourMap(cl, firstColour, nColours) ++ rfbClientPtr cl; ++ int firstColour; ++ int nColours; ++{ ++ VNCSCREENPTR(cl->pScreen); ++ BoxRec box; ++ ++ if (nColours == 0) { ++#if XFREE86VNC ++ nColours = miInstalledMaps[cl->pScreen->myNum]->pVisual->ColormapEntries; ++#else ++ nColours = pVNC->rfbInstalledColormap->pVisual->ColormapEntries; ++#endif ++ } ++ ++ if (pVNC->rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) { ++ return TRUE; ++ } ++ ++ if (cl->format.trueColour) { ++ (*rfbInitColourMapSingleTableFns ++ [cl->format.bitsPerPixel / 16]) (cl->pScreen, ++ &cl->translateLookupTable, ++ &pVNC->rfbServerFormat, &cl->format); ++ ++ REGION_UNINIT(cl->pScreen,&cl->modifiedRegion); ++ box.x1 = box.y1 = 0; ++ box.x2 = pVNC->width; ++ box.y2 = pVNC->height; ++ REGION_INIT(cl->pScreen,&cl->modifiedRegion,&box,0); ++ ++ return TRUE; ++ } ++ ++ return rfbSendSetColourMapEntries(cl, firstColour, nColours); ++} ++ ++ ++/* ++ * rfbSetClientColourMaps sets the colour map for each RFB client. ++ */ ++ ++void ++rfbSetClientColourMaps(firstColour, nColours) ++ int firstColour; ++ int nColours; ++{ ++ rfbClientPtr cl, nextCl; ++ ++ for (cl = rfbClientHead; cl; cl = nextCl) { ++ nextCl = cl->next; ++ rfbSetClientColourMap(cl, firstColour, nColours); ++ } ++} ++ ++ ++static void ++PrintPixelFormat(pf) ++ rfbPixelFormat *pf; ++{ ++ if (pf->bitsPerPixel == 1) { ++ rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n", ++ (pf->bigEndian ? "most" : "least")); ++ } else { ++ rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth, ++ ((pf->bitsPerPixel == 8) ? "" ++ : (pf->bigEndian ? ", big endian" : ", little endian"))); ++ if (pf->trueColour) { ++ rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n", ++ pf->redMax, pf->greenMax, pf->blueMax, ++ pf->redShift, pf->greenShift, pf->blueShift); ++ } else { ++ rfbLog(" uses a colour map (not true colour).\n"); ++ } ++ } ++} +diff --git a/hw/xfree86/vnc/vncInit.c b/hw/xfree86/vnc/vncInit.c +new file mode 100644 +index 0000000..c6b0a31 +--- /dev/null ++++ b/hw/xfree86/vnc/vncInit.c +@@ -0,0 +1,640 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "../ramdac/xf86CursorPriv.h" ++#include "rfb.h" ++#include "vncint.h" ++ ++#include "xf86.h" ++#include "xf86_OSproc.h" ++#include "xf86Resources.h" ++#include "xf86Version.h" ++ ++int vncScreenPrivateIndex = -1; ++int rfbGCIndex = -1; ++int inetdSock = -1; ++Atom VNC_LAST_CLIENT_ID = 0; ++Atom VNC_CONNECT = 0; ++char *desktopName = "x11"; ++char rfbThisHost[256]; ++ ++extern void VncExtensionInit(void); ++ ++Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart); ++ ++#ifndef XFree86LOADER ++static unsigned long VNCGeneration = 0; ++#endif ++static const OptionInfoRec *VNCAvailableOptions(void *unused); ++static void rfbWakeupHandler (int i, pointer blockData, unsigned long err, pointer pReadmask); ++ ++static Bool vncCursorRealizeCursor(ScreenPtr, CursorPtr); ++static Bool vncCursorUnrealizeCursor(ScreenPtr, CursorPtr); ++static void vncCursorSetCursor(ScreenPtr, CursorPtr, int, int); ++static void vncCursorMoveCursor(ScreenPtr, int, int); ++static Bool vncDisplayCursor(ScreenPtr, CursorPtr); ++ ++static miPointerSpriteFuncRec vncCursorSpriteFuncs = { ++ vncCursorRealizeCursor, ++ vncCursorUnrealizeCursor, ++ vncCursorSetCursor, ++ vncCursorMoveCursor ++}; ++ ++/* ++ * VNC Config options ++ */ ++ ++typedef enum { ++ OPTION_USEVNC, ++ OPTION_RFBPORT, ++ OPTION_HTTPPORT, ++ OPTION_ALWAYS_SHARED, ++ OPTION_NEVER_SHARED, ++ OPTION_DONT_DISCONNECT, ++ OPTION_HTTPDIR, ++ OPTION_PASSWD_FILE, ++ OPTION_USER_ACCEPT, ++ OPTION_LOCALHOST, ++ OPTION_INTERFACE, ++ OPTION_VIEWONLY, ++ OPTION_LOGIN_AUTH, ++ OPTION_USE_GETIMAGE ++} VNCOpts; ++ ++static const OptionInfoRec VNCOptions[] = { ++ {OPTION_USEVNC, "usevnc", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_RFBPORT, "rfbport", OPTV_INTEGER, {0}, FALSE }, ++ {OPTION_HTTPPORT, "httpport", OPTV_INTEGER, {0}, FALSE }, ++ {OPTION_ALWAYS_SHARED, "alwaysshared", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_NEVER_SHARED, "nevershared", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_DONT_DISCONNECT, "dontdisconnect", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_HTTPDIR, "httpdir", OPTV_STRING, {0}, FALSE }, ++ {OPTION_PASSWD_FILE, "rfbauth", OPTV_STRING, {0}, FALSE }, ++ {OPTION_USER_ACCEPT, "useraccept", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_LOCALHOST, "localhost", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_INTERFACE, "interface", OPTV_STRING, {0}, FALSE }, ++ {OPTION_VIEWONLY, "viewonly", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_LOGIN_AUTH, "loginauth", OPTV_BOOLEAN, {0}, FALSE }, ++ {OPTION_USE_GETIMAGE, "usegetimage", OPTV_BOOLEAN, {0}, FALSE }, ++ { -1, NULL, OPTV_NONE, {0}, FALSE } ++}; ++ ++/*ARGSUSED*/ ++static const OptionInfoRec * ++VNCAvailableOptions(void *unused) ++{ ++ return (VNCOptions); ++} ++ ++/* ++ * rfbLog prints a time-stamped message to the log file (stderr). ++ */ ++ ++void rfbLog(char *format, ...) ++{ ++ va_list ap; ++ char buf[256]; ++ time_t clock; ++ ++ time(&clock); ++ strftime(buf, 255, "%d/%m/%Y %H:%M:%S ", localtime(&clock)); ++ xf86DrvMsgVerb(-1, X_INFO, 1, buf); ++ ++ va_start(ap, format); ++ xf86VDrvMsgVerb(-1, X_NONE, 1, format, ap); ++ va_end(ap); ++} ++ ++void rfbLogPerror(char *str) ++{ ++ rfbLog(""); ++ perror(str); ++} ++ ++/* ++ * Called by vncCreateScreenResources() ++ */ ++Bool ++VNCInit(ScreenPtr pScreen, unsigned char *FBStart) ++{ ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++ VisualPtr visual; ++ vncScreenPtr pScreenPriv; ++ OptionInfoPtr options; ++ char *interface_str = NULL; ++ miPointerScreenPtr PointPriv; ++ xf86CursorScreenPtr xf86CursorPriv; ++#ifdef RENDER ++ PictureScreenPtr ps; ++#endif ++ ++ if (!FBStart) ++ return FALSE; ++ ++#ifndef XFree86LOADER ++ if (VNCGeneration != serverGeneration) { ++ VncExtensionInit(); ++ VNCGeneration = serverGeneration; ++ } ++#endif ++ ++ if (!AllocateGCPrivate(pScreen, rfbGCIndex, sizeof(rfbGCRec))) ++ return FALSE; ++ ++ if (!(pScreenPriv = xalloc(sizeof(vncScreenRec)))) ++ return FALSE; ++ ++ pScreen->devPrivates[vncScreenPrivateIndex].ptr = (pointer)pScreenPriv; ++ ++ options = xnfalloc(sizeof(VNCOptions)); ++ (void)memcpy(options, VNCOptions, sizeof(VNCOptions)); ++ xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); ++ ++ if (xf86ReturnOptValBool(options, OPTION_USEVNC, FALSE)) { ++ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VNC enabled\n"); ++ } else { ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VNC disabled\n"); ++ xfree(options); ++ return FALSE; ++ } ++ ++ pScreenPriv->rfbAuthTries = 0; ++ pScreenPriv->rfbAuthTooManyTries = FALSE; ++ pScreenPriv->timer = NULL; ++ pScreenPriv->udpPort = 0; ++ pScreenPriv->rfbListenSock = -1; ++ pScreenPriv->udpSock = -1; ++ pScreenPriv->udpSockConnected = FALSE; ++ pScreenPriv->httpListenSock = -1; ++ pScreenPriv->httpSock = -1; ++ pScreenPriv->maxFd = 0; ++ pScreenPriv->rfbAuthPasswdFile = NULL; ++ pScreenPriv->httpDir = NULL; ++ pScreenPriv->rfbInstalledColormap = NULL; ++ pScreenPriv->interface.s_addr = htonl (INADDR_ANY); ++ ++ pScreenPriv->rfbPort = 0; ++ xf86GetOptValInteger(options, OPTION_RFBPORT, &pScreenPriv->rfbPort); ++ pScreenPriv->httpPort = 0; ++ xf86GetOptValInteger(options, OPTION_HTTPPORT, &pScreenPriv->httpPort); ++ pScreenPriv->rfbAuthPasswdFile = ++ xf86GetOptValString(options, OPTION_PASSWD_FILE); ++ pScreenPriv->httpDir = ++ xf86GetOptValString(options, OPTION_HTTPDIR); ++ pScreenPriv->rfbAlwaysShared = FALSE; ++ xf86GetOptValBool(options, OPTION_ALWAYS_SHARED, ++ &pScreenPriv->rfbAlwaysShared); ++ pScreenPriv->rfbNeverShared = FALSE; ++ xf86GetOptValBool(options, OPTION_NEVER_SHARED, ++ &pScreenPriv->rfbNeverShared); ++ pScreenPriv->rfbUserAccept = FALSE; ++ xf86GetOptValBool(options, OPTION_USER_ACCEPT, ++ &pScreenPriv->rfbUserAccept); ++ pScreenPriv->useGetImage = FALSE; ++ xf86GetOptValBool(options, OPTION_USE_GETIMAGE, ++ &pScreenPriv->useGetImage); ++ pScreenPriv->rfbViewOnly = FALSE; ++ xf86GetOptValBool(options, OPTION_VIEWONLY, ++ &pScreenPriv->rfbViewOnly); ++ pScreenPriv->rfbDontDisconnect = FALSE; ++ xf86GetOptValBool(options, OPTION_DONT_DISCONNECT, ++ &pScreenPriv->rfbDontDisconnect); ++ pScreenPriv->loginAuthEnabled = FALSE; ++ xf86GetOptValBool(options, OPTION_LOGIN_AUTH, ++ &pScreenPriv->loginAuthEnabled); ++ ++ if (xf86ReturnOptValBool(options, OPTION_LOCALHOST, FALSE)) ++ pScreenPriv->interface.s_addr = htonl (INADDR_LOOPBACK); ++ ++ interface_str = xf86GetOptValString(options, OPTION_INTERFACE); ++ ++ if (interface_str && pScreenPriv->interface.s_addr == htonl(INADDR_ANY)) { ++ Bool failed = FALSE; ++ struct in_addr got; ++ unsigned long octet; ++ char *p = interface_str, *end; ++ int q; ++ ++ for (q = 0; q < 4; q++) { ++ octet = strtoul (p, &end, 10); ++ ++ if (p == end || octet > 255) ++ failed = TRUE; ++ ++ if ((q < 3 && *end != '.') || ++ (q == 3 && *end != '\0')) ++ failed = TRUE; ++ ++ got.s_addr = (got.s_addr << 8) | octet; ++ p = end + 1; ++ } ++ ++ if (!failed) ++ pScreenPriv->interface.s_addr = htonl (got.s_addr); ++ else ++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VNC interface option malformed, not using.\n"); ++ } ++ ++ xfree(options); ++ ++ if (!VNC_LAST_CLIENT_ID) ++ VNC_LAST_CLIENT_ID = MakeAtom("VNC_LAST_CLIENT_ID", ++ strlen("VNC_LAST_CLIENT_ID"), TRUE); ++ if (!VNC_CONNECT) ++ VNC_CONNECT = MakeAtom("VNC_CONNECT", strlen("VNC_CONNECT"), TRUE); ++ ++ rfbInitSockets(pScreen); ++ if (inetdSock == -1) ++ httpInitSockets(pScreen); ++ ++#ifdef CORBA ++ initialiseCORBA(argc, argv, desktopName); ++#endif ++ ++ pScreenPriv->width = pScrn->virtualX; ++ pScreenPriv->height = pScrn->virtualY; ++ pScreenPriv->depth = pScrn->depth; ++ pScreenPriv->paddedWidthInBytes = PixmapBytePad(pScrn->displayWidth, pScrn->depth); ++ pScreenPriv->bitsPerPixel = rfbBitsPerPixel(pScrn->depth); ++ pScreenPriv->pfbMemory = FBStart; ++ pScreenPriv->oldpfbMemory = FBStart; ++ ++ pScreenPriv->cursorIsDrawn = TRUE; ++ pScreenPriv->dontSendFramebufferUpdate = FALSE; ++ ++ pScreenPriv->CloseScreen = pScreen->CloseScreen; ++ pScreenPriv->CreateGC = pScreen->CreateGC; ++ pScreenPriv->PaintWindowBackground = pScreen->PaintWindowBackground; ++ pScreenPriv->PaintWindowBorder = pScreen->PaintWindowBorder; ++ pScreenPriv->CopyWindow = pScreen->CopyWindow; ++ pScreenPriv->ClearToBackground = pScreen->ClearToBackground; ++ pScreenPriv->RestoreAreas = pScreen->RestoreAreas; ++ pScreenPriv->WakeupHandler = pScreen->WakeupHandler; ++ pScreenPriv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess; ++ pScreenPriv->InstallColormap = pScreen->InstallColormap; ++ pScreenPriv->UninstallColormap = pScreen->UninstallColormap; ++ pScreenPriv->ListInstalledColormaps = pScreen->ListInstalledColormaps; ++ pScreenPriv->StoreColors = pScreen->StoreColors; ++ pScreenPriv->DisplayCursor = pScreen->DisplayCursor; ++#ifdef CHROMIUM ++ pScreenPriv->RealizeWindow = pScreen->RealizeWindow; ++ pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; ++ pScreenPriv->DestroyWindow = pScreen->DestroyWindow; ++ pScreenPriv->PositionWindow = pScreen->PositionWindow; ++ pScreenPriv->ResizeWindow = pScreen->ResizeWindow; ++ pScreenPriv->ClipNotify = pScreen->ClipNotify; ++#endif ++#ifdef RENDER ++ ps = GetPictureScreenIfSet(pScreen); ++ if (ps) ++ pScreenPriv->Composite = ps->Composite; ++#endif ++ pScreen->CloseScreen = rfbCloseScreen; ++ pScreen->CreateGC = rfbCreateGC; ++ pScreen->PaintWindowBackground = rfbPaintWindowBackground; ++ pScreen->PaintWindowBorder = rfbPaintWindowBorder; ++ pScreen->CopyWindow = rfbCopyWindow; ++ pScreen->ClearToBackground = rfbClearToBackground; ++ pScreen->RestoreAreas = rfbRestoreAreas; ++ pScreen->WakeupHandler = rfbWakeupHandler; ++ pScrn->EnableDisableFBAccess = rfbEnableDisableFBAccess; ++ pScreen->InstallColormap = rfbInstallColormap; ++ pScreen->UninstallColormap = rfbUninstallColormap; ++ pScreen->ListInstalledColormaps = rfbListInstalledColormaps; ++ pScreen->StoreColors = rfbStoreColors; ++ pScreen->DisplayCursor = vncDisplayCursor; /* it's defined in here */ ++ ++#ifdef CHROMIUM ++ pScreen->RealizeWindow = rfbRealizeWindow; ++ pScreen->UnrealizeWindow = rfbUnrealizeWindow; ++ pScreen->DestroyWindow = rfbDestroyWindow; ++ pScreen->PositionWindow = rfbPositionWindow; ++ pScreen->ResizeWindow = rfbResizeWindow; ++ pScreen->ClipNotify = rfbClipNotify; ++#endif ++#ifdef RENDER ++ if (ps) ++ ps->Composite = rfbComposite; ++#endif ++ ++ for (visual = pScreen->visuals; visual->vid != pScreen->rootVisual; visual++) ++ ; ++ ++ if (!visual) { ++ ErrorF("rfbScreenInit: couldn't find root visual\n"); ++ return FALSE; ++ } ++ ++ pScreenPriv->rfbServerFormat.bitsPerPixel = pScrn->bitsPerPixel; ++ pScreenPriv->rfbServerFormat.depth = pScrn->depth; ++ pScreenPriv->rfbServerFormat.bigEndian = !(*(char *)&rfbEndianTest); ++ pScreenPriv->rfbServerFormat.trueColour = (visual->class == TrueColor); ++ if (pScreenPriv->rfbServerFormat.trueColour) { ++ pScreenPriv->rfbServerFormat.redMax = visual->redMask >> visual->offsetRed; ++ pScreenPriv->rfbServerFormat.greenMax = visual->greenMask >> visual->offsetGreen; ++ pScreenPriv->rfbServerFormat.blueMax = visual->blueMask >> visual->offsetBlue; ++ pScreenPriv->rfbServerFormat.redShift = visual->offsetRed; ++ pScreenPriv->rfbServerFormat.greenShift = visual->offsetGreen; ++ pScreenPriv->rfbServerFormat.blueShift = visual->offsetBlue; ++ } else { ++ pScreenPriv->rfbServerFormat.redMax ++ = pScreenPriv->rfbServerFormat.greenMax ++ = pScreenPriv->rfbServerFormat.blueMax = 0; ++ pScreenPriv->rfbServerFormat.redShift ++ = pScreenPriv->rfbServerFormat.greenShift ++ = pScreenPriv->rfbServerFormat.blueShift = 0; ++ } ++ ++ PointPriv = pScreen->devPrivates[miPointerScreenIndex].ptr; ++ ++ pScreenPriv->spriteFuncs = PointPriv->spriteFuncs; ++ PointPriv->spriteFuncs = &vncCursorSpriteFuncs; ++ ++ if (xf86LoaderCheckSymbol("xf86CursorScreenIndex")) { ++ int *si; ++ ++ si = LoaderSymbol("xf86CursorScreenIndex"); ++ ++ if (*si != -1) { ++ xf86CursorPriv = pScreen->devPrivates[*si].ptr; ++ ++ if (xf86CursorPriv) { ++ pScreenPriv->UseHWCursor = xf86CursorPriv->CursorInfoPtr->UseHWCursor; ++ xf86CursorPriv->CursorInfoPtr->UseHWCursor = vncUseHWCursor; ++#ifdef ARGB_CURSOR ++ pScreenPriv->UseHWCursorARGB = xf86CursorPriv->CursorInfoPtr->UseHWCursorARGB; ++ xf86CursorPriv->CursorInfoPtr->UseHWCursorARGB = vncUseHWCursorARGB; ++#endif ++ pScreenPriv->SWCursor = &xf86CursorPriv->SWCursor; ++ } ++ } ++ } ++ ++ return TRUE; ++} ++ ++/****** miPointerSpriteFunctions *******/ ++ ++static Bool ++vncCursorRealizeCursor(ScreenPtr pScreen, CursorPtr pCurs) ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ ++ return (*pScreenPriv->spriteFuncs->RealizeCursor)(pScreen, pCurs); ++} ++ ++static Bool ++vncCursorUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCurs) ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ ++ return (*pScreenPriv->spriteFuncs->UnrealizeCursor)(pScreen, pCurs); ++} ++ ++static void ++vncCursorSetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y) ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ ++ pScreenPriv->pCurs = pCurs; ++ ++ /* Without this call, cursor changes only appear in the viewer when ++ * some other drawing has occured. Added by BrianP. ++ */ ++ rfbScheduleUpdate(pScreen); ++ ++#if 0 ++ if (pCurs == NullCursor) { /* means we're supposed to remove the cursor */ ++ if (pScreenPriv->cursorIsDrawn) ++ pScreenPriv->cursorIsDrawn = FALSE; ++ return; ++ } ++ ++ pScreenPriv->cursorIsDrawn = TRUE; ++#endif ++ ++ (*pScreenPriv->spriteFuncs->SetCursor)(pScreen, pCurs, x, y); ++} ++ ++static void ++vncCursorMoveCursor(ScreenPtr pScreen, int x, int y) ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ rfbClientPtr cl; ++ ++ for (cl = rfbClientHead; cl ; cl = cl->next) { ++ if (cl->enableCursorPosUpdates) ++ cl->cursorWasMoved = TRUE; ++ } ++ ++ (*pScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y); ++} ++ ++Bool ++vncUseHWCursor(pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ rfbClientPtr cl; ++ ++ if (!*pScreenPriv->UseHWCursor) { ++ /* If the driver doesn't have a UseHWCursor function we're ++ * basically saying we can have the HWCursor on all the time ++ */ ++ pScreenPriv->SWCursor = (Bool *)FALSE; ++ return TRUE; ++ } ++ ++ pScreenPriv->SWCursor = (Bool *)FALSE; ++ ++ /* If someone's connected, we revert to software cursor */ ++ for (cl = rfbClientHead; cl ; cl = cl->next) { ++ if (!cl->enableCursorShapeUpdates) ++ pScreenPriv->SWCursor = (Bool *)TRUE; ++ } ++ ++ if (pScreenPriv->SWCursor == (Bool *)TRUE) ++ return FALSE; ++ ++ return (*pScreenPriv->UseHWCursor)(pScreen, pCursor); ++} ++ ++#ifdef ARGB_CURSOR ++#include "cursorstr.h" ++ ++Bool ++vncUseHWCursorARGB(pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ rfbClientPtr cl; ++ ++ if (!*pScreenPriv->UseHWCursorARGB) { ++ pScreenPriv->SWCursor = (Bool *)TRUE; ++ return FALSE; ++ } ++ ++ pScreenPriv->SWCursor = (Bool *)FALSE; ++ ++ /* If someone's connected, we revert to software cursor */ ++ for (cl = rfbClientHead; cl ; cl = cl->next) { ++ if (!cl->enableCursorShapeUpdates) ++ pScreenPriv->SWCursor = (Bool *)TRUE; ++ } ++ ++ if (pScreenPriv->SWCursor == (Bool *)TRUE) ++ return FALSE; ++ ++ return (*pScreenPriv->UseHWCursorARGB)(pScreen, pCursor); ++} ++#endif ++ ++static Bool ++vncDisplayCursor(pScreen, pCursor) ++ ScreenPtr pScreen; ++ CursorPtr pCursor; ++{ ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ rfbClientPtr cl; ++ Bool ret; ++ ++ pScreen->DisplayCursor = pScreenPriv->DisplayCursor; ++ ++ for (cl = rfbClientHead; cl ; cl = cl->next) { ++ if (cl->enableCursorShapeUpdates) ++ cl->cursorWasChanged = TRUE; ++ } ++ ++ ret = (*pScreen->DisplayCursor)(pScreen, pCursor); ++ ++ pScreen->DisplayCursor = vncDisplayCursor; ++ ++ return ret; ++} ++ ++static void ++rfbWakeupHandler ( ++ int i, ++ pointer blockData, ++ unsigned long err, ++ pointer pReadmask ++){ ++ ScreenPtr pScreen = screenInfo.screens[i]; ++ vncScreenPtr pScreenPriv = VNCPTR(pScreen); ++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ++ int sigstate = xf86BlockSIGIO(); ++ ++ rfbRootPropertyChange(pScreen); /* Check clipboard */ ++ ++ if (pScrn->vtSema) { ++ rfbCheckFds(pScreen); ++ httpCheckFds(pScreen); ++#ifdef CORBA ++ corbaCheckFds(); ++#endif ++ } else { ++ rfbCheckFds(pScreen); ++ } ++ ++ xf86UnblockSIGIO(sigstate); ++ ++ pScreen->WakeupHandler = pScreenPriv->WakeupHandler; ++ (*pScreen->WakeupHandler) (i, blockData, err, pReadmask); ++ pScreen->WakeupHandler = rfbWakeupHandler; ++} ++ ++#ifdef XFree86LOADER ++static MODULESETUPPROTO(vncSetup); ++ ++static XF86ModuleVersionInfo vncVersRec = ++{ ++ "vnc", ++ "xf4vnc Project, see http://xf4vnc.sf.net (based on modular X.org)", ++ MODINFOSTRING1, ++ MODINFOSTRING2, ++ XORG_VERSION_CURRENT, ++ 1, 1, 0, ++ ABI_CLASS_EXTENSION, ++#if 0 ++ ABI_EXTENSION_VERSION, ++#else ++ /* Hack to allow module to work with more servers (vs. 0.3 above) */ ++ SET_ABI_VERSION(0, 2), ++#endif ++ MOD_CLASS_EXTENSION, ++ {0,0,0,0} ++}; ++ ++XF86ModuleData vncModuleData = { ++ &vncVersRec, /* vers */ ++ vncSetup, /* ModuleSetupProc */ ++ NULL /* ModuleTearDownProc */ ++}; ++ ++ModuleInfoRec VNC = { ++ 1, /* moduleVersion */ ++ "VNC", /* moduleName */ ++ NULL, /* module pointer */ ++ 0, /* refCount */ ++ VNCAvailableOptions, /* function returning array of OptionsInfoRec */ ++}; ++ ++ExtensionModule vncExtensionModule = { ++ VncExtensionInit, /* initFunc */ ++ "VNC", /* name */ ++ NULL, /* disablePtr */ ++ NULL, /* setupFunc */ ++ NULL /* initDependencies */ ++}; ++ ++ ++/*ARGSUSED*/ ++static pointer ++vncSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor) ++{ ++ static Bool Initialised = FALSE; ++ ++ if (!Initialised) { ++ Initialised = TRUE; ++#ifndef REMOVE_LOADER_CHECK_MODULE_INFO ++ if (xf86LoaderCheckSymbol("xf86AddModuleInfo")) ++#endif ++ xf86AddModuleInfo(&VNC, Module); ++ } ++ ++ LoadExtension(&vncExtensionModule, FALSE); ++ /* add mouse/kbd input drivers */ ++ vncInitMouse(); ++ vncInitKeyb(); ++ xf86Msg(X_INFO, "Ignore errors regarding the loading of the rfbmouse & rfbkeyb drivers\n"); ++ ++ return (pointer)TRUE; ++} ++#endif +diff --git a/hw/xfree86/vnc/vncauth.h b/hw/xfree86/vnc/vncauth.h +new file mode 100644 +index 0000000..5ece2e1 +--- /dev/null ++++ b/hw/xfree86/vnc/vncauth.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++/* ++ * vncauth.h - describes the functions provided by the vncauth library. ++ */ ++ ++#define MAXPWLEN 8 ++#define CHALLENGESIZE 16 ++ ++extern int vncEncryptAndStorePasswd(char *passwd, char *fname); ++extern char *vncDecryptPasswdFromFile(char *fname); ++extern void vncRandomBytes(unsigned char *bytes); ++extern void vncEncryptBytes(unsigned char *bytes, char *passwd); ++ ++extern int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname); ++extern int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly); ++ +diff --git a/hw/xfree86/vnc/vncext.c b/hw/xfree86/vnc/vncext.c +new file mode 100644 +index 0000000..f7d7d5a +--- /dev/null ++++ b/hw/xfree86/vnc/vncext.c +@@ -0,0 +1,791 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#include "rfb.h" ++#include "extnsionst.h" ++#define _VNC_SERVER ++#include ++#ifdef XFree86LOADER ++#include "xf86Module.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++int VncSelectNotify(ClientPtr client, BOOL onoff); ++void VncExtensionInit(void); ++ ++static int VncErrorBase; /* first vnc error number */ ++static int VncEventBase; /* first vnc event number */ ++ ++#define USE_ORIG_RES_CODE 0 ++ ++#if USE_ORIG_RES_CODE ++unsigned long VncResourceGeneration = 0; ++ ++static RESTYPE VncNotifyList; ++ ++static XID faked; ++ ++typedef struct _VncNotifyListRec { ++ struct _VncNotifyListRec *next; ++ ClientPtr client; ++} VncNotifyListRec, *VncNotifyListPtr; ++#endif ++ ++ ++/** ++ * Each X client that uses libVnc to talk to this extension will get ++ * recorded by one of these records. ++ */ ++typedef struct _VncClientRec { ++ ClientPtr client; ++ struct _VncClientRec *next; ++ XID fakeID; ++ RESTYPE res; ++} VncClientRec, *VncClientRecPtr; ++ ++static VncClientRecPtr ClientsList = NULL; ++ ++ ++/** ++ * Remove client record from list ++ */ ++static void ++VncRemoveClientRecord(ClientPtr client) ++{ ++ /* XXX need 'deleteresource' flag? */ ++ VncClientRecPtr p = ClientsList, prev = NULL; ++ rfbLog("%s client %p\n", __func__, (void *) client); ++ while (p) { ++ if (p->client == client) { ++ /* remove this one */ ++ if (prev) ++ prev->next = p->next; ++ else ++ ClientsList = p->next; ++ xfree(p); ++ return; ++ } ++ prev = p; ++ p = p->next; ++ } ++} ++ ++ ++/** ++ * This callback will be called by X's resource manager to delete the ++ * given resource. We create one resource for each client. When X ++ * deletes the resource, we know the client is going away. ++ */ ++static int ++VncDestroyClientResourceCallback(pointer pn, XID id) ++{ ++ VncClientRecPtr rec = (VncClientRecPtr) pn; ++ VncRemoveClientRecord(rec->client); ++ return Success; ++} ++ ++ ++/** ++ * Add a client record to the list of clients (unless already in list). ++ * We'll create a new, unique resource for this client. This is used ++ * to detect when an X client goes away. ++ */ ++static void ++VncSaveClientRecord(ClientPtr client) ++{ ++ VncClientRecPtr rec = ClientsList; ++ ++ rfbLog("%s saving client %p\n", __func__, (void *) client); ++ ++ /* look if already in list */ ++ while (rec) { ++ if (rec->client == client) { ++ return; /* already in list */ ++ } ++ rec = rec->next; ++ } ++ ++ /* allocate new client record */ ++ rec = (VncClientRecPtr) xalloc(sizeof(VncClientRec)); ++ if (rec) { ++ rec->client = client; ++ rec->fakeID = FakeClientID(client->index); ++ rec->res = CreateNewResourceType(VncDestroyClientResourceCallback); ++ if (!AddResource(rec->fakeID, rec->res, rec)) { ++ xfree(rec); ++ } ++ ++ /* insert at head of list */ ++ rec->next = ClientsList; ++ ClientsList = rec; ++ } ++} ++ ++ ++ ++static int ++ProcVncQueryVersion(ClientPtr client) ++{ ++ xVncQueryVersionReply rep; ++ ++ REQUEST_SIZE_MATCH(xVncQueryVersionReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ rep.majorVersion = VNC_MAJOR_VERSION; ++ rep.minorVersion = VNC_MINOR_VERSION; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.majorVersion, n); ++ swaps(&rep.minorVersion, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncQueryVersionReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncQueryVersion */ ++ ++static int ++ProcVncConnection(ClientPtr client) ++{ ++ REQUEST(xVncConnectionReq); ++ xVncConnectionReply rep; ++ ++ rfbUserAllow( stuff->sock, stuff->accept ); ++ ++ REQUEST_SIZE_MATCH(xVncConnectionReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ rep.sock = 0; ++ rep.accept = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.sock, n); ++ swaps(&rep.accept, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncConnectionReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncConnection */ ++ ++static int ++ProcVncSelectNotify(ClientPtr client) ++{ ++ REQUEST(xVncSelectNotifyReq); ++ xVncSelectNotifyReply rep; ++ ++ VncSelectNotify(client, stuff->onoff); ++ ++ REQUEST_SIZE_MATCH(xVncSelectNotifyReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncSelectNotifyReply), ++ (char *)&rep); ++ return (client->noClientException); ++ ++} ++ ++static int ++ProcVncListConnections(ClientPtr client) ++{ ++ xVncListConnectionsReply rep; ++ rfbClientPtr cl; ++ int count = 0; ++ struct in_addr ipaddress; ++ xVncConnectionListInfo Info; ++ ++ /* count connections */ ++ for (cl = rfbClientHead; cl; cl = cl->next) ++#ifdef CHROMIUM ++ /* ++ * Fix this, as it should be generic, but we're only using it ++ * for Chromium at the moment, so we only list the connections ++ * that have a valid chromium encoding. We should be able to list ++ * any type requested. FIXME! XXXX ++ * See furthur down this function too!!! ++ */ ++ if (cl->enableChromiumEncoding) ++#endif ++ count++; ++ ++ REQUEST_SIZE_MATCH(xVncListConnectionsReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.count = count; ++ rep.length = count * sizeof(xVncConnectionListInfo) >> 2; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ swaps(&rep.count, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncListConnectionsReply), ++ (char *)&rep); ++ ++ for (cl = rfbClientHead; cl; cl = cl->next) { ++#ifdef CHROMIUM ++ /* ++ * Fix this, as it should be generic, but we're only using it ++ * for Chromium at the moment, so we only list the connections ++ * that have a valid chromium encoding. We should be able to list ++ * any type requested. FIXME! XXXX ++ */ ++ if (!cl->enableChromiumEncoding) ++ continue; ++#endif ++ inet_aton(cl->host, &ipaddress); ++ memcpy(&Info, &ipaddress, sizeof(struct in_addr)); ++ WriteToClient(client, SIZEOF(xVncConnectionListInfo), (char*)&Info); ++ } ++ ++ return (client->noClientException); ++} /* ProcVncListConnections */ ++ ++#ifdef CHROMIUM ++static int ++ProcVncChromiumStart(ClientPtr client) ++{ ++ REQUEST(xVncChromiumStartReq); ++ xVncChromiumStartReply rep; ++ ++ rfbSendChromiumStart(stuff->ipaddress, stuff->crServerPort, stuff->mothershipPort); ++ ++ REQUEST_SIZE_MATCH(xVncChromiumStartReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncChromiumStartReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncChromiumStart */ ++ ++static int ++ProcVncChromiumMonitor(ClientPtr client) ++{ ++ REQUEST(xVncChromiumMonitorReq); ++ xVncChromiumMonitorReply rep; ++ ++ rfbChromiumMonitorWindowID(stuff->cr_windowid, stuff->windowid); ++ ++ REQUEST_SIZE_MATCH(xVncChromiumMonitorReq); ++ rep.type = X_Reply; ++ rep.sequenceNumber = client->sequence; ++ rep.length = 0; ++ if(client->swapped) ++ { ++ register char n; ++ swaps(&rep.sequenceNumber, n); ++ } ++ (void)WriteToClient(client, SIZEOF(xVncChromiumMonitorReply), ++ (char *)&rep); ++ return (client->noClientException); ++} /* ProcVncChromiumMonitor */ ++#endif /* CHROMIUM */ ++ ++static int ++ProcVncDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ ++ switch (stuff->data) ++ { ++ case X_VncQueryVersion: ++ return ProcVncQueryVersion(client); ++ case X_VncSelectNotify: ++ return ProcVncSelectNotify(client); ++ case X_VncConnection: ++ return ProcVncConnection(client); ++ case X_VncListConnections: ++ return ProcVncListConnections(client); ++#ifdef CHROMIUM ++ case X_VncChromiumStart: ++ return ProcVncChromiumStart(client); ++ case X_VncChromiumMonitor: ++ return ProcVncChromiumMonitor(client); ++#endif ++ default: ++ return BadRequest; ++ } ++} /* ProcVncDispatch */ ++ ++static int ++SProcVncQueryVersion(ClientPtr client) ++{ ++ REQUEST(xVncQueryVersionReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncQueryVersionReq); ++ swaps(&stuff->majorVersion, n); ++ swaps(&stuff->minorVersion,n); ++ return ProcVncQueryVersion(client); ++} /* SProcVncQueryVersion */ ++ ++static int ++SProcVncSelectNotify(ClientPtr client) ++{ ++ REQUEST(xVncSelectNotifyReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncSelectNotifyReq); ++ return ProcVncSelectNotify(client); ++} /* SProcVncSelectNotify */ ++ ++static int ++SProcVncListConnections(ClientPtr client) ++{ ++ REQUEST(xVncListConnectionsReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncListConnectionsReq); ++ return ProcVncListConnections(client); ++} /* SProcVncListConnections */ ++ ++#ifdef CHROMIUM ++static int ++SProcVncChromiumStart(ClientPtr client) ++{ ++ REQUEST(xVncChromiumStartReq); ++ register char n; ++ ++ swaps(&stuff->ipaddress, n); ++ swaps(&stuff->crServerPort, n); ++ swaps(&stuff->mothershipPort, n); ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncChromiumStartReq); ++ return ProcVncChromiumStart(client); ++} /* SProcVncChromiumStart */ ++ ++static int ++SProcVncChromiumMonitor(ClientPtr client) ++{ ++ REQUEST(xVncChromiumMonitorReq); ++ register char n; ++ ++ swaps(&stuff->length, n); ++ swaps(&stuff->windowid, n); ++ swaps(&stuff->cr_windowid, n); ++ REQUEST_SIZE_MATCH(xVncChromiumMonitorReq); ++ return ProcVncChromiumMonitor(client); ++} /* SProcVncChromiumMonitor */ ++#endif /* CHROMIUM */ ++ ++static int ++SProcVncConnection(ClientPtr client) ++{ ++ REQUEST(xVncConnectionReq); ++ register char n; ++ ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xVncConnectionReq); ++ swaps(&stuff->sock, n); ++ swaps(&stuff->accept,n); ++ return ProcVncConnection(client); ++} /* SProcVncConnection */ ++ ++static int ++SProcVncDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ ++ switch (stuff->data) ++ { ++ case X_VncQueryVersion: ++ return SProcVncQueryVersion(client); ++ case X_VncSelectNotify: ++ return SProcVncSelectNotify(client); ++ case X_VncConnection: ++ return SProcVncConnection(client); ++ case X_VncListConnections: ++ return SProcVncListConnections(client); ++#ifdef CHROMIUM ++ case X_VncChromiumStart: ++ return SProcVncChromiumStart(client); ++ case X_VncChromiumMonitor: ++ return SProcVncChromiumMonitor(client); ++#endif ++ default: ++ return BadRequest; ++ } ++} /* SProcVncDispatch */ ++ ++static void ++SwapVncConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++ ++#ifdef CHROMIUM ++static void ++SwapVncChromiumConnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++#endif ++ ++static void ++SwapVncDisconnectedEvent(xVncConnectedEvent *from, xVncConnectedEvent *to) ++{ ++ to->type = from->type; ++ to->detail = from->detail; ++ cpswaps(from->sequenceNumber, to->sequenceNumber); ++ cpswapl(from->connected, to->connected); ++} ++ ++int ++GenerateVncConnectedEvent(int sock) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++#else ++ VncClientRecPtr pn = ClientsList; ++#endif ++ ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncConnectedEvent conn; ++ SOCKLEN_T peer_len; ++ struct sockaddr_in peer; ++ ++ conn.type = VncEventBase + XVncConnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ ++ peer_len = sizeof(peer); ++ if (getpeername(sock, (struct sockaddr *) &peer, &peer_len) == -1) ++ conn.ipaddress = 0; ++ else ++ conn.ipaddress = (CARD32)peer.sin_addr.s_addr; ++ ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++ ++ ++ ++#ifdef CHROMIUM ++int ++GenerateVncChromiumConnectedEvent(int sock) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr pn; ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++#else ++ VncClientRecPtr pn = ClientsList; ++#endif ++ rfbLog("Enter GenerateVncChromiumConnectedEvent\n"); ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncConnectedEvent conn; ++ SOCKLEN_T peer_len; ++ struct sockaddr_in peer; ++ ++ rfbLog("Sending XVncChromiumConnected to client %p\n", ++ (void *) pn->client); ++ ++ conn.type = VncEventBase + XVncChromiumConnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ ++ peer_len = sizeof(peer); ++ if (getpeername(sock, (struct sockaddr *)&peer, &peer_len) == -1) ++ conn.ipaddress = 0; ++ else ++ conn.ipaddress = (CARD32)peer.sin_addr.s_addr; ++ ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ return 1; ++} ++#endif /* CHROMIUM */ ++ ++ ++int ++GenerateVncDisconnectedEvent(int sock) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr pn; ++ ++ pn = (VncNotifyListPtr)LookupIDByType(faked, VncNotifyList); ++#else ++ VncClientRecPtr pn = ClientsList; ++#endif ++ while (pn) ++ { ++ if (pn->client) ++ { ++ xVncDisconnectedEvent conn; ++ conn.type = VncEventBase + XVncDisconnected; ++ conn.sequenceNumber = pn->client->sequence; ++ conn.connected = sock; ++ (void) TryClientEvents(pn->client, (xEventPtr)&conn, 1, NoEventMask, ++ NoEventMask, NullGrab); ++ } ++ pn = pn->next; ++ } ++ ++ return 1; ++} ++ ++static void ++VncResetProc(ExtensionEntry *extEntry) ++{ ++} /* VncResetProc */ ++ ++ ++ ++/** ++ * When the app calls libVnc's XVncSelectNotify() we wind up here. ++ * Either add or remove 'client' from the VncNotifyList depending on 'onoff'. ++ */ ++int ++VncSelectNotify(ClientPtr client, BOOL onoff) ++{ ++#if USE_ORIG_RES_CODE ++ VncNotifyListPtr head, newRec, tmp, freeRec = NULL; ++ ++ rfbLog("%s client %p onoff=%d\n", __func__, (void *) client, (int) onoff); ++ if (!faked) ++ faked = FakeClientID(client->index); ++#else ++ /* ignore onoff param */ ++ VncSaveClientRecord(client); ++#endif ++ ++#if USE_ORIG_RES_CODE ++ /* Get the first VncNotifyListPtr */ ++ head = (VncNotifyListPtr) LookupIDByType(faked, VncNotifyList); ++ ++ /* search list for this client */ ++ tmp = head; ++ while (tmp) { ++ if (tmp->client == client) { ++ /* found client! */ ++ if (!onoff) ++ tmp->client = NULL; ++ return Success; ++ } ++ if (!tmp->client) ++ freeRec = tmp; /* save ptr to free record */ ++ tmp = tmp->next; ++ } ++ ++ /* if we get here, we didn't find client in the list */ ++ ++ if (!onoff) { ++ /* if turning off non-existing client, just return */ ++ return Success; ++ } ++ ++ /* OK, add new client to list now */ ++ ++ if (freeRec) { ++ /* re-using a free spot */ ++ freeRec->client = client; ++ return Success; ++ } ++ ++ /* need to allocate new node */ ++ if (!(newRec = (VncNotifyListPtr)xalloc(sizeof(VncNotifyListRec)))) ++ return BadAlloc; ++ /* insert at head, just as AddResource() does!!! */ ++ newRec->next = head; ++ newRec->client = client; ++ if (!AddResource(faked, VncNotifyList, newRec)) { ++ xfree(newRec); ++ return BadAlloc; ++ } ++#endif ++ return Success; ++} ++ ++ ++#if USE_ORIG_RES_CODE ++static int ++VncDestroyNotifyList(pointer pn, XID id) ++{ ++ VncNotifyListPtr cpn = (VncNotifyListPtr) pn; ++ rfbLog("%s client %p\n", __func__, (void *) cpn->client); ++ cpn->client = NULL; ++ return Success; ++} ++#endif ++ ++static Bool ++CreateResourceTypes(void) ++{ ++#if USE_ORIG_RES_CODE ++ if (VncResourceGeneration == serverGeneration) ++ return TRUE; ++ ++ VncResourceGeneration = serverGeneration; ++ ++ if (!(VncNotifyList = CreateNewResourceType(VncDestroyNotifyList))) { ++ ErrorF("CreateResourceTypes: failed to allocate vnc notify list resource.\n"); ++ return FALSE; ++ } ++#endif ++ return TRUE; ++} ++ ++ ++ ++#if XFREE86VNC ++static unsigned long vncCreateScreenResourcesIndex; ++static unsigned long vncExtGeneration = 0; ++extern Bool VNCInit(ScreenPtr pScreen, unsigned char *FBStart); ++ ++/* copied from miscrinit.c */ ++typedef struct ++{ ++ pointer pbits; /* pointer to framebuffer */ ++ int width; /* delta to add to a framebuffer addr to move one row down */ ++} miScreenInitParmsRec, *miScreenInitParmsPtr; ++ ++ ++static Bool ++vncCreateScreenResources(ScreenPtr pScreen) ++{ ++ int ret = TRUE; ++ CreateScreenResourcesProcPtr CreateScreenResources = ++ (CreateScreenResourcesProcPtr) ++ pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr; ++ miScreenInitParmsPtr pScrInitParms; ++ ++ pScrInitParms = (miScreenInitParmsPtr)pScreen->devPrivate; ++ ++ if ( pScreen->CreateScreenResources != vncCreateScreenResources ) { ++ /* Can't find hook we are hung on */ ++ xf86DrvMsg(pScreen->myNum, X_WARNING /* X_ERROR */, ++ "vncCreateScreenResources %p called when not in " ++ "pScreen->CreateScreenResources %p n", ++ (void *) vncCreateScreenResources, ++ (void *) pScreen->CreateScreenResources ); ++ } ++ ++ /* Now do our stuff */ ++ VNCInit(pScreen, pScrInitParms->pbits); ++ ++ /* Unhook this function ... */ ++ pScreen->CreateScreenResources = CreateScreenResources; ++ pScreen->devPrivates[vncCreateScreenResourcesIndex].ptr = NULL; ++ ++ /* ... and call the previous CreateScreenResources fuction, if any */ ++ if (pScreen->CreateScreenResources) { ++ ret = (*pScreen->CreateScreenResources)(pScreen); ++ } ++ ++ return ret; ++} ++#endif ++ ++ ++ ++void ++VncExtensionInit(void) ++{ ++ ExtensionEntry *extEntry; ++ ++#if XFREE86VNC ++ if (vncExtGeneration != serverGeneration) { ++ unsigned int i; ++ ++ vncExtGeneration = serverGeneration; ++ ++ if ( ((vncCreateScreenResourcesIndex = AllocateScreenPrivateIndex()) < 0) || ++ ((vncScreenPrivateIndex = AllocateScreenPrivateIndex()) < 0) || ++ ((rfbGCIndex = AllocateGCPrivateIndex()) < 0) ) ++ return; ++ ++ for (i = 0 ; i < screenInfo.numScreens; i++) ++ { ++ screenInfo.screens[i]->devPrivates[vncCreateScreenResourcesIndex].ptr ++ = (void*)(xf86Screens[i]->pScreen->CreateScreenResources); ++ xf86Screens[i]->pScreen->CreateScreenResources = vncCreateScreenResources; ++ } ++ ++ gethostname(rfbThisHost, 255); ++ } ++#endif ++ ++ if (!CreateResourceTypes()) ++ return; ++ ++ extEntry = AddExtension(VNC_EXTENSION_NAME, ++ XVncNumberEvents, XVncNumberErrors, ++ ProcVncDispatch, SProcVncDispatch, ++ VncResetProc, StandardMinorOpcode); ++ ++ VncErrorBase = extEntry->errorBase; ++ VncEventBase = extEntry->eventBase; ++ ++ EventSwapVector[VncEventBase + XVncConnected] = ++ (EventSwapPtr)SwapVncConnectedEvent; ++ EventSwapVector[VncEventBase + XVncDisconnected] = ++ (EventSwapPtr)SwapVncDisconnectedEvent; ++#ifdef CHROMIUM ++ EventSwapVector[VncEventBase + XVncChromiumConnected] = ++ (EventSwapPtr)SwapVncChromiumConnectedEvent; ++#endif ++} /* VncExtensionInit */ +diff --git a/hw/xfree86/vnc/vncint.h b/hw/xfree86/vnc/vncint.h +new file mode 100644 +index 0000000..53c4a81 +--- /dev/null ++++ b/hw/xfree86/vnc/vncint.h +@@ -0,0 +1,155 @@ ++/* ++ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * Author: Alan Hourihane ++ */ ++ ++#ifndef _VNC_H_ ++#define _VNC_H_ ++ ++#include ++/*#include */ ++ ++extern int vncScreenPrivateIndex; ++ ++#define VNCPTR(pScreen)\ ++ (vncScreenPtr)((pScreen)->devPrivates[vncScreenPrivateIndex].ptr) ++ ++typedef struct { ++ int rfbPort; ++ int rdpPort; ++ int udpPort; ++ int rfbListenSock; ++ int rdpListenSock; ++ int udpSock; ++ int httpPort; ++ int httpListenSock; ++ int httpSock; ++ char * httpDir; ++ char buf[HTTP_BUF_SIZE]; ++ Bool udpSockConnected; ++ char * rfbAuthPasswdFile; ++ size_t buf_filled; ++ int maxFd; ++ fd_set allFds; ++ unsigned char * oldpfbMemory; ++ Bool useGetImage; ++ Bool rfbAlwaysShared; ++ Bool rfbNeverShared; ++ Bool rfbDontDisconnect; ++ Bool rfbUserAccept; ++ Bool rfbViewOnly; ++ unsigned char * pfbMemory; ++ int paddedWidthInBytes; ++ ColormapPtr rfbInstalledColormap; ++ ColormapPtr savedColormap; ++ rfbPixelFormat rfbServerFormat; ++ Bool rfbAuthTooManyTries; ++ int rfbAuthTries; ++ Bool loginAuthEnabled; ++ struct in_addr interface; ++ OsTimerPtr timer; ++ char updateBuf[UPDATE_BUF_SIZE]; ++ int ublen; ++ int width; ++ int height; ++ int depth; ++ int bitsPerPixel; ++ ++ /* The following two members are used to minimise the amount of unnecessary ++ drawing caused by cursor movement. Whenever any drawing affects the ++ part of the screen where the cursor is, the cursor is removed first and ++ then the drawing is done (this is what the sprite routines test for). ++ Afterwards, however, we do not replace the cursor, even when the cursor ++ is logically being moved across the screen. We only draw the cursor ++ again just as we are about to send the client a framebuffer update. ++ ++ We need to be careful when removing and drawing the cursor because of ++ their relationship with the normal drawing routines. The drawing ++ routines can invoke the cursor routines, but also the cursor routines ++ themselves end up invoking drawing routines. ++ ++ Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by ++ doing a CopyArea from a pixmap to the screen, where the pixmap contains ++ the saved contents of the screen under the cursor. Before doing this, ++ however, we set cursorIsDrawn to FALSE. Then, when CopyArea is called, ++ it sees that cursorIsDrawn is FALSE and so doesn't feel the need to ++ (recursively!) remove the cursor before doing it. ++ ++ Putting up the cursor (rfbSpriteRestoreCursor) involves a call to ++ PushPixels. While this is happening, cursorIsDrawn must be FALSE so ++ that PushPixels doesn't think it has to remove the cursor first. ++ Obviously cursorIsDrawn is set to TRUE afterwards. ++ ++ Another problem we face is that drawing routines sometimes cause a ++ framebuffer update to be sent to the RFB client. When the RFB client is ++ already waiting for a framebuffer update and some drawing to the ++ framebuffer then happens, the drawing routine sees that the client is ++ ready, so it calls rfbSendFramebufferUpdate. If the cursor is not drawn ++ at this stage, it must be put up, and so rfbSpriteRestoreCursor is ++ called. However, if the original drawing routine was actually called ++ from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't ++ want this to happen. So both the cursor routines set ++ dontSendFramebufferUpdate to TRUE, and all the drawing routines check ++ this before calling rfbSendFramebufferUpdate. */ ++ ++ Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ ++ Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the ++ cursor */ ++ ++ /* wrapped screen functions */ ++ ++ CloseScreenProcPtr CloseScreen; ++ CreateGCProcPtr CreateGC; ++ PaintWindowBackgroundProcPtr PaintWindowBackground; ++ PaintWindowBorderProcPtr PaintWindowBorder; ++ CopyWindowProcPtr CopyWindow; ++ ClearToBackgroundProcPtr ClearToBackground; ++ RestoreAreasProcPtr RestoreAreas; ++ ScreenWakeupHandlerProcPtr WakeupHandler; ++ InstallColormapProcPtr InstallColormap; ++ UninstallColormapProcPtr UninstallColormap; ++ ListInstalledColormapsProcPtr ListInstalledColormaps; ++ StoreColorsProcPtr StoreColors; ++ xf86EnableDisableFBAccessProc *EnableDisableFBAccess; ++ miPointerSpriteFuncPtr spriteFuncs; ++ DisplayCursorProcPtr DisplayCursor; ++ CursorPtr pCurs; ++ Bool (*UseHWCursor)(ScreenPtr, CursorPtr); ++ Bool (*UseHWCursorARGB)(ScreenPtr, CursorPtr); ++ Bool *SWCursor; ++#ifdef CHROMIUM ++ RealizeWindowProcPtr RealizeWindow; ++ UnrealizeWindowProcPtr UnrealizeWindow; ++ DestroyWindowProcPtr DestroyWindow; ++ ResizeWindowProcPtr ResizeWindow; ++ PositionWindowProcPtr PositionWindow; ++ ClipNotifyProcPtr ClipNotify; ++#endif ++#ifdef RENDER ++ CompositeProcPtr Composite; ++#endif ++ ++} vncScreenRec, *vncScreenPtr; ++ ++extern Bool vncUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs); ++extern Bool vncUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs); ++extern void rfbEnableDisableFBAccess (int index, Bool enable); ++ ++#endif /* _VNC_H_ */ ++ +diff --git a/hw/xfree86/vnc/zlib.c b/hw/xfree86/vnc/zlib.c +new file mode 100644 +index 0000000..edc4467 +--- /dev/null ++++ b/hw/xfree86/vnc/zlib.c +@@ -0,0 +1,306 @@ ++/* ++ * zlib.c ++ * ++ * Routines to implement zlib based encoding (deflate). ++ * ++ * Modified for XFree86 4.x by Alan Hourihane ++ */ ++ ++/* ++ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. ++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ * For the latest source code, please check: ++ * ++ * http://www.developVNC.org/ ++ * ++ * or send email to feedback@developvnc.org. ++ */ ++ ++#include ++#include ++#include "rfb.h" ++ ++/* ++ * zlibBeforeBuf contains pixel data in the client's format. ++ * zlibAfterBuf contains the zlib (deflated) encoding version. ++ * If the zlib compressed/encoded version is ++ * larger than the raw data or if it exceeds zlibAfterBufSize then ++ * raw encoding is used instead. ++ */ ++ ++static int zlibBeforeBufSize = 0; ++static char *zlibBeforeBuf = NULL; ++ ++static int zlibAfterBufSize = 0; ++static char *zlibAfterBuf = NULL; ++static int zlibAfterBufLen; ++ ++/* ++ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib ++ * rectangle encoding. ++ */ ++ ++static Bool ++rfbSendOneRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ rfbFramebufferUpdateRectHeader rect; ++ rfbZlibHeader hdr; ++ int deflateResult; ++ int previousOut; ++ int i; ++ unsigned char *fbptr = (pVNC->pfbMemory + (pVNC->paddedWidthInBytes * y) ++ + (x * (pVNC->bitsPerPixel / 8))); ++ ++ int maxRawSize; ++ int maxCompSize; ++ ++ maxRawSize = (pVNC->width * pVNC->height ++ * (cl->format.bitsPerPixel / 8)); ++ ++ if (zlibBeforeBufSize < maxRawSize) { ++ zlibBeforeBufSize = maxRawSize; ++ if (zlibBeforeBuf == NULL) ++ zlibBeforeBuf = (char *)xalloc(zlibBeforeBufSize); ++ else ++ zlibBeforeBuf = (char *)xrealloc(zlibBeforeBuf, zlibBeforeBufSize); ++ } ++ ++ /* zlib compression is not useful for very small data sets. ++ * So, we just send these raw without any compression. ++ */ ++ if (( w * h * (pVNC->bitsPerPixel / 8)) < ++ VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) { ++ ++ int result; ++ ++ /* The translation function (used also by the in raw encoding) ++ * requires 4/2/1 byte alignment in the output buffer (which is ++ * pVNC->updateBuf for the raw encoding) based on the bitsPerPixel of ++ * the viewer/client. This prevents SIGBUS errors on some ++ * architectures like SPARC, PARISC... ++ */ ++ if (( cl->format.bitsPerPixel > 8 ) && ++ ( pVNC->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ result = rfbSendRectEncodingRaw(cl, x, y, w, h); ++ ++ return result; ++ ++ } ++ ++ /* ++ * zlib requires output buffer to be slightly larger than the input ++ * buffer, in the worst case. ++ */ ++ maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12; ++ ++ if (zlibAfterBufSize < maxCompSize) { ++ zlibAfterBufSize = maxCompSize; ++ if (zlibAfterBuf == NULL) ++ zlibAfterBuf = (char *)xalloc(zlibAfterBufSize); ++ else ++ zlibAfterBuf = (char *)xrealloc(zlibAfterBuf, zlibAfterBufSize); ++ } ++ ++ /* ++ * Convert pixel data to client format. ++ */ ++ (*cl->translateFn)(cl->pScreen, cl->translateLookupTable, ++ &pVNC->rfbServerFormat, ++ &cl->format, fbptr, zlibBeforeBuf, ++ pVNC->paddedWidthInBytes, w, h, x, y); ++ ++ cl->compStream.next_in = ( Bytef * )zlibBeforeBuf; ++ cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8); ++ cl->compStream.next_out = ( Bytef * )zlibAfterBuf; ++ cl->compStream.avail_out = maxCompSize; ++ cl->compStream.data_type = Z_BINARY; ++ ++ /* Initialize the deflation state. */ ++ if ( cl->compStreamInited == FALSE ) { ++ ++ cl->compStream.total_in = 0; ++ cl->compStream.total_out = 0; ++ cl->compStream.zalloc = Z_NULL; ++ cl->compStream.zfree = Z_NULL; ++ cl->compStream.opaque = Z_NULL; ++ ++ deflateInit2( &(cl->compStream), ++ cl->zlibCompressLevel, ++ Z_DEFLATED, ++ MAX_WBITS, ++ MAX_MEM_LEVEL, ++ Z_DEFAULT_STRATEGY ); ++ /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */ ++ /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */ ++ cl->compStreamInited = TRUE; ++ ++ } ++ ++ previousOut = cl->compStream.total_out; ++ ++ /* Perform the compression here. */ ++ deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH ); ++ ++ /* Find the total size of the resulting compressed data. */ ++ zlibAfterBufLen = cl->compStream.total_out - previousOut; ++ ++ if ( deflateResult != Z_OK ) { ++ rfbLog("zlib deflation error: %s\n", cl->compStream.msg); ++ return FALSE; ++ } ++ ++ /* Note that it is not possible to switch zlib parameters based on ++ * the results of the compression pass. The reason is ++ * that we rely on the compressor and decompressor states being ++ * in sync. Compressing and then discarding the results would ++ * cause lose of synchronization. ++ */ ++ ++ /* Update statics */ ++ cl->rfbRectanglesSent[rfbEncodingZlib]++; ++ cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader ++ + sz_rfbZlibHeader + zlibAfterBufLen); ++ ++ if (pVNC->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader ++ > UPDATE_BUF_SIZE) ++ { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ ++ rect.r.x = Swap16IfLE(x); ++ rect.r.y = Swap16IfLE(y); ++ rect.r.w = Swap16IfLE(w); ++ rect.r.h = Swap16IfLE(h); ++ rect.encoding = Swap32IfLE(rfbEncodingZlib); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&rect, ++ sz_rfbFramebufferUpdateRectHeader); ++ pVNC->ublen += sz_rfbFramebufferUpdateRectHeader; ++ ++ hdr.nBytes = Swap32IfLE(zlibAfterBufLen); ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], (char *)&hdr, sz_rfbZlibHeader); ++ pVNC->ublen += sz_rfbZlibHeader; ++ ++ for (i = 0; i < zlibAfterBufLen;) { ++ ++ int bytesToCopy = UPDATE_BUF_SIZE - pVNC->ublen; ++ ++ if (i + bytesToCopy > zlibAfterBufLen) { ++ bytesToCopy = zlibAfterBufLen - i; ++ } ++ ++ memcpy(&pVNC->updateBuf[pVNC->ublen], &zlibAfterBuf[i], bytesToCopy); ++ ++ pVNC->ublen += bytesToCopy; ++ i += bytesToCopy; ++ ++ if (pVNC->ublen == UPDATE_BUF_SIZE) { ++ if (!rfbSendUpdateBuf(cl)) ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ ++} ++ ++ ++/* ++ * rfbSendRectEncodingZlib - send a given rectangle using one or more ++ * Zlib encoding rectangles. ++ */ ++ ++Bool ++rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, int h) ++{ ++ VNCSCREENPTR(cl->pScreen); ++ int maxLines; ++ int linesRemaining; ++ rfbRectangle partialRect; ++ ++ partialRect.x = x; ++ partialRect.y = y; ++ partialRect.w = w; ++ partialRect.h = h; ++ ++ /* Determine maximum pixel/scan lines allowed per rectangle. */ ++ maxLines = ( ZLIB_MAX_SIZE(w) / w ); ++ ++ /* Initialize number of scan lines left to do. */ ++ linesRemaining = h; ++ ++ /* Loop until all work is done. */ ++ while ( linesRemaining > 0 ) { ++ ++ int linesToComp; ++ ++ if ( maxLines < linesRemaining ) ++ linesToComp = maxLines; ++ else ++ linesToComp = linesRemaining; ++ ++ partialRect.h = linesToComp; ++ ++ /* Encode (compress) and send the next rectangle. */ ++ if ( ! rfbSendOneRectEncodingZlib( cl, ++ partialRect.x, ++ partialRect.y, ++ partialRect.w, ++ partialRect.h )) { ++ ++ return FALSE; ++ } ++ ++ /* Technically, flushing the buffer here is not extrememly ++ * efficient. However, this improves the overall throughput ++ * of the system over very slow networks. By flushing ++ * the buffer with every maximum size zlib rectangle, we ++ * improve the pipelining usage of the server CPU, network, ++ * and viewer CPU components. Insuring that these components ++ * are working in parallel actually improves the performance ++ * seen by the user. ++ * Since, zlib is most useful for slow networks, this flush ++ * is appropriate for the desired behavior of the zlib encoding. ++ */ ++ if (( pVNC->ublen > 0 ) && ++ ( linesToComp == maxLines )) { ++ if (!rfbSendUpdateBuf(cl)) { ++ ++ return FALSE; ++ } ++ } ++ ++ /* Update remaining and incremental rectangle location. */ ++ linesRemaining -= linesToComp; ++ partialRect.y += linesToComp; ++ ++ } ++ ++ return TRUE; ++ ++} ++ ++ +diff --git a/mi/miinitext.c b/mi/miinitext.c +index 7939a5f..6a71a6f 100644 +--- a/mi/miinitext.c ++++ b/mi/miinitext.c +@@ -79,6 +79,18 @@ #undef XF86DRI + #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 ++#include ++ ++#include "dixstruct.h" ++#include "extnsionst.h" ++#include "windowstr.h" ++ ++#define _XCLIPLIST_SERVER_ ++#include ++ ++ ++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..3dae42c +--- /dev/null ++++ b/xcliplist/cliplistmod.c +@@ -0,0 +1,46 @@ ++ ++#include "xorg/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; ++} ++ +-- +1.4.2 + diff --git a/0018-vnc-support.txt.diff b/0018-vnc-support.txt.diff new file mode 100644 index 0000000..424e4ce --- /dev/null +++ b/0018-vnc-support.txt.diff @@ -0,0 +1,21 @@ +diff -x .deps -u -r xcliplist.orig/cliplistmod.c xcliplist/cliplistmod.c +--- xcliplist.orig/cliplistmod.c 2007-01-14 13:45:20.000000000 +0000 ++++ xcliplist/cliplistmod.c 2007-01-14 13:46:44.000000000 +0000 +@@ -1,5 +1,5 @@ + +-#include "xorg/xf86Module.h" ++#include "../hw/xfree86/common/xf86Module.h" + + extern Bool noTestExtensions; + +--- hw/vnc/loginauth.c.orig 2007-01-13 18:00:45.106884000 +0100 ++++ hw/vnc/loginauth.c 2007-01-13 18:08:04.104447000 +0100 +@@ -37,6 +37,8 @@ + #include + #include "rfb.h" + ++char *crypt(const char *key, const char *salt); ++ + void rfbLoginAuthProcessClientMessage(rfbClientPtr cl) + { + int n1 = 0, n2 = 0; diff --git a/0018-vnc-support.txt.mbox b/0018-vnc-support.txt.mbox new file mode 100644 index 0000000..b7db9eb --- /dev/null +++ b/0018-vnc-support.txt.mbox @@ -0,0 +1,187 @@ +From xorg-bounces@lists.freedesktop.org Thu Jan 11 18:09:18 2007 +Return-Path: +X-Original-To: sndirsch@wotan.suse.de +Received: from Relay2.suse.de (relay2.suse.de [149.44.160.89]) + by wotan.suse.de (Postfix) with ESMTP id 8F76413E45 + for ; Thu, 11 Jan 2007 18:09:18 +0100 (CET) +Received: by Relay2.suse.de (Postfix) + id 8B0DAC03BF; Thu, 11 Jan 2007 18:09:18 +0100 (CET) +Received: from Relay2.suse.de (localhost [127.0.0.1]) + by Relay2.suse.de (Postfix) with ESMTP id 6B1D2AE3B2; + Thu, 11 Jan 2007 18:09:18 +0100 (CET) +Received: from Relay2.suse.de ([127.0.0.1]) + by Relay2.suse.de (Relay2 [127.0.0.1]) (amavisd-new, port 10026) with ESMTP + id 32754-05; Thu, 11 Jan 2007 18:09:12 +0100 (CET) +Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) + (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) + (No client certificate requested) + by Relay2.suse.de (Postfix) with ESMTP id 03A1CC03AF; + Thu, 11 Jan 2007 18:09:12 +0100 (CET) +Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.208.82]) + by mx2.suse.de (Postfix) with ESMTP id BED2E215E1; + Thu, 11 Jan 2007 18:09:11 +0100 (CET) +Received: from gabe.freedesktop.org (localhost [127.0.0.1]) + by gabe.freedesktop.org (Postfix) with ESMTP id 5525D9EB5A; + Thu, 11 Jan 2007 09:09:07 -0800 (PST) +X-Original-To: xorg@freedesktop.org +Delivered-To: xorg@freedesktop.org +Received: from ciao.gmane.org (main.gmane.org [80.91.229.2]) + by gabe.freedesktop.org (Postfix) with ESMTP id 6CC819EAF1 + for ; Thu, 11 Jan 2007 09:09:03 -0800 (PST) +Received: from list by ciao.gmane.org with local (Exim 4.43) + id 1H53Q4-0002Z1-Np + for xorg@freedesktop.org; Thu, 11 Jan 2007 18:08:52 +0100 +Received: from host-84-9-255-116.bulldogdsl.com ([84.9.255.116]) + by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) + id 1AlnuQ-0007hv-00 + for ; Thu, 11 Jan 2007 18:08:52 +0100 +Received: from gmane by host-84-9-255-116.bulldogdsl.com with local (Gmexim + 0.1 (Debian)) id 1AlnuQ-0007hv-00 + for ; Thu, 11 Jan 2007 18:08:52 +0100 +X-Injected-Via-Gmane: http://gmane.org/ +To: xorg@freedesktop.org +From: Colin Guthrie +Date: Thu, 11 Jan 2007 17:08:41 +0000 +Message-ID: +References: <45A66ACD.2060605@Sun.COM> +Mime-Version: 1.0 +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 7bit +X-Complaints-To: usenet@sea.gmane.org +X-Gmane-NNTP-Posting-Host: host-84-9-255-116.bulldogdsl.com +User-Agent: Thunderbird 1.5.0.9 (X11/20070105) +In-Reply-To: <45A66ACD.2060605@Sun.COM> +Subject: Re: VNC on Xorg? +X-BeenThere: xorg@lists.freedesktop.org +X-Mailman-Version: 2.1.5 +Precedence: list +List-Id: Discuss issues related to the xorg tree +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: xorg-bounces@lists.freedesktop.org +Errors-To: xorg-bounces@lists.freedesktop.org +X-Virus-Scanned: by amavisd-new at Relay2.suse.de +X-Spam-Status: No, hits=-1.7 tagged_above=-20.0 required=5.0 tests=BAYES_20, + IS_MAILMAN_LIST +X-Spam-Level: +Status: RO +Content-Length: 561 +Lines: 12 + +Deron Johnson wrote: +> Does anybody know of a version of VNC which is based on Xorg 6.9 or +> greater? For example, Tight VNC is based on an ancient version (XFree86). + +I recently updated the Mandriva VNC patch for Xorg 1.1.99.903, but I've +not tested it at all. It compiles up fine tho'. + +http://svn.mandriva.com/cgi-bin/viewvc.cgi/packages/cooker/x11-server/current/SOURCES/0018-vnc-support.txt?view=log + +HTH + +Col. + +_______________________________________________ +xorg mailing list +xorg@lists.freedesktop.org +http://lists.freedesktop.org/mailman/listinfo/xorg + +From xorg-bounces@lists.freedesktop.org Thu Jan 11 18:15:18 2007 +Return-Path: +X-Original-To: sndirsch@wotan.suse.de +Received: from Relay1.suse.de (relay1.suse.de [149.44.160.87]) + by wotan.suse.de (Postfix) with ESMTP id 08DF413E45 + for ; Thu, 11 Jan 2007 18:15:18 +0100 (CET) +Received: by Relay1.suse.de (Postfix) + id 054EBB189D; Thu, 11 Jan 2007 18:15:18 +0100 (CET) +Received: from Relay1.suse.de (localhost [127.0.0.1]) + by Relay1.suse.de (Postfix) with ESMTP id E8AF9BCC22; + Thu, 11 Jan 2007 18:15:17 +0100 (CET) +Received: from Relay1.suse.de ([127.0.0.1]) + by Relay1.suse.de (Relay1 [127.0.0.1]) (amavisd-new, port 10026) with ESMTP + id 22518-16; Thu, 11 Jan 2007 18:15:12 +0100 (CET) +Received: from mx1.suse.de (ns1.suse.de [195.135.220.2]) + (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) + (No client certificate requested) + by Relay1.suse.de (Postfix) with ESMTP id AACF2BA55A; + Thu, 11 Jan 2007 18:15:12 +0100 (CET) +Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.208.82]) + by mx1.suse.de (Postfix) with ESMTP id 6D30F12208; + Thu, 11 Jan 2007 18:15:12 +0100 (CET) +Received: from gabe.freedesktop.org (localhost [127.0.0.1]) + by gabe.freedesktop.org (Postfix) with ESMTP id E3A279EB68; + Thu, 11 Jan 2007 09:15:08 -0800 (PST) +X-Original-To: xorg@freedesktop.org +Delivered-To: xorg@freedesktop.org +Received: from ciao.gmane.org (main.gmane.org [80.91.229.2]) + by gabe.freedesktop.org (Postfix) with ESMTP id 29AC49EB59 + for ; Thu, 11 Jan 2007 09:15:03 -0800 (PST) +Received: from root by ciao.gmane.org with local (Exim 4.43) + id 1H53W2-0003Hz-6X + for xorg@freedesktop.org; Thu, 11 Jan 2007 18:15:02 +0100 +Received: from host-84-9-255-116.bulldogdsl.com ([84.9.255.116]) + by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) + id 1AlnuQ-0007hv-00 + for ; Thu, 11 Jan 2007 18:15:02 +0100 +Received: from gmane by host-84-9-255-116.bulldogdsl.com with local (Gmexim + 0.1 (Debian)) id 1AlnuQ-0007hv-00 + for ; Thu, 11 Jan 2007 18:15:02 +0100 +X-Injected-Via-Gmane: http://gmane.org/ +To: xorg@freedesktop.org +From: Colin Guthrie +Date: Thu, 11 Jan 2007 17:12:37 +0000 +Message-ID: +References: <45A66ACD.2060605@Sun.COM> +Mime-Version: 1.0 +Content-Type: text/plain; charset=ISO-8859-1 +Content-Transfer-Encoding: 7bit +X-Complaints-To: usenet@sea.gmane.org +X-Gmane-NNTP-Posting-Host: host-84-9-255-116.bulldogdsl.com +User-Agent: Thunderbird 1.5.0.9 (X11/20070105) +In-Reply-To: +Subject: Re: VNC on Xorg? +X-BeenThere: xorg@lists.freedesktop.org +X-Mailman-Version: 2.1.5 +Precedence: list +List-Id: Discuss issues related to the xorg tree +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: xorg-bounces@lists.freedesktop.org +Errors-To: xorg-bounces@lists.freedesktop.org +X-Virus-Scanned: by amavisd-new at Relay1.suse.de +X-Spam-Status: No, hits=-1.7 tagged_above=-20.0 required=5.0 tests=BAYES_20, + IS_MAILMAN_LIST +X-Spam-Level: +Status: RO +Content-Length: 657 +Lines: 13 + +Colin Guthrie wrote: +> Deron Johnson wrote: +>> Does anybody know of a version of VNC which is based on Xorg 6.9 or +>> greater? For example, Tight VNC is based on an ancient version (XFree86). +> +> I recently updated the Mandriva VNC patch for Xorg 1.1.99.903, but I've +> not tested it at all. It compiles up fine tho'. +> +> http://svn.mandriva.com/cgi-bin/viewvc.cgi/packages/cooker/x11-server/current/SOURCES/0018-vnc-support.txt?view=log + +I should also state that the previous revision is for Xorg 1.1.1 + +Col. + +_______________________________________________ +xorg mailing list +xorg@lists.freedesktop.org +http://lists.freedesktop.org/mailman/listinfo/xorg + diff --git a/xorg-x11-server.changes b/xorg-x11-server.changes index f91a4ab..15abcbe 100644 --- a/xorg-x11-server.changes +++ b/xorg-x11-server.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Sun Jan 14 15:12:59 CET 2007 - sndirsch@suse.de + +- added build of VNC support (0018-vnc-support.txt/ + 0018-vnc-support.txt.diff); see 0018-vnc-support.txt.mbox for + reference + ------------------------------------------------------------------- Tue Jan 9 17:05:27 CET 2007 - sndirsch@suse.de diff --git a/xorg-x11-server.spec b/xorg-x11-server.spec index 04cffb8..49df79b 100644 --- a/xorg-x11-server.spec +++ b/xorg-x11-server.spec @@ -13,11 +13,15 @@ Name: xorg-x11-server %define dirsuffix 1.1.99.903 %define fglrx_driver_hack 0 +%define vnc 1 BuildRequires: Mesa-devel fontconfig-devel freetype2-devel ghostscript-library glitz-devel libdrm-devel pkgconfig xorg-x11 xorg-x11-devel xorg-x11-libICE-devel xorg-x11-libSM-devel xorg-x11-libX11-devel xorg-x11-libXau-devel xorg-x11-libXdmcp-devel xorg-x11-libXext-devel xorg-x11-libXfixes-devel xorg-x11-libXmu-devel xorg-x11-libXp-devel xorg-x11-libXpm-devel xorg-x11-libXprintUtil-devel xorg-x11-libXrender-devel xorg-x11-libXt-devel xorg-x11-libXv-devel xorg-x11-libfontenc-devel xorg-x11-libxkbfile-devel xorg-x11-proto-devel xorg-x11-xtrans-devel +%if %vnc +BuildRequires: libjpeg-devel +%endif URL: http://xorg.freedesktop.org/ %define EXPERIMENTAL 0 Version: 7.2 -Release: 39 +Release: 41 License: X11/MIT BuildRoot: %{_tmppath}/%{name}-%{version}-build Group: System/X11/Servers/XF86_4 @@ -35,6 +39,9 @@ Source4: xorgcfg.tar.bz2 %if %suse_version > 1010 Source5: modprobe.nvidia %endif +%if %vnc +Source6: 0018-vnc-support.txt.mbox +%endif Patch: 64bit.diff Patch1: fpic.diff Patch2: p_default-module-path.diff @@ -70,6 +77,10 @@ Patch35: xorg-server-1.1.99.901-GetDrawableAttributes.patch Patch36: libdrm.diff Patch37: int10-fix.diff Patch38: cve-2006-6101_6102_6103.diff +%if %vnc +Patch39: 0018-vnc-support.txt +Patch40: 0018-vnc-support.txt.diff +%endif Patch334: p_pci-domain.diff Patch357: p_pci-ce-x.diff @@ -92,6 +103,24 @@ This package contains the X.Org Server SDK. +%endif +%if %vnc +%package -n xorg-x11-Xvnc +Summary: VNC Server for the X Window System +Group: System/X11/Servers/XF86_4 +Provides: vnc:/usr/X11R6/bin/Xvnc XFree86-Xvnc +Obsoletes: XFree86-Xvnc +%ifarch ia64 +Provides: vnc-x86 +Obsoletes: vnc-x86 +%endif +Autoreqprov: on + +%description -n xorg-x11-Xvnc +An X Window System server for Virtual Network Computing (VNC). + + + %endif %prep %setup -q -n xorg-server-%{dirsuffix} -b1 -a4 @@ -140,6 +169,10 @@ popd %patch36 -p0 %patch37 -p1 %patch38 -p1 +%if %vnc +%patch39 -p1 +%patch40 -p0 +%endif %build autoreconf -fi @@ -151,6 +184,14 @@ autoreconf -fi --with-release-snap=0 \ --with-release-date="%(date)" \ --with-release-version=7.1.0.0 \ +%endif +%if %vnc +%ifnarch s390 s390x + --enable-xorg-vnc \ + --enable-xcliplist \ +%endif + --enable-xdmx-vnc \ + --enable-xvnc \ %endif --prefix=/usr \ --sysconfdir=/etc \ @@ -238,6 +279,11 @@ install -m 644 $RPM_SOURCE_DIR/modprobe.nvidia $RPM_BUILD_ROOT/etc/modprobe.d/nv %endif rm $RPM_BUILD_ROOT/etc/X11/Xsession.d/92xprint-xpserverlist rmdir $RPM_BUILD_ROOT/etc/X11/Xsession.d +%if %vnc +%ifarch s390 s390x +rm $RPM_BUILD_ROOT/mfb.h +%endif +%endif %clean rm -rf "$RPM_BUILD_ROOT" @@ -442,8 +488,18 @@ exit 0 /usr/%{_lib}/*.a /usr/share/aclocal/*.m4 %endif +%if %vnc + +%files -n xorg-x11-Xvnc +%defattr(-, root, root) +/usr/bin/Xvnc +%endif %changelog -n xorg-x11-server +* Sun Jan 14 2007 - sndirsch@suse.de +- added build of VNC support (0018-vnc-support.txt/ + 0018-vnc-support.txt.diff); see 0018-vnc-support.txt.mbox for + reference * Tue Jan 09 2007 - sndirsch@suse.de - cve-2006-6101_6102_6103.diff: * CVE-2006-6101 iDefense X.org ProcRenderAddGlyphs (Bug #225972)