summaryrefslogtreecommitdiffstats
path: root/krdc/vnc
diff options
context:
space:
mode:
Diffstat (limited to 'krdc/vnc')
-rw-r--r--krdc/vnc/Makefile.am16
-rw-r--r--krdc/vnc/colour.c415
-rw-r--r--krdc/vnc/d3des.c440
-rw-r--r--krdc/vnc/d3des.h51
-rw-r--r--krdc/vnc/desktop.c1613
-rw-r--r--krdc/vnc/hextile.c129
-rw-r--r--krdc/vnc/kvncview.cpp828
-rw-r--r--krdc/vnc/kvncview.h121
-rw-r--r--krdc/vnc/pointerlatencyometer.h83
-rw-r--r--krdc/vnc/rfbproto.c1335
-rw-r--r--krdc/vnc/rfbproto.h957
-rw-r--r--krdc/vnc/sockets.c325
-rw-r--r--krdc/vnc/threads.cpp392
-rw-r--r--krdc/vnc/threads.h126
-rw-r--r--krdc/vnc/tight.c610
-rw-r--r--krdc/vnc/vncauth.c161
-rw-r--r--krdc/vnc/vncauth.h30
-rw-r--r--krdc/vnc/vnchostpref.cpp127
-rw-r--r--krdc/vnc/vnchostpref.h52
-rw-r--r--krdc/vnc/vncprefs.ui165
-rw-r--r--krdc/vnc/vncprefs.ui.h53
-rw-r--r--krdc/vnc/vnctypes.h73
-rw-r--r--krdc/vnc/vncviewer.h186
-rw-r--r--krdc/vnc/zlib.c157
24 files changed, 8445 insertions, 0 deletions
diff --git a/krdc/vnc/Makefile.am b/krdc/vnc/Makefile.am
new file mode 100644
index 00000000..23956297
--- /dev/null
+++ b/krdc/vnc/Makefile.am
@@ -0,0 +1,16 @@
+KDE_CXXFLAGS = $(USE_THREADS)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libvnc.la
+
+libvnc_la_SOURCES = kvncview.cpp threads.cpp colour.c d3des.c desktop.c \
+ rfbproto.c sockets.c vncauth.c vncprefs.ui vnchostpref.cpp
+
+noinst_HEADERS = kvncview.h rfbproto.h vncviewer.h vnctypes.h vncauth.h \
+ pointerlatencyometer.h threads.h d3des.h vnchostpref.h
+
+libvnc_la_LIBADD = $(LIB_KDEUI) $(LIBJPEG)
+libvnc_la_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+INCLUDES= -I$(top_srcdir)/krdc -I.. $(all_includes)
diff --git a/krdc/vnc/colour.c b/krdc/vnc/colour.c
new file mode 100644
index 00000000..a51d6e61
--- /dev/null
+++ b/krdc/vnc/colour.c
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+/*
+ * colour.c - functions to deal with colour - i.e. RFB pixel formats, X visuals
+ * and colormaps. Thanks to Grant McDorman for some of the ideas used here.
+ */
+
+#include "vncviewer.h"
+#include <limits.h>
+
+
+#define INVALID_PIXEL 0xffffffff
+#define MAX_CMAP_SIZE 256
+#define BGR233_SIZE 256
+unsigned long BGR233ToPixel[BGR233_SIZE];
+
+Colormap cmap;
+Visual *vis;
+unsigned int visdepth, visbpp;
+Bool allocColorFailed = False;
+
+static int nBGR233ColoursAllocated;
+
+static int GetBPPForDepth(int depth);
+static void SetupBGR233Map(void);
+static void AllocateExactBGR233Colours(void);
+static Bool AllocateBGR233Colour(int r, int g, int b);
+
+
+/*
+ * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
+ * equivalent to the RFB protocol's "pixel format"). Having decided on the
+ * best visual, it also creates a colormap if necessary, sets the appropriate
+ * resources on the toplevel widget, and sets up the myFormat structure to
+ * describe the pixel format in terms that the RFB server will be able to
+ * understand.
+ *
+ * The algorithm for deciding which visual to use is as follows:
+ *
+ * If forceOwnCmap is true then we try to use a PseudoColor visual - we first
+ * see if there's one of the same depth as the RFB server, followed by an 8-bit
+ * deep one.
+ *
+ * If forceTrueColour is true then we try to use a TrueColor visual - if
+ * requestedDepth is set then it must be of that depth, otherwise any depth
+ * will be used.
+ *
+ * Otherwise, we use the X server's default visual and colormap. If this is
+ * TrueColor then we just ask the RFB server for this format. If the default
+ * isn't TrueColor, or if useBGR233 is true, then we ask the RFB server for
+ * BGR233 pixel format and use a lookup table to translate to the nearest
+ * colours provided by the X server.
+ */
+
+void
+SetVisualAndCmap()
+{
+ /* just use default visual and colormap */
+
+ vis = DefaultVisual(dpy,DefaultScreen(dpy));
+ visdepth = DefaultDepth(dpy,DefaultScreen(dpy));
+ visbpp = GetBPPForDepth(visdepth);
+ cmap = DefaultColormap(dpy,DefaultScreen(dpy));
+
+ if (!appData.useBGR233 && (vis->class == TrueColor)) {
+
+ myFormat.bitsPerPixel = visbpp;
+ myFormat.depth = visdepth;
+ myFormat.trueColour = 1;
+ myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
+ myFormat.redShift = ffs(vis->red_mask) - 1;
+ myFormat.greenShift = ffs(vis->green_mask) - 1;
+ myFormat.blueShift = ffs(vis->blue_mask) - 1;
+ myFormat.redMax = vis->red_mask >> myFormat.redShift;
+ myFormat.greenMax = vis->green_mask >> myFormat.greenShift;
+ myFormat.blueMax = vis->blue_mask >> myFormat.blueShift;
+
+ fprintf(stderr,
+ "Using default colormap which is TrueColor. Pixel format:\n");
+ PrintPixelFormat(&myFormat);
+ return;
+ }
+
+ appData.useBGR233 = True;
+
+ myFormat.bitsPerPixel = 8;
+ myFormat.depth = 8;
+ myFormat.trueColour = 1;
+ myFormat.bigEndian = 0;
+ myFormat.redMax = 7;
+ myFormat.greenMax = 7;
+ myFormat.blueMax = 3;
+ myFormat.redShift = 0;
+ myFormat.greenShift = 3;
+ myFormat.blueShift = 6;
+
+ fprintf(stderr,
+ "Using default colormap and translating from BGR233. Pixel format:\n");
+ PrintPixelFormat(&myFormat);
+
+ SetupBGR233Map();
+}
+
+
+/*
+ * GetBPPForDepth looks through the "pixmap formats" to find the bits-per-pixel
+ * for the given depth.
+ */
+
+static int
+GetBPPForDepth(int depth)
+{
+ XPixmapFormatValues *format;
+ int nformats;
+ int i;
+ int bpp;
+
+ format = XListPixmapFormats(dpy, &nformats);
+
+ for (i = 0; i < nformats; i++) {
+ if (format[i].depth == depth)
+ break;
+ }
+
+ if (i == nformats) {
+ fprintf(stderr,"no pixmap format for depth %d???\n", depth);
+ exit(1);
+ }
+
+ bpp = format[i].bits_per_pixel;
+
+ XFree(format);
+
+ if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) {
+ fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp);
+ exit(1);
+ }
+
+ return bpp;
+}
+
+
+
+/*
+ * SetupBGR233Map() sets up the BGR233ToPixel array.
+ *
+ * It calls AllocateExactBGR233Colours to allocate some exact BGR233 colours
+ * (limited by space in the colormap and/or by the value of the nColours
+ * resource). If the number allocated is less than BGR233_SIZE then it fills
+ * the rest in using the "nearest" colours available. How this is done depends
+ * on the value of the useSharedColours resource. If it's false, we use only
+ * colours from the exact BGR233 colours we've just allocated. If it's true,
+ * then we also use other clients' "shared" colours available in the colormap.
+ */
+
+static void
+SetupBGR233Map(void)
+{
+ int r, g, b;
+ long i;
+ unsigned long nearestPixel = 0;
+ int cmapSize;
+ XColor cmapEntry[MAX_CMAP_SIZE];
+ Bool exactBGR233[MAX_CMAP_SIZE];
+ Bool shared[MAX_CMAP_SIZE];
+ Bool usedAsNearest[MAX_CMAP_SIZE];
+ int nSharedUsed = 0;
+
+ if (visdepth > 8) {
+ appData.nColours = 256; /* ignore nColours setting for > 8-bit deep */
+ }
+
+ for (i = 0; i < BGR233_SIZE; i++) {
+ BGR233ToPixel[i] = INVALID_PIXEL;
+ }
+
+ AllocateExactBGR233Colours();
+
+ fprintf(stderr,"Got %d exact BGR233 colours out of %d\n",
+ nBGR233ColoursAllocated, appData.nColours);
+
+ if (nBGR233ColoursAllocated < BGR233_SIZE) {
+
+ if (visdepth > 8) { /* shouldn't get here */
+ fprintf(stderr,"Error: couldn't allocate BGR233 colours even though "
+ "depth is %d\n", visdepth);
+ exit(1);
+ }
+
+ cmapSize = (1 << visdepth);
+
+ for (i = 0; i < cmapSize; i++) {
+ cmapEntry[i].pixel = i;
+ exactBGR233[i] = False;
+ shared[i] = False;
+ usedAsNearest[i] = False;
+ }
+
+ XQueryColors(dpy, cmap, cmapEntry, cmapSize);
+
+ /* mark all our exact BGR233 pixels */
+
+ for (i = 0; i < BGR233_SIZE; i++) {
+ if (BGR233ToPixel[i] != INVALID_PIXEL)
+ exactBGR233[BGR233ToPixel[i]] = True;
+ }
+
+ if (appData.useSharedColours) {
+
+ /* Try to find existing shared colours. This is harder than it sounds
+ because XQueryColors doesn't tell us whether colours are shared,
+ private or unallocated. What we do is go through the colormap and for
+ each pixel try to allocate exactly its RGB values. If this returns a
+ different pixel then it's definitely either a private or unallocated
+ pixel, so no use to us. If it returns us the same pixel again, then
+ it's likely that it's a shared colour - however, it is possible that
+ it was actually an unallocated pixel, which we've now allocated. We
+ minimise this possibility by going through the pixels in reverse order
+ - this helps becuse the X server allocates new pixels from the lowest
+ number up, so it should only be a problem for the lowest unallocated
+ pixel. Got that? */
+
+ for (i = cmapSize-1; i >= 0; i--) {
+ if (!exactBGR233[i] &&
+ XAllocColor(dpy, cmap, &cmapEntry[i])) {
+
+ if (cmapEntry[i].pixel == (unsigned long) i) {
+
+ shared[i] = True; /* probably shared */
+
+ } else {
+
+ /* "i" is either unallocated or private. We have now unnecessarily
+ allocated cmapEntry[i].pixel. Free it. */
+
+ XFreeColors(dpy, cmap, &cmapEntry[i].pixel, 1, 0);
+ }
+ }
+ }
+ }
+
+ /* Now fill in the nearest colours */
+
+ for (r = 0; r < 8; r++) {
+ for (g = 0; g < 8; g++) {
+ for (b = 0; b < 4; b++) {
+ if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) {
+
+ unsigned long minDistance = ULONG_MAX;
+
+ for (i = 0; i < cmapSize; i++) {
+ if (exactBGR233[i] || shared[i]) {
+ unsigned long distance
+ = (abs(cmapEntry[i].red - r * 65535 / 7)
+ + abs(cmapEntry[i].green - g * 65535 / 7)
+ + abs(cmapEntry[i].blue - b * 65535 / 3));
+
+ if (distance < minDistance) {
+ minDistance = distance;
+ nearestPixel = i;
+ }
+ }
+ }
+
+ BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel;
+ if (shared[nearestPixel] && !usedAsNearest[nearestPixel])
+ nSharedUsed++;
+ usedAsNearest[nearestPixel] = True;
+ }
+ }
+ }
+ }
+
+ /* Tidy up shared colours which we allocated but aren't going to use */
+
+ for (i = 0; i < cmapSize; i++) {
+ if (shared[i] && !usedAsNearest[i]) {
+ XFreeColors(dpy, cmap, (unsigned long *)&i, 1, 0);
+ }
+ }
+
+ fprintf(stderr,"Using %d existing shared colours\n", nSharedUsed);
+ }
+}
+
+
+/*
+ * AllocateExactBGR233Colours() attempts to allocate each of the colours in the
+ * BGR233 colour cube, stopping when an allocation fails. The order it does
+ * this in is such that we should get a fairly well spread subset of the cube,
+ * however many allocations are made. There's probably a neater algorithm for
+ * doing this, but it's not obvious to me anyway. The way this algorithm works
+ * is:
+ *
+ * At each stage, we introduce a new value for one of the primaries, and
+ * allocate all the colours with the new value of that primary and all previous
+ * values of the other two primaries. We start with r=0 as the "new" value
+ * for r, and g=0, b=0 as the "previous" values of g and b. So we get:
+ *
+ * New primary value Previous values of other primaries Colours allocated
+ * ----------------- ---------------------------------- -----------------
+ * r=0 g=0 b=0 r0 g0 b0
+ * g=7 r=0 b=0 r0 g7 b0
+ * b=3 r=0 g=0,7 r0 g0 b3
+ * r0 g7 b3
+ * r=7 g=0,7 b=0,3 r7 g0 b0
+ * r7 g0 b3
+ * r7 g7 b0
+ * r7 g7 b3
+ * g=3 r=0,7 b=0,3 r0 g3 b0
+ * r0 g3 b3
+ * r7 g3 b0
+ * r7 g3 b3
+ * ....etc.
+ * */
+
+static void
+AllocateExactBGR233Colours(void)
+{
+ int rv[] = {0,7,3,5,1,6,2,4};
+ int gv[] = {0,7,3,5,1,6,2,4};
+ int bv[] = {0,3,1,2};
+ int rn = 0;
+ int gn = 1;
+ int bn = 1;
+ int ri, gi, bi;
+
+ nBGR233ColoursAllocated = 0;
+
+ while (1) {
+ if (rn == 8)
+ break;
+
+ ri = rn;
+ for (gi = 0; gi < gn; gi++) {
+ for (bi = 0; bi < bn; bi++) {
+ if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
+ return;
+ }
+ }
+ rn++;
+
+ if (gn == 8)
+ break;
+
+ gi = gn;
+ for (ri = 0; ri < rn; ri++) {
+ for (bi = 0; bi < bn; bi++) {
+ if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
+ return;
+ }
+ }
+ gn++;
+
+ if (bn < 4) {
+
+ bi = bn;
+ for (ri = 0; ri < rn; ri++) {
+ for (gi = 0; gi < gn; gi++) {
+ if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
+ return;
+ }
+ }
+ bn++;
+ }
+ }
+}
+
+
+/*
+ * AllocateBGR233Colour() attempts to allocate the given BGR233 colour as a
+ * shared colormap entry, storing its pixel value in the BGR233ToPixel array.
+ * r is from 0 to 7, g from 0 to 7 and b from 0 to 3. It fails either when the
+ * allocation fails or when we would exceed the number of colours specified in
+ * the nColours resource.
+ */
+
+static Bool
+AllocateBGR233Colour(int r, int g, int b)
+{
+ XColor c;
+
+ if (nBGR233ColoursAllocated >= appData.nColours)
+ return False;
+
+ c.red = r * 65535 / 7;
+ c.green = g * 65535 / 7;
+ c.blue = b * 65535 / 3;
+
+ if (!XAllocColor(dpy, cmap, &c))
+ return False;
+
+ BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel;
+
+ nBGR233ColoursAllocated++;
+
+ return True;
+}
diff --git a/krdc/vnc/d3des.c b/krdc/vnc/d3des.c
new file mode 100644
index 00000000..8a358ce6
--- /dev/null
+++ b/krdc/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/krdc/vnc/d3des.h b/krdc/vnc/d3des.h
new file mode 100644
index 00000000..ea3da44c
--- /dev/null
+++ b/krdc/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/krdc/vnc/desktop.c b/krdc/vnc/desktop.c
new file mode 100644
index 00000000..f5a60966
--- /dev/null
+++ b/krdc/vnc/desktop.c
@@ -0,0 +1,1613 @@
+/*
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ * Copyright (C) 2002 Tim Jansen. All Rights Reserved.
+ * Copyright (C) 1999-2001 Anders Lindström
+ *
+ *
+ *
+ * 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.
+ *
+ * tim@tjansen.de: - removed stuff for krdc
+ * - merged with shm.c and misc.c
+ * - added FillRectangle and Sync methods to draw only on
+ * the image
+ * - added Zoom functionality, based on rotation funcs from
+ * SGE by Anders Lindström)
+ * - added support for softcursor encoding
+ *
+ */
+
+/*
+ * desktop.c - functions to deal with "desktop" window.
+ */
+
+#include <X11/Xlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <math.h>
+#include <limits.h>
+#include "vncviewer.h"
+
+static XShmSegmentInfo shminfo;
+static Bool caughtShmError = False;
+static Bool needShmCleanup = False;
+
+static XShmSegmentInfo zoomshminfo;
+static Bool caughtZoomShmError = False;
+static Bool needZoomShmCleanup = False;
+
+static Bool gcInited = False;
+GC gc;
+GC srcGC, dstGC; /* used for debugging copyrect */
+Dimension dpyWidth, dpyHeight;
+
+static XImage *image = NULL;
+Bool useShm = True;
+
+static Bool zoomActive = False;
+static int zoomWidth, zoomHeight;
+static XImage *zoomImage = NULL;
+static Bool useZoomShm = True;
+
+/* for softcursor */
+static char *savedArea = NULL;
+
+typedef enum {
+ SOFTCURSOR_UNDER,
+ SOFTCURSOR_PART_UNDER,
+ SOFTCURSOR_UNAFFECTED
+} SoftCursorState;
+
+typedef int Sint32;
+typedef short Sint16;
+typedef char Sint8;
+typedef unsigned int Uint32;
+typedef unsigned short Uint16;
+typedef unsigned char Uint8;
+
+typedef struct {
+ int w, h;
+ unsigned int pitch;
+ void *pixels;
+ int BytesPerPixel;
+} Surface;
+
+typedef struct {
+ Sint16 x, y;
+ Uint16 w, h;
+} Rect;
+
+static void bgr233cpy(CARD8 *dst, CARD8 *src, int len);
+static void CopyDataToScreenRaw(char *buf, int x, int y, int width, int height);
+static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height);
+static void FillRectangleBGR233(CARD8 buf, int x, int y, int width,int height);
+static int CheckRectangle(int x, int y, int width, int height);
+static SoftCursorState getSoftCursorState(int x, int y, int width, int height);
+static void discardCursorSavedArea(void);
+static void saveCursorSavedArea(void);
+
+static void ZoomInit(void);
+static void transformZoomSrc(int six, int siy, int siw, int sih,
+ int *dix, int *diy, int *diw, int *dih,
+ int srcW, int dstW, int srcH, int dstH);
+static void transformZoomDst(int *six, int *siy, int *siw, int *sih,
+ int dix, int diy, int diw, int dih,
+ int srcW, int dstW, int srcH, int dstH);
+static void ZoomSurfaceSrcCoords(int x, int y, int w, int h,
+ int *dix, int *diy, int *diw, int *dih,
+ Surface * src, Surface * dst);
+static void ZoomSurfaceCoords32(int sx, int sy, int sw, int sh,
+ int dx, int dy, Surface * src, Surface * dst);
+static void sge_transform(Surface *src, Surface *dst, float xscale, float yscale,
+ Uint16 qx, Uint16 qy);
+
+
+void
+DesktopInit(Window win)
+{
+ XGCValues gcv;
+
+ image = CreateShmImage();
+
+ if (!image) {
+ useShm = False;
+ image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
+ si.framebufferWidth, si.framebufferHeight,
+ BitmapPad(dpy), 0);
+
+ image->data = calloc(image->bytes_per_line * image->height, 1);
+ if (!image->data) {
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ }
+
+ gc = XCreateGC(dpy,win,0,NULL);
+
+ gcv.function = GXxor;
+ gcv.foreground = 0x0f0f0f0f;
+ srcGC = XCreateGC(dpy,win,GCFunction|GCForeground,&gcv);
+ gcv.foreground = 0xf0f0f0f0;
+ dstGC = XCreateGC(dpy,win,GCFunction|GCForeground,&gcv);
+ gcInited = True;
+}
+
+/*
+ * DrawScreenRegionX11Thread
+ * Never call from any other desktop.c function, only for X11 thread
+ */
+
+void
+DrawScreenRegionX11Thread(Window win, int x, int y, int width, int height) {
+ zoomActive = False;
+ zoomWidth = 0;
+ zoomHeight = 0;
+
+ if (!image)
+ return;
+
+ if (useShm)
+ XShmPutImage(dpy, win, gc, image, x, y, x, y, width, height, False);
+ else
+ XPutImage(dpy, win, gc, image, x, y, x, y, width, height);
+}
+
+/*
+ * CheckRectangle
+ */
+
+static int CheckRectangle(int x, int y, int width, int height) {
+ if ((x < 0) || (y < 0))
+ return 0;
+
+ if (((x+width) > si.framebufferWidth) || ((y+height) > si.framebufferHeight))
+ return 0;
+
+ return 1;
+}
+
+static
+void bgr233cpy(CARD8 *dst, CARD8 *src, int len) {
+ int i;
+ CARD16 *d16;
+ CARD32 *d32;
+
+ switch (visbpp) {
+ case 8:
+ for (i = 0; i < len; i++)
+ *(dst++) = (CARD8) BGR233ToPixel[*(src++)];
+ break;
+ case 16:
+ d16 = (CARD16*) dst;
+ for (i = 0; i < len; i++)
+ *(d16++) = (CARD16) BGR233ToPixel[*(src++)];
+ break;
+ case 32:
+ d32 = (CARD32*) dst;
+ for (i = 0; i < len; i++)
+ *(d32++) = (CARD32) BGR233ToPixel[*(src++)];
+ break;
+ default:
+ fprintf(stderr, "Unsupported softcursor depth %d\n", visbpp);
+ }
+}
+
+
+/*
+ * CopyDataToScreen.
+ */
+
+void
+CopyDataToScreen(char *buf, int x, int y, int width, int height)
+{
+ SoftCursorState s;
+
+ if (!CheckRectangle(x, y, width, height))
+ return;
+
+ LockFramebuffer();
+ s = getSoftCursorState(x, y, width, height);
+ if (s == SOFTCURSOR_PART_UNDER)
+ undrawCursor();
+
+ if (!appData.useBGR233)
+ CopyDataToScreenRaw(buf, x, y, width, height);
+ else
+ CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height);
+
+ if (s != SOFTCURSOR_UNAFFECTED)
+ drawCursor();
+
+ UnlockFramebuffer();
+ SyncScreenRegion(x, y, width, height);
+}
+
+/*
+ * CopyDataToScreenRaw.
+ */
+
+static void
+CopyDataToScreenRaw(char *buf, int x, int y, int width, int height)
+{
+ int h;
+ int widthInBytes = width * visbpp / 8;
+ int scrWidthInBytes = image->bytes_per_line;
+ char *scr = (image->data + y * scrWidthInBytes
+ + x * visbpp / 8);
+
+ for (h = 0; h < height; h++) {
+ memcpy(scr, buf, widthInBytes);
+ buf += widthInBytes;
+ scr += scrWidthInBytes;
+ }
+}
+
+/*
+ * CopyBGR233ToScreen.
+ */
+
+static void
+CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height)
+{
+ int p, q;
+ int xoff = 7 - (x & 7);
+ int xcur;
+ int fbwb = si.framebufferWidth / 8;
+ CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8;
+ CARD8 *scrt;
+ CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x;
+ CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x;
+ CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x;
+
+ switch (visbpp) {
+
+ /* thanks to Chris Hooper for single bpp support */
+
+ case 1:
+ for (q = 0; q < height; q++) {
+ xcur = xoff;
+ scrt = scr1;
+ for (p = 0; p < width; p++) {
+ *scrt = ((*scrt & ~(1 << xcur))
+ | (BGR233ToPixel[*(buf++)] << xcur));
+
+ if (xcur-- == 0) {
+ xcur = 7;
+ scrt++;
+ }
+ }
+ scr1 += fbwb;
+ }
+ break;
+
+ case 8:
+ for (q = 0; q < height; q++) {
+ for (p = 0; p < width; p++) {
+ *(scr8++) = BGR233ToPixel[*(buf++)];
+ }
+ scr8 += si.framebufferWidth - width;
+ }
+ break;
+
+ case 16:
+ for (q = 0; q < height; q++) {
+ for (p = 0; p < width; p++) {
+ *(scr16++) = BGR233ToPixel[*(buf++)];
+ }
+ scr16 += si.framebufferWidth - width;
+ }
+ break;
+
+ case 32:
+ for (q = 0; q < height; q++) {
+ for (p = 0; p < width; p++) {
+ *(scr32++) = BGR233ToPixel[*(buf++)];
+ }
+ scr32 += si.framebufferWidth - width;
+ }
+ break;
+ }
+}
+
+/*
+ * FillRectangle8.
+ */
+
+void
+FillRectangle8(CARD8 fg, int x, int y, int width, int height)
+{
+ SoftCursorState s;
+
+ if (!CheckRectangle(x, y, width, height))
+ return;
+
+ s = getSoftCursorState(x, y, width, height);
+ if (s == SOFTCURSOR_PART_UNDER)
+ undrawCursor();
+
+ if (!appData.useBGR233) {
+ int h;
+ int widthInBytes = width * visbpp / 8;
+ int scrWidthInBytes = image->bytes_per_line;
+
+ char *scr = (image->data + y * scrWidthInBytes
+ + x * visbpp / 8);
+
+ for (h = 0; h < height; h++) {
+ memset(scr, fg, widthInBytes);
+ scr += scrWidthInBytes;
+ }
+ } else {
+ FillRectangleBGR233(fg, x, y, width, height);
+ }
+
+ if (s != SOFTCURSOR_UNAFFECTED)
+ drawCursor();
+}
+
+/*
+ * FillRectangleBGR233.
+ */
+
+static void
+FillRectangleBGR233(CARD8 fg, int x, int y, int width, int height)
+{
+ int p, q;
+ int xoff = 7 - (x & 7);
+ int xcur;
+ int fbwb = si.framebufferWidth / 8;
+ CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8;
+ CARD8 *scrt;
+ CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x;
+ CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x;
+ CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x;
+
+ unsigned long fg233 = BGR233ToPixel[fg];
+
+ switch (visbpp) {
+
+ /* thanks to Chris Hooper for single bpp support */
+
+ case 1:
+ for (q = 0; q < height; q++) {
+ xcur = xoff;
+ scrt = scr1;
+ for (p = 0; p < width; p++) {
+ *scrt = ((*scrt & ~(1 << xcur))
+ | (fg233 << xcur));
+
+ if (xcur-- == 0) {
+ xcur = 7;
+ scrt++;
+ }
+ }
+ scr1 += fbwb;
+ }
+ break;
+
+ case 8:
+ for (q = 0; q < height; q++) {
+ for (p = 0; p < width; p++) {
+ *(scr8++) = fg233;
+ }
+ scr8 += si.framebufferWidth - width;
+ }
+ break;
+
+ case 16:
+ for (q = 0; q < height; q++) {
+ for (p = 0; p < width; p++) {
+ *(scr16++) = fg233;
+ }
+ scr16 += si.framebufferWidth - width;
+ }
+ break;
+
+ case 32:
+ for (q = 0; q < height; q++) {
+ for (p = 0; p < width; p++) {
+ *(scr32++) = fg233;
+ }
+ scr32 += si.framebufferWidth - width;
+ }
+ break;
+ }
+}
+
+/*
+ * FillRectangle16
+ */
+
+void
+FillRectangle16(CARD16 fg, int x, int y, int width, int height)
+{
+ int i, h;
+ int scrWidthInBytes = image->bytes_per_line;
+
+ char *scr = (image->data + y * scrWidthInBytes
+ + x * visbpp / 8);
+ CARD16 *scr16;
+ SoftCursorState s;
+
+ if (!CheckRectangle(x, y, width, height))
+ return;
+
+ s = getSoftCursorState(x, y, width, height);
+ if (s == SOFTCURSOR_PART_UNDER)
+ undrawCursor();
+
+ for (h = 0; h < height; h++) {
+ scr16 = (CARD16*) scr;
+ for (i = 0; i < width; i++)
+ scr16[i] = fg;
+ scr += scrWidthInBytes;
+ }
+
+ if (s != SOFTCURSOR_UNAFFECTED)
+ drawCursor();
+}
+
+/*
+ * FillRectangle32
+ */
+
+void
+FillRectangle32(CARD32 fg, int x, int y, int width, int height)
+{
+ int i, h;
+ int scrWidthInBytes = image->bytes_per_line;
+ SoftCursorState s;
+
+ char *scr = (image->data + y * scrWidthInBytes
+ + x * visbpp / 8);
+ CARD32 *scr32;
+
+ if (!CheckRectangle(x, y, width, height))
+ return;
+
+ s = getSoftCursorState(x, y, width, height);
+ if (s == SOFTCURSOR_PART_UNDER)
+ undrawCursor();
+
+ for (h = 0; h < height; h++) {
+ scr32 = (CARD32*) scr;
+ for (i = 0; i < width; i++)
+ scr32[i] = fg;
+ scr += scrWidthInBytes;
+ }
+
+ if (s != SOFTCURSOR_UNAFFECTED)
+ drawCursor();
+}
+
+/*
+ * CopyDataFromScreen.
+ */
+
+void
+CopyDataFromScreen(char *buf, int x, int y, int width, int height)
+{
+ int widthInBytes = width * visbpp / 8;
+ int scrWidthInBytes = image->bytes_per_line;
+ char *src = (image->data + y * scrWidthInBytes
+ + x * visbpp / 8);
+ int h;
+
+ if (!CheckRectangle(x, y, width, height))
+ return;
+
+ for (h = 0; h < height; h++) {
+ memcpy(buf, src, widthInBytes);
+ src += scrWidthInBytes;
+ buf += widthInBytes;
+ }
+}
+
+/*
+ * CopyArea
+ */
+
+void
+CopyArea(int srcX, int srcY, int width, int height, int x, int y)
+{
+ int widthInBytes = width * visbpp / 8;
+ SoftCursorState sSrc, sDst;
+
+ LockFramebuffer();
+ sSrc = getSoftCursorState(srcX, srcY, width, height);
+ sDst = getSoftCursorState(x, y, width, height);
+ if ((sSrc != SOFTCURSOR_UNAFFECTED) ||
+ (sDst == SOFTCURSOR_PART_UNDER))
+ undrawCursor();
+
+ if ((srcY+height < y) || (y+height < srcY) ||
+ (srcX+width < x) || (x+width < srcX)) {
+
+ int scrWidthInBytes = image->bytes_per_line;
+ char *src = (image->data + srcY * scrWidthInBytes
+ + srcX * visbpp / 8);
+ char *dst = (image->data + y * scrWidthInBytes
+ + x * visbpp / 8);
+ int h;
+
+ if (!CheckRectangle(srcX, srcY, width, height)) {
+ UnlockFramebuffer();
+ return;
+ }
+ if (!CheckRectangle(x, y, width, height)) {
+ UnlockFramebuffer();
+ return;
+ }
+
+ for (h = 0; h < height; h++) {
+ memcpy(dst, src, widthInBytes);
+ src += scrWidthInBytes;
+ dst += scrWidthInBytes;
+ }
+ }
+ else {
+ char *buf = malloc(widthInBytes*height);
+ if (!buf) {
+ UnlockFramebuffer();
+ fprintf(stderr, "Out of memory, CopyArea impossible\n");
+ return;
+ }
+ CopyDataFromScreen(buf, srcX, srcY, width, height);
+ CopyDataToScreenRaw(buf, x, y, width, height);
+ free(buf);
+ }
+ if ((sSrc != SOFTCURSOR_UNAFFECTED) ||
+ (sDst != SOFTCURSOR_UNAFFECTED))
+ drawCursor();
+ UnlockFramebuffer();
+ SyncScreenRegion(x, y, width, height);
+}
+
+void SyncScreenRegion(int x, int y, int width, int height) {
+ int dx, dy, dw, dh;
+
+ if (zoomActive) {
+ Surface src, dest;
+ src.w = si.framebufferWidth;
+ src.h = si.framebufferHeight;
+ src.pitch = image->bytes_per_line;
+ src.pixels = image->data;
+ src.BytesPerPixel = visbpp / 8;
+ dest.w = zoomWidth;
+ dest.h = zoomHeight;
+ dest.pitch = zoomImage->bytes_per_line;
+ dest.pixels = zoomImage->data;
+ dest.BytesPerPixel = visbpp / 8;
+ ZoomSurfaceSrcCoords(x, y, width, height, &dx, &dy, &dw, &dh, &src, &dest);
+ }
+ else {
+ dx = x; dy = y;
+ dw = width; dh = height;
+ }
+ DrawScreenRegion(dx, dy, dw, dh);
+}
+
+void SyncScreenRegionX11Thread(int x, int y, int width, int height) {
+ int dx, dy, dw, dh;
+
+ if (zoomActive) {
+ Surface src, dest;
+ src.w = si.framebufferWidth;
+ src.h = si.framebufferHeight;
+ src.pitch = image->bytes_per_line;
+ src.pixels = image->data;
+ src.BytesPerPixel = visbpp / 8;
+ dest.w = zoomWidth;
+ dest.h = zoomHeight;
+ dest.pitch = zoomImage->bytes_per_line;
+ dest.pixels = zoomImage->data;
+ dest.BytesPerPixel = visbpp / 8;
+ ZoomSurfaceSrcCoords(x, y, width, height, &dx, &dy, &dw, &dh, &src, &dest);
+ }
+ else {
+ dx = x; dy = y;
+ dw = width; dh = height;
+ }
+ DrawAnyScreenRegionX11Thread(dx, dy, dw, dh);
+}
+
+/*
+ * ToplevelInitBeforeRealization sets the title, geometry and other resources
+ * on the toplevel window.
+ */
+
+void
+ToplevelInit()
+{
+ dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
+ dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
+}
+
+/*
+ * Cleanup - perform shm cleanup operations prior to exiting.
+ */
+
+void
+Cleanup()
+{
+ if (useShm || useZoomShm)
+ ShmCleanup();
+}
+
+void
+ShmCleanup()
+{
+ fprintf(stderr,"ShmCleanup called\n");
+ if (needShmCleanup) {
+ shmdt(shminfo.shmaddr);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+ needShmCleanup = False;
+ }
+ if (needZoomShmCleanup) {
+ shmdt(zoomshminfo.shmaddr);
+ shmctl(zoomshminfo.shmid, IPC_RMID, 0);
+ needZoomShmCleanup = False;
+ }
+}
+
+static int
+ShmCreationXErrorHandler(Display *d, XErrorEvent *e)
+{
+ caughtShmError = True;
+ return 0;
+}
+
+XImage *
+CreateShmImage()
+{
+ XImage *_image;
+ XErrorHandler oldXErrorHandler;
+
+ if (!XShmQueryExtension(dpy))
+ return NULL;
+
+ _image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo,
+ si.framebufferWidth, si.framebufferHeight);
+ if (!_image) return NULL;
+
+ shminfo.shmid = shmget(IPC_PRIVATE,
+ _image->bytes_per_line * _image->height,
+ IPC_CREAT|0777);
+
+ if (shminfo.shmid == -1) {
+ XDestroyImage(_image);
+ return NULL;
+ }
+
+ shminfo.shmaddr = _image->data = shmat(shminfo.shmid, 0, 0);
+
+ if (shminfo.shmaddr == (char *)-1) {
+ XDestroyImage(_image);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+ return NULL;
+ }
+
+ shminfo.readOnly = True;
+
+ oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler);
+ XShmAttach(dpy, &shminfo);
+ XSync(dpy, False);
+ XSetErrorHandler(oldXErrorHandler);
+
+ if (caughtShmError) {
+ XDestroyImage(_image);
+ shmdt(shminfo.shmaddr);
+ shmctl(shminfo.shmid, IPC_RMID, 0);
+ return NULL;
+ }
+
+ needShmCleanup = True;
+
+ fprintf(stderr,"Using shared memory PutImage\n");
+
+ return _image;
+}
+
+void undrawCursor() {
+ int x, y, w, h;
+
+ if ((imageIndex < 0) || !savedArea)
+ return;
+
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &x, &y, &w, &h);
+
+ if ((w < 1) || (h < 1))
+ return;
+
+ CopyDataToScreenRaw(savedArea, x, y, w, h);
+ discardCursorSavedArea();
+}
+
+static void drawCursorImage() {
+ int x, y, w, h, pw, pixelsLeft, processingMask;
+ int skipLeft, skipRight;
+ PointerImage *pi = &pointerImages[imageIndex];
+ CARD8 *img = (CARD8*) pi->image;
+ CARD8 *imgEnd = &img[pi->len];
+ CARD8 *fb;
+
+ /* check whether the source image has ended (image broken) */
+#define CHECK_IMG(x) if (&img[x] > imgEnd) goto imgError
+
+/* check whether the end of the framebuffer has been reached (last line) */
+#define CHECK_END() if ((wl == 0) && (h == 1)) return
+
+/* skip x pixels in the source (x must be < pixelsLeft!) */
+#define SKIP_IMG(x) if ((x > 0) && !processingMask) { \
+ CHECK_END(); \
+ img += pw * x; \
+ CHECK_IMG(0); \
+ }
+
+/* skip x pixels in source and destination */
+#define SKIP_PIXELS(x) { int wl = x; \
+ while (pixelsLeft <= wl) { \
+ wl -= pixelsLeft; \
+ SKIP_IMG(pixelsLeft); \
+ CHECK_END(); \
+ pixelsLeft = *(img++); \
+ CHECK_IMG(0); \
+ processingMask = processingMask ? 0 : 1; \
+ } \
+ pixelsLeft -= wl; \
+ SKIP_IMG(wl); \
+ }
+
+ if (!img)
+ return;
+
+ x = cursorX - pi->hotX;
+ y = cursorY - pi->hotY;
+ w = pi->w;
+ h = pi->h;
+
+ if (!rectsIntersect(x, y, w, h,
+ 0, 0, si.framebufferWidth, si.framebufferHeight)) {
+ fprintf(stderr, "intersect abort\n");
+ return;
+ }
+
+ pw = myFormat.bitsPerPixel / 8;
+ processingMask = 1;
+ pixelsLeft = *(img++);
+
+/* at this point everything is initialized for the macros */
+
+ /* skip/clip bottom lines */
+ if ((y+h) > si.framebufferHeight)
+ h = si.framebufferHeight - y;
+
+ /* Skip invisible top lines */
+ while (y < 0) {
+ SKIP_PIXELS(w);
+ y++;
+ h--;
+ }
+
+ /* calculate left/right clipping */
+ if (x < 0) {
+ skipLeft = -x;
+ w += x;
+ x = 0;
+ }
+ else
+ skipLeft = 0;
+
+ if ((x+w) > si.framebufferWidth) {
+ skipRight = (x+w) - si.framebufferWidth;
+ w = si.framebufferWidth - x;
+ }
+ else
+ skipRight = 0;
+
+ fb = (CARD8*) image->data + y * image->bytes_per_line + x * visbpp / 8;
+
+ /* Paint the thing */
+ while (h > 0) {
+ SKIP_PIXELS(skipLeft);
+
+ {
+ CARD8 *fbx = fb;
+ int wl = w;
+ while (pixelsLeft <= wl) {
+ wl -= pixelsLeft;
+ if ((pixelsLeft > 0) && !processingMask) {
+ int pl = pw * pixelsLeft;
+ CHECK_IMG(pl);
+ if (!appData.useBGR233)
+ memcpy(fbx, img, pl);
+ else
+ bgr233cpy(fbx, img, pixelsLeft);
+ img += pl;
+ }
+
+ CHECK_END();
+ fbx += pixelsLeft * visbpp / 8;
+ pixelsLeft = *(img++);
+
+ CHECK_IMG(0);
+ processingMask = processingMask ? 0 : 1;
+ }
+ pixelsLeft -= wl;
+ if ((wl > 0) && !processingMask) {
+ int pl = pw * wl;
+ CHECK_IMG(pl);
+ if (!appData.useBGR233)
+ memcpy(fbx, img, pl);
+ else
+ bgr233cpy(fbx, img, wl);
+ img += pl;
+ }
+ }
+
+ SKIP_PIXELS(skipRight);
+ fb += image->bytes_per_line;
+ h--;
+ }
+ return;
+
+imgError:
+ fprintf(stderr, "Error in softcursor image %d\n", imageIndex);
+ pointerImages[imageIndex].set = 0;
+}
+
+static void discardCursorSavedArea() {
+ if (savedArea)
+ free(savedArea);
+ savedArea = 0;
+}
+
+static void saveCursorSavedArea() {
+ int x, y, w, h;
+
+ if (imageIndex < 0)
+ return;
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &x, &y, &w, &h);
+ if ((w < 1) || (h < 1))
+ return;
+ discardCursorSavedArea();
+ savedArea = malloc(h*image->bytes_per_line);
+ if (!savedArea) {
+ fprintf(stderr,"malloc failed, saving cursor not possible\n");
+ exit(1);
+ }
+ CopyDataFromScreen(savedArea, x, y, w, h);
+}
+
+void drawCursor() {
+ saveCursorSavedArea();
+ drawCursorImage();
+}
+
+void getBoundingRectCursor(int cx, int cy, int _imageIndex,
+ int *x, int *y, int *w, int *h) {
+ int nx, ny, nw, nh;
+
+ if ((_imageIndex < 0) || !pointerImages[_imageIndex].set) {
+ *x = 0;
+ *y = 0;
+ *w = 0;
+ *h = 0;
+ return;
+ }
+
+ nx = cx - pointerImages[_imageIndex].hotX;
+ ny = cy - pointerImages[_imageIndex].hotY;
+ nw = pointerImages[_imageIndex].w;
+ nh = pointerImages[_imageIndex].h;
+ if (nx < 0) {
+ nw += nx;
+ nx = 0;
+ }
+ if (ny < 0) {
+ nh += ny;
+ ny = 0;
+ }
+ if ((nx+nw) > si.framebufferWidth)
+ nw = si.framebufferWidth - nx;
+ if ((ny+nh) > si.framebufferHeight)
+ nh = si.framebufferHeight - ny;
+ if ((nw <= 0) || (nh <= 0)) {
+ *x = 0;
+ *y = 0;
+ *w = 0;
+ *h = 0;
+ return;
+ }
+
+ *x = nx;
+ *y = ny;
+ *w = nw;
+ *h = nh;
+}
+
+static SoftCursorState getSoftCursorState(int x, int y, int w, int h) {
+ int cx, cy, cw, ch;
+
+ if (imageIndex < 0)
+ return SOFTCURSOR_UNAFFECTED;
+
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &cx, &cy, &cw, &ch);
+
+ if ((cw == 0) || (ch == 0))
+ return SOFTCURSOR_UNAFFECTED;
+
+ if (!rectsIntersect(x, y, w, h, cx, cy, cw, ch))
+ return SOFTCURSOR_UNAFFECTED;
+ if (rectContains(x, y, w, h, cx, cy, cw, ch))
+ return SOFTCURSOR_UNDER;
+ else
+ return SOFTCURSOR_PART_UNDER;
+}
+
+int rectsIntersect(int x, int y, int w, int h,
+ int x2, int y2, int w2, int h2) {
+ if (x2 >= (x+w))
+ return 0;
+ if (y2 >= (y+h))
+ return 0;
+ if ((x2+w2) <= x)
+ return 0;
+ if ((y2+h2) <= y)
+ return 0;
+ return 1;
+}
+
+int rectContains(int outX, int outY, int outW, int outH,
+ int inX, int inY, int inW, int inH) {
+ if (inX < outX)
+ return 0;
+ if (inY < outY)
+ return 0;
+ if ((inX+inW) > (outX+outW))
+ return 0;
+ if ((inY+inH) > (outY+outH))
+ return 0;
+ return 1;
+}
+
+void rectsJoin(int *nx1, int *ny1, int *nw1, int *nh1,
+ int x2, int y2, int w2, int h2) {
+ int ox, oy, ow, oh;
+ ox = *nx1;
+ oy = *ny1;
+ ow = *nw1;
+ oh = *nh1;
+
+ if (x2 < ox) {
+ ow += ox - x2;
+ ox = x2;
+ }
+ if (y2 < oy) {
+ oh += oy - y2;
+ oy = y2;
+ }
+ if ((x2+w2) > (ox+ow))
+ ow = (x2+w2) - ox;
+ if ((y2+h2) > (oy+oh))
+ oh = (y2+h2) - oy;
+
+ *nx1 = ox;
+ *ny1 = oy;
+ *nw1 = ow;
+ *nh1 = oh;
+}
+
+XImage *
+CreateShmZoomImage()
+{
+ XImage *_image;
+ XErrorHandler oldXErrorHandler;
+
+ if (!XShmQueryExtension(dpy))
+ return NULL;
+
+ _image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &zoomshminfo,
+ si.framebufferWidth, si.framebufferHeight);
+ if (!_image) return NULL;
+
+ zoomshminfo.shmid = shmget(IPC_PRIVATE,
+ _image->bytes_per_line * _image->height,
+ IPC_CREAT|0777);
+
+ if (zoomshminfo.shmid == -1) {
+ XDestroyImage(_image);
+ return NULL;
+ }
+
+ zoomshminfo.shmaddr = _image->data = shmat(zoomshminfo.shmid, 0, 0);
+
+ if (zoomshminfo.shmaddr == (char *)-1) {
+ XDestroyImage(_image);
+ shmctl(zoomshminfo.shmid, IPC_RMID, 0);
+ return NULL;
+ }
+
+ zoomshminfo.readOnly = True;
+
+ oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler);
+ XShmAttach(dpy, &zoomshminfo);
+ XSync(dpy, False);
+ XSetErrorHandler(oldXErrorHandler);
+
+ if (caughtZoomShmError) {
+ XDestroyImage(_image);
+ shmdt(zoomshminfo.shmaddr);
+ shmctl(zoomshminfo.shmid, IPC_RMID, 0);
+ return NULL;
+ }
+
+ needZoomShmCleanup = True;
+
+ fprintf(stderr,"Using shared memory PutImage\n");
+
+ return _image;
+}
+
+
+/*
+ * DrawZoomedScreenRegionX11Thread
+ * Never call from any other desktop.c function, only for X11 thread
+ */
+
+void
+DrawZoomedScreenRegionX11Thread(Window win, int zwidth, int zheight,
+ int x, int y, int width, int height) {
+ if (!image)
+ return;
+
+ if (zwidth > si.framebufferWidth)
+ zwidth = si.framebufferWidth;
+ if (zheight > si.framebufferHeight)
+ zheight = si.framebufferHeight;
+
+ if (!zoomActive) {
+ ZoomInit();
+ zoomActive = True;
+ }
+
+ if ((zoomWidth != zwidth) || (zoomHeight != zheight)) {
+ Surface src, dest;
+
+ zoomWidth = zwidth;
+ zoomHeight = zheight;
+
+ src.w = si.framebufferWidth;
+ src.h = si.framebufferHeight;
+ src.pitch = image->bytes_per_line;
+ src.pixels = image->data;
+ src.BytesPerPixel = visbpp / 8;
+ dest.w = zwidth;
+ dest.h = zheight;
+ dest.pitch = zoomImage->bytes_per_line;
+ dest.pixels = zoomImage->data;
+ dest.BytesPerPixel = visbpp / 8;
+ sge_transform(&src, &dest,
+ (float)dest.w/(float)src.w, (float)dest.h/(float)src.h,
+ 0, 0);
+
+ if (useZoomShm)
+ XShmPutImage(dpy, win, gc, zoomImage, 0, 0, 0, 0, zwidth, zheight, False);
+ else
+ XPutImage(dpy, win, gc, zoomImage, 0, 0, 0, 0, zwidth, zheight);
+ return;
+ }
+
+ if (useZoomShm)
+ XShmPutImage(dpy, win, gc, zoomImage, x, y, x, y, width, height, False);
+ else
+ XPutImage(dpy, win, gc, zoomImage, x, y, x, y, width, height);
+}
+
+
+static void
+ZoomInit()
+{
+ if (zoomImage)
+ return;
+
+ zoomImage = CreateShmZoomImage();
+
+ if (!zoomImage) {
+ useZoomShm = False;
+ zoomImage = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
+ si.framebufferWidth, si.framebufferHeight,
+ BitmapPad(dpy), 0);
+
+ zoomImage->data = calloc(zoomImage->bytes_per_line * zoomImage->height, 1);
+ if (!zoomImage->data) {
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ }
+}
+
+static void transformZoomSrc(int six, int siy, int siw, int sih,
+ int *dix, int *diy, int *diw, int *dih,
+ int srcW, int dstW, int srcH, int dstH) {
+ double sx, sy, sw, sh;
+ double dx, dy, dw, dh;
+ double wq, hq;
+
+ sx = six; sy = siy;
+ sw = siw; sh = sih;
+
+ wq = ((double)dstW) / (double) srcW;
+ hq = ((double)dstH) / (double) srcH;
+
+ dx = sx * wq;
+ dy = sy * hq;
+ dw = sw * wq;
+ dh = sh * hq;
+
+ *dix = dx;
+ *diy = dy;
+ *diw = dw+(dx-(int)dx)+0.5;
+ *dih = dh+(dy-(int)dy)+0.5;
+}
+
+static void transformZoomDst(int *six, int *siy, int *siw, int *sih,
+ int dix, int diy, int diw, int dih,
+ int srcW, int dstW, int srcH, int dstH) {
+ double sx, sy, sw, sh;
+ double dx, dy, dw, dh;
+ double wq, hq;
+
+ dx = dix; dy = diy;
+ dw = diw; dh = dih;
+
+ wq = ((double)dstW) / (double) srcW;
+ hq = ((double)dstH) / (double) srcH;
+
+ sx = dx / wq;
+ sy = dy / hq;
+ sw = dw / wq;
+ sh = dh / hq;
+
+ *six = sx;
+ *siy = sy;
+ *siw = sw+(sx-(int)sx)+0.5;
+ *sih = sh+(sy-(int)sy)+0.5;
+}
+
+
+static void ZoomSurfaceSrcCoords(int six, int siy, int siw, int sih,
+ int *dix, int *diy, int *diw, int *dih,
+ Surface * src, Surface * dst)
+{
+ int dx, dy, dw, dh;
+ int sx, sy, sw, sh;
+
+ transformZoomSrc(six, siy, siw, sih,
+ &dx, &dy, &dw, &dh,
+ src->w, dst->w, src->h, dst->h);
+ dx-=2;
+ dy-=2;
+ dw+=4;
+ dh+=4;
+
+ if (dx < 0)
+ dx = 0;
+ if (dy < 0)
+ dy = 0;
+ if (dx+dw > dst->w)
+ dw = dst->w - dx;
+ if (dy+dh > dst->h)
+ dh = dst->h - dy;
+
+ transformZoomDst(&sx, &sy, &sw, &sh,
+ dx, dy, dw, dh,
+ src->w, dst->w, src->h, dst->h);
+
+ if (sx+sw > src->w)
+ sw = src->w - sx;
+ if (sy+sh > src->h)
+ sh = src->h - sy;
+
+ ZoomSurfaceCoords32(sx, sy, sw, sh, dx, dy, src, dst);
+
+ *dix = dx;
+ *diy = dy;
+ *diw = dw;
+ *dih = dh;
+}
+
+static void ZoomSurfaceCoords32(int sx, int sy, int sw, int sh,
+ int dx, int dy,
+ Surface * src, Surface * dst)
+{
+ Surface s2;
+
+ s2 = *src;
+ s2.pixels = ((char*)s2.pixels) + (sx * s2.BytesPerPixel) + (sy * src->pitch);
+ s2.w = sw;
+ s2.h = sh;
+ sge_transform(&s2, dst,
+ (float)dst->w/(float)src->w, (float)dst->h/(float)src->h,
+ dx, dy);
+}
+
+
+#define sge_clip_xmin(pnt) 0
+#define sge_clip_xmax(pnt) pnt->w
+#define sge_clip_ymin(pnt) 0
+#define sge_clip_ymax(pnt) pnt->h
+
+/*==================================================================================
+// Helper function to sge_transform()
+// Returns the bounding box
+//==================================================================================
+*/
+static void _calcRect(Surface *src, Surface *dst, float xscale, float yscale,
+ Uint16 qx, Uint16 qy,
+ Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax)
+{
+ Sint16 x, y, rx, ry;
+ int i;
+
+ /* Clip to src surface */
+ Sint16 sxmin = sge_clip_xmin(src);
+ Sint16 sxmax = sge_clip_xmax(src);
+ Sint16 symin = sge_clip_ymin(src);
+ Sint16 symax = sge_clip_ymax(src);
+ Sint16 sx[5];
+ Sint16 sy[4];
+
+ /* We don't really need fixed-point here
+ * but why not? */
+ Sint32 ictx = (Sint32) (xscale * 8192.0);
+ Sint32 icty = (Sint32) (yscale * 8192.0);
+
+ sx[0] = sxmin;
+ sx[1] = sxmax;
+ sx[2] = sxmin;
+ sx[3] = sxmax;
+ sy[0] = symin;
+ sy[1] = symax;
+ sy[2] = symax;
+ sy[3] = symin;
+
+ /* Calculate the four corner points */
+ for(i=0; i<4; i++){
+ rx = sx[i];
+ ry = sy[i];
+
+ x = (Sint16)(((ictx*rx) >> 13) + qx);
+ y = (Sint16)(((icty*ry) >> 13) + qy);
+
+
+ if(i==0){
+ *xmax = *xmin = x;
+ *ymax = *ymin = y;
+ }else{
+ if(x>*xmax)
+ *xmax=x;
+ else if(x<*xmin)
+ *xmin=x;
+
+ if(y>*ymax)
+ *ymax=y;
+ else if(y<*ymin)
+ *ymin=y;
+ }
+ }
+
+ /* Better safe than sorry...*/
+ *xmin -= 1;
+ *ymin -= 1;
+ *xmax += 1;
+ *ymax += 1;
+
+ /* Clip to dst surface */
+ if( !dst )
+ return;
+ if( *xmin < sge_clip_xmin(dst) )
+ *xmin = sge_clip_xmin(dst);
+ if( *xmax > sge_clip_xmax(dst) )
+ *xmax = sge_clip_xmax(dst);
+ if( *ymin < sge_clip_ymin(dst) )
+ *ymin = sge_clip_ymin(dst);
+ if( *ymax > sge_clip_ymax(dst) )
+ *ymax = sge_clip_ymax(dst);
+}
+
+
+/*==================================================================================
+** Scale by scale and place at position (qx,qy).
+**
+**
+** Developed with the help from Terry Hancock (hancock@earthlink.net)
+**
+**==================================================================================*/
+/* First we need some macros to handle different bpp
+ * I'm sorry about this...
+ */
+#define TRANSFORM(UintXX, DIV) \
+ Sint32 src_pitch=src->pitch/DIV; \
+ Sint32 dst_pitch=dst->pitch/DIV; \
+ UintXX *src_row = (UintXX *)src->pixels; \
+ UintXX *dst_row; \
+\
+ for (y=ymin; y<ymax; y++){ \
+ dy = y - qy; \
+\
+ sx = (Sint32)ctdx; /* Compute source anchor points */ \
+ sy = (Sint32)(cty*dy); \
+\
+ /* Calculate pointer to dst surface */ \
+ dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
+\
+ for (x=xmin; x<xmax; x++){ \
+ rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13); \
+\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if( (rx>=sxmin) && (rx<sxmax) && (ry>=symin) && (ry<symax) ) \
+ *(dst_row + x) = *(src_row + ry*src_pitch + rx); \
+\
+ sx += ctx; /* Incremental transformations */ \
+ } \
+ }
+
+
+/* Interpolated transform */
+#define TRANSFORM_AA(UintXX, DIV) \
+ Sint32 src_pitch=src->pitch/DIV; \
+ Sint32 dst_pitch=dst->pitch/DIV; \
+ UintXX *src_row = (UintXX *)src->pixels; \
+ UintXX *dst_row; \
+ UintXX c1, c2, c3, c4;\
+ Uint32 R, G, B, A=0; \
+ UintXX Rmask = image->red_mask;\
+ UintXX Gmask = image->green_mask;\
+ UintXX Bmask = image->blue_mask;\
+ UintXX Amask = 0;\
+ Uint32 wx, wy;\
+ Uint32 p1, p2, p3, p4;\
+\
+ /*
+ * Interpolation:
+ * We calculate the distances from our point to the four nearest pixels, d1..d4.
+ * d(a,b) = sqrt(a²+b²) ~= 0.707(a+b) (Pythagoras (Taylor) expanded around (0.5;0.5))
+ *
+ * 1 wx 2
+ * *-|-* (+ = our point at (x,y))
+ * | | | (* = the four nearest pixels)
+ * wy --+ | wx = float(x) - int(x)
+ * | | wy = float(y) - int(y)
+ * *---*
+ * 3 4
+ * d1 = d(wx,wy) d2 = d(1-wx,wy) d3 = d(wx,1-wy) d4 = d(1-wx,1-wy)
+ * We now want to weight each pixels importance - it's vicinity to our point:
+ * w1=d4 w2=d3 w3=d2 w4=d1 (Yes it works... just think a bit about it)
+ *
+ * If the pixels have the colors c1..c4 then our point should have the color
+ * c = (w1*c1 + w2*c2 + w3*c3 + w4*c4)/(w1+w2+w3+w4) (the weighted average)
+ * but w1+w2+w3+w4 = 4*0.707 so we might as well write it as
+ * c = p1*c1 + p2*c2 + p3*c3 + p4*c4 where p1..p4 = (w1..w4)/(4*0.707)
+ *
+ * But p1..p4 are fixed point so we can just divide the fixed point constant!
+ * 8192/(4*0.71) = 2897 and we can skip 0.71 too (the division will cancel it everywhere)
+ * 8192/4 = 2048
+ *
+ * 020102: I changed the fixed-point representation for the variables in the weighted average
+ * to 24.7 to avoid problems with 32bit colors. Everything else is still 18.13. This
+ * does however not solve the problem with 32bit RGBA colors...
+ */\
+\
+ Sint32 one = 2048>>6; /* 1 in Fixed-point */ \
+ Sint32 two = 2*2048>>6; /* 2 in Fixed-point */ \
+\
+ for (y=ymin; y<ymax; y++){ \
+ dy = y - qy; \
+\
+ sx = (Sint32)(ctdx); /* Compute source anchor points */ \
+ sy = (Sint32)(cty*dy); \
+\
+ /* Calculate pointer to dst surface */ \
+ dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
+\
+ for (x=xmin; x<xmax; x++){ \
+ rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13); \
+\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if( (rx>=sxmin) && (rx+1<sxmax) && (ry>=symin) && (ry+1<symax) ){ \
+ wx = (sx & 0x00001FFF) >>8; /* (float(x) - int(x)) / 4 */ \
+ wy = (sy & 0x00001FFF) >>8;\
+\
+ p4 = wx+wy;\
+ p3 = one-wx+wy;\
+ p2 = wx+one-wy;\
+ p1 = two-wx-wy;\
+\
+ c1 = *(src_row + ry*src_pitch + rx);\
+ c2 = *(src_row + ry*src_pitch + rx+1);\
+ c3 = *(src_row + (ry+1)*src_pitch + rx);\
+ c4 = *(src_row + (ry+1)*src_pitch + rx+1);\
+\
+ /* Calculate the average */\
+ R = ((p1*(c1 & Rmask) + p2*(c2 & Rmask) + p3*(c3 & Rmask) + p4*(c4 & Rmask))>>7) & Rmask;\
+ G = ((p1*(c1 & Gmask) + p2*(c2 & Gmask) + p3*(c3 & Gmask) + p4*(c4 & Gmask))>>7) & Gmask;\
+ B = ((p1*(c1 & Bmask) + p2*(c2 & Bmask) + p3*(c3 & Bmask) + p4*(c4 & Bmask))>>7) & Bmask;\
+ if(Amask)\
+ A = ((p1*(c1 & Amask) + p2*(c2 & Amask) + p3*(c3 & Amask) + p4*(c4 & Amask))>>7) & Amask;\
+ \
+ *(dst_row + x) = R | G | B | A;\
+ } \
+ sx += ctx; /* Incremental transformations */ \
+ } \
+ }
+
+void sge_transform(Surface *src, Surface *dst, float xscale, float yscale, Uint16 qx, Uint16 qy)
+{
+ Sint32 dy, sx, sy;
+ Sint16 x, y, rx, ry;
+ Rect r;
+
+ Sint32 ctx, cty;
+ Sint16 xmin, xmax, ymin, ymax;
+ Sint16 sxmin, sxmax, symin, symax;
+ Sint32 dx, ctdx;
+
+
+ /* Here we use 18.13 fixed point integer math
+ // Sint32 should have 31 usable bits and one for sign
+ // 2^13 = 8192
+ */
+
+ /* Check scales */
+ Sint32 maxint = (Sint32)(pow(2, sizeof(Sint32)*8 - 1 - 13)); /* 2^(31-13) */
+
+ r.x = r.y = r.w = r.h = 0;
+
+ if( xscale == 0 || yscale == 0)
+ return;
+
+ if( 8192.0/xscale > maxint )
+ xscale = (float)(8192.0/maxint);
+ else if( 8192.0/xscale < -maxint )
+ xscale = (float)(-8192.0/maxint);
+
+ if( 8192.0/yscale > maxint )
+ yscale = (float)(8192.0/maxint);
+ else if( 8192.0/yscale < -maxint )
+ yscale = (float)(-8192.0/maxint);
+
+
+ /* Fixed-point equivalents */
+ ctx = (Sint32)(8192.0/xscale);
+ cty = (Sint32)(8192.0/yscale);
+
+ /* Compute a bounding rectangle */
+ xmin=0; xmax=dst->w; ymin=0; ymax=dst->h;
+ _calcRect(src, dst, xscale, yscale,
+ qx, qy, &xmin, &ymin, &xmax, &ymax);
+
+ /* Clip to src surface */
+ sxmin = sge_clip_xmin(src);
+ sxmax = sge_clip_xmax(src);
+ symin = sge_clip_ymin(src);
+ symax = sge_clip_ymax(src);
+
+ /* Some terms in the transform are constant */
+ dx = xmin - qx;
+ ctdx = ctx*dx;
+
+ /* Use the correct bpp */
+ if( src->BytesPerPixel == dst->BytesPerPixel){
+ switch( src->BytesPerPixel ){
+ case 1: { /* Assuming 8-bpp */
+ TRANSFORM(Uint8, 1)
+ }
+ break;
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ TRANSFORM_AA(Uint16, 2)
+ }
+ break;
+ case 4: { /* Probably 32-bpp */
+ TRANSFORM_AA(Uint32, 4)
+ }
+ break;
+ }
+ }
+}
+
+void freeDesktopResources() {
+ Cleanup();
+ if (image) {
+ XDestroyImage(image);
+ }
+ if (zoomImage) {
+ XDestroyImage(zoomImage);
+ }
+ if (savedArea)
+ free(savedArea);
+
+ if (gcInited) {
+ XFreeGC(dpy, gc);
+ XFreeGC(dpy, srcGC);
+ XFreeGC(dpy, dstGC);
+ }
+
+ caughtShmError = False;
+ needShmCleanup = False;
+ caughtZoomShmError = False;
+ needZoomShmCleanup = False;
+ gcInited = False;
+ image = NULL;
+ useShm = True;
+ zoomActive = False;
+ zoomImage = NULL;
+ useZoomShm = True;
+ savedArea = NULL;
+}
+
+
+/*
+ * ColorRectangle32
+ * Only used for debugging / visualizing output
+ */
+/*
+static void
+ColorRectangle32(XImage *img, CARD32 fg, int x, int y, int width, int height)
+{
+ int i, h;
+ int scrWidthInBytes = img->bytes_per_line;
+ char *scr;
+ CARD32 *scr32;
+
+ if ((!img) || (!img->data))
+ return;
+
+ scr = (img->data + y * scrWidthInBytes + x * 4);
+
+ if (!CheckRectangle(x, y, width, height))
+ return;
+
+ for (h = 0; h < height; h++) {
+ scr32 = (CARD32*) scr;
+ for (i = 0; i < width; i++) {
+ CARD32 n = 0;
+ CARD32 p = scr32[i];
+ if (0xff & fg)
+ n |= ((( 0xff & p)+( 0xff & fg)) >> 2) & 0xff;
+ else
+ n |= (0xff & p);
+ if (0xff00 & fg)
+ n |= ((( 0xff00 & p)+( 0xff00 & fg)) >> 2) & 0xff00;
+ else
+ n |= (0xff00 & p);
+ if (0xff0000 & fg)
+ n |= (((0xff0000 & p)+(0xff0000 & fg)) >> 2) & 0xff0000;
+ else
+ n |= (0xff0000 & p);
+ scr32[i] = n;
+ }
+ scr += scrWidthInBytes;
+ }
+}
+*/
+
diff --git a/krdc/vnc/hextile.c b/krdc/vnc/hextile.c
new file mode 100644
index 00000000..002880af
--- /dev/null
+++ b/krdc/vnc/hextile.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+/*
+ * hextile.c - handle hextile encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP. For
+ * each value of BPP, this file defines a function which handles a hextile
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
+#define CARDBPP CONCAT2E(CARD,BPP)
+#define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
+#define FillRectangleBPP CONCAT2E(FillRectangle,BPP)
+
+static Bool
+HandleHextileBPP (int rx, int ry, int rw, int rh)
+{
+ CARDBPP bg, fg;
+ int i;
+ CARD8 *ptr;
+ int x, y, w, h;
+ int sx, sy, sw, sh;
+ CARD8 subencoding;
+ CARD8 nSubrects;
+
+ 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 (!ReadFromRFBServer((char *)&subencoding, 1))
+ return False;
+
+ if (subencoding & rfbHextileRaw) {
+ if (!ReadFromRFBServer(buffer, w * h * (BPP / 8)))
+ return False;
+
+ CopyDataToScreen(buffer, x, y, w, h);
+ continue;
+ }
+
+ if (subencoding & rfbHextileBackgroundSpecified)
+ if (!ReadFromRFBServer((char *)&bg, sizeof(bg)))
+ return False;
+
+ LockFramebuffer();
+ FillRectangleBPP(bg, x, y, w, h);
+
+ if (subencoding & rfbHextileForegroundSpecified)
+ if (!ReadFromRFBServer((char *)&fg, sizeof(fg))) {
+ UnlockFramebuffer();
+ return False;
+ }
+
+ if (!(subencoding & rfbHextileAnySubrects)) {
+ UnlockFramebuffer();
+ SyncScreenRegion(x, y, w, h);
+ continue;
+ }
+
+ if (!ReadFromRFBServer((char *)&nSubrects, 1)) {
+ UnlockFramebuffer();
+ return False;
+ }
+
+ ptr = (CARD8 *)buffer;
+
+ if (subencoding & rfbHextileSubrectsColoured) {
+ if (!ReadFromRFBServer(buffer, nSubrects * (2 + (BPP / 8)))) {
+ UnlockFramebuffer();
+ return False;
+ }
+
+ for (i = 0; i < nSubrects; i++) {
+ GET_PIXEL(fg, ptr);
+ sx = rfbHextileExtractX(*ptr);
+ sy = rfbHextileExtractY(*ptr);
+ ptr++;
+ sw = rfbHextileExtractW(*ptr);
+ sh = rfbHextileExtractH(*ptr);
+ ptr++;
+ FillRectangleBPP(fg, x+sx, y+sy, sw, sh);
+ }
+
+ } else {
+ if (!ReadFromRFBServer(buffer, nSubrects * 2)) {
+ UnlockFramebuffer();
+ return False;
+ }
+
+ for (i = 0; i < nSubrects; i++) {
+ sx = rfbHextileExtractX(*ptr);
+ sy = rfbHextileExtractY(*ptr);
+ ptr++;
+ sw = rfbHextileExtractW(*ptr);
+ sh = rfbHextileExtractH(*ptr);
+ ptr++;
+ FillRectangleBPP(fg, x+sx, y+sy, sw, sh);
+ }
+ }
+ UnlockFramebuffer();
+ SyncScreenRegion(x, y, w, h);
+ }
+ }
+
+ return True;
+}
diff --git a/krdc/vnc/kvncview.cpp b/krdc/vnc/kvncview.cpp
new file mode 100644
index 00000000..1b6a8de2
--- /dev/null
+++ b/krdc/vnc/kvncview.cpp
@@ -0,0 +1,828 @@
+/***************************************************************************
+ kvncview.cpp - main widget
+ -------------------
+ begin : Thu Dec 20 15:11:42 CET 2001
+ copyright : (C) 2001-2003 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "kvncview.h"
+#include "vncprefs.h"
+#include "vnchostpref.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kpassdlg.h>
+#include <kdialogbase.h>
+#include <kwallet.h>
+
+#include <qdatastream.h>
+#include <dcopclient.h>
+#include <qclipboard.h>
+#include <qbitmap.h>
+#include <qmutex.h>
+#include <qvbox.h>
+#include <qwaitcondition.h>
+
+#include "vncviewer.h"
+
+#include <X11/Xlib.h>
+
+/*
+ * appData is our application-specific data which can be set by the user with
+ * application resource specs. The AppData structure is defined in the header
+ * file.
+ */
+AppData appData;
+bool appDataConfigured = false;
+
+Display* dpy;
+
+static KVncView *kvncview;
+
+//Passwords and KWallet data
+extern KWallet::Wallet *wallet;
+bool useKWallet = false;
+static QCString password;
+static QMutex passwordLock;
+static QWaitCondition passwordWaiter;
+
+const unsigned int MAX_SELECTION_LENGTH = 4096;
+
+
+KVncView::KVncView(QWidget *parent,
+ const char *name,
+ const QString &_host,
+ int _port,
+ const QString &_password,
+ Quality quality,
+ DotCursorState dotCursorState,
+ const QString &encodings) :
+ KRemoteView(parent, name, Qt::WResizeNoErase | Qt::WRepaintNoErase | Qt::WStaticContents),
+ m_cthread(this, m_wthread, m_quitFlag),
+ m_wthread(this, m_quitFlag),
+ m_quitFlag(false),
+ m_enableFramebufferLocking(false),
+ m_scaling(false),
+ m_remoteMouseTracking(false),
+ m_viewOnly(false),
+ m_buttonMask(0),
+ m_host(_host),
+ m_port(_port),
+ m_dontSendCb(false),
+ m_cursorState(dotCursorState)
+{
+ kvncview = this;
+ password = _password.latin1();
+ dpy = qt_xdisplay();
+ setFixedSize(16,16);
+ setFocusPolicy(QWidget::StrongFocus);
+
+ m_cb = QApplication::clipboard();
+ connect(m_cb, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
+ connect(m_cb, SIGNAL(dataChanged()), this, SLOT(clipboardChanged()));
+
+ KStandardDirs *dirs = KGlobal::dirs();
+ QBitmap cursorBitmap(dirs->findResource("appdata",
+ "pics/pointcursor.png"));
+ QBitmap cursorMask(dirs->findResource("appdata",
+ "pics/pointcursormask.png"));
+ m_cursor = QCursor(cursorBitmap, cursorMask);
+
+ if ((quality != QUALITY_UNKNOWN) ||
+ !encodings.isNull())
+ configureApp(quality, encodings);
+}
+
+void KVncView::showDotCursor(DotCursorState state) {
+ if (state == m_cursorState)
+ return;
+
+ m_cursorState = state;
+ showDotCursorInternal();
+}
+
+DotCursorState KVncView::dotCursorState() const {
+ return m_cursorState;
+}
+
+void KVncView::showDotCursorInternal() {
+ switch (m_cursorState) {
+ case DOT_CURSOR_ON:
+ setCursor(m_cursor);
+ break;
+ case DOT_CURSOR_OFF:
+ setCursor(QCursor(Qt::BlankCursor));
+ break;
+ case DOT_CURSOR_AUTO:
+ if (m_enableClientCursor)
+ setCursor(QCursor(Qt::BlankCursor));
+ else
+ setCursor(m_cursor);
+ break;
+ }
+}
+
+QString KVncView::host() {
+ return m_host;
+}
+
+int KVncView::port() {
+ return m_port;
+}
+
+void KVncView::startQuitting() {
+ m_quitFlag = true;
+ m_wthread.kick();
+ m_cthread.kick();
+}
+
+bool KVncView::isQuitting() {
+ return m_quitFlag;
+}
+
+void KVncView::configureApp(Quality q, const QString specialEncodings) {
+ appDataConfigured = true;
+ appData.shareDesktop = 1;
+ appData.viewOnly = 0;
+
+ if (q == QUALITY_LOW) {
+ appData.useBGR233 = 1;
+ appData.encodingsString = "background copyrect softcursor tight zlib hextile raw";
+ appData.compressLevel = -1;
+ appData.qualityLevel = 1;
+ appData.dotCursor = 1;
+ }
+ else if (q == QUALITY_MEDIUM) {
+ appData.useBGR233 = 0;
+ appData.encodingsString = "background copyrect softcursor tight zlib hextile raw";
+ appData.compressLevel = -1;
+ appData.qualityLevel = 7;
+ appData.dotCursor = 1;
+ }
+ else if ((q == QUALITY_HIGH) || (q == QUALITY_UNKNOWN)) {
+ appData.useBGR233 = 0;
+ appData.encodingsString = "copyrect softcursor hextile raw";
+ appData.compressLevel = -1;
+ appData.qualityLevel = 9;
+ appData.dotCursor = 1;
+ }
+
+ if (!specialEncodings.isNull())
+ appData.encodingsString = specialEncodings.latin1();
+
+ appData.nColours = 256;
+ appData.useSharedColours = 1;
+ appData.requestedDepth = 0;
+
+ appData.rawDelay = 0;
+ appData.copyRectDelay = 0;
+
+ if (!appData.dotCursor)
+ m_cursorState = DOT_CURSOR_OFF;
+ showDotCursorInternal();
+}
+
+bool KVncView::checkLocalKRfb() {
+ if ( m_host != "localhost" && !m_host.isEmpty() )
+ return true;
+ DCOPClient *d = KApplication::dcopClient();
+
+ int portNum;
+ QByteArray sdata, rdata;
+ QCString replyType;
+ QDataStream arg(sdata, IO_WriteOnly);
+ arg << QString("krfb");
+ if (!d->call ("kded", "kinetd", "port(QString)", sdata, replyType, rdata))
+ return true;
+
+ if (replyType != "int")
+ return true;
+
+ QDataStream answer(rdata, IO_ReadOnly);
+ answer >> portNum;
+
+ if (m_port != portNum)
+ return true;
+
+ setStatus(REMOTE_VIEW_DISCONNECTED);
+ KMessageBox::error(0,
+ i18n("It is not possible to connect to a local desktop sharing service."),
+ i18n("Connection Failure"));
+ emit disconnectedError();
+ return false;
+}
+
+bool KVncView::editPreferences( HostPrefPtr host )
+{
+ SmartPtr<VncHostPref> hp( host );
+
+ int ci = hp->quality();
+ bool kwallet = hp->useKWallet();
+
+ // show preferences dialog
+ KDialogBase *dlg = new KDialogBase( 0L, "dlg", true,
+ i18n( "VNC Host Preferences for %1" ).arg( host->host() ),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true );
+
+ QVBox *vbox = dlg->makeVBoxMainWidget();
+ VncPrefs *prefs = new VncPrefs( vbox );
+ QWidget *spacer = new QWidget( vbox );
+ vbox->setStretchFactor( spacer, 10 );
+
+ prefs->setQuality( ci );
+ prefs->setShowPrefs(true);
+ prefs->setUseKWallet(kwallet);
+
+ if ( dlg->exec() == QDialog::Rejected )
+ return false;
+
+ ci = prefs->quality();
+ hp->setAskOnConnect(prefs->showPrefs());
+ hp->setQuality(ci);
+ hp->setUseKWallet(prefs->useKWallet());
+
+ delete dlg;
+ return true;
+}
+
+bool KVncView::start() {
+
+ if (!checkLocalKRfb())
+ return false;
+
+ if (!appDataConfigured) {
+
+ HostPreferences *hps = HostPreferences::instance();
+ SmartPtr<VncHostPref> hp =
+ SmartPtr<VncHostPref>(hps->createHostPref(m_host,
+ VncHostPref::VncType));
+ if (hp->askOnConnect()) {
+ if (!editPreferences(hp))
+ return false;
+ hps->sync();
+ }
+
+ int ci = hp->quality();
+
+ Quality quality;
+ if (ci == 0)
+ quality = QUALITY_HIGH;
+ else if (ci == 1)
+ quality = QUALITY_MEDIUM;
+ else if (ci == 2)
+ quality = QUALITY_LOW;
+ else {
+ kdDebug() << "Unknown quality";
+ return false;
+ }
+
+ configureApp(quality);
+ useKWallet = hp->useKWallet();
+ }
+
+ setStatus(REMOTE_VIEW_CONNECTING);
+
+ m_cthread.start();
+ setBackgroundMode(Qt::NoBackground);
+ return true;
+}
+
+KVncView::~KVncView()
+{
+ startQuitting();
+ m_cthread.wait();
+ m_wthread.wait();
+ freeResources();
+}
+
+bool KVncView::supportsLocalCursor() const {
+ return true;
+}
+
+bool KVncView::supportsScaling() const {
+ return true;
+}
+
+bool KVncView::scaling() const {
+ return m_scaling;
+}
+
+bool KVncView::viewOnly() {
+ return m_viewOnly;
+}
+
+QSize KVncView::framebufferSize() {
+ return m_framebufferSize;
+}
+
+void KVncView::setViewOnly(bool s) {
+ m_viewOnly = s;
+
+ if (s)
+ setCursor(Qt::ArrowCursor);
+ else
+ showDotCursorInternal();
+}
+
+void KVncView::enableScaling(bool s) {
+ bool os = m_scaling;
+ m_scaling = s;
+ if (s != os) {
+ if (s) {
+ setMaximumSize(m_framebufferSize);
+ setMinimumSize(m_framebufferSize.width()/16,
+ m_framebufferSize.height()/16);
+ }
+ else
+ setFixedSize(m_framebufferSize);
+ }
+}
+
+void KVncView::paintEvent(QPaintEvent *e) {
+ drawRegion(e->rect().x(),
+ e->rect().y(),
+ e->rect().width(),
+ e->rect().height());
+}
+
+void KVncView::drawRegion(int x, int y, int w, int h) {
+ if (m_scaling)
+ DrawZoomedScreenRegionX11Thread(winId(), width(), height(),
+ x, y, w, h);
+ else
+ DrawScreenRegionX11Thread(winId(), x, y, w, h);
+}
+
+void KVncView::customEvent(QCustomEvent *e)
+{
+ if (e->type() == ScreenRepaintEventType) {
+ ScreenRepaintEvent *sre = (ScreenRepaintEvent*) e;
+ drawRegion(sre->x(), sre->y(),sre->width(), sre->height());
+ }
+ else if (e->type() == ScreenResizeEventType) {
+ ScreenResizeEvent *sre = (ScreenResizeEvent*) e;
+ m_framebufferSize = QSize(sre->width(), sre->height());
+ setFixedSize(m_framebufferSize);
+ emit changeSize(sre->width(), sre->height());
+ }
+ else if (e->type() == DesktopInitEventType) {
+ m_cthread.desktopInit();
+ }
+ else if (e->type() == StatusChangeEventType) {
+ StatusChangeEvent *sce = (StatusChangeEvent*) e;
+ setStatus(sce->status());
+ if (m_status == REMOTE_VIEW_CONNECTED) {
+ emit connected();
+ setFocus();
+ setMouseTracking(true);
+ }
+ else if (m_status == REMOTE_VIEW_DISCONNECTED) {
+ setMouseTracking(false);
+ emit disconnected();
+ }
+ else if (m_status == REMOTE_VIEW_PREPARING) {
+ //Login was successfull: Write KWallet password if necessary.
+ if ( useKWallet && !password.isNull() && wallet && wallet->isOpen() && !wallet->hasEntry(host())) {
+ wallet->writePassword(host(), password);
+ }
+ delete wallet; wallet=0;
+ }
+ }
+ else if (e->type() == PasswordRequiredEventType) {
+ emit showingPasswordDialog(true);
+
+ if (KPasswordDialog::getPassword(password, i18n("Access to the system requires a password.")) != KPasswordDialog::Accepted)
+ password = QCString();
+
+ emit showingPasswordDialog(false);
+
+ passwordLock.lock(); // to guarantee that thread is waiting
+ passwordWaiter.wakeAll();
+ passwordLock.unlock();
+ }
+ else if (e->type() == WalletOpenEventType) {
+ QString krdc_folder = "KRDC-VNC";
+ emit showingPasswordDialog(true); //Bad things happen if you don't do this.
+
+ // Bugfix: Check if wallet has been closed by an outside source
+ if ( wallet && !wallet->isOpen() ) {
+ delete wallet; wallet=0;
+ }
+
+ // Do we need to open the wallet?
+ if ( !wallet ) {
+ QString walletName = KWallet::Wallet::NetworkWallet();
+ wallet = KWallet::Wallet::openWallet(walletName);
+ }
+
+ if (wallet && wallet->isOpen()) {
+ bool walletOK = wallet->hasFolder(krdc_folder);
+ if (walletOK == false) {
+ walletOK = wallet->createFolder(krdc_folder);
+ }
+
+ if (walletOK == true) {
+ wallet->setFolder(krdc_folder);
+ QString newPass;
+ if ( wallet->hasEntry(kvncview->host()) && !wallet->readPassword(kvncview->host(), newPass) ) {
+ password=newPass.latin1();
+ }
+ }
+ }
+
+ passwordLock.lock(); // to guarantee that thread is waiting
+ passwordWaiter.wakeAll();
+ passwordLock.unlock();
+
+ emit showingPasswordDialog(false);
+ }
+ else if (e->type() == FatalErrorEventType) {
+ FatalErrorEvent *fee = (FatalErrorEvent*) e;
+ setStatus(REMOTE_VIEW_DISCONNECTED);
+ switch (fee->errorCode()) {
+ case ERROR_CONNECTION:
+ KMessageBox::error(0,
+ i18n("Connection attempt to host failed."),
+ i18n("Connection Failure"));
+ break;
+ case ERROR_PROTOCOL:
+ KMessageBox::error(0,
+ i18n("Remote host is using an incompatible protocol."),
+ i18n("Connection Failure"));
+ break;
+ case ERROR_IO:
+ KMessageBox::error(0,
+ i18n("The connection to the host has been interrupted."),
+ i18n("Connection Failure"));
+ break;
+ case ERROR_SERVER_BLOCKED:
+ KMessageBox::error(0,
+ i18n("Connection failed. The server does not accept new connections."),
+ i18n("Connection Failure"));
+ break;
+ case ERROR_NAME:
+ KMessageBox::error(0,
+ i18n("Connection failed. A server with the given name cannot be found."),
+ i18n("Connection Failure"));
+ break;
+ case ERROR_NO_SERVER:
+ KMessageBox::error(0,
+ i18n("Connection failed. No server running at the given address and port."),
+ i18n("Connection Failure"));
+ break;
+ case ERROR_AUTHENTICATION:
+ //Login failed: Remove wallet entry if there is one.
+ if ( useKWallet && wallet && wallet->isOpen() && wallet->hasEntry(host()) ) {
+ wallet->removeEntry(host());
+ }
+ KMessageBox::error(0,
+ i18n("Authentication failed. Connection aborted."),
+ i18n("Authentication Failure"));
+ break;
+ default:
+ KMessageBox::error(0,
+ i18n("Unknown error."),
+ i18n("Unknown Error"));
+ break;
+ }
+ emit disconnectedError();
+ }
+ else if (e->type() == BeepEventType) {
+ QApplication::beep();
+ }
+ else if (e->type() == ServerCutEventType) {
+ ServerCutEvent *sce = (ServerCutEvent*) e;
+ QString ctext = QString::fromUtf8(sce->bytes(), sce->length());
+ m_dontSendCb = true;
+ m_cb->setText(ctext, QClipboard::Clipboard);
+ m_cb->setText(ctext, QClipboard::Selection);
+ m_dontSendCb = false;
+ }
+ else if (e->type() == MouseStateEventType) {
+ MouseStateEvent *mse = (MouseStateEvent*) e;
+ emit mouseStateChanged(mse->x(), mse->y(), mse->buttonMask());
+ bool show = m_plom.handlePointerEvent(mse->x(), mse->y());
+ if (m_cursorState != DOT_CURSOR_ON)
+ showDotCursor(show ? DOT_CURSOR_AUTO : DOT_CURSOR_OFF);
+ }
+}
+
+void KVncView::mouseEvent(QMouseEvent *e) {
+ if (m_status != REMOTE_VIEW_CONNECTED)
+ return;
+ if (m_viewOnly)
+ return;
+
+ if ( e->type() != QEvent::MouseMove ) {
+ if ( (e->type() == QEvent::MouseButtonPress) ||
+ (e->type() == QEvent::MouseButtonDblClick)) {
+ if ( e->button() & LeftButton )
+ m_buttonMask |= 0x01;
+ if ( e->button() & MidButton )
+ m_buttonMask |= 0x02;
+ if ( e->button() & RightButton )
+ m_buttonMask |= 0x04;
+ }
+ else if ( e->type() == QEvent::MouseButtonRelease ) {
+ if ( e->button() & LeftButton )
+ m_buttonMask &= 0xfe;
+ if ( e->button() & MidButton )
+ m_buttonMask &= 0xfd;
+ if ( e->button() & RightButton )
+ m_buttonMask &= 0xfb;
+ }
+ }
+
+ int x = e->x();
+ int y = e->y();
+ m_plom.registerPointerState(x, y);
+ if (m_scaling) {
+ x = (x * m_framebufferSize.width()) / width();
+ y = (y * m_framebufferSize.height()) / height();
+ }
+ m_wthread.queueMouseEvent(x, y, m_buttonMask);
+
+ if (m_enableClientCursor)
+ DrawCursorX11Thread(x, y); // in rfbproto.c
+}
+
+void KVncView::mousePressEvent(QMouseEvent *e) {
+ mouseEvent(e);
+ e->accept();
+}
+
+void KVncView::mouseDoubleClickEvent(QMouseEvent *e) {
+ mouseEvent(e);
+ e->accept();
+}
+
+void KVncView::mouseReleaseEvent(QMouseEvent *e) {
+ mouseEvent(e);
+ e->accept();
+}
+
+void KVncView::mouseMoveEvent(QMouseEvent *e) {
+ mouseEvent(e);
+ e->ignore();
+}
+
+void KVncView::wheelEvent(QWheelEvent *e) {
+ if (m_status != REMOTE_VIEW_CONNECTED)
+ return;
+ if (m_viewOnly)
+ return;
+
+ int eb = 0;
+ if ( e->delta() < 0 )
+ eb |= 0x10;
+ else
+ eb |= 0x8;
+
+ int x = e->pos().x();
+ int y = e->pos().y();
+ if (m_scaling) {
+ x = (x * m_framebufferSize.width()) / width();
+ y = (y * m_framebufferSize.height()) / height();
+ }
+ m_wthread.queueMouseEvent(x, y, eb|m_buttonMask);
+ m_wthread.queueMouseEvent(x, y, m_buttonMask);
+ e->accept();
+}
+
+void KVncView::pressKey(XEvent *xe) {
+ KKeyNative k(xe);
+ uint mod = k.mod();
+ if (mod & KKeyNative::modX(KKey::SHIFT))
+ m_wthread.queueKeyEvent(XK_Shift_L, true);
+ if (mod & KKeyNative::modX(KKey::CTRL))
+ m_wthread.queueKeyEvent(XK_Control_L, true);
+ if (mod & KKeyNative::modX(KKey::ALT))
+ m_wthread.queueKeyEvent(XK_Alt_L, true);
+ if (mod & KKeyNative::modX(KKey::WIN))
+ m_wthread.queueKeyEvent(XK_Meta_L, true);
+
+ m_wthread.queueKeyEvent(k.sym(), true);
+ m_wthread.queueKeyEvent(k.sym(), false);
+
+ if (mod & KKeyNative::modX(KKey::WIN))
+ m_wthread.queueKeyEvent(XK_Meta_L, false);
+ if (mod & KKeyNative::modX(KKey::ALT))
+ m_wthread.queueKeyEvent(XK_Alt_L, false);
+ if (mod & KKeyNative::modX(KKey::CTRL))
+ m_wthread.queueKeyEvent(XK_Control_L, false);
+ if (mod & KKeyNative::modX(KKey::SHIFT))
+ m_wthread.queueKeyEvent(XK_Shift_L, false);
+
+ m_mods.clear();
+}
+
+bool KVncView::x11Event(XEvent *e) {
+ bool pressed;
+ if (e->type == KeyPress)
+ pressed = true;
+ else if (e->type == KeyRelease)
+ pressed = false;
+ else
+ return QWidget::x11Event(e);
+
+ if (!m_viewOnly) {
+ unsigned int s = KKeyNative(e).sym();
+
+ switch (s) {
+ case XK_Meta_L:
+ case XK_Alt_L:
+ case XK_Control_L:
+ case XK_Shift_L:
+ case XK_Meta_R:
+ case XK_Alt_R:
+ case XK_Control_R:
+ case XK_Shift_R:
+ if (pressed)
+ m_mods[s] = true;
+ else if (m_mods.contains(s))
+ m_mods.remove(s);
+ else
+ unpressModifiers();
+ }
+ m_wthread.queueKeyEvent(s, pressed);
+ }
+ return true;
+}
+
+void KVncView::unpressModifiers() {
+ QValueList<unsigned int> keys = m_mods.keys();
+ QValueList<unsigned int>::const_iterator it = keys.begin();
+ while (it != keys.end()) {
+ m_wthread.queueKeyEvent(*it, false);
+ it++;
+ }
+ m_mods.clear();
+}
+
+void KVncView::focusOutEvent(QFocusEvent *) {
+ unpressModifiers();
+}
+
+QSize KVncView::sizeHint() {
+ return maximumSize();
+}
+
+void KVncView::setRemoteMouseTracking(bool s) {
+ m_remoteMouseTracking = s;
+}
+
+bool KVncView::remoteMouseTracking() {
+ return m_remoteMouseTracking;
+}
+
+void KVncView::clipboardChanged() {
+ if (m_status != REMOTE_VIEW_CONNECTED)
+ return;
+
+ if (m_cb->ownsClipboard() || m_dontSendCb)
+ return;
+
+ QString text = m_cb->text(QClipboard::Clipboard);
+ if (text.length() > MAX_SELECTION_LENGTH)
+ return;
+
+ m_wthread.queueClientCut(text);
+}
+
+void KVncView::selectionChanged() {
+ if (m_status != REMOTE_VIEW_CONNECTED)
+ return;
+
+ if (m_cb->ownsSelection() || m_dontSendCb)
+ return;
+
+ QString text = m_cb->text(QClipboard::Selection);
+ if (text.length() > MAX_SELECTION_LENGTH)
+ return;
+
+ m_wthread.queueClientCut(text);
+}
+
+
+void KVncView::lockFramebuffer() {
+ if (m_enableFramebufferLocking)
+ m_framebufferLock.lock();
+}
+
+void KVncView::unlockFramebuffer() {
+ if (m_enableFramebufferLocking)
+ m_framebufferLock.unlock();
+}
+
+void KVncView::enableClientCursor(bool enable) {
+ if (enable) {
+ m_enableFramebufferLocking = true; // cant be turned off
+ }
+ m_enableClientCursor = enable;
+ lockFramebuffer();
+ showDotCursorInternal();
+ unlockFramebuffer();
+}
+
+/*!
+ \brief Get a password for this host.
+ Tries to get a password from the url or wallet if at all possible. If
+ both of these fail, it then asks the user to enter a password.
+ \note Lots of dialogs can be popped up during this process. The thread
+ locks and signals are there to protect against deadlocks and other
+ horribleness. Be careful making changes here.
+*/
+int getPassword(char *passwd, int pwlen) {
+ int retV = 0;
+
+ //Prepare the system
+ passwordLock.lock();
+
+ //Try #1: Did the user give a password in the URL?
+ if (!password.isNull()) {
+ retV = 1; //got it!
+ }
+
+ //Try #2: Is there something in the wallet?
+ if ( !retV && useKWallet ) {
+ QApplication::postEvent(kvncview, new WalletOpenEvent());
+ passwordWaiter.wait(&passwordLock); //block
+ if (!password.isNull()) retV = 1; //got it!
+ }
+
+ //Last try: Ask the user
+ if (!retV) {
+ QApplication::postEvent(kvncview, new PasswordRequiredEvent());
+ passwordWaiter.wait(&passwordLock); //block
+ if (!password.isNull()) retV = 1; //got it!
+ }
+
+ //Process the password if we got it, clear it if we didn't
+ if (retV) {
+ strncpy(passwd, (const char*)password, pwlen);
+ } else {
+ passwd[0] = 0;
+ }
+
+ //Pack up and go home
+ passwordLock.unlock();
+ if (!retV) kvncview->startQuitting();
+
+ return retV;
+}
+
+extern int isQuitFlagSet() {
+ return kvncview->isQuitting() ? 1 : 0;
+}
+
+extern void DrawScreenRegion(int x, int y, int width, int height) {
+/* KApplication::kApplication()->lock();
+ kvncview->drawRegion(x, y, width, height);
+ KApplication::kApplication()->unlock();
+*/
+ QApplication::postEvent(kvncview, new ScreenRepaintEvent(x, y, width, height));
+}
+
+// call only from x11 thread!
+extern void DrawAnyScreenRegionX11Thread(int x, int y, int width, int height) {
+ kvncview->drawRegion(x, y, width, height);
+}
+
+extern void EnableClientCursor(int enable) {
+ kvncview->enableClientCursor(enable);
+}
+
+extern void LockFramebuffer() {
+ kvncview->lockFramebuffer();
+}
+
+extern void UnlockFramebuffer() {
+ kvncview->unlockFramebuffer();
+}
+
+extern void beep() {
+ QApplication::postEvent(kvncview, new BeepEvent());
+}
+
+extern void newServerCut(char *bytes, int length) {
+ QApplication::postEvent(kvncview, new ServerCutEvent(bytes, length));
+}
+
+extern void postMouseEvent(int x, int y, int buttonMask) {
+ QApplication::postEvent(kvncview, new MouseStateEvent(x, y, buttonMask));
+}
+
+#include "kvncview.moc"
diff --git a/krdc/vnc/kvncview.h b/krdc/vnc/kvncview.h
new file mode 100644
index 00000000..1b961f3d
--- /dev/null
+++ b/krdc/vnc/kvncview.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+ kvncview.h - widget that shows the vnc client
+ -------------------
+ begin : Thu Dec 20 15:11:42 CET 2001
+ copyright : (C) 2001-2003 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KVNCVIEW_H
+#define KVNCVIEW_H
+
+#include "kremoteview.h"
+#include <qcursor.h>
+#include <qmap.h>
+
+#include "pointerlatencyometer.h"
+#include "hostpreferences.h"
+#include "vnctypes.h"
+#include "threads.h"
+
+class QClipBoard;
+
+class KVncView : public KRemoteView
+{
+ Q_OBJECT
+private:
+ ControllerThread m_cthread;
+ WriterThread m_wthread;
+ volatile bool m_quitFlag; // if set: all threads should die ASAP
+ QMutex m_framebufferLock;
+ bool m_enableFramebufferLocking;
+ bool m_enableClientCursor;
+
+ QSize m_framebufferSize;
+ bool m_scaling;
+ bool m_remoteMouseTracking;
+ bool m_viewOnly;
+
+ int m_buttonMask;
+ QMap<unsigned int,bool> m_mods;
+
+ QString m_host;
+ int m_port;
+
+ QClipboard *m_cb;
+ bool m_dontSendCb;
+ QCursor m_cursor;
+ DotCursorState m_cursorState;
+ PointerLatencyOMeter m_plom;
+
+ void mouseEvent(QMouseEvent*);
+ unsigned long toKeySym(QKeyEvent *k);
+ bool checkLocalKRfb();
+ void paintMessage(const QString &msg);
+ void showDotCursorInternal();
+ void unpressModifiers();
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void customEvent(QCustomEvent*);
+ void mousePressEvent(QMouseEvent*);
+ void mouseDoubleClickEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+ void mouseMoveEvent(QMouseEvent*);
+ void wheelEvent(QWheelEvent *);
+ void focusOutEvent(QFocusEvent *);
+ bool x11Event(XEvent*);
+
+public:
+ KVncView(QWidget* parent=0, const char *name=0,
+ const QString &host = QString(""), int port = 5900,
+ const QString &password = QString::null,
+ Quality quality = QUALITY_UNKNOWN,
+ DotCursorState dotCursorState = DOT_CURSOR_AUTO,
+ const QString &encodings = QString::null);
+ ~KVncView();
+ QSize sizeHint();
+ void drawRegion(int x, int y, int w, int h);
+ void lockFramebuffer();
+ void unlockFramebuffer();
+ void enableClientCursor(bool enable);
+ virtual bool scaling() const;
+ virtual bool supportsScaling() const;
+ virtual bool supportsLocalCursor() const;
+ virtual QSize framebufferSize();
+ void setRemoteMouseTracking(bool s);
+ bool remoteMouseTracking();
+ void configureApp(Quality q, const QString specialEncodings = QString::null);
+ void showDotCursor(DotCursorState state);
+ DotCursorState dotCursorState() const;
+ virtual void startQuitting();
+ virtual bool isQuitting();
+ virtual QString host();
+ virtual int port();
+ virtual bool start();
+
+ virtual bool viewOnly();
+
+ static bool editPreferences( HostPrefPtr );
+
+public slots:
+ virtual void enableScaling(bool s);
+ virtual void setViewOnly(bool s);
+ virtual void pressKey(XEvent *k);
+
+
+private slots:
+ void clipboardChanged();
+ void selectionChanged();
+};
+
+#endif
diff --git a/krdc/vnc/pointerlatencyometer.h b/krdc/vnc/pointerlatencyometer.h
new file mode 100644
index 00000000..559536b2
--- /dev/null
+++ b/krdc/vnc/pointerlatencyometer.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ pointerlatencyometer.h - measuring pointer latency
+ -------------------
+ begin : Wed Jun 30 12:04:44 CET 2002
+ copyright : (C) 2002-2003 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qdatetime.h>
+#include <kdebug.h>
+
+struct PointerState {
+ int x, y;
+ QTime timestamp;
+};
+
+class PointerLatencyOMeter {
+private:
+ enum { stateCapacity = 30, maximumLatency = 1000 };
+ PointerState states[stateCapacity];
+ int firstState, stateNum;
+ float last3Latency, last20Latency;
+
+public:
+ PointerLatencyOMeter() :
+ firstState(0),
+ stateNum(0),
+ last3Latency(125),
+ last20Latency(25) {
+ }
+
+ // registers a client pointer state
+ void registerPointerState(int x, int y) {
+ if (stateNum == stateCapacity)
+ stateNum--;
+ if (firstState == 0)
+ firstState = stateCapacity-1;
+ else
+ firstState--;
+ states[firstState].x = x;
+ states[firstState].y = y;
+ states[firstState].timestamp.start();
+ stateNum++;
+ }
+
+ /* Returns true if pointer should be visible */
+ bool registerLatency(int msecs) {
+ last3Latency = ((last3Latency * 2.0) + msecs) / 3.0;
+ last20Latency = ((last20Latency * 19.0) + msecs) / 20.0;
+
+ if (msecs >= maximumLatency)
+ return true;
+ if (last3Latency > (1000/4))
+ return true;
+ return last20Latency > (1000/12);
+ }
+
+ // Called with server-side coordinates.
+ // Returns true if pointer should be visible
+ bool handlePointerEvent(int x, int y) {
+ for (int i = stateNum-1; i >= 0; i--) {
+ int idx = (i+firstState) % stateCapacity;
+ if ((states[idx].x != x) ||
+ (states[idx].y != y))
+ continue;
+
+ stateNum = i;
+ int l = states[idx].timestamp.elapsed();
+ return registerLatency((l > maximumLatency) ? maximumLatency : l);
+ }
+ return true;
+ }
+
+};
diff --git a/krdc/vnc/rfbproto.c b/krdc/vnc/rfbproto.c
new file mode 100644
index 00000000..e9ed5764
--- /dev/null
+++ b/krdc/vnc/rfbproto.c
@@ -0,0 +1,1335 @@
+/*
+ * Copyright (C) 2002, Tim Jansen. All Rights Reserved.
+ * Copyright (C) 2000-2002 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.c - functions to deal with client side of RFB protocol.
+ * tim@tjansen.de: - added softcursor encoding
+ * - changed various things for krdc
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include "vncviewer.h"
+#include "vncauth.h"
+#include <zlib.h>
+#include <jpeglib.h>
+
+static Bool HandleHextile8(int rx, int ry, int rw, int rh);
+static Bool HandleHextile16(int rx, int ry, int rw, int rh);
+static Bool HandleHextile32(int rx, int ry, int rw, int rh);
+static Bool HandleZlib8(int rx, int ry, int rw, int rh);
+static Bool HandleZlib16(int rx, int ry, int rw, int rh);
+static Bool HandleZlib32(int rx, int ry, int rw, int rh);
+static Bool HandleTight8(int rx, int ry, int rw, int rh);
+static Bool HandleTight16(int rx, int ry, int rw, int rh);
+static Bool HandleTight32(int rx, int ry, int rw, int rh);
+
+static long ReadCompactLen (void);
+
+static void JpegInitSource(j_decompress_ptr cinfo);
+static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
+static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
+static void JpegTermSource(j_decompress_ptr cinfo);
+static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
+ int compressedLen);
+
+
+#define RGB24_TO_PIXEL(bpp,r,g,b) \
+ ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \
+ << myFormat.redShift | \
+ (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \
+ << myFormat.greenShift | \
+ (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \
+ << myFormat.blueShift)
+
+int rfbsock;
+char *desktopName;
+rfbPixelFormat myFormat;
+rfbServerInitMsg si;
+
+int endianTest = 1;
+
+/*
+ * Softcursor variables
+ */
+
+int cursorX, cursorY;
+int imageIndex = -1;
+
+PointerImage pointerImages[rfbSoftCursorMaxImages];
+
+
+/* Hextile assumes it is big enough to hold 16 * 16 * 32 bits.
+ Tight encoding assumes BUFFER_SIZE is at least 16384 bytes. */
+
+#define BUFFER_SIZE (16384)
+static char buffer[BUFFER_SIZE];
+
+
+/* The zlib encoding requires expansion/decompression/deflation of the
+ compressed data in the "buffer" above into another, result buffer.
+ However, the size of the result buffer can be determined precisely
+ based on the bitsPerPixel, height and width of the rectangle. We
+ allocate this buffer one time to be the full size of the buffer. */
+
+static int raw_buffer_size = -1;
+static char *raw_buffer = NULL;
+
+static z_stream decompStream;
+static Bool decompStreamInited = False;
+
+
+/*
+ * Variables for the ``tight'' encoding implementation.
+ */
+
+/* Separate buffer for compressed data. */
+#define ZLIB_BUFFER_SIZE 512
+static char zlib_buffer[ZLIB_BUFFER_SIZE];
+
+/* Four independent compression streams for zlib library. */
+static z_stream zlibStream[4];
+static Bool zlibStreamActive[4] = {
+ False, False, False, False
+};
+
+/* Filter stuff. Should be initialized by filter initialization code. */
+static Bool cutZeros;
+static int rectWidth, rectColors;
+static char tightPalette[256*4];
+static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
+
+/* JPEG decoder state. */
+static Bool jpegError;
+
+/* Maximum length for the cut buffer (16 MB)*/
+#define MAX_CUTBUFFER (1024*1024*16)
+
+/* Maximum length for the strings (64 kB)*/
+#define MAX_STRING (1024*64)
+
+/* Maximum length for the strings (32 MB)*/
+#define MAX_JPEG_SIZE (1024*1024*32)
+
+
+/*
+ * ConnectToRFBServer.
+ */
+
+int
+ConnectToRFBServer(const char *hostname, int port)
+{
+ unsigned int host;
+
+ if (!StringToIPAddr(hostname, &host)) {
+ fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname);
+ return -(int)INIT_NAME_RESOLUTION_FAILURE;
+ }
+
+ rfbsock = ConnectToTcpAddr(host, port);
+ if (rfbsock < 0) {
+ fprintf(stderr,"Unable to connect to VNC server\n");
+ }
+
+ return rfbsock;
+}
+
+
+/*
+ * InitialiseRFBConnection.
+ */
+
+enum InitStatus
+InitialiseRFBConnection()
+{
+ rfbProtocolVersionMsg pv;
+ int major,minor;
+ CARD32 authScheme, reasonLen, authResult;
+ char *reason;
+ CARD8 challenge[CHALLENGESIZE];
+ char passwd[9];
+ int i;
+ rfbClientInitMsg ci;
+
+ /* if the connection is immediately closed, don't report anything, so
+ that pmw's monitor can make test connections */
+
+ if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) return INIT_SERVER_BLOCKED;
+
+ errorMessageOnReadFailure = True;
+
+ pv[sz_rfbProtocolVersionMsg] = 0;
+
+ if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
+ fprintf(stderr,"Not a valid VNC server\n");
+ return INIT_PROTOCOL_FAILURE;
+ }
+
+ fprintf(stderr,"VNC server supports protocol version %d.%d (viewer %d.%d)\n",
+ major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+ major = rfbProtocolMajorVersion;
+ minor = rfbProtocolMinorVersion;
+
+ sprintf(pv,rfbProtocolVersionFormat,major,minor);
+
+ if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) return INIT_CONNECTION_FAILED;
+
+ if (!ReadFromRFBServer((char *)&authScheme, 4)) return INIT_CONNECTION_FAILED;
+
+ authScheme = Swap32IfLE(authScheme);
+
+ switch (authScheme) {
+
+ case rfbConnFailed:
+ if (!ReadFromRFBServer((char *)&reasonLen, 4)) return INIT_CONNECTION_FAILED;
+ reasonLen = Swap32IfLE(reasonLen);
+
+ if (reasonLen > MAX_STRING) {
+ fprintf(stderr, "Connection failure reason too long.\n");
+ return INIT_CONNECTION_FAILED;
+ }
+
+ reason = malloc(reasonLen);
+ if (!reason)
+ return INIT_CONNECTION_FAILED;
+
+ if (!ReadFromRFBServer(reason, reasonLen)) return INIT_CONNECTION_FAILED;
+
+ fprintf(stderr,"VNC connection failed: %.*s\n",(int)reasonLen, reason);
+ free(reason);
+ return INIT_CONNECTION_FAILED;
+
+ case rfbNoAuth:
+ fprintf(stderr,"No authentication needed\n");
+ break;
+
+ case rfbVncAuth:
+ if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) return INIT_CONNECTION_FAILED;
+
+ if (!getPassword(passwd, 8))
+ return INIT_ABORTED;
+
+ passwd[8] = '\0';
+
+ vncEncryptBytes(challenge, passwd);
+
+ /* Lose the password from memory */
+ for (i = strlen(passwd); i >= 0; i--) {
+ passwd[i] = '\0';
+ }
+
+ if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) return INIT_CONNECTION_FAILED;
+
+ if (!ReadFromRFBServer((char *)&authResult, 4)) return INIT_CONNECTION_FAILED;
+
+ authResult = Swap32IfLE(authResult);
+
+ switch (authResult) {
+ case rfbVncAuthOK:
+ fprintf(stderr,"VNC authentication succeeded\n");
+ break;
+ case rfbVncAuthFailed:
+ fprintf(stderr,"VNC authentication failed\n");
+ return INIT_AUTHENTICATION_FAILED;
+ case rfbVncAuthTooMany:
+ fprintf(stderr,"VNC authentication failed - too many tries\n");
+ return INIT_AUTHENTICATION_FAILED;
+ default:
+ fprintf(stderr,"Unknown VNC authentication result: %d\n",
+ (int)authResult);
+ return INIT_CONNECTION_FAILED;
+ }
+ break;
+
+ default:
+ fprintf(stderr,"Unknown authentication scheme from VNC server: %d\n",
+ (int)authScheme);
+ return INIT_CONNECTION_FAILED;
+ }
+
+ ci.shared = (appData.shareDesktop ? 1 : 0);
+
+ if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) return INIT_CONNECTION_FAILED;
+
+ if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) return INIT_CONNECTION_FAILED;
+
+ si.framebufferWidth = Swap16IfLE(si.framebufferWidth);
+ si.framebufferHeight = Swap16IfLE(si.framebufferHeight);
+ si.format.redMax = Swap16IfLE(si.format.redMax);
+ si.format.greenMax = Swap16IfLE(si.format.greenMax);
+ si.format.blueMax = Swap16IfLE(si.format.blueMax);
+ si.nameLength = Swap32IfLE(si.nameLength);
+
+ if ((si.framebufferWidth*si.framebufferHeight) > (4096*4096))
+ return INIT_CONNECTION_FAILED;
+
+ if (si.nameLength > MAX_STRING) {
+ fprintf(stderr, "Display name too long.\n");
+ return INIT_CONNECTION_FAILED;
+ }
+
+ desktopName = malloc(si.nameLength + 1);
+ if (!desktopName) {
+ fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n",
+ (unsigned long)si.nameLength);
+ return INIT_CONNECTION_FAILED;
+ }
+
+ if (!ReadFromRFBServer(desktopName, si.nameLength)) return INIT_CONNECTION_FAILED;
+
+ desktopName[si.nameLength] = 0;
+
+ fprintf(stderr,"Desktop name \"%s\"\n",desktopName);
+
+ fprintf(stderr,"Connected to VNC server, using protocol version %d.%d\n",
+ rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+ fprintf(stderr,"VNC server default format:\n");
+ PrintPixelFormat(&si.format);
+
+ return INIT_OK;
+}
+
+
+/*
+ * SetFormatAndEncodings.
+ */
+
+Bool
+SetFormatAndEncodings()
+{
+ rfbSetPixelFormatMsg spf;
+ char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
+ rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
+ CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]);
+ int len = 0;
+ Bool requestCompressLevel = False;
+ Bool requestQualityLevel = False;
+ Bool requestLastRectEncoding = False;
+
+ spf.type = rfbSetPixelFormat;
+ spf.pad1 = 0;
+ spf.pad2 = 0;
+ spf.format = myFormat;
+ spf.format.redMax = Swap16IfLE(spf.format.redMax);
+ spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
+ spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
+
+ if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg))
+ return False;
+
+ se->type = rfbSetEncodings;
+ se->pad = 0;
+ se->nEncodings = 0;
+
+ if (appData.encodingsString) {
+ const char *encStr = appData.encodingsString;
+ int encStrLen;
+ do {
+ char *nextEncStr = strchr(encStr, ' ');
+ if (nextEncStr) {
+ encStrLen = nextEncStr - encStr;
+ nextEncStr++;
+ } else {
+ encStrLen = strlen(encStr);
+ }
+
+ if (strncasecmp(encStr,"raw",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
+ } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
+ } else if (strncasecmp(encStr,"softcursor",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingSoftCursor);
+ /* if server supports SoftCursor, it will ignore X/RichCursor
+ * and PointerPos */
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos);
+ } else if (strncasecmp(encStr,"background",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingBackground);
+ } else if (strncasecmp(encStr,"tight",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+ requestLastRectEncoding = True;
+ if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
+ requestCompressLevel = True;
+ if (appData.qualityLevel >= 0 && appData.qualityLevel <= 9)
+ requestQualityLevel = True;
+ } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
+ } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+ if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
+ requestCompressLevel = True;
+ } else {
+ fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr);
+ }
+
+ encStr = nextEncStr;
+ } while (encStr && se->nEncodings < MAX_ENCODINGS);
+
+ if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) {
+ encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
+ rfbEncodingCompressLevel0);
+ }
+
+ if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) {
+ encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
+ rfbEncodingQualityLevel0);
+ }
+
+ if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+ }
+ }
+ else {
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
+
+ if (appData.compressLevel >= 0 && appData.compressLevel <= 9) {
+ encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
+ rfbEncodingCompressLevel0);
+ }
+
+ if (appData.qualityLevel >= 0 && appData.qualityLevel <= 9) {
+ encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
+ rfbEncodingQualityLevel0);
+ }
+
+ if (si.format.depth >= 8)
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingSoftCursor);
+ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+ }
+
+ len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
+
+ se->nEncodings = Swap16IfLE(se->nEncodings);
+
+ if (!WriteExact(rfbsock, buf, len)) return False;
+
+ return True;
+}
+
+
+/*
+ * SendIncrementalFramebufferUpdateRequest.
+ * Note: this should only be called by the WriterThread
+ */
+
+Bool
+SendIncrementalFramebufferUpdateRequest()
+{
+ return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
+ si.framebufferHeight, True);
+}
+
+
+/*
+ * SendFramebufferUpdateRequest.
+ * Note: this should only be called by the WriterThread
+ */
+
+Bool
+SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental)
+{
+ rfbFramebufferUpdateRequestMsg fur;
+
+ fur.type = rfbFramebufferUpdateRequest;
+ fur.incremental = incremental ? 1 : 0;
+ fur.x = Swap16IfLE(x);
+ fur.y = Swap16IfLE(y);
+ fur.w = Swap16IfLE(w);
+ fur.h = Swap16IfLE(h);
+
+ if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg))
+ return False;
+
+ return True;
+}
+
+
+/*
+ * SendPointerEvent.
+ * Note: this should only be called by the WriterThread
+ */
+
+Bool
+SendPointerEvent(int x, int y, int buttonMask)
+{
+ rfbPointerEventMsg pe;
+
+ pe.type = rfbPointerEvent;
+ pe.buttonMask = buttonMask;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ pe.x = Swap16IfLE(x);
+ pe.y = Swap16IfLE(y);
+ return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg);
+}
+
+
+/*
+ * SendKeyEvent.
+ * Note: this should only be called by the WriterThread
+ */
+
+Bool
+SendKeyEvent(CARD32 key, Bool down)
+{
+ rfbKeyEventMsg ke;
+
+ ke.type = rfbKeyEvent;
+ ke.down = down ? 1 : 0;
+ ke.key = Swap32IfLE(key);
+ return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg);
+}
+
+
+/*
+ * SendClientCutText.
+ * Note: this should only be called by the WriterThread
+ */
+
+Bool
+SendClientCutText(const char *str, int len)
+{
+ rfbClientCutTextMsg cct;
+
+ cct.type = rfbClientCutText;
+ cct.length = Swap32IfLE((unsigned int)len);
+ return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) &&
+ WriteExact(rfbsock, str, len));
+}
+
+
+static Bool
+HandleSoftCursorSetImage(rfbSoftCursorSetImage *msg, rfbRectangle *rect)
+{
+ int iindex = msg->imageIndex - rfbSoftCursorSetIconOffset;
+ PointerImage *pi = &pointerImages[iindex];
+ if (iindex >= rfbSoftCursorMaxImages) {
+ fprintf(stderr, "Received invalid soft cursor image index %d for SetImage\n", iindex);
+ return False;
+ }
+ EnableClientCursor(0);
+
+ if (pi->set && pi->image)
+ free(pi->image);
+
+ pi->w = rect->w;
+ pi->h = rect->h;
+ pi->hotX = rect->x;
+ pi->hotY = rect->y;
+ pi->len = Swap16IfLE(msg->imageLength);
+ pi->image = malloc(pi->len);
+ if (!pi->image) {
+ fprintf(stderr, "out of memory (size=%d)\n", pi->len);
+ return False;
+ }
+
+ if (!ReadFromRFBServer(pi->image, pi->len))
+ return False;
+ pi->set = 1;
+ return True;
+}
+
+/* framebuffer must be locked when calling this!!! */
+static Bool
+PointerMove(unsigned int x, unsigned int y, unsigned int mask,
+ int ox, int oy, int ow, int oh)
+{
+ int nx, ny, nw, nh;
+
+ if (x >= si.framebufferWidth)
+ x = si.framebufferWidth - 1;
+ if (y >= si.framebufferHeight)
+ y = si.framebufferHeight - 1;
+
+ cursorX = x;
+ cursorY = y;
+ drawCursor();
+ UnlockFramebuffer();
+
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &nx, &ny, &nw, &nh);
+
+ if (rectsIntersect(ox, oy, ow, oh, nx, ny, nw, nh)) {
+ rectsJoin(&ox, &oy, &ow, &oh, nx, ny, nw, nh);
+ SyncScreenRegion(ox, oy, ow, oh);
+ }
+ else {
+ SyncScreenRegion(ox, oy, ow, oh);
+ SyncScreenRegion(nx, ny, nw, nh);
+ }
+
+ postMouseEvent(cursorX, cursorY, mask);
+
+ return True;
+}
+
+static Bool
+HandleSoftCursorMove(rfbSoftCursorMove *msg, rfbRectangle *rect)
+{
+ int ii, ox, oy, ow, oh;
+
+ /* get old cursor rect to know what to update */
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &ox, &oy, &ow, &oh);
+
+ ii = msg->imageIndex;
+ if (ii >= rfbSoftCursorMaxImages) {
+ fprintf(stderr, "Received invalid soft cursor image index %d for Move\n", ii);
+ return False;
+ }
+
+ if (!pointerImages[ii].set)
+ return True;
+
+ LockFramebuffer();
+ undrawCursor();
+ imageIndex = ii;
+
+ return PointerMove(rect->w, rect->h, msg->buttonMask, ox, oy, ow, oh);
+}
+
+static Bool
+HandleCursorPos(unsigned int x, unsigned int y)
+{
+ int ox, oy, ow, oh;
+
+ /* get old cursor rect to know what to update */
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &ox, &oy, &ow, &oh);
+ if (!pointerImages[0].set)
+ return True;
+
+ LockFramebuffer();
+ undrawCursor();
+ imageIndex = 0;
+ return PointerMove(x, y, 0, ox, oy, ow, oh);
+}
+
+/* call only from X11 thread. Only updates framebuffer, does not sync! */
+void DrawCursorX11Thread(int x, int y) {
+ int ox, oy, ow, oh, nx, ny, nw, nh;
+ if (!pointerImages[0].set)
+ return True;
+ imageIndex = 0;
+
+ if (x >= si.framebufferWidth)
+ x = si.framebufferWidth - 1;
+ if (y >= si.framebufferHeight)
+ y = si.framebufferHeight - 1;
+
+ LockFramebuffer();
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &ox, &oy, &ow, &oh);
+ undrawCursor();
+ cursorX = x;
+ cursorY = y;
+ drawCursor();
+ UnlockFramebuffer();
+
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &nx, &ny, &nw, &nh);
+ if (rectsIntersect(ox, oy, ow, oh, nx, ny, nw, nh)) {
+ rectsJoin(&ox, &oy, &ow, &oh, nx, ny, nw, nh);
+ SyncScreenRegionX11Thread(ox, oy, ow, oh);
+ }
+ else {
+ SyncScreenRegionX11Thread(ox, oy, ow, oh);
+ SyncScreenRegionX11Thread(nx, ny, nw, nh);
+ }
+}
+
+/**
+ * Create a softcursor in the "compressed alpha" format.
+ * Returns the softcursor, caller owns the object
+ */
+static void *MakeSoftCursor(int bpp, int cursorWidth, int cursorHeight,
+ CARD8 *cursorData, CARD8 *cursorMask, short *imageLen)
+{
+ int w = (cursorWidth+7)/8;
+ unsigned char *cp, *sp, *dstData;
+ int state; /* 0 = transparent, 1 otherwise */
+ CARD8 *counter;
+ unsigned char bit;
+ int i,j;
+
+ sp = (unsigned char*)cursorData;
+ dstData = cp = (unsigned char*)calloc(cursorWidth*(bpp+2),cursorHeight);
+ if (!dstData)
+ return 0;
+
+ state = 0;
+ counter = cp++;
+ *counter = 0;
+
+ for(j=0;j<cursorHeight;j++)
+ for(i=0,bit=0x80;i<cursorWidth;i++,bit=(bit&1)?0x80:bit>>1)
+ if(cursorMask[j*w+i/8]&bit) {
+ if (state) {
+ memcpy(cp,sp,bpp);
+ cp += bpp;
+ sp += bpp;
+ (*counter)++;
+ if (*counter == 255) {
+ state = 0;
+ counter = cp++;
+ *counter = 0;
+ }
+ }
+ else {
+ state = 1;
+ counter = cp++;
+ *counter = 1;
+ memcpy(cp,sp,bpp);
+ cp += bpp;
+ sp += bpp;
+ }
+ }
+ else {
+ if (!state) {
+ (*counter)++;
+ if (*counter == 255) {
+ state = 1;
+ counter = cp++;
+ *counter = 0;
+ }
+ }
+ else {
+ state = 0;
+ counter = cp++;
+ *counter = 1;
+ }
+ sp += bpp;
+ }
+
+ *imageLen = cp - dstData;
+ return (void*) dstData;
+}
+
+
+/*********************************************************************
+ * HandleCursorShape(). Support for XCursor and RichCursor shape
+ * updates. We emulate cursor operating on the frame buffer (that is
+ * why we call it "software cursor").
+ ********************************************************************/
+
+static Bool HandleCursorShape(int xhot, int yhot, int width, int height, CARD32 enc)
+{
+ int bytesPerPixel;
+ size_t bytesPerRow, bytesMaskData;
+ rfbXCursorColors rgb;
+ CARD32 colors[2];
+ CARD8 *ptr, *rcSource, *rcMask;
+ void *softCursor;
+ int x, y, b;
+ int ox, oy, ow, oh;
+ PointerImage *pi;
+ short imageLen;
+
+ bytesPerPixel = myFormat.bitsPerPixel / 8;
+ bytesPerRow = (width + 7) / 8;
+ bytesMaskData = bytesPerRow * height;
+
+ if (width * height == 0)
+ return True;
+
+ /* Allocate memory for pixel data and temporary mask data. */
+
+ rcSource = malloc(width * height * bytesPerPixel);
+ if (rcSource == NULL)
+ return False;
+
+ rcMask = malloc(bytesMaskData);
+ if (rcMask == NULL) {
+ free(rcSource);
+ return False;
+ }
+
+ /* Read and decode cursor pixel data, depending on the encoding type. */
+
+ if (enc == rfbEncodingXCursor) {
+ /* Read and convert background and foreground colors. */
+ if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) {
+ free(rcSource);
+ free(rcMask);
+ return False;
+ }
+ colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue);
+ colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue);
+
+ /* Read 1bpp pixel data into a temporary buffer. */
+ if (!ReadFromRFBServer((char*)rcMask, bytesMaskData)) {
+ free(rcSource);
+ free(rcMask);
+ return False;
+ }
+
+ /* Convert 1bpp data to byte-wide color indices. */
+ ptr = rcSource;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width / 8; x++) {
+ for (b = 7; b >= 0; b--) {
+ *ptr = rcMask[y * bytesPerRow + x] >> b & 1;
+ ptr += bytesPerPixel;
+ }
+ }
+ for (b = 7; b > 7 - width % 8; b--) {
+ *ptr = rcMask[y * bytesPerRow + x] >> b & 1;
+ ptr += bytesPerPixel;
+ }
+ }
+
+ /* Convert indices into the actual pixel values. */
+ switch (bytesPerPixel) {
+ case 1:
+ for (x = 0; x < width * height; x++)
+ rcSource[x] = (CARD8)colors[rcSource[x]];
+ break;
+ case 2:
+ for (x = 0; x < width * height; x++)
+ ((CARD16 *)rcSource)[x] = (CARD16)colors[rcSource[x * 2]];
+ break;
+ case 4:
+ for (x = 0; x < width * height; x++)
+ ((CARD32 *)rcSource)[x] = colors[rcSource[x * 4]];
+ break;
+ }
+
+
+ } else {
+ if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) {
+ free(rcSource);
+ free(rcMask);
+ return False;
+ }
+ }
+
+ /* Read mask data. */
+
+ if (!ReadFromRFBServer((char*)rcMask, bytesMaskData)) {
+ free(rcSource);
+ free(rcMask);
+ return False;
+ }
+
+
+ /* Set the soft cursor. */
+ softCursor = MakeSoftCursor(bytesPerPixel, width, height, rcSource, rcMask, &imageLen);
+ if (!softCursor) {
+ free(rcMask);
+ free(rcSource);
+ return False;
+ }
+
+ /* get old cursor rect to know what to update */
+ EnableClientCursor(1);
+ LockFramebuffer();
+ getBoundingRectCursor(cursorX, cursorY, imageIndex,
+ &ox, &oy, &ow, &oh);
+ undrawCursor();
+
+ pi = &pointerImages[0];
+ if (pi->set && pi->image)
+ free(pi->image);
+ pi->w = width;
+ pi->h = height;
+ pi->hotX = xhot;
+ pi->hotY = yhot;
+ pi->len = imageLen;
+ pi->image = softCursor;
+ pi->set = 1;
+
+ imageIndex = 0;
+
+ free(rcMask);
+ free(rcSource);
+
+ return PointerMove(cursorX, cursorY, 0, ox, oy, ow, oh);
+}
+
+
+
+/*
+ * HandleRFBServerMessage.
+ */
+
+Bool
+HandleRFBServerMessage()
+{
+ rfbServerToClientMsg msg;
+ if (!ReadFromRFBServer((char *)&msg, 1))
+ return False;
+
+ switch (msg.type) {
+
+ case rfbSetColourMapEntries:
+ {
+ int i;
+ CARD16 rgb[3];
+ XColor xc;
+
+ if (!ReadFromRFBServer(((char *)&msg) + 1,
+ sz_rfbSetColourMapEntriesMsg - 1))
+ return False;
+
+ msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour);
+ msg.scme.nColours = Swap16IfLE(msg.scme.nColours);
+
+ for (i = 0; i < msg.scme.nColours; i++) {
+ if (!ReadFromRFBServer((char *)rgb, 6))
+ return False;
+ xc.pixel = msg.scme.firstColour + i;
+ xc.red = Swap16IfLE(rgb[0]);
+ xc.green = Swap16IfLE(rgb[1]);
+ xc.blue = Swap16IfLE(rgb[2]);
+ xc.flags = DoRed|DoGreen|DoBlue;
+ /* Disable colormaps
+ lockQt();
+ XStoreColor(dpy, cmap, &xc);
+ unlockQt();
+ */
+ }
+
+ break;
+ }
+
+ case rfbFramebufferUpdate:
+ {
+ rfbFramebufferUpdateRectHeader rect;
+ int linesToRead;
+ int bytesPerLine;
+ int i;
+
+ announceIncrementalUpdateRequest();
+
+ if (!ReadFromRFBServer(((char *)&msg.fu) + 1,
+ sz_rfbFramebufferUpdateMsg - 1))
+ return False;
+
+ msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
+
+ for (i = 0; i < msg.fu.nRects; i++) {
+ if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader))
+ return False;
+
+ rect.encoding = Swap32IfLE(rect.encoding);
+ if (rect.encoding == rfbEncodingLastRect)
+ break;
+
+ rect.r.x = Swap16IfLE(rect.r.x);
+ rect.r.y = Swap16IfLE(rect.r.y);
+ rect.r.w = Swap16IfLE(rect.r.w);
+ rect.r.h = Swap16IfLE(rect.r.h);
+
+ if (rect.encoding == rfbEncodingPointerPos) {
+ if (!HandleCursorPos(rect.r.x, rect.r.y)) {
+ return False;
+ }
+ continue;
+ }
+
+ if (rect.encoding == rfbEncodingXCursor ||
+ rect.encoding == rfbEncodingRichCursor) {
+ if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h,
+ rect.encoding)) {
+ return False;
+ }
+ continue;
+ }
+
+ if ((rect.r.x + rect.r.w > si.framebufferWidth) ||
+ (rect.r.y + rect.r.h > si.framebufferHeight))
+ {
+ fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n",
+ rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+ return False;
+ }
+
+ if ((rect.r.h * rect.r.w == 0) &&
+ (rect.encoding != rfbEncodingSoftCursor)) {
+ fprintf(stderr,"Zero size rect - ignoring\n");
+ continue;
+ }
+
+ switch (rect.encoding) {
+
+ case rfbEncodingRaw:
+
+ bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8;
+ linesToRead = BUFFER_SIZE / bytesPerLine;
+
+ while (rect.r.h > 0) {
+ if (linesToRead > rect.r.h)
+ linesToRead = rect.r.h;
+
+ if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead))
+ return False;
+
+ CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w,
+ linesToRead);
+
+ rect.r.h -= linesToRead;
+ rect.r.y += linesToRead;
+
+ }
+ break;
+
+ case rfbEncodingCopyRect:
+ {
+ rfbCopyRect cr;
+
+ if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect))
+ return False;
+
+ cr.srcX = Swap16IfLE(cr.srcX);
+ cr.srcY = Swap16IfLE(cr.srcY);
+
+ CopyArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+
+ break;
+ }
+
+ case rfbEncodingHextile:
+ {
+ switch (myFormat.bitsPerPixel) {
+ case 8:
+ if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ case 16:
+ if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ case 32:
+ if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ }
+ break;
+ }
+
+ case rfbEncodingZlib:
+ {
+ switch (myFormat.bitsPerPixel) {
+ case 8:
+ if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ case 16:
+ if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ case 32:
+ if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ }
+ break;
+ }
+
+ case rfbEncodingTight:
+ {
+ switch (myFormat.bitsPerPixel) {
+ case 8:
+ if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ case 16:
+ if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ case 32:
+ if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+ return False;
+ break;
+ }
+ break;
+ }
+
+ case rfbEncodingSoftCursor:
+ {
+ rfbSoftCursorMsg scmsg;
+ if (!ReadFromRFBServer((char *)&scmsg, 1))
+ return False;
+ if (scmsg.type < rfbSoftCursorMaxImages) {
+ if (!ReadFromRFBServer(((char *)&scmsg)+1,
+ sizeof(rfbSoftCursorMove)- 1))
+ return False;
+ if (!HandleSoftCursorMove(&scmsg.move, &rect.r))
+ return False;
+ }
+ else if((scmsg.type >= rfbSoftCursorSetIconOffset) &&
+ (scmsg.type < rfbSoftCursorSetIconOffset+rfbSoftCursorMaxImages)) {
+ if (!ReadFromRFBServer(((char *)&scmsg)+1,
+ sizeof(rfbSoftCursorSetImage)- 1))
+ return False;
+ if (!HandleSoftCursorSetImage(&scmsg.setImage, &rect.r))
+ return False;
+ }
+ else {
+ fprintf(stderr,"Unknown soft cursor image index %d\n",
+ (int)scmsg.type);
+ return False;
+ }
+ break;
+ }
+
+ default:
+ fprintf(stderr,"Unknown rect encoding %d\n",
+ (int)rect.encoding);
+ return False;
+ }
+
+ }
+
+ queueIncrementalUpdateRequest();
+
+ break;
+ }
+
+ case rfbBell:
+ {
+ beep();
+ break;
+ }
+
+ case rfbServerCutText:
+ {
+ char *serverCutText;
+ if (!ReadFromRFBServer(((char *)&msg) + 1,
+ sz_rfbServerCutTextMsg - 1))
+ return False;
+
+ msg.sct.length = Swap32IfLE(msg.sct.length);
+
+ if (msg.sct.length > MAX_CUTBUFFER) {
+ fprintf(stderr, "Cutbuffer too long.\n");
+ return False;
+ }
+
+ serverCutText = malloc(msg.sct.length+1);
+
+ if (!serverCutText) {
+ fprintf(stderr, "Out-of-memory, cutbuffer too long.\n");
+ return False;
+ }
+
+ if (!ReadFromRFBServer(serverCutText, msg.sct.length))
+ return False;
+
+ serverCutText[msg.sct.length] = 0;
+ newServerCut(serverCutText, msg.sct.length); /* takes ownership of serverCutText */
+
+ break;
+ }
+
+ default:
+ fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type);
+ return False;
+ }
+
+ return True;
+}
+
+
+#define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++)
+
+#define GET_PIXEL16(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
+ ((CARD8*)&(pix))[1] = *(ptr)++)
+
+#define GET_PIXEL32(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
+ ((CARD8*)&(pix))[1] = *(ptr)++, \
+ ((CARD8*)&(pix))[2] = *(ptr)++, \
+ ((CARD8*)&(pix))[3] = *(ptr)++)
+
+/* CONCAT2 concatenates its two arguments. CONCAT2E does the same but also
+ expands its arguments if they are macros */
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+
+#define BPP 8
+#include "hextile.c"
+#include "zlib.c"
+#include "tight.c"
+#undef BPP
+#define BPP 16
+#include "hextile.c"
+#include "zlib.c"
+#include "tight.c"
+#undef BPP
+#define BPP 32
+#include "hextile.c"
+#include "zlib.c"
+#include "tight.c"
+#undef BPP
+
+
+/*
+ * PrintPixelFormat.
+ */
+
+void
+PrintPixelFormat(format)
+ rfbPixelFormat *format;
+{
+ if (format->bitsPerPixel == 1) {
+ fprintf(stderr," Single bit per pixel.\n");
+ fprintf(stderr,
+ " %s significant bit in each byte is leftmost on the screen.\n",
+ (format->bigEndian ? "Most" : "Least"));
+ } else {
+ fprintf(stderr," %d bits per pixel.\n",format->bitsPerPixel);
+ if (format->bitsPerPixel != 8) {
+ fprintf(stderr," %s significant byte first in each pixel.\n",
+ (format->bigEndian ? "Most" : "Least"));
+ }
+ if (format->trueColour) {
+ fprintf(stderr," True colour: max red %d green %d blue %d",
+ format->redMax, format->greenMax, format->blueMax);
+ fprintf(stderr,", shift red %d green %d blue %d\n",
+ format->redShift, format->greenShift, format->blueShift);
+ } else {
+ fprintf(stderr," Colour map (not true colour).\n");
+ }
+ }
+}
+
+static long
+ReadCompactLen (void)
+{
+ long len;
+ CARD8 b;
+
+ if (!ReadFromRFBServer((char *)&b, 1))
+ return -1;
+ len = (int)b & 0x7F;
+ if (b & 0x80) {
+ if (!ReadFromRFBServer((char *)&b, 1))
+ return -1;
+ len |= ((int)b & 0x7F) << 7;
+ if (b & 0x80) {
+ if (!ReadFromRFBServer((char *)&b, 1))
+ return -1;
+ len |= ((int)b & 0xFF) << 14;
+ }
+ }
+ return len;
+}
+
+void freeRFBProtoResources() {
+ int i;
+
+ if (desktopName)
+ free(desktopName);
+ if (raw_buffer)
+ free(raw_buffer);
+ for (i = 0; i < rfbSoftCursorMaxImages; i++)
+ if (pointerImages[i].set && pointerImages[i].image)
+ free(pointerImages[i].image);
+
+ raw_buffer_size = -1;
+ raw_buffer = NULL;
+ decompStreamInited = False;
+ zlibStreamActive[0] = False;
+ zlibStreamActive[1] = False;
+ zlibStreamActive[2] = False;
+ zlibStreamActive[3] = False;
+ for (i = 0; i < rfbSoftCursorMaxImages; i++)
+ pointerImages[i].set = 0;
+ imageIndex = -1;
+}
+
+void freeResources() {
+ freeSocketsResources();
+ freeDesktopResources();
+ freeRFBProtoResources();
+}
+
+/*
+ * JPEG source manager functions for JPEG decompression in Tight decoder.
+ */
+
+static struct jpeg_source_mgr jpegSrcManager;
+static JOCTET *jpegBufferPtr;
+static size_t jpegBufferLen;
+
+static void
+JpegInitSource(j_decompress_ptr cinfo)
+{
+ jpegError = False;
+}
+
+static boolean
+JpegFillInputBuffer(j_decompress_ptr cinfo)
+{
+ jpegError = True;
+ jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+ jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+
+ return TRUE;
+}
+
+static void
+JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
+{
+ if (num_bytes < 0 || num_bytes > jpegSrcManager.bytes_in_buffer) {
+ jpegError = True;
+ jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+ jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+ } else {
+ jpegSrcManager.next_input_byte += (size_t) num_bytes;
+ jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void
+JpegTermSource(j_decompress_ptr cinfo)
+{
+ /* No work necessary here. */
+}
+
+static void
+JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
+ int compressedLen)
+{
+ jpegBufferPtr = (JOCTET *)compressedData;
+ jpegBufferLen = (size_t)compressedLen;
+
+ jpegSrcManager.init_source = JpegInitSource;
+ jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
+ jpegSrcManager.skip_input_data = JpegSkipInputData;
+ jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
+ jpegSrcManager.term_source = JpegTermSource;
+ jpegSrcManager.next_input_byte = jpegBufferPtr;
+ jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+
+ cinfo->src = &jpegSrcManager;
+}
+
diff --git a/krdc/vnc/rfbproto.h b/krdc/vnc/rfbproto.h
new file mode 100644
index 00000000..61ceb903
--- /dev/null
+++ b/krdc/vnc/rfbproto.h
@@ -0,0 +1,957 @@
+/*
+ * Copyright (C) 2000-2002 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 version 3.3
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first). Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data. The order of definitions in
+ * this file is as follows:
+ *
+ * (1) Structures used in several types of message.
+ * (2) Structures used in the initial handshaking.
+ * (3) Message types.
+ * (4) Encoding types.
+ * (5) For each message type, the form of the data following the type byte.
+ * Sometimes this is defined by a single structure but the more complex
+ * messages have to be explained by comments.
+ */
+
+#include "vnctypes.h"
+
+/*****************************************************************************
+ *
+ * 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 {
+ CARD16 x;
+ CARD16 y;
+ CARD16 w;
+ CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct {
+
+ 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
+
+
+
+/*****************************************************************************
+ *
+ * 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.3
+ * this is "RFB 003.003\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 3
+
+typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * Authentication
+ *
+ * Once the protocol version has been decided, the server then sends a 32-bit
+ * word indicating whether any authentication is needed on the connection.
+ * The value of this word determines the authentication scheme in use. For
+ * version 3.0 of the protocol this may have one of the following values:
+ */
+
+#define rfbConnFailed 0
+#define rfbNoAuth 1
+#define rfbVncAuth 2
+
+/*
+ * rfbConnFailed: For some reason the connection failed (e.g. the server
+ * cannot support the desired protocol version). This is
+ * followed by a string describing the reason (where a
+ * string is specified as a 32-bit length followed by that
+ * many ASCII characters).
+ *
+ * rfbNoAuth: No authentication is needed.
+ *
+ * rfbVncAuth: The VNC authentication scheme is to be used. A 16-byte
+ * challenge follows, which the client encrypts as
+ * appropriate using the password and sends the resulting
+ * 16-byte response. If the response is correct, the
+ * server sends the 32-bit word rfbVncAuthOK. If a simple
+ * failure happens, the server sends rfbVncAuthFailed and
+ * closes the connection. If the server decides that too
+ * many failures have occurred, it sends rfbVncAuthTooMany
+ * and closes the connection. In the latter case, the
+ * server should not allow an immediate reconnection by
+ * the client.
+ */
+
+#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 {
+ 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 {
+ 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)
+
+
+/*
+ * 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
+
+
+/* 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
+
+
+
+
+/*****************************************************************************
+ *
+ * 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
+
+/*
+ * 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 -- cross-encoding compression levels.
+ */
+
+#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 rfbEncodingSoftCursor 0xFFFFFF12
+#define rfbEncodingPointerPos 0xFFFFFF18
+
+#define rfbEncodingLastRect 0xFFFFFF20
+#define rfbEncodingBackground 0xFFFFFF25
+
+#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
+
+
+/*****************************************************************************
+ *
+ * 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 {
+ 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 {
+ 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 {
+ CARD16 srcX;
+ CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding. We have an rfbRREHeader structure
+ * giving the number of subrectangles following. Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct {
+ CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding. We have an rfbRREHeader structure giving
+ * the number of subrectangles following. Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>]. This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct {
+ 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 compressed Encoding. We have an rfbZlibHeader structure
+ * giving the number of bytes following. Finally the data follows is
+ * zlib compressed version of the raw pixel data as negotiated.
+ */
+
+typedef struct {
+ 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
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * 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 {
+ 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).
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * SoftCursor encoding. This encoding is used to transmit image and position
+ * of the remote cursor. It has two sub-messages: SetImage is used to upload
+ * one of 16 images, and Move selects the image and sets the position of the
+ * cursor.
+ * Each SoftCursor message starts with a CARD8. If it is in the 0-15 range
+ * it specifies the number of the cursor image and is followed by the
+ * rfbSoftCursorMove message. If the given cursor has not been set yet the
+ * message will be ignored. If the first CARD8 is in the 128-143 range it
+ * specifies the cursor that will be set in the following
+ * rfbSoftCursorSetImage message. To hide the cursor send a SetImage
+ * message with width and height 0 and imageLength 0.
+ * SetImage transmits the hotspot coordinates in the x/y fields of the
+ * rfbFramebufferUpdateRectHeader, width and height of the image are in the
+ * header's width and height fields.
+ * Move transmits the pointer coordinates in the w/h fields of the
+ * header, x/y are always 0.
+ */
+
+typedef struct {
+ CARD8 imageIndex;
+ CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */
+} rfbSoftCursorMove;
+
+typedef struct {
+ CARD8 imageIndex;
+ CARD8 padding;
+ CARD16 imageLength;
+ /*
+ * Followed by an image of the cursor in the client's image format
+ * with the following RLE mask compression. It begins with CARD8 that
+ * specifies the number of mask'ed pixels that will be NOT transmitted.
+ * Then follows a CARD8 that specified by the number of unmask'd pixels
+ * that will be transmitted next. Then a CARD8 with the number of mask'd
+ * pixels and so on.
+ */
+} rfbSoftCursorSetImage;
+
+typedef union {
+ CARD8 type;
+ rfbSoftCursorMove move;
+ rfbSoftCursorSetImage setImage;
+} rfbSoftCursorMsg;
+
+#define rfbSoftCursorMaxImages 16
+#define rfbSoftCursorSetIconOffset 128
+
+/*-----------------------------------------------------------------------------
+ * 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 {
+ CARD8 type; /* always rfbSetColourMapEntries */
+ CARD8 pad;
+ 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 {
+ CARD8 type; /* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbServerCutText */
+ CARD8 pad1;
+ CARD16 pad2;
+ CARD32 length;
+ /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union {
+ CARD8 type;
+ rfbFramebufferUpdateMsg fu;
+ rfbSetColourMapEntriesMsg scme;
+ rfbBellMsg b;
+ rfbServerCutTextMsg sct;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbClientCutText */
+ CARD8 pad1;
+ CARD16 pad2;
+ CARD32 length;
+ /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union {
+ CARD8 type;
+ rfbSetPixelFormatMsg spf;
+ rfbFixColourMapEntriesMsg fcme;
+ rfbSetEncodingsMsg se;
+ rfbFramebufferUpdateRequestMsg fur;
+ rfbKeyEventMsg ke;
+ rfbPointerEventMsg pe;
+ rfbClientCutTextMsg cct;
+} rfbClientToServerMsg;
diff --git a/krdc/vnc/sockets.c b/krdc/vnc/sockets.c
new file mode 100644
index 00000000..797dd22d
--- /dev/null
+++ b/krdc/vnc/sockets.c
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ *
+ * 03-05-2002 tim@tjansen.de: removed Xt event processing for krdc
+ */
+
+/*
+ * sockets.c - functions to deal with sockets.
+ */
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <assert.h>
+#include "vncviewer.h"
+
+void PrintInHex(char *buf, int len);
+
+Bool errorMessageOnReadFailure = True;
+
+#define BUF_SIZE 8192
+static char buf[BUF_SIZE];
+static char *bufoutptr = buf;
+static unsigned int buffered = 0;
+
+/* Wait duration of select in seconds */
+#define SELECT_PERIOD 3
+
+
+/*
+ * ReadFromRFBServer is called whenever we want to read some data from the RFB
+ * server.
+ */
+Bool
+ReadFromRFBServer(char *out, unsigned int n)
+{
+ fd_set fds;
+ int e;
+ struct timeval tx;
+
+ if (isQuitFlagSet())
+ return False;
+
+ if (n <= buffered) {
+ memcpy(out, bufoutptr, n);
+ bufoutptr += n;
+ buffered -= n;
+ return True;
+ }
+
+ memcpy(out, bufoutptr, buffered);
+
+ out += buffered;
+ n -= buffered;
+
+ bufoutptr = buf;
+ buffered = 0;
+
+ if (n <= BUF_SIZE) {
+
+ while (buffered < n) {
+ int i;
+ if (isQuitFlagSet())
+ return False;
+ i = read(rfbsock, buf + buffered, BUF_SIZE - buffered);
+
+ if (i <= 0) {
+ if (i < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ FD_ZERO(&fds);
+ FD_SET(rfbsock,&fds);
+
+ tx.tv_sec = SELECT_PERIOD;
+ tx.tv_usec = 0;
+ if ((e=select(rfbsock+1, &fds, NULL, &fds, &tx)) < 0) {
+ perror("krdc: select read");
+ return False;
+ }
+ i = 0;
+ } else {
+ perror("krdc: read");
+ return False;
+ }
+ } else {
+ fprintf(stderr,"VNC server closed connection\n");
+ return False;
+ }
+ }
+ buffered += i;
+ }
+
+ memcpy(out, bufoutptr, n);
+ bufoutptr += n;
+ buffered -= n;
+ return isQuitFlagSet() ? False : True;
+
+ } else {
+
+ while (n > 0) {
+ int i;
+ if (isQuitFlagSet())
+ return False;
+ i = read(rfbsock, out, n);
+ if (i <= 0) {
+ if (i < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ FD_ZERO(&fds);
+ FD_SET(rfbsock,&fds);
+
+ tx.tv_sec = SELECT_PERIOD;
+ tx.tv_usec = 0;
+ if ((e=select(rfbsock+1, &fds, NULL, &fds, &tx)) < 0) {
+ perror("krdc: select");
+ return False;
+ }
+ i = 0;
+ } else {
+ perror("krdc: read");
+ return False;
+ }
+ } else {
+ fprintf(stderr,"VNC server closed connection\n");
+ return False;
+ }
+ }
+ out += i;
+ n -= i;
+ }
+
+ return isQuitFlagSet() ? False : True;
+ }
+}
+
+
+/*
+ * Write an exact number of bytes, and don't return until you've sent them.
+ * Note: this should only be called by the WriterThread
+ */
+
+Bool
+WriteExact(int sock, const char *_buf, int n)
+{
+ fd_set fds;
+ int i = 0;
+ int j;
+ int e;
+ struct timeval tx;
+
+ while (i < n) {
+ if (isQuitFlagSet())
+ return False;
+ j = write(sock, _buf + i, (n - i));
+ if (j <= 0) {
+ if (j < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ FD_ZERO(&fds);
+ FD_SET(rfbsock,&fds);
+
+ tx.tv_sec = SELECT_PERIOD;
+ tx.tv_usec = 0;
+ if ((e=select(rfbsock+1, NULL, &fds, NULL, &tx)) < 0) {
+ perror("krdc: select write");
+ return False;
+ }
+ j = 0;
+ } else {
+ perror("krdc: write");
+ return False;
+ }
+ } else {
+ fprintf(stderr,"write failed\n");
+ return False;
+ }
+ }
+ i += j;
+ }
+ return True;
+}
+
+
+/*
+ * ConnectToTcpAddr connects to the given TCP port.
+ */
+
+int
+ConnectToTcpAddr(unsigned int host, int port)
+{
+ int sock;
+ struct sockaddr_in addr;
+ int one = 1;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = host;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("krdc: ConnectToTcpAddr: socket");
+ return -(int)INIT_CONNECTION_FAILED;
+ }
+
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("krdc: ConnectToTcpAddr: connect");
+ close(sock);
+ return -(int)INIT_NO_SERVER;
+ }
+
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&one, sizeof(one)) < 0) {
+ perror("krdc: ConnectToTcpAddr: setsockopt");
+ close(sock);
+ return -(int)INIT_CONNECTION_FAILED;
+ }
+
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+ perror(": AcceptTcpConnection: fcntl");
+ close(sock);
+ return -(int)INIT_CONNECTION_FAILED;
+ }
+
+ return sock;
+}
+
+
+/*
+ * StringToIPAddr - convert a host string to an IP address.
+ */
+
+Bool
+StringToIPAddr(const char *str, unsigned int *addr)
+{
+ struct hostent *hp;
+
+ if (strcmp(str,"") == 0) {
+ *addr = 0; /* local */
+ return True;
+ }
+
+ *addr = inet_addr(str);
+
+ if (*addr != -1)
+ return True;
+
+ hp = gethostbyname(str);
+
+ if (hp) {
+ *addr = *(unsigned int *)hp->h_addr;
+ return True;
+ }
+
+ return False;
+}
+
+
+/*
+ * Print out the contents of a packet for debugging.
+ */
+
+void
+PrintInHex(char *_buf, int len)
+{
+ int i, j;
+ char c, str[17];
+
+ str[16] = 0;
+
+ fprintf(stderr,"ReadExact: ");
+
+ for (i = 0; i < len; i++)
+ {
+ if ((i % 16 == 0) && (i != 0)) {
+ fprintf(stderr," ");
+ }
+ c = _buf[i];
+ str[i % 16] = (((c > 31) && (c < 127)) ? c : '.');
+ fprintf(stderr,"%02x ",(unsigned char)c);
+ if ((i % 4) == 3)
+ fprintf(stderr," ");
+ if ((i % 16) == 15)
+ {
+ fprintf(stderr,"%s\n",str);
+ }
+ }
+ if ((i % 16) != 0)
+ {
+ for (j = i % 16; j < 16; j++)
+ {
+ fprintf(stderr," ");
+ if ((j % 4) == 3) fprintf(stderr," ");
+ }
+ str[i % 16] = 0;
+ fprintf(stderr,"%s\n",str);
+ }
+
+ fflush(stderr);
+}
+
+void freeSocketsResources() {
+ close(rfbsock);
+
+ errorMessageOnReadFailure = True;
+ bufoutptr = buf;
+ buffered = 0;
+}
+
diff --git a/krdc/vnc/threads.cpp b/krdc/vnc/threads.cpp
new file mode 100644
index 00000000..fe5a1d62
--- /dev/null
+++ b/krdc/vnc/threads.cpp
@@ -0,0 +1,392 @@
+/***************************************************************************
+ threads.cpp - threads
+ -------------------
+ begin : Thu May 09 17:01:44 CET 2002
+ copyright : (C) 2002 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "kvncview.h"
+
+#include <kdebug.h>
+#include <kapplication.h>
+
+#include "vncviewer.h"
+#include "threads.h"
+
+#include <qcstring.h>
+
+// Maximum idle time for writer thread in ms. When it timeouts, it will request
+// another incremental update. Must be smaller than the timeout of the server
+// (krfb's is 20s).
+static const int MAXIMUM_WAIT_PERIOD = 8000;
+
+// time to postpone incremental updates that have not been requested explicitly
+static const int POSTPONED_INCRRQ_WAIT_PERIOD = 110;
+
+static const int MOUSEPRESS_QUEUE_SIZE = 5;
+static const int MOUSEMOVE_QUEUE_SIZE = 3;
+static const int KEY_QUEUE_SIZE = 8192;
+
+
+ControllerThread::ControllerThread(KVncView *v, WriterThread &wt, volatile bool &quitFlag) :
+ m_view(v),
+ m_status(REMOTE_VIEW_CONNECTING),
+ m_wthread(wt),
+ m_quitFlag(quitFlag),
+ m_desktopInitialized(false)
+{
+}
+
+void ControllerThread::changeStatus(RemoteViewStatus s) {
+ m_status = s;
+ QApplication::postEvent(m_view, new StatusChangeEvent(s));
+}
+
+void ControllerThread::sendFatalError(ErrorCode s) {
+ m_quitFlag = true;
+ QApplication::postEvent(m_view, new FatalErrorEvent(s));
+ m_wthread.kick();
+}
+
+/*
+ * Calls this from the X11 thread
+ */
+void ControllerThread::desktopInit() {
+ SetVisualAndCmap();
+ ToplevelInit();
+ DesktopInit(m_view->winId());
+ m_desktopInitialized = true;
+ m_waiter.wakeAll();
+}
+
+void ControllerThread::kick() {
+ m_waiter.wakeAll();
+}
+
+void ControllerThread::run() {
+ int fd;
+ fd = ConnectToRFBServer(m_view->host().latin1(), m_view->port());
+ if (fd < 0) {
+ if (fd == -(int)INIT_NO_SERVER)
+ sendFatalError(ERROR_NO_SERVER);
+ else if (fd == -(int)INIT_NAME_RESOLUTION_FAILURE)
+ sendFatalError(ERROR_NAME);
+ else
+ sendFatalError(ERROR_CONNECTION);
+ return;
+ }
+ if (m_quitFlag) {
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
+ return;
+ }
+
+ changeStatus(REMOTE_VIEW_AUTHENTICATING);
+
+ enum InitStatus s = InitialiseRFBConnection();
+ if (s != INIT_OK) {
+ if (s == INIT_CONNECTION_FAILED)
+ sendFatalError(ERROR_IO);
+ else if (s == INIT_SERVER_BLOCKED)
+ sendFatalError(ERROR_SERVER_BLOCKED);
+ else if (s == INIT_PROTOCOL_FAILURE)
+ sendFatalError(ERROR_PROTOCOL);
+ else if (s == INIT_AUTHENTICATION_FAILED)
+ sendFatalError(ERROR_AUTHENTICATION);
+ else if (s == INIT_ABORTED)
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
+ else
+ sendFatalError(ERROR_INTERNAL);
+ return;
+ }
+
+ QApplication::postEvent(m_view,
+ new ScreenResizeEvent(si.framebufferWidth,
+ si.framebufferHeight));
+ m_wthread.queueUpdateRequest(QRegion(QRect(0,0,si.framebufferWidth,
+ si.framebufferHeight)));
+
+ QApplication::postEvent(m_view, new DesktopInitEvent());
+ while ((!m_quitFlag) && (!m_desktopInitialized))
+ m_waiter.wait(1000);
+
+ if (m_quitFlag) {
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
+ return;
+ }
+
+ changeStatus(REMOTE_VIEW_PREPARING);
+
+ if (!SetFormatAndEncodings()) {
+ sendFatalError(ERROR_INTERNAL);
+ return;
+ }
+
+ changeStatus(REMOTE_VIEW_CONNECTED);
+
+ m_wthread.start();
+
+ while (!m_quitFlag) {
+ if ((!HandleRFBServerMessage()) && (!m_quitFlag)) {
+ sendFatalError(ERROR_IO);
+ return;
+ }
+ }
+
+ m_quitFlag = true;
+ changeStatus(REMOTE_VIEW_DISCONNECTED);
+ m_wthread.kick();
+}
+
+enum RemoteViewStatus ControllerThread::status() {
+ return m_status;
+}
+
+
+
+
+
+static WriterThread *writerThread;
+void queueIncrementalUpdateRequest() {
+ writerThread->queueIncrementalUpdateRequest();
+}
+
+void announceIncrementalUpdateRequest() {
+ writerThread->announceIncrementalUpdateRequest();
+}
+
+
+WriterThread::WriterThread(KVncView *v, volatile bool &quitFlag) :
+ m_quitFlag(quitFlag),
+ m_view(v),
+ m_lastIncrUpdatePostponed(false),
+ m_incrementalUpdateRQ(false),
+ m_incrementalUpdateAnnounced(false),
+ m_mouseEventNum(0),
+ m_keyEventNum(0),
+ m_clientCut(QString::null)
+{
+ writerThread = this;
+ m_lastIncrUpdate.start();
+}
+
+bool WriterThread::sendIncrementalUpdateRequest() {
+ m_lastIncrUpdate.restart();
+ return SendIncrementalFramebufferUpdateRequest();
+}
+
+bool WriterThread::sendUpdateRequest(const QRegion &region) {
+ QMemArray<QRect> r = region.rects();
+ for (unsigned int i = 0; i < r.size(); i++)
+ if (!SendFramebufferUpdateRequest(r[i].x(),
+ r[i].y(),
+ r[i].width(),
+ r[i].height(), False))
+ return false;
+ return true;
+}
+
+bool WriterThread::sendInputEvents(const QValueList<InputEvent> &events) {
+ QValueList<InputEvent>::const_iterator it = events.begin();
+ while (it != events.end()) {
+ if ((*it).type == KeyEventType) {
+ if (!SendKeyEvent((*it).e.k.k, (*it).e.k.down ? True : False))
+ return false;
+ }
+ else
+ if (!SendPointerEvent((*it).e.m.x, (*it).e.m.y, (*it).e.m.buttons))
+ return false;
+ it++;
+ }
+ return true;
+}
+
+void WriterThread::queueIncrementalUpdateRequest() {
+ m_lock.lock();
+ m_incrementalUpdateRQ = true;
+ m_waiter.wakeAll();
+ m_lock.unlock();
+}
+
+void WriterThread::announceIncrementalUpdateRequest() {
+ m_lock.lock();
+ m_incrementalUpdateAnnounced = true;
+ m_lock.unlock();
+}
+
+
+void WriterThread::queueUpdateRequest(const QRegion &r) {
+ m_lock.lock();
+ m_updateRegionRQ += r;
+ m_waiter.wakeAll();
+ m_lock.unlock();
+}
+
+void WriterThread::queueMouseEvent(int x, int y, int buttonMask) {
+ InputEvent e;
+ e.type = MouseEventType;
+ e.e.m.x = x;
+ e.e.m.y = y;
+ e.e.m.buttons = buttonMask;
+
+ m_lock.lock();
+ if (m_mouseEventNum > 0) {
+ if ((e.e.m.x == m_lastMouseEvent.x) &&
+ (e.e.m.y == m_lastMouseEvent.y) &&
+ (e.e.m.buttons == m_lastMouseEvent.buttons)) {
+ m_lock.unlock();
+ return;
+ }
+ if (m_mouseEventNum >= MOUSEPRESS_QUEUE_SIZE) {
+ m_lock.unlock();
+ return;
+ }
+ if ((m_lastMouseEvent.buttons == buttonMask) &&
+ (m_mouseEventNum >= MOUSEMOVE_QUEUE_SIZE)) {
+ m_lock.unlock();
+ return;
+ }
+ }
+
+ m_mouseEventNum++;
+ m_lastMouseEvent = e.e.m;
+
+ m_inputEvents.push_back(e);
+ m_waiter.wakeAll();
+ m_lock.unlock();
+}
+
+void WriterThread::queueKeyEvent(unsigned int k, bool down) {
+ InputEvent e;
+ e.type = KeyEventType;
+ e.e.k.k = k;
+ e.e.k.down = down;
+
+ m_lock.lock();
+ if (m_keyEventNum >= KEY_QUEUE_SIZE) {
+ m_lock.unlock();
+ return;
+ }
+
+ m_keyEventNum++;
+ m_inputEvents.push_back(e);
+ m_waiter.wakeAll();
+ m_lock.unlock();
+}
+
+void WriterThread::queueClientCut(const QString &text) {
+ m_lock.lock();
+
+ m_clientCut = text;
+
+ m_waiter.wakeAll();
+ m_lock.unlock();
+}
+
+void WriterThread::kick() {
+ m_waiter.wakeAll();
+}
+
+void WriterThread::run() {
+ bool incrementalUpdateRQ = false;
+ bool incrementalUpdateAnnounced = false;
+ QRegion updateRegionRQ;
+ QValueList<InputEvent> inputEvents;
+ QString clientCut;
+
+ while (!m_quitFlag) {
+ m_lock.lock();
+ incrementalUpdateRQ = m_incrementalUpdateRQ;
+ incrementalUpdateAnnounced = m_incrementalUpdateAnnounced;
+ updateRegionRQ = m_updateRegionRQ;
+ inputEvents = m_inputEvents;
+ clientCut = m_clientCut;
+
+ if ((!incrementalUpdateRQ) &&
+ (updateRegionRQ.isNull()) &&
+ (inputEvents.size() == 0) &&
+ (clientCut.isNull())) {
+ if (!m_waiter.wait(&m_lock,
+ m_lastIncrUpdatePostponed ?
+ POSTPONED_INCRRQ_WAIT_PERIOD : MAXIMUM_WAIT_PERIOD))
+ m_incrementalUpdateRQ = true;
+ m_lock.unlock();
+ }
+ else {
+ m_incrementalUpdateRQ = false;
+ m_incrementalUpdateAnnounced = false;
+ m_updateRegionRQ = QRegion();
+ m_inputEvents.clear();
+ m_keyEventNum = 0;
+ m_mouseEventNum = 0;
+ m_clientCut = QString::null;
+ m_lock.unlock();
+
+ // always send incremental update, unless
+ // a) a framebuffer update is done ATM and will do the request later, or
+ // b) the last unrequested update has been done less than 0.1s ago
+ //
+ // if the update has not been done because of b, postpone it.
+ if (incrementalUpdateRQ || !incrementalUpdateAnnounced) {
+ bool sendUpdate;
+ if (incrementalUpdateRQ) {
+ sendUpdate = true;
+ m_lastIncrUpdatePostponed = false;
+ }
+ else {
+ if (m_lastIncrUpdate.elapsed() < 100) {
+ sendUpdate = false;
+ m_lastIncrUpdatePostponed = true;
+ }
+ else {
+ sendUpdate = true;
+ m_lastIncrUpdatePostponed = false;
+ }
+ }
+
+ if (sendUpdate)
+ if (!sendIncrementalUpdateRequest()) {
+ sendFatalError(ERROR_IO);
+ break;
+ }
+ }
+ else
+ m_lastIncrUpdatePostponed = false;
+
+ if (!updateRegionRQ.isNull())
+ if (!sendUpdateRequest(updateRegionRQ)) {
+ sendFatalError(ERROR_IO);
+ break;
+ }
+ if (inputEvents.size() != 0)
+ if (!sendInputEvents(inputEvents)) {
+ sendFatalError(ERROR_IO);
+ break;
+ }
+ if (!clientCut.isNull()) {
+ QCString cutTextUtf8(clientCut.utf8());
+ if (!SendClientCutText(cutTextUtf8.data(),
+ (int)cutTextUtf8.length())) {
+ sendFatalError(ERROR_IO);
+ break;
+ }
+ }
+ }
+ }
+ m_quitFlag = true;
+}
+
+void WriterThread::sendFatalError(ErrorCode s) {
+ m_quitFlag = true;
+ QApplication::postEvent(m_view, new FatalErrorEvent(s));
+}
+
diff --git a/krdc/vnc/threads.h b/krdc/vnc/threads.h
new file mode 100644
index 00000000..5f38b71f
--- /dev/null
+++ b/krdc/vnc/threads.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ threads.h - threads for kvncview
+ -------------------
+ begin : Thu May 09 16:01:42 CET 2002
+ copyright : (C) 2002 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef THREADS_H
+#define THREADS_H
+
+#include <qthread.h>
+#include <qregion.h>
+#include <qrect.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qevent.h>
+#include <qvaluelist.h>
+#include <qdatetime.h>
+
+#include <stdlib.h>
+
+#include "events.h"
+#include "vnctypes.h"
+
+class KVncView;
+
+enum EventType {
+ MouseEventType,
+ KeyEventType
+};
+
+
+struct MouseEvent {
+ int x, y, buttons;
+};
+
+struct KeyEvent {
+ unsigned int k;
+ bool down;
+};
+
+struct InputEvent {
+ EventType type;
+ union {
+ MouseEvent m;
+ KeyEvent k;
+ } e;
+};
+
+
+class WriterThread : public QThread {
+private:
+ QMutex m_lock;
+ QWaitCondition m_waiter;
+ volatile bool &m_quitFlag;
+ KVncView *m_view;
+
+ QTime m_lastIncrUpdate; // start()ed when a incr update is sent
+ bool m_lastIncrUpdatePostponed;
+
+ // all things that can be send follow:
+ bool m_incrementalUpdateRQ; // for sending an incremental request
+ bool m_incrementalUpdateAnnounced; // set when a RQ will come soon
+ QRegion m_updateRegionRQ; // for sending updates, null if it is done
+ QValueList<InputEvent> m_inputEvents; // list of unsent input events
+ MouseEvent m_lastMouseEvent;
+ int m_mouseEventNum, m_keyEventNum;
+ QString m_clientCut;
+
+ void sendFatalError(ErrorCode s);
+
+public:
+ WriterThread(KVncView *v, volatile bool &quitFlag);
+
+ void queueIncrementalUpdateRequest();
+ void announceIncrementalUpdateRequest();
+ void queueUpdateRequest(const QRegion &r);
+ void queueMouseEvent(int x, int y, int buttonMask);
+ void queueKeyEvent(unsigned int k, bool down);
+ void queueClientCut(const QString &text);
+ void kick();
+
+protected:
+ void run();
+ bool sendIncrementalUpdateRequest();
+ bool sendUpdateRequest(const QRegion &r);
+ bool sendInputEvents(const QValueList<InputEvent> &events);
+};
+
+
+
+class ControllerThread : public QThread {
+private:
+ KVncView *m_view;
+ enum RemoteViewStatus m_status;
+ WriterThread &m_wthread;
+ volatile bool &m_quitFlag;
+ volatile bool m_desktopInitialized;
+ QWaitCondition m_waiter;
+
+ void changeStatus(RemoteViewStatus s);
+ void sendFatalError(ErrorCode s);
+
+public:
+ ControllerThread(KVncView *v, WriterThread &wt, volatile bool &quitFlag);
+ enum RemoteViewStatus status();
+ void desktopInit();
+ void kick();
+
+protected:
+ void run();
+};
+
+
+
+#endif
diff --git a/krdc/vnc/tight.c b/krdc/vnc/tight.c
new file mode 100644
index 00000000..2f08cfb0
--- /dev/null
+++ b/krdc/vnc/tight.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2000, 2001 Const 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.
+ */
+
+/*
+ * tight.c - handle ``tight'' encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple
+ * times by rfbproto.c, each time with a different definition of the
+ * macro BPP. For each value of BPP, this file defines a function
+ * which handles a tight-encoded rectangle with BPP bits per pixel.
+ *
+ */
+
+#define TIGHT_MIN_TO_COMPRESS 12
+
+#define CARDBPP CONCAT2E(CARD,BPP)
+#define filterPtrBPP CONCAT2E(filterPtr,BPP)
+
+#define HandleTightBPP CONCAT2E(HandleTight,BPP)
+#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
+#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
+#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
+#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
+#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
+#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
+#define FillRectangleBPP CONCAT2E(FillRectangle,BPP)
+
+#if BPP != 8
+#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
+#endif
+
+#ifndef RGB_TO_PIXEL
+
+#define RGB_TO_PIXEL(bpp,r,g,b) \
+ (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift | \
+ ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift | \
+ ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL(bpp,r,g,b) \
+ ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \
+ << myFormat.redShift | \
+ (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \
+ << myFormat.greenShift | \
+ (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \
+ << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL32(r,g,b) \
+ (((CARD32)(r) & 0xFF) << myFormat.redShift | \
+ ((CARD32)(g) & 0xFF) << myFormat.greenShift | \
+ ((CARD32)(b) & 0xFF) << myFormat.blueShift)
+
+#endif
+
+/* Type declarations */
+
+typedef void (*filterPtrBPP)(int, CARDBPP *);
+
+/* Prototypes */
+
+static int InitFilterCopyBPP (int rw, int rh);
+static int InitFilterPaletteBPP (int rw, int rh);
+static int InitFilterGradientBPP (int rw, int rh);
+static void FilterCopyBPP (int numRows, CARDBPP *destBuffer);
+static void FilterPaletteBPP (int numRows, CARDBPP *destBuffer);
+static void FilterGradientBPP (int numRows, CARDBPP *destBuffer);
+
+static Bool DecompressJpegRectBPP(int x, int y, int w, int h);
+
+/* Definitions */
+
+static Bool
+HandleTightBPP (int rx, int ry, int rw, int rh)
+{
+ CARDBPP fill_colour;
+ XGCValues gcv;
+ CARD8 comp_ctl;
+ CARD8 filter_id;
+ filterPtrBPP filterFn;
+ z_streamp zs;
+ char *buffer2;
+ int err, stream_id, compressedLen, bitsPixel;
+ int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
+ CARDBPP *rawData;
+
+ if (!ReadFromRFBServer((char *)&comp_ctl, 1))
+ return False;
+
+ /* Flush zlib streams if we are told by the server to do so. */
+ for (stream_id = 0; stream_id < 4; stream_id++) {
+ if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
+ if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
+ zlibStream[stream_id].msg != NULL)
+ fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
+ zlibStreamActive[stream_id] = False;
+ }
+ comp_ctl >>= 1;
+ }
+
+ /* Handle solid rectangles. */
+ if (comp_ctl == rfbTightFill) {
+#if BPP == 32
+ if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+ myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+ if (!ReadFromRFBServer(buffer, 3))
+ return False;
+ fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]);
+ } else {
+ if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
+ return False;
+ }
+#else
+ if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
+ return False;
+#endif
+
+ LockFramebuffer();
+ FillRectangleBPP(fill_colour, rx, ry, rw, rh);
+ UnlockFramebuffer();
+ SyncScreenRegion(rx, ry, rw, rh);
+ return True;
+ }
+
+#if BPP == 8
+ if (comp_ctl == rfbTightJpeg) {
+ fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
+ return False;
+ }
+#else
+ if (comp_ctl == rfbTightJpeg) {
+ return DecompressJpegRectBPP(rx, ry, rw, rh);
+ }
+#endif
+
+ /* Quit on unsupported subencoding value. */
+ if (comp_ctl > rfbTightMaxSubencoding) {
+ fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
+ return False;
+ }
+
+ /*
+ * Here primary compression mode handling begins.
+ * Data was processed with optional filter + zlib compression.
+ */
+
+ /* First, we should identify a filter to use. */
+ if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+ if (!ReadFromRFBServer((char*)&filter_id, 1))
+ return False;
+
+ switch (filter_id) {
+ case rfbTightFilterCopy:
+ filterFn = FilterCopyBPP;
+ bitsPixel = InitFilterCopyBPP(rw, rh);
+ break;
+ case rfbTightFilterPalette:
+ filterFn = FilterPaletteBPP;
+ bitsPixel = InitFilterPaletteBPP(rw, rh);
+ break;
+ case rfbTightFilterGradient:
+ filterFn = FilterGradientBPP;
+ bitsPixel = InitFilterGradientBPP(rw, rh);
+ break;
+ default:
+ fprintf(stderr, "Tight encoding: unknown filter code received.\n");
+ return False;
+ }
+ } else {
+ filterFn = FilterCopyBPP;
+ bitsPixel = InitFilterCopyBPP(rw, rh);
+ }
+ if (bitsPixel == 0) {
+ fprintf(stderr, "Tight encoding: error receiving palette.\n");
+ return False;
+ }
+
+ /* Determine if the data should be decompressed or just copied. */
+ rowSize = (rw * bitsPixel + 7) / 8;
+ if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
+ if (!ReadFromRFBServer((char*)buffer, rh * rowSize))
+ return False;
+
+ buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4];
+ filterFn(rh, (CARDBPP *)buffer2);
+ CopyDataToScreen(buffer2, rx, ry, rw, rh);
+
+ return True;
+ }
+
+ /* Read the length (1..3 bytes) of compressed data following. */
+ compressedLen = (int)ReadCompactLen();
+ if (compressedLen <= 0) {
+ fprintf(stderr, "Incorrect data received from the server.\n");
+ return False;
+ }
+
+ /* Now let's initialize compression stream if needed. */
+ stream_id = comp_ctl & 0x03;
+ zs = &zlibStream[stream_id];
+ if (!zlibStreamActive[stream_id]) {
+ zs->zalloc = Z_NULL;
+ zs->zfree = Z_NULL;
+ zs->opaque = Z_NULL;
+ err = inflateInit(zs);
+ if (err != Z_OK) {
+ if (zs->msg != NULL)
+ fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
+ return False;
+ }
+ zlibStreamActive[stream_id] = True;
+ }
+
+ /* Read, decode and draw actual pixel data in a loop. */
+
+ bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
+ buffer2 = &buffer[bufferSize];
+ if (rowSize > bufferSize) {
+ /* Should be impossible when BUFFER_SIZE >= 16384 */
+ fprintf(stderr, "Internal error: incorrect buffer size.\n");
+ return False;
+ }
+
+ rowsProcessed = 0;
+ extraBytes = 0;
+
+ while (compressedLen > 0) {
+ if (compressedLen > ZLIB_BUFFER_SIZE)
+ portionLen = ZLIB_BUFFER_SIZE;
+ else
+ portionLen = compressedLen;
+
+ if (!ReadFromRFBServer((char*)zlib_buffer, portionLen))
+ return False;
+
+ compressedLen -= portionLen;
+
+ zs->next_in = (Bytef *)zlib_buffer;
+ zs->avail_in = portionLen;
+
+ do {
+ zs->next_out = (Bytef *)&buffer[extraBytes];
+ zs->avail_out = bufferSize - extraBytes;
+
+ err = inflate(zs, Z_SYNC_FLUSH);
+ if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */
+ break;
+ if (err != Z_OK && err != Z_STREAM_END) {
+ if (zs->msg != NULL) {
+ fprintf(stderr, "Inflate error: %s.\n", zs->msg);
+ } else {
+ fprintf(stderr, "Inflate error: %d.\n", err);
+ }
+ return False;
+ }
+
+ numRows = (bufferSize - zs->avail_out) / rowSize;
+
+ filterFn(numRows, (CARDBPP *)buffer2);
+
+ extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
+ if (extraBytes > 0)
+ memcpy(buffer, &buffer[numRows * rowSize], extraBytes);
+
+ CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows);
+ rowsProcessed += numRows;
+ }
+ while (zs->avail_out == 0);
+ }
+
+ if (rowsProcessed != rh) {
+ fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
+ return False;
+ }
+
+ return True;
+}
+
+/*----------------------------------------------------------------------------
+ *
+ * Filter stuff.
+ *
+ */
+
+/*
+ The following variables are defined in rfbproto.c:
+ static Bool cutZeros;
+ static int rectWidth, rectColors;
+ static CARD8 tightPalette[256*4];
+ static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
+*/
+
+static int
+InitFilterCopyBPP (int rw, int rh)
+{
+ rectWidth = rw;
+
+#if BPP == 32
+ if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+ myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+ cutZeros = True;
+ return 24;
+ } else {
+ cutZeros = False;
+ }
+#endif
+
+ return BPP;
+}
+
+static void
+FilterCopyBPP (int numRows, CARDBPP *dst)
+{
+
+#if BPP == 32
+ int x, y;
+
+ if (cutZeros) {
+ for (y = 0; y < numRows; y++) {
+ for (x = 0; x < rectWidth; x++) {
+ dst[y*rectWidth+x] =
+ RGB24_TO_PIXEL32(buffer[(y*rectWidth+x)*3],
+ buffer[(y*rectWidth+x)*3+1],
+ buffer[(y*rectWidth+x)*3+2]);
+ }
+ }
+ return;
+ }
+#endif
+
+ memcpy (dst, buffer, numRows * rectWidth * (BPP / 8));
+}
+
+static int
+InitFilterGradientBPP (int rw, int rh)
+{
+ int bits;
+
+ bits = InitFilterCopyBPP(rw, rh);
+ if (cutZeros)
+ memset(tightPrevRow, 0, rw * 3);
+ else
+ memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
+
+ return bits;
+}
+
+#if BPP == 32
+
+static void
+FilterGradient24 (int numRows, CARD32 *dst)
+{
+ int x, y, c;
+ CARD8 thisRow[2048*3];
+ CARD8 pix[3];
+ int est[3];
+
+ for (y = 0; y < numRows; y++) {
+
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = tightPrevRow[c] + buffer[y*rectWidth*3+c];
+ thisRow[c] = pix[c];
+ }
+ dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
+ (int)tightPrevRow[(x-1)*3+c];
+ if (est[c] > 0xFF) {
+ est[c] = 0xFF;
+ } else if (est[c] < 0x00) {
+ est[c] = 0x00;
+ }
+ pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c];
+ thisRow[x*3+c] = pix[c];
+ }
+ dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+ }
+
+ memcpy(tightPrevRow, thisRow, rectWidth * 3);
+ }
+}
+
+#endif
+
+static void
+FilterGradientBPP (int numRows, CARDBPP *dst)
+{
+ int x, y, c;
+ CARDBPP *src = (CARDBPP *)buffer;
+ CARD16 *thatRow = (CARD16 *)tightPrevRow;
+ CARD16 thisRow[2048*3];
+ CARD16 pix[3];
+ CARD16 max[3];
+ int shift[3];
+ int est[3];
+
+#if BPP == 32
+ if (cutZeros) {
+ FilterGradient24(numRows, dst);
+ return;
+ }
+#endif
+
+ max[0] = myFormat.redMax;
+ max[1] = myFormat.greenMax;
+ max[2] = myFormat.blueMax;
+
+ shift[0] = myFormat.redShift;
+ shift[1] = myFormat.greenShift;
+ shift[2] = myFormat.blueShift;
+
+ for (y = 0; y < numRows; y++) {
+
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
+ thisRow[c] = pix[c];
+ }
+ dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
+ if (est[c] > (int)max[c]) {
+ est[c] = (int)max[c];
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
+ thisRow[x*3+c] = pix[c];
+ }
+ dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+ }
+ memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
+ }
+}
+
+static int
+InitFilterPaletteBPP (int rw, int rh)
+{
+ int i;
+ CARD8 numColors;
+ CARDBPP *palette = (CARDBPP *)tightPalette;
+
+ rectWidth = rw;
+
+ if (!ReadFromRFBServer((char*)&numColors, 1))
+ return 0;
+
+ rectColors = (int)numColors;
+ if (++rectColors < 2)
+ return 0;
+
+#if BPP == 32
+ if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+ myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+ if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3))
+ return 0;
+ for (i = rectColors - 1; i >= 0; i--) {
+ palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+ tightPalette[i*3+1],
+ tightPalette[i*3+2]);
+ }
+ return (rectColors == 2) ? 1 : 8;
+ }
+#endif
+
+ if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8)))
+ return 0;
+
+ return (rectColors == 2) ? 1 : 8;
+}
+
+static void
+FilterPaletteBPP (int numRows, CARDBPP *dst)
+{
+ int x, y, b, w;
+ CARD8 *src = (CARD8 *)buffer;
+ CARDBPP *palette = (CARDBPP *)tightPalette;
+
+ if (rectColors == 2) {
+ w = (rectWidth + 7) / 8;
+ for (y = 0; y < numRows; y++) {
+ for (x = 0; x < rectWidth / 8; x++) {
+ for (b = 7; b >= 0; b--)
+ dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+ }
+ for (b = 7; b >= 8 - rectWidth % 8; b--) {
+ dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+ }
+ }
+ } else {
+ for (y = 0; y < numRows; y++)
+ for (x = 0; x < rectWidth; x++)
+ dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
+ }
+}
+
+#if BPP != 8
+
+/*----------------------------------------------------------------------------
+ *
+ * JPEG decompression.
+ *
+ */
+
+/*
+ The following variables are defined in rfbproto.c:
+ static Bool jpegError;
+ static struct jpeg_source_mgr jpegSrcManager;
+ static JOCTET *jpegBufferPtr;
+ static size_t *jpegBufferLen;
+*/
+
+static Bool
+DecompressJpegRectBPP(int x, int y, int w, int h)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ int compressedLen;
+ CARD8 *compressedData;
+ CARDBPP *pixelPtr;
+ JSAMPROW rowPointer[1];
+ int dx, dy;
+
+ compressedLen = (int)ReadCompactLen();
+ if (compressedLen <= 0) {
+ fprintf(stderr, "Incorrect data received from the server.\n");
+ return False;
+ }
+
+ if (compressedLen > MAX_JPEG_SIZE) {
+ fprintf(stderr, "To large data announced by the server.\n");
+ return False;
+ }
+
+ compressedData = malloc(compressedLen);
+ if (compressedData == NULL) {
+ fprintf(stderr, "Memory allocation error.\n");
+ return False;
+ }
+
+ if (!ReadFromRFBServer((char*)compressedData, compressedLen)) {
+ free(compressedData);
+ return False;
+ }
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+
+ JpegSetSrcManager(&cinfo, compressedData, compressedLen);
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.out_color_space = JCS_RGB;
+
+ jpeg_start_decompress(&cinfo);
+ if (cinfo.output_width != w || cinfo.output_height != h ||
+ cinfo.output_components != 3) {
+ fprintf(stderr, "Tight Encoding: Wrong JPEG data received.\n");
+ jpeg_destroy_decompress(&cinfo);
+ free(compressedData);
+ return False;
+ }
+
+ rowPointer[0] = (JSAMPROW)buffer;
+ dy = 0;
+ while (cinfo.output_scanline < cinfo.output_height) {
+ jpeg_read_scanlines(&cinfo, rowPointer, 1);
+ if (jpegError) {
+ break;
+ }
+ pixelPtr = (CARDBPP *)&buffer[BUFFER_SIZE / 2];
+ for (dx = 0; dx < w; dx++) {
+ *pixelPtr++ =
+ RGB24_TO_PIXEL(BPP, buffer[dx*3], buffer[dx*3+1], buffer[dx*3+2]);
+ }
+ CopyDataToScreen(&buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
+ dy++;
+ }
+
+ if (!jpegError)
+ jpeg_finish_decompress(&cinfo);
+
+ jpeg_destroy_decompress(&cinfo);
+ free(compressedData);
+
+ return !jpegError;
+}
+
+#endif
+
diff --git a/krdc/vnc/vncauth.c b/krdc/vnc/vncauth.c
new file mode 100644
index 00000000..b5d42836
--- /dev/null
+++ b/krdc/vnc/vncauth.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*
+ * vncauth.c - Functions for VNC password management and authentication.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <vncauth.h>
+#include <d3des.h>
+
+
+/*
+ * 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.
+ */
+
+unsigned char 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.
+ */
+
+int
+vncEncryptAndStorePasswd(char *passwd, char *fname)
+{
+ FILE *fp;
+ int i;
+ unsigned char encryptedPasswd[8];
+
+ if ((fp = fopen(fname,"w")) == NULL) return 1;
+
+ chmod(fname, S_IRUSR|S_IWUSR);
+
+ /* pad password with nulls */
+
+ for (i = 0; i < 8; i++) {
+ if (i < strlen(passwd)) {
+ encryptedPasswd[i] = passwd[i];
+ } else {
+ encryptedPasswd[i] = 0;
+ }
+ }
+
+ /* Do encryption in-place - this way we overwrite our copy of the plaintext
+ password */
+
+ deskey(fixedkey, EN0);
+ des(encryptedPasswd, encryptedPasswd);
+
+ for (i = 0; i < 8; i++) {
+ putc(encryptedPasswd[i], fp);
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+
+/*
+ * 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.
+ */
+
+char *
+vncDecryptPasswdFromFile(char *fname)
+{
+ FILE *fp;
+ int i, ch;
+ unsigned char *passwd = (unsigned char *)malloc(9);
+
+ if ((fp = fopen(fname,"r")) == NULL) return NULL;
+
+ for (i = 0; i < 8; i++) {
+ ch = getc(fp);
+ if (ch == EOF) {
+ fclose(fp);
+ return NULL;
+ }
+ passwd[i] = ch;
+ }
+
+ fclose(fp);
+
+ deskey(fixedkey, DE1);
+ des(passwd, passwd);
+
+ passwd[8] = 0;
+
+ return (char *)passwd;
+}
+
+
+/*
+ * Generate CHALLENGESIZE random bytes for use in challenge-response
+ * authentication.
+ */
+
+void
+vncRandomBytes(unsigned char *bytes)
+{
+ int i;
+ unsigned int seed = (unsigned int) time(0);
+
+ srandom(seed);
+ 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/krdc/vnc/vncauth.h b/krdc/vnc/vncauth.h
new file mode 100644
index 00000000..86dc455c
--- /dev/null
+++ b/krdc/vnc/vncauth.h
@@ -0,0 +1,30 @@
+/*
+ * 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);
diff --git a/krdc/vnc/vnchostpref.cpp b/krdc/vnc/vnchostpref.cpp
new file mode 100644
index 00000000..a17f8ea1
--- /dev/null
+++ b/krdc/vnc/vnchostpref.cpp
@@ -0,0 +1,127 @@
+/***************************************************************************
+ vnchostprefs.cpp - vnc host preferences
+ -------------------
+ begin : Fri May 09 22:32 CET 2003
+ copyright : (C) 2003 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "vnchostpref.h"
+#include <kconfig.h>
+#include <klocale.h>
+
+const QString VncHostPref::VncType = "VNC";
+
+VncHostPref::VncHostPref(KConfig *conf, const QString &host, const QString &type) :
+ HostPref(conf, host, type),
+ m_quality(0),
+ m_useKWallet(true),
+ m_askOnConnect(true) {
+}
+
+VncHostPref::~VncHostPref() {
+}
+
+void VncHostPref::save() {
+ if ( !m_host.isEmpty() && !m_type.isEmpty() )
+ {
+ m_config->setGroup("PerHostSettings");
+ QString p = prefix();
+ m_config->writeEntry(p+"exists", true);
+ m_config->writeEntry(p+"quality", m_quality);
+ m_config->writeEntry(p+"askOnConnect", m_askOnConnect);
+ m_config->writeEntry(p+"useKWallet", m_useKWallet);
+ }
+ else
+ {
+ m_config->setGroup( "VncDefaultSettings" );
+ m_config->writeEntry( "vncQuality", m_quality );
+ m_config->writeEntry( "vncShowHostPreferences", m_askOnConnect );
+ m_config->writeEntry( "vncUseKWallet", m_useKWallet );
+ }
+}
+
+void VncHostPref::load() {
+ if ( !m_host.isEmpty() && !m_type.isEmpty() )
+ {
+ m_config->setGroup("PerHostSettings");
+ QString p = prefix();
+ m_quality = m_config->readNumEntry(p+"quality", 0);
+ m_askOnConnect = m_config->readBoolEntry(p+"askOnConnect", true);
+ m_useKWallet = m_config->readBoolEntry(p+"useKWallet", true);
+ }
+ else
+ {
+ setDefaults();
+ }
+}
+
+void VncHostPref::remove() {
+ m_config->setGroup("PerHostSettings");
+ QString p = prefix();
+ m_config->deleteEntry(p+"exists");
+ m_config->deleteEntry(p+"quality");
+ m_config->deleteEntry(p+"askOnConnect");
+}
+
+void VncHostPref::setDefaults() {
+ m_config->setGroup("VncDefaultSettings");
+ m_quality = m_config->readNumEntry("vncQuality", 0);
+ m_askOnConnect = m_config->readBoolEntry("vncShowHostPreferences", true);
+ m_useKWallet = m_config->readBoolEntry("vncUseKWallet", true);
+}
+
+QString VncHostPref::prefDescription() const {
+ QString q;
+ switch(m_quality) {
+ case 0:
+ q = i18n("High");
+ break;
+ case 1:
+ q = i18n("Medium");
+ break;
+ case 2:
+ q = i18n("Low");
+ break;
+ default:
+ Q_ASSERT(true);
+ }
+ return i18n("Show Preferences: %1, Quality: %2, KWallet: %3")
+ .arg(m_askOnConnect ? i18n("yes") : i18n("no")).arg(q).arg(m_useKWallet ? i18n("yes") : i18n("no"));
+}
+
+void VncHostPref::setQuality(int q) {
+ m_quality = q;
+ save();
+}
+
+int VncHostPref::quality() const {
+ return m_quality;
+}
+
+void VncHostPref::setAskOnConnect(bool ask) {
+ m_askOnConnect = ask;
+ save();
+}
+
+bool VncHostPref::askOnConnect() const {
+ return m_askOnConnect;
+}
+
+void VncHostPref::setUseKWallet(bool use) {
+ m_useKWallet = use;
+ save();
+}
+
+bool VncHostPref::useKWallet() const {
+ return m_useKWallet;
+}
diff --git a/krdc/vnc/vnchostpref.h b/krdc/vnc/vnchostpref.h
new file mode 100644
index 00000000..33a20600
--- /dev/null
+++ b/krdc/vnc/vnchostpref.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ vnchostprefs.h - vnc host preferences
+ -------------------
+ begin : Fri May 09 22:32 CET 2003
+ copyright : (C) 2003 by Tim Jansen
+ email : tim@tjansen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef VNCHOSTPREF_H
+#define VNCHOSTPREF_H
+
+#include "hostpreferences.h"
+
+class VncHostPref : public HostPref {
+protected:
+ friend class HostPreferences;
+
+ int m_quality;
+ bool m_askOnConnect;
+ bool m_useKWallet;
+
+ virtual void load();
+ virtual void setDefaults();
+ virtual void save();
+ virtual void remove();
+
+public:
+ static const QString VncType;
+
+ VncHostPref(KConfig *conf, const QString &host=QString::null,
+ const QString &type=QString::null);
+ virtual ~VncHostPref();
+
+ virtual QString prefDescription() const;
+ void setQuality(int q);
+ int quality() const;
+ void setAskOnConnect(bool ask);
+ bool askOnConnect() const;
+ void setUseKWallet(bool);
+ bool useKWallet() const;
+};
+
+#endif
diff --git a/krdc/vnc/vncprefs.ui b/krdc/vnc/vncprefs.ui
new file mode 100644
index 00000000..034b2b1a
--- /dev/null
+++ b/krdc/vnc/vncprefs.ui
@@ -0,0 +1,165 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>VncPrefs</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>VncPrefs</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>472</width>
+ <height>126</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox</cstring>
+ </property>
+ <property name="title">
+ <string>Connection</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>cbUseEncryption</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Enable encryption (secure, but slow and not always possible)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enable this option to encrypt the connection. Only newer servers support this option. Encrypting prevents others from eavesdropping, but can slow down the connection considerably.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>cbUseKWallet</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Use K&amp;Wallet for passwords</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enable this option to store your passwords with KWallet.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>connectionTypeLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Connection &amp;type:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>cmbQuality</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>High Quality (LAN, direct connection)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Medium Quality (DSL, Cable, fast Internet)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Low Quality (Modem, ISDN, slow Internet)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>cmbQuality</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>280</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Use this to specify the performance of your connection. Note that you should select the speed of the weakest link - even if you have a high speed connection, it will not help you if the remote computer uses a slow modem. Choosing a level of quality that is too high on a slow link will cause slower response times. Choosing a lower quality will increase latencies in high speed connections and results in lower image quality, especially in 'Low Quality' mode.</string>
+ </property>
+ </widget>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>Spacer</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>84</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>cbShowPrefs</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show this dialog again for this host</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select this option if you do not want to be asked for the settings when connecting to a host. For hosts with existing profiles these profiles will be taken. New hosts will be configured with the defaults.</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="local" impldecl="in implementation">vncprefs.ui.h</include>
+</includes>
+<functions>
+ <function specifier="non virtual">setQuality( int quality )</function>
+ <function specifier="non virtual" returnType="int">quality()</function>
+ <function specifier="non virtual">setShowPrefs( bool b )</function>
+ <function specifier="non virtual" returnType="int">showPrefs()</function>
+ <function specifier="non virtual">setUseEncryption( bool b )</function>
+ <function specifier="non virtual" returnType="bool">useEncryption()</function>
+ <function specifier="non virtual">setUseKWallet( bool b )</function>
+ <function specifier="non virtual" returnType="bool">useKWallet()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/krdc/vnc/vncprefs.ui.h b/krdc/vnc/vncprefs.ui.h
new file mode 100644
index 00000000..a3438f05
--- /dev/null
+++ b/krdc/vnc/vncprefs.ui.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+void VncPrefs::setQuality( int quality )
+{
+ cmbQuality->setCurrentItem(quality);
+}
+
+
+int VncPrefs::quality()
+{
+ return cmbQuality->currentItem();
+}
+
+
+void VncPrefs::setShowPrefs( bool b )
+{
+ cbShowPrefs->setChecked(b);
+}
+
+
+int VncPrefs::showPrefs()
+{
+ return cbShowPrefs->isChecked();
+}
+
+
+void VncPrefs::setUseEncryption( bool b )
+{
+ cbUseEncryption->setChecked(b);
+}
+
+
+bool VncPrefs::useEncryption()
+{
+ return cbUseEncryption->isChecked();
+}
+
+void VncPrefs::setUseKWallet( bool b )
+{
+ cbUseKWallet->setChecked(b);
+}
+
+bool VncPrefs::useKWallet()
+{
+ return cbUseKWallet->isChecked();
+}
diff --git a/krdc/vnc/vnctypes.h b/krdc/vnc/vnctypes.h
new file mode 100644
index 00000000..15329ee2
--- /dev/null
+++ b/krdc/vnc/vnctypes.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2002 Tim Jansen. All Rights Reserved.
+ * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
+ * Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef VNCTYPES_H
+#define VNCTYPES_H
+
+#if(defined __cplusplus)
+extern "C"
+{
+#endif
+
+#include <X11/Xmd.h>
+
+
+typedef struct {
+ int shareDesktop; /* bool */
+ int viewOnly; /* bool */
+
+ const char* encodingsString;
+
+ int useBGR233; /* bool */
+ int nColours;
+ int useSharedColours; /* bool */
+ int requestedDepth;
+
+ int rawDelay;
+ int copyRectDelay;
+
+ int debug; /* bool */
+
+ int compressLevel;
+ int qualityLevel;
+ int dotCursor; /* bool */
+
+} AppData;
+
+
+enum InitStatus {
+ INIT_OK = 0,
+ INIT_NAME_RESOLUTION_FAILURE = 1,
+ INIT_PROTOCOL_FAILURE = 2,
+ INIT_CONNECTION_FAILED = 3,
+ INIT_AUTHENTICATION_FAILED = 4,
+ INIT_NO_SERVER = 5,
+ INIT_SERVER_BLOCKED = 6,
+ INIT_ABORTED = 7
+};
+
+
+#if(defined __cplusplus)
+}
+#endif
+
+#endif
diff --git a/krdc/vnc/vncviewer.h b/krdc/vnc/vncviewer.h
new file mode 100644
index 00000000..dcc66cde
--- /dev/null
+++ b/krdc/vnc/vncviewer.h
@@ -0,0 +1,186 @@
+#ifndef VNCVIEWER_H
+#define VNCVIEWER_H
+/*
+ * Copyright (C) 2000, 2001 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.
+ */
+
+/*
+ * vncviewer.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Xmu/StdSel.h>
+#include "vnctypes.h"
+
+#if(defined __cplusplus)
+extern "C"
+{
+#endif
+
+#include "rfbproto.h"
+
+extern int endianTest;
+
+#define Swap16IfLE(s) \
+ (*(char *)&endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s))
+
+#define Swap32IfLE(l) \
+ (*(char *)&endianTest ? ((((l) & 0xff000000) >> 24) | \
+ (((l) & 0x00ff0000) >> 8) | \
+ (((l) & 0x0000ff00) << 8) | \
+ (((l) & 0x000000ff) << 24)) : (l))
+
+#define MAX_ENCODINGS 20
+
+
+/** kvncview.cpp **/
+
+extern AppData appData;
+
+extern Display* dpy;
+extern const char *vncServerHost;
+extern int vncServerPort;
+
+extern int isQuitFlagSet();
+extern int getPassword(char *passwd, int pwlen);
+extern void DrawScreenRegion(int x, int y, int width, int height);
+extern void DrawAnyScreenRegionX11Thread(int x, int y, int width, int height);
+extern void LockFramebuffer();
+extern void UnlockFramebuffer();
+extern void EnableClientCursor(int state);
+extern void beep();
+extern void newServerCut(char *bytes, int len);
+extern void postMouseEvent(int x, int y, int buttonMask);
+
+/** threads.cpp **/
+
+extern void queueIncrementalUpdateRequest();
+extern void announceIncrementalUpdateRequest();
+
+/* colour.c */
+
+extern unsigned long BGR233ToPixel[];
+
+extern Colormap cmap;
+extern Visual *vis;
+extern unsigned int visdepth, visbpp;
+
+extern void SetVisualAndCmap(void);
+
+/* desktop.c */
+
+extern Widget form, viewport, desktop;
+extern GC gc;
+extern GC srcGC, dstGC;
+extern Dimension dpyWidth, dpyHeight;
+
+extern void DesktopInit(Window win);
+extern void ToplevelInit(void);
+extern void SendRFBEvent(XEvent *event, String *params, Cardinal *num_params);
+extern void CopyDataToScreen(char *buf, int x, int y, int width, int height);
+extern void CopyDataFromScreen(char *buf, int x, int y, int width, int height);
+extern void FillRectangle8(CARD8, int x, int y, int width, int height);
+extern void FillRectangle16(CARD16, int x, int y, int width, int height);
+extern void FillRectangle32(CARD32, int x, int y, int width, int height);
+extern void CopyArea(int srcX, int srcY, int width, int height, int x, int y);
+extern void SyncScreenRegion(int x, int y, int width, int height);
+extern void SyncScreenRegionX11Thread(int x, int y, int width, int height);
+extern void drawCursor(void);
+extern void DrawCursorX11Thread(int x, int y);
+extern void undrawCursor(void);
+extern void getBoundingRectCursor(int cx, int cy, int _imageIndex,
+ int *x, int *y, int *w, int *h);
+extern int rectsIntersect(int x, int y, int w, int h,
+ int x2, int y2, int w2, int h2);
+extern int rectContains(int outX, int outY, int outW, int outH,
+ int inX, int inY, int inW, int inH);
+extern void rectsJoin(int *nx1, int *ny1, int *nw1, int *nh1,
+ int x2, int y2, int w2, int h2);
+extern void DrawZoomedScreenRegionX11Thread(Window win, int zwidth,
+ int zheight,
+ int x, int y,
+ int width, int height);
+extern void DrawScreenRegionX11Thread(Window win, int x, int y,
+ int width, int height);
+extern void Cleanup(void);
+extern XImage *CreateShmZoomImage(void);
+extern XImage *CreateShmImage(void);
+extern void ShmCleanup(void);
+extern void freeDesktopResources(void);
+
+/* rfbproto.c */
+
+extern int rfbsock;
+extern Bool canUseCoRRE;
+extern Bool canUseHextile;
+extern char *desktopName;
+extern rfbPixelFormat myFormat;
+extern rfbServerInitMsg si;
+
+extern int cursorX, cursorY;
+extern int imageIndex;
+typedef struct {
+ int set;
+ int w, h;
+ int hotX, hotY;
+ int len;
+ char *image;
+} PointerImage;
+extern PointerImage pointerImages[];
+
+extern int ConnectToRFBServer(const char *hostname, int port);
+extern enum InitStatus InitialiseRFBConnection(void);
+extern Bool SetFormatAndEncodings(void);
+extern Bool SendIncrementalFramebufferUpdateRequest(void);
+extern Bool SendFramebufferUpdateRequest(int x, int y, int w, int h,
+ Bool incremental);
+extern Bool SendPointerEvent(int x, int y, int buttonMask);
+extern Bool SendKeyEvent(CARD32 key, Bool down);
+extern Bool SendClientCutText(const char *str, int len);
+extern Bool HandleRFBServerMessage(void);
+
+extern void PrintPixelFormat(rfbPixelFormat *format);
+extern void freeRFBProtoResources(void);
+extern void freeResources(void);
+
+/* sockets.c */
+
+extern Bool errorMessageOnReadFailure;
+
+extern Bool ReadFromRFBServer(char *out, unsigned int n);
+extern Bool WriteExact(int sock, const char *buf, int n);
+extern int ConnectToTcpAddr(unsigned int host, int port);
+
+extern int StringToIPAddr(const char *str, unsigned int *addr);
+extern void freeSocketsResources(void);
+
+#if(defined __cplusplus)
+}
+#endif
+#endif
diff --git a/krdc/vnc/zlib.c b/krdc/vnc/zlib.c
new file mode 100644
index 00000000..80c4eeea
--- /dev/null
+++ b/krdc/vnc/zlib.c
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+/*
+ * zlib.c - handle zlib encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP. For
+ * each value of BPP, this file defines a function which handles an zlib
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
+#define CARDBPP CONCAT2E(CARD,BPP)
+
+static Bool
+HandleZlibBPP (int rx, int ry, int rw, int rh)
+{
+ rfbZlibHeader hdr;
+ int remaining;
+ int inflateResult;
+ int toRead;
+
+ /* First make sure we have a large enough raw buffer to hold the
+ * decompressed data. In practice, with a fixed BPP, fixed frame
+ * buffer size and the first update containing the entire frame
+ * buffer, this buffer allocation should only happen once, on the
+ * first update.
+ */
+ if ( raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
+
+ if ( raw_buffer != NULL ) {
+
+ free( raw_buffer );
+
+ }
+
+ raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
+ raw_buffer = (char*) malloc( raw_buffer_size );
+
+ }
+
+ if (!ReadFromRFBServer((char *)&hdr, sz_rfbZlibHeader))
+ return False;
+
+ remaining = Swap32IfLE(hdr.nBytes);
+
+ /* Need to initialize the decompressor state. */
+ decompStream.next_in = ( Bytef * )buffer;
+ decompStream.avail_in = 0;
+ decompStream.next_out = ( Bytef * )raw_buffer;
+ decompStream.avail_out = raw_buffer_size;
+ decompStream.data_type = Z_BINARY;
+
+ /* Initialize the decompression stream structures on the first invocation. */
+ if ( decompStreamInited == False ) {
+
+ inflateResult = inflateInit( &decompStream );
+
+ if ( inflateResult != Z_OK ) {
+ fprintf(stderr,
+ "inflateInit returned error: %d, msg: %s\n",
+ inflateResult,
+ decompStream.msg);
+ return False;
+ }
+
+ decompStreamInited = True;
+
+ }
+
+ inflateResult = Z_OK;
+
+ /* Process buffer full of data until no more to process, or
+ * some type of inflater error, or Z_STREAM_END.
+ */
+ while (( remaining > 0 ) &&
+ ( inflateResult == Z_OK )) {
+
+ if ( remaining > BUFFER_SIZE ) {
+ toRead = BUFFER_SIZE;
+ }
+ else {
+ toRead = remaining;
+ }
+
+ /* Fill the buffer, obtaining data from the server. */
+ if (!ReadFromRFBServer(buffer,toRead))
+ return False;
+
+ decompStream.next_in = ( Bytef * )buffer;
+ decompStream.avail_in = toRead;
+
+ /* Need to uncompress buffer full. */
+ inflateResult = inflate( &decompStream, Z_SYNC_FLUSH );
+
+ /* We never supply a dictionary for compression. */
+ if ( inflateResult == Z_NEED_DICT ) {
+ fprintf(stderr,"zlib inflate needs a dictionary!\n");
+ return False;
+ }
+ if ( inflateResult < 0 ) {
+ fprintf(stderr,
+ "zlib inflate returned error: %d, msg: %s\n",
+ inflateResult,
+ decompStream.msg);
+ return False;
+ }
+
+ /* Result buffer allocated to be at least large enough. We should
+ * never run out of space!
+ */
+ if (( decompStream.avail_in > 0 ) &&
+ ( decompStream.avail_out <= 0 )) {
+ fprintf(stderr,"zlib inflate ran out of space!\n");
+ return False;
+ }
+
+ remaining -= toRead;
+
+ } /* while ( remaining > 0 ) */
+
+ if ( inflateResult == Z_OK ) {
+
+ /* Put the uncompressed contents of the update on the screen. */
+ CopyDataToScreen(raw_buffer, rx, ry, rw, rh);
+
+ }
+ else {
+
+ fprintf(stderr,
+ "zlib inflate returned error: %d, msg: %s\n",
+ inflateResult,
+ decompStream.msg);
+ return False;
+
+ }
+
+ return True;
+}