From 4d87189420b6225da7f38aa71aee840d816bd570 Mon Sep 17 00:00:00 2001
From: dscho <dscho>
Date: Fri, 6 Dec 2002 16:03:50 +0000
Subject: compiler warnings, contrib directory, new x11vnc from Karl Runge

---
 CHANGES          |    1 +
 Makefile         |   31 +-
 contrib/x11vnc.c | 1352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 contrib/zippy.c  |  181 ++++++++
 httpd.c          |    4 +-
 main.c           |    2 +-
 rfb.h            |   22 +-
 x11vnc.c         |  583 -----------------------
 zippy.c          |  181 --------
 9 files changed, 1570 insertions(+), 787 deletions(-)
 create mode 100644 contrib/x11vnc.c
 create mode 100644 contrib/zippy.c
 delete mode 100644 x11vnc.c
 delete mode 100644 zippy.c

diff --git a/CHANGES b/CHANGES
index b58f6d9..0f49c74 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+   Better x11vnc from Karl J. Runge!
    fixed severe bug (Const Kaplinsky)
    got patch from Const Kaplisnky with CursorPosUpdate encoding and some Docs
    sync'ed with newest RealVNC (ZRLE encoding)
diff --git a/Makefile b/Makefile
index 8d28dfb..67370d3 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ VNCSERVERLIB=-L. -lvncserver -L/usr/local/lib -lz -ljpeg
 
 CXX=g++
 CC=gcc
+LINK=gcc
 
 # for Solaris
 #EXTRALIBS=-lsocket -lnsl -L/usr/X/lib
@@ -36,6 +37,7 @@ ZRLE_SRCS=zrle.cc rdr/FdInStream.cxx rdr/FdOutStream.cxx rdr/InStream.cxx \
 ZRLE_OBJS=zrle.o rdr/FdInStream.o rdr/FdOutStream.o rdr/InStream.o \
 	rdr/NullOutStream.o rdr/ZlibInStream.o rdr/ZlibOutStream.o
 ZRLE_DEF=-DHAVE_ZRLE
+LINK=$(CXX)
 
 %.o: %.cxx
 	$(CXX) $(CXXFLAGS) -c -o $@ $<
@@ -75,52 +77,53 @@ libvncserver.a: $(OBJS)
 translate.o: translate.c tableinit24.c tableinitcmtemplate.c tableinittctemplate.c tabletrans24template.c tabletranstemplate.c
 
 example: example.o libvncserver.a
-	$(CC) -o example example.o $(LIBS)
+	$(LINK) -o example example.o $(LIBS)
 
 pnmshow: pnmshow.o libvncserver.a
-	$(CC) -o pnmshow pnmshow.o $(LIBS)
+	$(LINK) -o pnmshow pnmshow.o $(LIBS)
 
 mac.o: mac.c 1instance.c
 
 OSXvnc-server: mac.o libvncserver.a
-	$(CC) -o OSXvnc-server mac.o $(LIBS) $(OSX_LIBS)
+	$(LINK) -o OSXvnc-server mac.o $(LIBS) $(OSX_LIBS)
 
-x11vnc.o: x11vnc.c 1instance.c
+x11vnc.o: contrib/x11vnc.c rfb.h 1instance.c Makefile
+	$(CC) $(CFLAGS) -I. -c -o x11vnc.o contrib/x11vnc.c
 
 x11vnc: x11vnc.o libvncserver.a
-	$(CC) -g -o x11vnc x11vnc.o $(LIBS) $(XLIBS)
+	$(LINK) -g -o x11vnc x11vnc.o $(LIBS) $(XLIBS)
 
 x11vnc_static: x11vnc.o libvncserver.a
-	$(CC) -o x11vnc_static x11vnc.o libvncserver.a /usr/lib/libz.a /usr/lib/libjpeg.a $(XLIBS)
+	$(LINK) -o x11vnc_static x11vnc.o libvncserver.a /usr/lib/libz.a /usr/lib/libjpeg.a $(XLIBS)
 #$(LIBS) $(XLIBS)
 
 storepasswd: storepasswd.o d3des.o vncauth.o
-	$(CC) -o storepasswd storepasswd.o d3des.o vncauth.o
+	$(LINK) -o storepasswd storepasswd.o d3des.o vncauth.o
 
 sratest: sratest.o
-	$(CC) -o sratest sratest.o
+	$(LINK) -o sratest sratest.o
 
 sratest.o: sraRegion.c
 	$(CC) $(CFLAGS) -DSRA_TEST -c -o sratest.o sraRegion.c
 
 blooptest: blooptest.o libvncserver.a
-	$(CC) -o blooptest blooptest.o $(LIBS)
+	$(LINK) -o blooptest blooptest.o $(LIBS)
 
 blooptest.o: example.c rfb.h
 	$(CC) $(CFLAGS) -DBACKGROUND_LOOP_TEST -c -o blooptest.o example.c
 
 pnmshow24: pnmshow24.o libvncserver.a
-	$(CC) -o pnmshow24 pnmshow24.o $(LIBS)
+	$(LINK) -o pnmshow24 pnmshow24.o $(LIBS)
 
 fontsel: fontsel.o libvncserver.a
-	$(CC) -o fontsel fontsel.o -L. -lvncserver -lz -ljpeg
+	$(LINK) -o fontsel fontsel.o -L. -lvncserver -lz -ljpeg
 
 vncev: vncev.o libvncserver.a
-	$(CC) -o vncev vncev.o -L. -lvncserver -lz -ljpeg
+	$(LINK) -o vncev vncev.o -L. -lvncserver -lz -ljpeg
 
 # Example from Justin
-zippy: zippy.o libvncserver.a
-	$(CC) -o zippy zippy.o -L. -lvncserver -lz -ljpeg
+zippy: contrib/zippy.o libvncserver.a
+	$(LINK) -o zippy contrib/zippy.o -L. -lvncserver -lz -ljpeg
 
 clean:
 	rm -f $(OBJS) *~ core "#"* *.bak *.orig storepasswd.o \
diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c
new file mode 100644
index 0000000..85366b7
--- /dev/null
+++ b/contrib/x11vnc.c
@@ -0,0 +1,1352 @@
+/*
+ * x0vnc.c: a VNC server for X displays.
+ *
+ * Copyright (c) 2002 Karl J. Runge <runge@karlrunge.com>  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.
+ *
+ *
+ * This program is based heavily on the following programs:
+ *
+ *       x11vnc.c of the libvncserver project (Johannes E. Schindelin)
+ *       krfb, the KDE desktopsharing project (Tim Jansen)
+ *	 x0rfbserver, the original native X vnc server (Jens Wagner)
+ *
+ * The primary goal of this program is to create a portable and simple
+ * command-line server utility that allows a VNC viewer to connect to an
+ * actual X display (as x11vnc, krfb, and x0rfbserver do).  The only
+ * non-standard dependency of this program is the static library
+ * libvncserver.a (although in some environments libjpeg.so may not be
+ * readily available).  To increase portability it is written in plain C.
+ *
+ * The next goal is to improve performance and interactive response.
+ * The algorithm currently used here to achieve this is that of krfb
+ * (based on x0rfbserver algorithm).  Additional heuristics are also
+ * applied.  Currently there are a bit too many of these...
+ *
+ * To build:
+ * Obtain the libvncserver package (http://libvncserver.sourceforge.net)
+ * and ensure that "make" and "make x11vnc" work correctly.  Defining
+ * HAVE_PTHREADS in the Makefile is recommended.  One then could move the
+ * x11vnc.c file aside, copy this file in its place into the source tree,
+ * and issue:
+ *
+ *	make x11vnc
+ *	mv x11vnc x0vnc
+ *
+ * to create the x0vnc binary.  Otherwise, with x0vnc.c copied to
+ * libvncserver source directory, something like this should work:
+ *
+ * gcc -Wall  -DALLOW24BPP -I.  -DBACKCHANNEL -c x0vnc.c
+ * gcc -o x0vnc x0vnc.o  -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
+ *     -L/usr/X11R6/lib -lX11 -lXext -lXtst
+ *
+ * include -DHAVE_PTHREADS ... -lpthread to use threads.
+ *
+ * On Solaris the 2nd command might look something like:
+ *
+ * gcc -o x0vnc x0vnc.o -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
+ *     -lsocket -lnsl -L/usr/X/lib -R/usr/X/lib -lX11 -lXext -lXtst 
+ */
+
+#define KeySym RFBKeySym
+#include "rfb.h"
+
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+
+Display *dpy = 0;
+int dpy_x, dpy_y;
+int bpp;
+int window;
+int button_mask = 0;
+
+XImage *tile;
+XImage *scanline;
+XImage *fullscreen;
+int fs_factor = 0;
+
+XShmSegmentInfo tile_shm;
+XShmSegmentInfo scanline_shm;
+XShmSegmentInfo fullscreen_shm;
+
+rfbScreenInfoPtr screen;
+rfbCursorPtr cursor;
+int bytes_per_line;
+
+/* size of the basic tile unit that is polled for changes: */
+int tile_x = 32;
+int tile_y = 32;
+int ntiles, ntiles_x, ntiles_y;
+
+/* arrays that indicate changed or checked tiles. */
+char *tile_has_diff, *tile_tried;
+
+typedef struct tile_change_region {
+	short first_line, last_line;  /* start and end lines, along y,      */
+				      /* of the changed area inside a tile. */
+	short left_diff, right_diff;  /* info about differences along edges. */
+	short top_diff,  bot_diff;
+} region_t;
+
+/* array to hold the tiles region_t-s. */
+region_t *tile_region;
+
+typedef struct hint {
+	/* location x, y, height, and width of a change-rectangle  */
+	/* (grows as adjacent horizontal tiles are glued together) */
+	int x, y, w, h;
+} hint_t;
+
+/* array to hold the hints: */
+hint_t *hint_list;
+
+int shared = 0;		/* share vnc display. */
+int view_only = 0;	/* client can only watch. */
+int connect_once = 1;	/* allow only one client connection. */
+
+/*
+ * waitms is the msec to wait between screen polls.  Not too old h/w shows
+ * poll times of 15-35ms, so maybe this value cuts the rest load by 2 or so.
+ */
+int waitms = 30;
+int defer_update = 30;	/* rfbDeferUpdateTime ms to wait before sends. */
+int use_threads = 1;	/* but only if compiled with HAVE_PTHREADS */
+
+/* tile heuristics: */
+int use_hints = 1;	/* use the krfb scheme of gluing tiles together. */
+int tile_fuzz = 2;	/* tolerance for suspecting changed tiles touching */
+			/* a known changed tile. */
+int grow_fill = 3;	/* do the grow islands heuristic with this width. */
+int gaps_fill = 4;	/* do a final pass to try to fill gaps between tiles. */
+double fs_frac = 0.5;	/* threshold tile fraction to do fullscreen updates. */
+
+#define NSCAN 32
+int scanlines[NSCAN] = {	 /* scan pattern jitter from x0rfbserver */
+	 0, 16,  8, 24,  4, 20, 12, 28,
+	10, 26, 18,  2, 22,  6, 30, 14,
+	 1, 17,  9, 25,  7, 23, 15, 31,
+	19,  3, 27, 11, 29, 13,  5, 21
+};
+
+int got_user_input;
+int count = 0;
+int shut_down = 0;	
+
+/*
+ * Not sure why... but when threaded we have to mutex our X11 calls to
+ * avoid XIO crashes.  This should not be too bad since keyboard and pointer
+ * updates are infrequent compared to the scanning. (note: these lines are
+ * noops unless HAVE_PTHREADS)  XXX: what is going on?
+ */
+MUTEX(x11Mutex);
+#define X_LOCK     LOCK(x11Mutex);
+#define X_UNLOCK UNLOCK(x11Mutex);
+
+void mark_hint(hint_t);
+
+void clean_up_exit (void) {
+
+	X_LOCK
+
+	XTestDiscard(dpy);
+
+	/* remove the shm areas: */
+
+	XShmDetach(dpy, &tile_shm);
+	XDestroyImage(tile);
+	shmdt(tile_shm.shmaddr);
+	shmctl(tile_shm.shmid, IPC_RMID, 0);
+
+	XShmDetach(dpy, &scanline_shm);
+	XDestroyImage(scanline);
+	shmdt(scanline_shm.shmaddr);
+	shmctl(scanline_shm.shmid, IPC_RMID, 0);
+
+	XShmDetach(dpy, &fullscreen_shm);
+	XDestroyImage(fullscreen);
+	shmdt(fullscreen_shm.shmaddr);
+	shmctl(fullscreen_shm.shmid, IPC_RMID, 0);
+
+	/* more cleanup? */
+
+	X_UNLOCK
+	exit(0);
+}
+
+void client_gone(rfbClientPtr client) {
+	if (connect_once) {
+		printf("only one connection allowed.\n");
+		clean_up_exit();
+	}
+}
+
+enum rfbNewClientAction new_client(rfbClientPtr client) {
+	if (connect_once) {
+		client->clientGoneHook = client_gone;
+	}
+	if (view_only)  {
+		client->clientData = (void *) -1;
+	} else {
+		client->clientData = (void *) 0;
+	}
+	return(RFB_CLIENT_ACCEPT);
+}
+
+/* key event handler */
+static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
+	KeyCode k;
+
+	if (view_only) {
+		return;
+	}
+
+	X_LOCK
+
+	k = XKeysymToKeycode(dpy, keysym);
+
+	if ( k != NoSymbol ) {
+		XTestFakeKeyEvent(dpy, k, down, CurrentTime);
+		XFlush(dpy);
+
+		got_user_input++;
+	}
+	X_UNLOCK
+}
+
+/* mouse event handler */
+static void pointer(int mask, int x, int y, rfbClientPtr client) {
+	int i;
+
+	if (view_only) {
+		return;
+	}
+
+	X_LOCK
+
+	XTestFakeMotionEvent(dpy, 0, x, y, CurrentTime);
+
+	got_user_input++;
+
+	for (i=0; i < 5; i++) {
+		if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) {
+			XTestFakeButtonEvent(dpy, i+1, 
+			    (mask & (1<<i)) ? True : False, CurrentTime);
+		}
+	}
+	X_UNLOCK
+
+	/* remember the button state for next time: */
+	button_mask = mask;
+}
+
+/* simple fixed cursor */
+static char* cur_data =
+"                  "
+"                  "
+"  x               "
+"  xx              "
+"  xxx             "
+"  xxxx            "
+"  xxxxx           "
+"  xxxxxx          "
+"  xxxxxxx         "
+"  xxxxxxxx        "
+"  xxxxx           "
+"  xx xx           "
+"  x   xx          "
+"      xx          "
+"       xx         "
+"       xx         "
+"                  "
+"                  ";
+
+static char* cur_mask =
+"                  "
+" xx               "
+" xxx              "
+" xxxx             "
+" xxxxx            "
+" xxxxxx           "
+" xxxxxxx          "
+" xxxxxxxx         "
+" xxxxxxxxx        "
+" xxxxxxxxxx       "
+" xxxxxxxxxx       "
+" xxxxxxx          "
+" xxx xxxx         "
+" xx  xxxx         "
+"      xxxx        "
+"      xxxx        "
+"       xx         "
+"                  ";
+int cursor_x = 18;
+int cursor_y = 18;
+
+void initialize_screen(int *argc, char **argv, XImage *fb) {
+
+	screen = rfbGetScreen(argc, argv, fb->width, fb->height,
+	    fb->bits_per_pixel, 8, fb->bits_per_pixel/8);
+
+	screen->paddedWidthInBytes = fb->bytes_per_line;
+	screen->rfbServerFormat.bitsPerPixel = fb->bits_per_pixel;
+	screen->rfbServerFormat.depth = fb->depth;
+	screen->rfbServerFormat.trueColour = (CARD8) TRUE;
+
+	if ( screen->rfbServerFormat.bitsPerPixel == 8 ) {
+		/* 8 bpp */
+		screen->rfbServerFormat.redShift   = 0;
+		screen->rfbServerFormat.greenShift = 2;
+		screen->rfbServerFormat.blueShift  = 5;
+		screen->rfbServerFormat.redMax     = 3;
+		screen->rfbServerFormat.greenMax   = 7;
+		screen->rfbServerFormat.blueMax    = 3;
+	} else {
+		/* general case ... */
+		screen->rfbServerFormat.redShift = 0;
+		if ( fb->red_mask ) {
+			while ( ! (fb->red_mask
+			    & (1 << screen->rfbServerFormat.redShift) ) ) {
+				    screen->rfbServerFormat.redShift++;
+			}
+		}
+		screen->rfbServerFormat.greenShift = 0;
+		if ( fb->green_mask ) {
+			while ( ! (fb->green_mask
+			    & (1 << screen->rfbServerFormat.greenShift) ) ) {
+				    screen->rfbServerFormat.greenShift++;
+			}
+		}
+		screen->rfbServerFormat.blueShift = 0;
+		if ( fb->blue_mask ) {
+			while ( ! (fb->blue_mask
+			    & (1 << screen->rfbServerFormat.blueShift) ) ) {
+				    screen->rfbServerFormat.blueShift++;
+			}
+		}
+		screen->rfbServerFormat.redMax
+		    = fb->red_mask >> screen->rfbServerFormat.redShift;
+		screen->rfbServerFormat.greenMax
+		    = fb->green_mask >> screen->rfbServerFormat.greenShift;
+		screen->rfbServerFormat.blueMax
+		    = fb->blue_mask >> screen->rfbServerFormat.blueShift;
+	}
+
+	screen->frameBuffer = fb->data; 
+
+	/* XXX the following 3 settings are based on libvncserver defaults. */
+	if (screen->rfbPort == 5900) {
+		screen->autoPort = TRUE;
+	}
+	if (screen->rfbDeferUpdateTime == 5) {
+		screen->rfbDeferUpdateTime = defer_update;
+	}
+	if (shared && ! screen->rfbNeverShared) {
+		screen->rfbAlwaysShared = TRUE;
+	}
+
+	/* event callbacks: */
+	screen->newClientHook = new_client;
+	screen->kbdAddEvent = keyboard;
+	screen->ptrAddEvent = pointer;
+
+	cursor = rfbMakeXCursor(cursor_x, cursor_y, cur_data, cur_mask);
+	screen->cursor = cursor;
+
+	rfbInitServer(screen);
+
+	bytes_per_line = screen->paddedWidthInBytes;
+	bpp = screen->rfbServerFormat.bitsPerPixel;
+}
+
+/*
+ * setup tile numbers and allocate the tile and hint arrays:
+ */
+void initialize_tiles() {
+
+	ntiles_x = (dpy_x - 1)/tile_x + 1;
+	ntiles_y = (dpy_y - 1)/tile_y + 1;
+	ntiles = ntiles_x * ntiles_y;
+
+	tile_has_diff = (char *) malloc((size_t) (ntiles * sizeof(char)));
+	tile_tried    = (char *) malloc((size_t) (ntiles * sizeof(char)));
+	tile_region = (region_t *) malloc((size_t) (ntiles * sizeof(region_t)));
+
+	/* there will never be more hints than tiles: */
+	hint_list = (hint_t *) malloc((size_t) (ntiles * sizeof(hint_t)));
+}
+
+/*
+ * silly function to factor dpy_y until fullscreen shm is not bigger than max.
+ * should always work unless dpy_y is a large prime or something... under
+ * failure fs_factor remains 0 and no fullscreen updates will be tried.
+ */
+void set_fs_factor(int max) {
+	int f, fac = 1, n = dpy_y;
+
+	if ( (bpp/8) * dpy_x * dpy_y <= max )  {
+		fs_factor = 1;
+		return;
+	}
+	for (f=2; f <= 101; f++) {
+		while (n % f == 0) {
+			n = n / f;
+			fac = fac * f;
+			if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max )  {
+				fs_factor = fac;
+				return;
+			}
+		}
+	}
+}
+
+void initialize_shm() {
+
+	/* the tile (e.g. 32x32) shared memory area image: */
+
+	tile = XShmCreateImage(dpy, DefaultVisual(dpy, 0), bpp, ZPixmap,
+	    NULL, &tile_shm, tile_x, tile_y);
+
+	tile_shm.shmid = shmget(IPC_PRIVATE,
+	    tile->bytes_per_line * tile->height, IPC_CREAT | 0777);
+
+	tile_shm.shmaddr = tile->data = (char *) shmat(tile_shm.shmid, 0, 0);
+	tile_shm.readOnly = False;
+
+	XShmAttach(dpy, &tile_shm);
+
+
+	/* the scanline (e.g. 1280x1) shared memory area image: */
+
+	scanline = XShmCreateImage(dpy, DefaultVisual(dpy, 0), bpp, ZPixmap,
+	    NULL, &scanline_shm, dpy_x, 1);
+
+	scanline_shm.shmid = shmget(IPC_PRIVATE,
+	    scanline->bytes_per_line * scanline->height, IPC_CREAT | 0777);
+
+	scanline_shm.shmaddr = scanline->data
+	    = (char *) shmat(scanline_shm.shmid, 0, 0);
+	scanline_shm.readOnly = False;
+
+	XShmAttach(dpy, &scanline_shm);
+
+	/*
+	 * the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
+	 * (we cut down the size of the shm area to try avoid and shm segment
+	 * limits, e.g. the default 1MB on Solaris)
+	 */
+	set_fs_factor(1024 * 1024);
+	if (! fs_factor) {
+		printf("warning: fullscreen updates are disabled.\n");
+		return;
+	}
+
+	fullscreen = XShmCreateImage(dpy, DefaultVisual(dpy, 0), bpp, ZPixmap,
+	    NULL, &fullscreen_shm, dpy_x, dpy_y/fs_factor);
+
+	fullscreen_shm.shmid = shmget(IPC_PRIVATE,
+	    fullscreen->bytes_per_line * fullscreen->height, IPC_CREAT | 0777);
+
+	fullscreen_shm.shmaddr = fullscreen->data
+	    = (char *) shmat(fullscreen_shm.shmid, 0, 0);
+	fullscreen_shm.readOnly = False;
+
+	XShmAttach(dpy, &fullscreen_shm);
+}
+
+/*
+ * A hint is a rectangular region built from 1 or more adjacent tiles
+ * glued together.  Ultimately, this information in a single hint is sent
+ * to libvncserver rather than sending each tile separately.
+ */
+void create_tile_hint(int x, int y, int th, hint_t *hint) {
+	int w = dpy_x - x;
+	int h = dpy_y - y;
+
+	if (w > tile_x) {
+		w = tile_x;
+	}
+	if (h > th) {
+		h = th;
+	}
+
+	hint->x = x;
+	hint->y = y;
+	hint->w = w;
+	hint->h = h;
+}
+
+void extend_tile_hint(int x, int y, int th, hint_t *hint) {
+	int w = dpy_x - x;
+	int h = dpy_y - y;
+
+	if (w > tile_x) {
+		w = tile_x;
+	}
+	if (h > th) {
+		h = th;
+	}
+
+	if (hint->x > x) {			/* extend to the left */
+		hint->w += hint->x - x;
+		hint->x = x;
+	}
+	if (hint->y > y) {			/* extend upward */
+		hint->h += hint->y - y;
+		hint->y = y;
+	}
+
+	if (hint->x + hint->w < x + w) {	/* extend to the right */
+		hint->w = x + w - hint->x;
+	}
+	if (hint->y + hint->h < y + h) {	/* extend downward */
+		hint->h = y + h - hint->y;
+	}
+}
+
+void save_hint(hint_t hint, int loc) {
+	/* copy it to the global array: */
+
+	hint_list[loc].x = hint.x;
+	hint_list[loc].y = hint.y;
+	hint_list[loc].w = hint.w;
+	hint_list[loc].h = hint.h;
+}
+
+
+/*
+ * Glue together horizontal "runs" of adjacent changed tiles into one big
+ * rectangle change "hint" to be passed to the vnc machinery.
+ */
+void hint_updates() {
+	hint_t hint;
+	int x, y, i, n, ty, th;
+	int hint_count = 0, in_run = 0;
+
+	for (y=0; y < ntiles_y; y++) {
+		for (x=0; x < ntiles_x; x++) {
+			n = x + y * ntiles_x;
+
+			if (tile_has_diff[n]) {
+				ty = tile_region[n].first_line;
+				th = tile_region[n].last_line - ty + 1;
+				if (! in_run) {
+					create_tile_hint( x * tile_x,
+					    y * tile_y + ty, th, &hint);
+					in_run = 1;
+				} else {
+					extend_tile_hint( x * tile_x,
+					    y * tile_y + ty, th, &hint);
+				}
+			} else {
+				if (in_run) {
+					/* end of a row run of altered tiles: */
+					save_hint(hint, hint_count++);
+					in_run = 0;
+				}
+			}
+		}
+		if (in_run) {	/* save the last row run */
+			save_hint(hint, hint_count++);
+			in_run = 0;
+		}
+	}
+
+	for (i=0; i < hint_count; i++) {
+		/* pass update info to vnc: */
+		mark_hint(hint_list[i]);
+	}
+}
+
+/*
+ * Notifies libvncserver of a changed hint rectangle.
+ */
+void mark_hint(hint_t hint) {
+	int x = hint.x;	
+	int y = hint.y;	
+	int w = hint.w;	
+	int h = hint.h;	
+
+	rfbMarkRectAsModified(screen, x, y, x + w, y + h);
+}
+
+/*
+ * Notifies libvncserver of a changed tile rectangle.
+ */
+void mark_tile(int x, int y, int height) {
+	int w = dpy_x - x;
+	int h = dpy_y - y;
+
+	if (w > tile_x) {
+		w = tile_x;
+	}
+
+	/* height is the height of the changed portion of the tile */
+	if (h > height) {
+		h = height;
+	}
+
+	rfbMarkRectAsModified(screen, x, y, x + w, y + h);
+}
+
+/*
+ * Simply send each modified tile separately to the vnc machinery:
+ * (i.e. no hints)
+ */
+void tile_updates() {
+	int x, y, n, ty, th;
+
+	for (y=0; y < ntiles_y; y++) {
+		for (x=0; x < ntiles_x; x++) {
+			n = x + y * ntiles_x;
+
+			if (tile_has_diff[n]) {
+				ty = tile_region[n].first_line;
+				th = tile_region[n].last_line - ty + 1;
+
+				mark_tile(x * tile_x, y * tile_y + ty, th);
+			}
+		}
+	}
+}
+
+/*
+ * copy_tile() is called on a tile with a known change (from a scanline
+ * diff) or a suspected change (from our various heuristics).
+ *
+ * Examine the whole tile for the y-range of difference, copy that
+ * image difference to the vnc framebuffer, and do bookkeepping wrt
+ * the y-range and edge differences.
+ *
+ * This call is somewhat costly, maybe 1-2 ms.  Primarily the XShmGetImage
+ * and then the memcpy/memcmp.
+ */
+void copy_tile(int tx, int ty) {
+	int x, y, line, first_line, last_line;
+	int size_x, size_y, n, dw, dx;
+	int pixelsize = bpp >> 3;
+	short l_diff = 0, r_diff = 0;
+
+	char *src, *dst, *s_src, *s_dst, *m_src, *m_dst;
+	char *h_src, *h_dst;
+
+	x = tx * tile_x;
+	y = ty * tile_y;
+
+	size_x = dpy_x - x;
+	if ( size_x > tile_x ) {
+		size_x = tile_x;
+	}
+	size_y = dpy_y - y;
+	if ( size_y > tile_y ) {
+		size_y = tile_y;
+	}
+	n = tx + ty * ntiles_x;		/* number of the tile */
+
+	X_LOCK
+	if ( size_x == tile_x && size_y == tile_y ) {
+		/* general case: */
+		XShmGetImage(dpy, window, tile, x, y, AllPlanes);
+	} else {
+		/*
+		 * near bottom or rhs edge case:
+		 * (but only if tile size does not divide screen size)
+		 */
+		XGetSubImage(dpy, window, x, y, size_x, size_y, AllPlanes,
+		    ZPixmap, tile, 0, 0);
+	}
+	X_UNLOCK
+
+	src = (unsigned char*) tile->data;
+	dst = screen->frameBuffer + y * bytes_per_line + x * pixelsize;
+
+	s_src = src;
+	s_dst = dst;
+
+	first_line = -1;
+
+	/* find the first line with difference: */
+	for (line = 0; line < size_y; line++) {
+		if ( memcmp(s_dst, s_src, size_x * pixelsize) ) {
+			first_line = line;
+			break;
+		}
+		s_src += tile->bytes_per_line;
+		s_dst += bytes_per_line;
+	}
+
+	tile_tried[n] = 1;
+	if (first_line == -1) {
+		/* tile has no difference, note it and get out: */
+		tile_has_diff[n] = 0;
+		return;
+	} else {
+		/*
+		 * make sure it is recorded (e.g. sometimes we guess tiles
+		 * and they came in with tile_has_diff 0)
+		 */
+		tile_has_diff[n] = 1;
+	}
+
+	m_src = src + (tile->bytes_per_line * size_y);
+	m_dst = dst + (bytes_per_line * size_y);
+	last_line = first_line;
+
+	/* find the last line with difference: */
+	for (line = size_y - 1; line > first_line; line--) {
+		m_src -= tile->bytes_per_line;
+		m_dst -= bytes_per_line;
+		if ( memcmp(m_dst, m_src, size_x * pixelsize) ) {
+			last_line = line;
+			break;
+		}
+	}
+
+	/* look for differences on left and right hand edges: */
+	dx = (size_x - tile_fuzz) * pixelsize;
+	dw = tile_fuzz * pixelsize; 
+
+	h_src = src;
+	h_dst = dst;
+	for (line = 0; line < size_y; line++) {
+		if (! l_diff && memcmp(h_dst, h_src, dw) ) {
+			l_diff = 1;
+		}
+		if (! r_diff && memcmp(h_dst + dx, h_src + dx, dw) ) {
+			r_diff = 1;
+		}
+		if (l_diff && r_diff) {
+			break;
+		}
+		h_src += tile->bytes_per_line;
+		h_dst += bytes_per_line;
+	}
+
+	/* now copy the difference to the vnc framebuffer: */
+	for (line = first_line; line <= last_line; line++) {
+		memcpy(s_dst, s_src, size_x * pixelsize);
+		s_src += tile->bytes_per_line;
+		s_dst += bytes_per_line;
+	}
+
+	/* record all the info in the region array for this tile: */
+	tile_region[n].first_line = first_line;
+	tile_region[n].last_line  = last_line;
+	tile_region[n].left_diff  = l_diff;
+	tile_region[n].right_diff = r_diff;
+
+	tile_region[n].top_diff = 0;
+	tile_region[n].bot_diff = 0;
+	if ( first_line < tile_fuzz ) {
+		tile_region[n].top_diff = 1;
+	}
+	if ( last_line > (size_y - 1) - tile_fuzz ) {
+		tile_region[n].bot_diff = 1;
+	}
+}
+
+/*
+ * The copy_tile() call in the loop below copies the changed tile into
+ * the vnc framebuffer.  Note that copy_tile() sets the tile_region
+ * struct to have info about the y-range of the changed region and also
+ * whether the tile edges contain diffs (within distance tile_fuzz).
+ *
+ * We use this tile_region info to try to guess if the downward and right
+ * tiles will have diffs.  These tiles will be checked later in the loop
+ * (since y+1 > y and x+1 > x).
+ *
+ * See copy_tiles_backward_pass() for analogous checking upward and
+ * left tiles.
+ */
+void copy_all_tiles() {
+	int x, y, n, m;
+
+	for (y=0; y < ntiles_y; y++) {
+		for (x=0; x < ntiles_x; x++) {
+			n = x + y * ntiles_x;
+
+			if (tile_has_diff[n]) {
+				copy_tile(x, y);
+			}
+			if (! tile_has_diff[n]) {
+				/*
+				 * n.b. copy_tile() may have detected
+				 * no change and reset tile_has_diff to 0.
+				 */
+				continue;
+			}
+
+			/* neighboring tile downward: */
+			if ( (y+1) < ntiles_y && tile_region[n].bot_diff) {
+				m = x + (y+1) * ntiles_x;
+				if (! tile_has_diff[m]) {
+					tile_has_diff[m] = 1;
+				}
+			}
+			/* neighboring tile to right: */
+			if ( (x+1) < ntiles_x && tile_region[n].right_diff) {
+				m = (x+1) + y * ntiles_x;
+				if (! tile_has_diff[m]) {
+					tile_has_diff[m] = 1;
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Here starts a bunch of heuristics to guess/detect changed tiles.
+ * They are:
+ *   copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try
+ * They are of varying utility... and perhaps some should be dropped.
+ */
+
+/*
+ * Try to predict whether the upward and/or leftward tile has been modified.
+ * copy_all_tiles() has already done downward and rightward tiles.
+ */
+void copy_tiles_backward_pass() {
+	int x, y, n, m;
+
+	for (y = ntiles_y - 1; y >= 0; y--) {
+	    for (x = ntiles_x - 1; x >= 0; x--) {
+		n = x + y * ntiles_x;		/* number of this tile */
+
+		if (! tile_has_diff[n]) {
+			continue;
+		}
+
+		m = x + (y-1) * ntiles_x;	/* neighboring tile upward */
+
+		if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) {
+			if (! tile_tried[m]) {
+				copy_tile(x, y-1);
+			}
+		}
+
+		m = (x-1) + y * ntiles_x;	/* neighboring tile to left */
+
+		if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) {
+			if (! tile_tried[m]) {
+				copy_tile(x-1, y);
+			}
+		}
+	    }
+	}
+}
+
+void gap_try(int x, int y, int *run, int *saw, int along_x) {
+	int n, m, i, xt, yt;
+
+	n = x + y * ntiles_x;
+
+	if (! tile_has_diff[n]) {
+		if (*saw) {
+			(*run)++;	/* extend the gap run. */
+		}
+		return;
+	}
+	if (! *saw || *run == 0 || *run > gaps_fill) {
+		*run = 0;		/* unacceptable run. */
+		*saw = 1;
+		return;
+	}
+
+	for (i=1; i <= *run; i++) {	/* iterate thru the run. */
+		if (along_x) {
+			xt = x - i;
+			yt = y;
+		} else {
+			xt = x;
+			yt = y - i;
+		}
+
+		m = xt + yt * ntiles_x;
+		if (tile_tried[m]) {	/* do not repeat tiles */
+			continue;
+		}
+
+		copy_tile(xt, yt);
+	}
+	*run = 0;
+	*saw = 1;
+}
+
+/*
+ * Look for small gaps of unchanged tiles that may actually contain changes.
+ * E.g. when paging up and down in a web broswer or terminal there can
+ * be a distracting delayed filling in of such gaps.  gaps_fill is the
+ * tweak parameter that sets the width of the gaps that are checked.
+ *
+ * btw, grow_islands() is actually pretty successful at doing this too.
+ */
+void fill_tile_gaps() {
+	int x, y, run, saw;
+
+	/* horizontal: */
+	for (y=0; y < ntiles_y; y++) {
+		run = 0;
+		saw = 0;
+		for (x=0; x < ntiles_x; x++) {
+			gap_try(x, y, &run, &saw, 1);
+		}
+	}
+
+	/* vertical: */
+	for (x=0; x < ntiles_x; x++) {
+		run = 0;
+		saw = 0;
+		for (y=0; y < ntiles_y; y++) {
+			gap_try(x, y, &run, &saw, 0);
+		}
+	}
+}
+
+void island_try(int x, int y, int u, int v, int *run) {
+	int n, m;
+
+	n = x + y * ntiles_x;
+	m = u + v * ntiles_x;
+
+	if (tile_has_diff[n]) {
+		(*run)++;
+	} else {
+		*run = 0;
+	}
+
+	if (tile_has_diff[n] && ! tile_has_diff[m]) {
+		/* found discontinuity */
+
+		if (tile_tried[m]) {
+			return;
+		} else if (*run < grow_fill) {
+			return;
+		}
+
+		copy_tile(u, v);
+	}
+}
+
+/*
+ * Scan looking for discontinuities in tile_has_diff[].  Try to extend
+ * the boundary of the discontinuity (i.e. make the island larger).
+ * Vertical scans are skipped since they do not seem to yield much...
+ */
+void grow_islands() {
+	int x, y, run;
+
+	/*
+	 * n.b. the way we scan here should keep an extension going,
+	 * and so also fill in gaps effectively...
+	 */
+
+	/* left to right: */
+	for (y=0; y < ntiles_y; y++) {
+		run = 0;
+		for (x=0; x <= ntiles_x - 2; x++) {
+			island_try(x, y, x+1, y, &run);
+		}
+	}
+	/* right to left: */
+	for (y=0; y < ntiles_y; y++) {
+		run = 0;
+		for (x = ntiles_x - 1; x >= 1; x--) {
+			island_try(x, y, x-1, y, &run);
+		}
+	}
+}
+
+/*
+ * copy the whole X screen to the vnc framebuffer.  For a large enough
+ * number of changed tiles, this is faster than tiles scheme at retrieving
+ * the info from the X server.  Bandwidth to client is another issue...
+ * use -fs 1.0 to disable.
+ */
+void copy_screen() {
+	int pixelsize = bpp >> 3;
+	char *vnc_fb;
+	int i, y, block_size, xi;
+
+	block_size = (dpy_x * (dpy_y/fs_factor) * pixelsize);
+
+	vnc_fb = screen->frameBuffer;
+	y = 0;
+
+	for (i=0; i < fs_factor; i++) {
+		xi = XShmGetImage(dpy, window, fullscreen, 0, y, AllPlanes);
+		memcpy(vnc_fb, fullscreen->data, (size_t) block_size);
+
+		y += dpy_y / fs_factor;
+		vnc_fb += block_size;
+	}
+
+	rfbMarkRectAsModified(screen, 0, 0, dpy_x, dpy_y);
+}
+
+/*
+ * Loop over 1-pixel tall horizontal scanlines looking for changes.  
+ * Record the changes in tile_has_diff[].  Scanlines in the loop are
+ * equally spaced along y by NSCAN pixels, but have a slightly random
+ * starting offset ystart ( < NSCAN ) from scanlines[].
+ */
+int scan_display(int ystart, int rescan) {
+	int x, y, w, n;
+	int tile_count = 0;
+	int pixelsize = bpp >> 3;
+	char *src, *dst;
+
+	y = ystart;
+
+	while (y < dpy_y) {
+
+		/* grab the horizontal scanline from the display: */
+		X_LOCK
+		XShmGetImage(dpy, window, scanline, 0, y, AllPlanes);
+		X_UNLOCK
+
+		x = 0;
+		while (x < dpy_x) {
+			n = (x/tile_x) + (y/tile_y) * ntiles_x;
+
+			if (rescan && tile_has_diff[n]) {
+				tile_count++;
+				x += NSCAN;
+				continue;
+			}
+
+			/* set ptrs to correspond to the x offset: */
+			src = (unsigned char*) scanline->data + x * pixelsize;
+			dst = screen->frameBuffer + y * bytes_per_line
+			    + x * pixelsize;
+
+			/* compute the width of data to be compared: */
+			if ( x + NSCAN > dpy_x ) {
+				w = dpy_x - x;
+			} else {
+				w = NSCAN;
+			}
+
+			if (memcmp(dst, src, w * pixelsize) ) {
+				/* found a difference, record it: */
+				tile_has_diff[n] = 1;
+				tile_count++;		
+			}
+			x += NSCAN;
+		}
+		y += NSCAN;
+	}
+	return tile_count;
+}
+
+/*
+ * toplevel for the scanning, rescanning, and applying the heuristics.
+ */
+void scan_for_updates() {
+	int i, tile_count;
+	double frac1 = 0.1;   /* tweak parameter to try a 2nd scan_display() */
+
+	for (i=0; i < ntiles; i++) {
+		tile_has_diff[i] = 0;
+		tile_tried[i] = 0;
+	}
+
+	/*
+	 * n.b. this program has only been tested so far with
+	 * tile_x = tile_y = NSCAN = 32!
+	 */
+
+	count++;
+	count %= NSCAN;
+
+	/* scan with the initial y to the jitter value from scanlines: */
+	tile_count = scan_display( scanlines[count], 0 );
+
+	if (fs_factor && frac1 >= fs_frac) {
+		/* make frac1 < fs_frac if fullscreen updates are enabled */
+		frac1 = fs_frac/2.0;
+	}
+
+	if ( tile_count > frac1 * ntiles) {
+		/*
+		 * many tiles have changed, so try a rescan (since it should
+		 * be short compared to the many upcoming copy_tile() calls)
+		 */
+
+		/* this check is done to skip the extra scan_display() call */
+		if (! fs_factor || tile_count <= fs_frac * ntiles) {
+			int cp;
+			
+			/* choose a different y shift for the 2nd scan: */
+			cp = (NSCAN - count) % NSCAN;
+
+			tile_count = scan_display( scanlines[cp], 1 );
+		}
+
+		/*
+		 * At some number of changed tiles it is better to just
+		 * copy the full screen at once.  I.e. time = c1 + m * r1
+		 * where m is number of tiles and c1 is the scan_display()
+		 * time: for some m it crosses the full screen update time.
+		 *
+		 * We try to predict that crossover with the fs_frac fudge
+		 * factor... seems to be about 1/2 the total number
+		 * of tiles.  n.b. this ignores network bandwidth, etc.
+		 * use -fs 1.0 to disable on slow links.
+		 */
+		if (fs_factor && tile_count > fs_frac * ntiles) {
+			copy_screen();
+			return;
+		}
+	}
+
+	/* copy all tiles with differences from display to vnc framebuffer: */
+	copy_all_tiles();
+
+	/*
+	 * This backward pass for upward and left tiles complements what
+	 * was done in copy_all_tiles() for downward and right tiles.
+	 */
+	copy_tiles_backward_pass();
+
+	if (grow_fill) {
+		grow_islands();
+	}
+
+	if (gaps_fill) {
+		fill_tile_gaps();
+	}
+
+	if (use_hints) {
+		hint_updates();	/* use krfb/x0rfbserver hints algorithm */
+	} else {
+		tile_updates();	/* send each tile change individually */
+	}
+}
+
+void watch_loop(void) {
+	int cnt = 0;
+
+#if !defined(HAVE_PTHREADS)
+	use_threads = 0;
+#endif
+
+	if (use_threads) {
+		rfbRunEventLoop(screen, -1, TRUE);
+	}
+
+	while (1) {
+		got_user_input = 0;
+
+		if (! use_threads) {
+			rfbProcessEvents(screen, -1);
+
+			if (got_user_input && cnt % 10 != 0) {
+				/* every 10-th drops thru to code below... */
+				XFlush(dpy);
+				continue;
+			}
+		}
+
+		if (shut_down) {
+			clean_up_exit();
+		}
+
+		if (! screen->rfbClientHead) {	/* waiting for a client */
+			usleep(200 * 1000);
+			continue;
+		}
+
+		rfbUndrawCursor(screen);
+		scan_for_updates();
+
+		usleep(waitms * 1000);
+
+		cnt++;
+	}
+}
+
+void print_help() {
+	char help[] = "
+x0vnc options:
+
+-defer time            time in ms to wait for updates before sending to
+                       client [rfbDeferUpdateTime]  (default %d)
+-wait time             time in ms to pause between screen polls.  used
+                       to cut down on load (default %d)
+
+-gaps n                heuristic to fill in gaps in rows or cols of n or less
+                       tiles.  used to improve text paging (default %d).
+-grow n                heuristic to grow islands of changed tiles n or wider
+                       by checking the tile near the boundary (default %d).
+-fs f                  if the fraction of changed tiles in a poll is greater
+                       than f, the whole screen is updated (default %.2f)
+-fuzz n                tolerance in pixels to mark a tiles edges as changed.
+                       (default %d).
+-hints                 use krfb/x0rfbserver hints (glue changed adjacent
+                       horizontal tiles into one big rectangle)  (default %s).
+-nohints               do not use hints; send each tile separately.
+
+-threads               use threaded algorithm [rfbRunEventLoop] if compiled
+                       with threads (default %s).
+-nothreads             do not use [rfbRunEventLoop].
+-viewonly              clients can only watch (default %s).
+-shared                VNC display is shared (default %s)
+
+These options are passed to libvncserver:
+
+";
+	fprintf(stderr, help, defer_update, waitms, gaps_fill, grow_fill,
+	    fs_frac, tile_fuzz,
+	    use_hints ? "on":"off", use_threads ? "on":"off",
+	    view_only ? "on":"off", shared ? "on":"off");
+	rfbUsage();
+	exit(1);
+}
+
+int main(int argc, char** argv) {
+
+	XImage *fb;
+	int i, scr, ev, er, maj, min;
+	char *use_dpy = NULL;
+
+
+	/* used to pass args we do not know about to rfbGetScreen(): */
+	int argc2 = 1; char *argv2[100];
+	argv2[0] = argv[0];
+	
+	for (i=1; i < argc; i++) {
+		if (!strcmp(argv[i], "-display")) {
+			use_dpy = argv[++i];
+		} else if (!strcmp(argv[i], "-defer")) {
+			defer_update = atoi(argv[++i]);
+		} else if (!strcmp(argv[i], "-wait")) {
+			waitms = atoi(argv[++i]);
+		} else if (!strcmp(argv[i], "-gaps")) {
+			gaps_fill = atoi(argv[++i]);
+		} else if (!strcmp(argv[i], "-grow")) {
+			grow_fill = atoi(argv[++i]);
+		} else if (!strcmp(argv[i], "-fs")) {
+			fs_frac = atof(argv[++i]);
+		} else if (!strcmp(argv[i], "-fuzz")) {
+			tile_fuzz = atoi(argv[++i]);
+		} else if (!strcmp(argv[i], "-hints")) {
+			use_hints = 1;
+		} else if (!strcmp(argv[i], "-nohints")) {
+			use_hints = 0;
+		} else if (!strcmp(argv[i], "-threads")) {
+			use_threads = 1;
+		} else if (!strcmp(argv[i], "-nothreads")) {
+			use_threads = 0;
+		} else if (!strcmp(argv[i], "-viewonly")) {
+			view_only = 1;
+		} else if (!strcmp(argv[i], "-shared")) {
+			shared = 1;
+		} else if (!strcmp(argv[i], "-h")
+		    || !strcmp(argv[i], "-help")) {
+			print_help();
+		} else {
+			/* otherwise copy it for use below. */
+			printf("passing arg to libvncserver: %s\n", argv[i]);
+			if (argc2 < 100) {
+				argv2[argc2++] = argv[i];
+			}
+		}
+	}
+	if (tile_fuzz < 1) {
+		tile_fuzz = 1;
+	}
+	if (waitms < 0) {
+		waitms = 0;
+	}
+	printf("defer:      %d\n", defer_update);
+	printf("waitms:     %d\n", waitms);
+	printf("tile_fuzz:  %d\n", tile_fuzz);
+	printf("gaps_fill:  %d\n", gaps_fill);
+	printf("grow_fill:  %d\n", grow_fill);
+	printf("fs_frac:    %.2f\n", fs_frac);
+	printf("use_hints:  %d\n", use_hints);
+	printf("viewonly:   %d\n", view_only);
+	printf("shared:     %d\n", shared);
+
+	if (use_dpy) {
+		dpy = XOpenDisplay(use_dpy);
+	} else if ( (use_dpy = getenv("DISPLAY")) ) {
+		dpy = XOpenDisplay(use_dpy);
+	} else {
+		dpy = XOpenDisplay("");
+	}
+	if (! dpy) {
+		printf("XOpenDisplay failed (%s)\n", use_dpy);
+		exit(1);
+	} else if (use_dpy) {
+		printf("Using display %s\n", use_dpy);
+	} else {
+		printf("Using default display.\n");
+	}
+
+	if (! XTestQueryExtension(dpy, &ev, &er, &maj, &min)) {
+		printf("Display does not support the XTest extension.\n");
+		exit(1);
+	}
+	if (! XShmQueryExtension(dpy)) {
+		printf("Display does not support XShm extension"
+		    " (must be local).\n");
+		exit(1);
+	}
+
+	/*
+	 * Window managers will often grab the display during resize, etc.
+	 * To avoid deadlock (our user resize input is not processed)
+	 * we tell the server to process our requests during all grabs:
+	 */
+	XTestGrabControl(dpy, True);
+
+	scr = DefaultScreen(dpy);
+	window = RootWindow(dpy, scr);
+
+	dpy_x = DisplayWidth(dpy, scr);
+	dpy_y = DisplayHeight(dpy, scr);
+
+	fb = XGetImage(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap);
+	printf("Read initial data from display into framebuffer.\n");
+
+	if (fb->bits_per_pixel == 24) {
+		printf("warning: 24 bpp may have poor performance.\n");
+	}
+
+	/*
+	 * n.b. we do not have to X_LOCK X11 calls until watch_loop()
+	 * is called since we are single-threaded until then.
+	 */
+
+	initialize_screen(&argc2, argv2, fb);
+
+	initialize_tiles();
+
+	initialize_shm();
+
+	printf("screen setup finished.\n");
+
+	watch_loop();
+
+	return(0);
+}
diff --git a/contrib/zippy.c b/contrib/zippy.c
new file mode 100644
index 0000000..58ad3ee
--- /dev/null
+++ b/contrib/zippy.c
@@ -0,0 +1,181 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <rfb.h>
+#include <keysym.h>
+#include "radon.h"
+
+int maxx=400, maxy=400, bpp=4;
+/* odd maxx doesn't work (vncviewer bug) */
+
+/* Here we create a structure so that every client has it's own pointer */
+
+/* turns the framebuffer black */
+void blank_framebuffer(char* frame_buffer, int x1, int y1, int x2, int y2);
+/* displays a red bar, a green bar, and a blue bar */
+void draw_primary_colors (char* frame_buffer, int x1, int y1, int x2, int y2);
+void linecount (char* frame_buffer);
+/* handles mouse events */
+void on_mouse_event (int buttonMask,int x,int y,rfbClientPtr cl);
+/* handles keyboard events */
+void on_key_press (Bool down,KeySym key,rfbClientPtr cl);
+
+int main (int argc, char **argv)
+{
+	rfbScreenInfoPtr server;
+
+	rfbProcessSizeArguments(&maxx,&maxy,&bpp,&argc,argv);
+	  
+        server = rfbGetScreen (&argc, argv, maxx, maxy, 8, 3, bpp);
+	server->desktopName = "Zippy das wundersquirrel\'s VNC server";
+	server->frameBuffer = (char*)malloc(maxx*maxy*bpp);
+	server->rfbAlwaysShared = TRUE;
+        server->kbdAddEvent = on_key_press;
+	server->ptrAddEvent = on_mouse_event;
+
+	rfbInitServer (server);
+
+	blank_framebuffer(server->frameBuffer, 0, 0, maxx, maxy);
+	rfbRunEventLoop (server, -1, FALSE);
+	free(server->frameBuffer);
+	rfbScreenCleanup (server);
+	return 0;
+}
+
+void blank_framebuffer(char* frame_buffer, int x1, int y1, int x2, int y2)
+{
+	int i;
+        for (i=0; i < maxx * maxy * bpp; i++) frame_buffer[i]=(char) 0;
+}
+
+void draw_primary_colors (char* frame_buffer, int x1, int y1, int x2, int y2)
+{
+        int i, j, current_pixel;
+        for (i=y1; i < y2; i++){
+                for (j=x1; j < x2; j++) {
+                        current_pixel = (i*x2 + j) * bpp;
+                        if (i < y2 ) {
+                                frame_buffer[current_pixel+0] = (char) 128;
+                                frame_buffer[current_pixel+1] = (char) 0;
+                                frame_buffer[current_pixel+2] = (char) 0;
+                        }
+                        if (i < y2/3*2) {
+                                frame_buffer[current_pixel+0] = (char) 0;
+                                frame_buffer[current_pixel+1] = (char) 128;
+                                frame_buffer[current_pixel+2] = (char) 0;
+                        }
+                        if (i < y2/3) {
+                                frame_buffer[current_pixel+0] = (char) 0;
+                                frame_buffer[current_pixel+1] = (char) 0;
+                                frame_buffer[current_pixel+2] = (char) 128;
+                        }
+                }
+        }
+ }
+
+/* Dscho's versions (slower, but works for bpp != 3 or 4) */
+void draw_primary_colours_generic(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
+{
+  rfbPixelFormat f=s->rfbServerFormat;
+  int i,j;
+  for(j=y1;j<y2;j++)
+    for(i=x1;i<x2;i++)
+      if(j<y1*2/3+y2/3)
+	rfbDrawPixel(s,i,j,f.redMax<<f.redShift);
+      else if(j<y1/3+y2*2/3)
+	rfbDrawPixel(s,i,j,f.greenMax<<f.greenShift);
+      else
+	rfbDrawPixel(s,i,j,f.blueMax<<f.blueShift);
+}
+
+void draw_primary_colours_generic_fast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
+{
+  rfbPixelFormat f=s->rfbServerFormat;
+  int i,j,y3=(y1*2+y2)/3,y4=(y1+y2*2)/3;
+  /* draw first pixel */
+  rfbDrawPixel(s,x1,y1,f.redMax<<f.redShift);
+  rfbDrawPixel(s,x1,y3,f.greenMax<<f.greenShift);
+  rfbDrawPixel(s,x1,y4,f.blueMax<<f.blueShift);
+  /* then copy stripes */
+  for(j=0;j<y2-y4;j++)
+    for(i=x1;i<x2;i++) {
+#define ADDR(x,y) s->frameBuffer+(x)*bpp+(y)*s->paddedWidthInBytes
+      memcpy(ADDR(i,j+y1),ADDR(x1,y1),bpp);
+      memcpy(ADDR(i,j+y3),ADDR(x1,y3),bpp);
+      memcpy(ADDR(i,j+y4),ADDR(x1,y4),bpp);
+    }
+}
+
+void draw_primary_colours_generic_ultrafast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
+{
+  rfbPixelFormat f=s->rfbServerFormat;
+  int y3=(y1*2+y2)/3,y4=(y1+y2*2)/3;
+  /* fill rectangles */
+  rfbFillRect(s,x1,y1,x2,y3,f.redMax<<f.redShift);
+  rfbFillRect(s,x1,y3,x2,y4,f.greenMax<<f.greenShift);
+  rfbFillRect(s,x1,y4,x2,y2,f.blueMax<<f.blueShift);
+}
+
+void linecount (char* frame_buffer)
+{
+        int i,j,k, current_pixel;
+        for (i=maxy-4; i>maxy-20; i-=4)
+                for (j=0; j<4; j++) for (k=0; k < maxx; k++) {
+                        current_pixel = (i*j*maxx + k) * bpp;
+                        if (i%2 == 0) {
+                                frame_buffer[current_pixel+0] = (char) 0;
+                                frame_buffer[current_pixel+1] = (char) 0;
+                                frame_buffer[current_pixel+2] = (char) 128;
+                        }
+
+                        if (i%2 == 1) {
+                                frame_buffer[current_pixel+0] = (char) 128;
+                                frame_buffer[current_pixel+1] = (char) 0;
+                                frame_buffer[current_pixel+2] = (char) 0;
+                        }
+                }
+
+}
+
+
+void on_key_press (Bool down,KeySym key,rfbClientPtr cl)
+{
+        if (down)		//or else the action occurs on both the press and depress
+	switch (key) {
+
+        case XK_b:
+        case XK_B:
+                rfbUndrawCursor(cl->screen);
+                blank_framebuffer(cl->screen->frameBuffer, 0, 0, maxx, maxy);
+                rfbDrawString(cl->screen,&radonFont,20,maxy-20,"Hello, World!",0xffffff);
+                rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
+                fprintf (stderr, "Framebuffer blanked\n");
+                break;
+        case XK_p:
+        case XK_P:
+                rfbUndrawCursor(cl->screen);
+                /* draw_primary_colors (cl->screen->frameBuffer, 0, 0, maxx, maxy); */
+		draw_primary_colours_generic_ultrafast (cl->screen, 0, 0, maxx, maxy);
+                rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
+                fprintf (stderr, "Primary colors displayed\n");
+                break;
+        case XK_Q:
+        case XK_q:
+                fprintf (stderr, "Exiting now\n");
+                exit(0);
+        case XK_C:
+        case XK_c:
+                rfbUndrawCursor(cl->screen);
+		rfbDrawString(cl->screen,&radonFont,20,100,"Hello, World!",0xffffff);
+                rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
+                break;
+        default:
+                fprintf (stderr, "The %c key was pressed\n", (char) key);
+        }
+}
+
+
+void on_mouse_event (int buttonMask,int x,int y,rfbClientPtr cl)
+{
+	printf("buttonMask: %i\n"
+		"x: %i\n" "y: %i\n", buttonMask, x, y);
+}
diff --git a/httpd.c b/httpd.c
index 5207c72..328f416 100644
--- a/httpd.c
+++ b/httpd.c
@@ -266,7 +266,7 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
 		httpCloseSock(rfbScreen);
 		return;
 	    }
-	    // proxy connection
+	    /* proxy connection */
 	    rfbLog("httpd: client asked for CONNECT\n");
 	    WriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
 	    rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
@@ -274,7 +274,7 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
 	    return;
 	}
 	if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) {
-	    // proxy connection
+	    /* proxy connection */
 	    rfbLog("httpd: client asked for /proxied.connection\n");
 	    WriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
 	    rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
diff --git a/main.c b/main.c
index ab4c149..b975481 100644
--- a/main.c
+++ b/main.c
@@ -128,7 +128,7 @@ void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,in
        sraRgnDestroy(modifiedRegionBackup);
 
 #if 0
-//TODO: is this needed? Or does it mess up deferring?
+       /* TODO: is this needed? Or does it mess up deferring? */
        /* while(!sraRgnEmpty(cl->copyRegion)) */ {
 #ifdef HAVE_PTHREADS
 	 if(!cl->screen->backgroundLoop)
diff --git a/rfb.h b/rfb.h
index 856dd9b..37aac35 100644
--- a/rfb.h
+++ b/rfb.h
@@ -164,9 +164,17 @@ typedef int socklen_t;
    the library and your application (at least the parts including rfb.h)
    with the same support for pthreads. */
 #ifdef HAVE_PTHREADS
-#define rfbInitServer rfbInitServerWithPthreads
+#ifdef HAVE_ZRLE
+#define rfbInitServer rfbInitServerWithPthreadsAndZRLE
+#else
+#define rfbInitServer rfbInitServerWithPthreadsButWithoutZRLE
+#endif
+#else
+#ifdef HAVE_ZRLE
+#define rfbInitServer rfbInitServerWithoutPthreadsButWithZRLE
 #else
-#define rfbInitServer rfbInitServerWithoutPthreads
+#define rfbInitServer rfbInitServerWithoutPthreadsAndZRLE
+#endif
 #endif
 
 #define MAX_ENCODINGS 10
@@ -409,9 +417,6 @@ typedef struct _rfbClientRec {
     Bool useCopyRect;
     int preferredEncoding;
     int correMaxWidth, correMaxHeight;
-#ifdef HAVE_ZRLE
-    void* zrleData;
-#endif
 
     /* The following member is only used during VNC authentication */
     CARD8 authChallenge[CHALLENGESIZE];
@@ -538,6 +543,10 @@ typedef struct _rfbClientRec {
     COND(updateCond);
 #endif
 
+#ifdef HAVE_ZRLE
+    void* zrleData;
+#endif
+
 } rfbClientRec, *rfbClientPtr;
 
 /*
@@ -725,9 +734,10 @@ extern void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,Bool freeOld)
 extern void defaultPtrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl);
 
 /* zrle.c */
-
+#ifdef HAVE_ZRLE
 extern Bool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w,int h);
 extern void FreeZrleData(rfbClientPtr cl);
+#endif
 
 /* stats.c */
 
diff --git a/x11vnc.c b/x11vnc.c
deleted file mode 100644
index ee21d03..0000000
--- a/x11vnc.c
+++ /dev/null
@@ -1,583 +0,0 @@
-/* This file (x11vnc.c) is part of LibVNCServer.
-   It is a small clone of x0rfbserver by HexoNet, demonstrating the
-   capabilities of LibVNCServer.
-*/
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-#include <X11/extensions/XTest.h>
-#ifndef NO_SHM
-#include <X11/extensions/XShm.h>
-#include <sys/shm.h>
-#endif
-#define KEYSYM_H
-#undef Bool
-#define KeySym RFBKeySym
-#include "rfb.h"
-
-Display *dpy = 0;
-int window;
-int c=0,blockLength = 32;
-int tileX=0,tileY=0,tileWidth=32,tileHeight=32*2,dontTile=TRUE;
-Bool gotInput = FALSE;
-Bool viewOnly = FALSE;
-Bool sharedMode = FALSE;
-
-Bool disconnectAfterFirstClient = TRUE;
-
-/* keyboard handling */
-#define KBDDEBUG
-
-char modifiers[0x100];
-KeyCode keycodes[0x100],leftShiftCode,rightShiftCode,altGrCode;
-
-void init_keycodes()
-{
-  KeySym key,*keymap;
-  int i,j,minkey,maxkey,syms_per_keycode;
-
-  memset(modifiers,-1,sizeof(modifiers));
-
-  XDisplayKeycodes(dpy,&minkey,&maxkey);
-  keymap=XGetKeyboardMapping(dpy,minkey,(maxkey - minkey + 1),&syms_per_keycode);
-
-#ifdef KBDDEBUG
-  fprintf(stderr,"minkey=%d, maxkey=%d, syms_per_keycode=%d\n",
-	  minkey,maxkey,syms_per_keycode);
-#endif
-  for (i = minkey; i <= maxkey; i++)
-    for(j=0;j<syms_per_keycode;j++) {
-      key=keymap[(i-minkey)*syms_per_keycode+j];
-#ifdef KBDDEBUG
-      fprintf(stderr,"keymap(i=0x%x,j=%d)==0x%lx\n",i,j,key);
-#endif
-      if(key>=' ' && key<0x100 && i==XKeysymToKeycode(dpy,key)) {
-	keycodes[key]=i;
-	modifiers[key]=j;
-#ifdef KBDDEBUG
-	fprintf(stderr,"key 0x%lx (%c): keycode=0x%x, modifier=%d\n",
-		key,(char)key,i,j);
-#endif
-      }
-    }
-
-  leftShiftCode=XKeysymToKeycode(dpy,XK_Shift_L);
-  rightShiftCode=XKeysymToKeycode(dpy,XK_Shift_R);
-  altGrCode=XKeysymToKeycode(dpy,XK_Mode_switch);
-
-#ifdef KBDDEBUG
-  fprintf(stderr,"leftShift=0x%x, rightShift=0x%x, altGr=0x%x\n",
-	  leftShiftCode,rightShiftCode,altGrCode);
-#endif
-
-  XFree ((char *) keymap);
-}
-
-static Bool shutDownServer=0;
-
-/* the hooks */
-
-void clientGone(rfbClientPtr cl)
-{
-  shutDownServer=-1;
-}
-
-enum rfbNewClientAction newClient(rfbClientPtr cl)
-{
-  if(disconnectAfterFirstClient)
-    cl->clientGoneHook = clientGone;
-  if(viewOnly)
-    cl->clientData = (void*)-1;
-  else
-    cl->clientData = (void*)0;
-  return(RFB_CLIENT_ACCEPT);
-}
-
-#define LEFTSHIFT 1
-#define RIGHTSHIFT 2
-#define ALTGR 4
-char ModifierState = 0;
-
-/* this function adjusts the modifiers according to mod (as from modifiers) and ModifierState */
-
-void tweakModifiers(signed char mod,Bool down)
-{
-  Bool isShift=ModifierState&(LEFTSHIFT|RIGHTSHIFT);
-#ifdef KBDDEBUG
-  fprintf(stderr,"tweakModifiers: 0x%x %s\n",
-	  mod,down?"down":"up");
-#endif
-  if(mod<0) return;
-  if(isShift && mod!=1) {
-    if(ModifierState&LEFTSHIFT)
-      XTestFakeKeyEvent(dpy,leftShiftCode,!down,CurrentTime);
-    if(ModifierState&RIGHTSHIFT)
-      XTestFakeKeyEvent(dpy,rightShiftCode,!down,CurrentTime);
-  }
-  if(!isShift && mod==1)
-    XTestFakeKeyEvent(dpy,leftShiftCode,down,CurrentTime);
-
-  if(ModifierState&ALTGR && mod!=2)
-    XTestFakeKeyEvent(dpy,altGrCode,!down,CurrentTime);
-  if(!(ModifierState&ALTGR) && mod==2)
-    XTestFakeKeyEvent(dpy,altGrCode,down,CurrentTime);
-}
-
-void keyboard(Bool down,KeySym keySym,rfbClientPtr cl)
-{
-  if(((int)cl->clientData)==-1) return; /* viewOnly */
-
-#define ADJUSTMOD(sym,state) \
-  if(keySym==sym) { if(down) ModifierState|=state; else ModifierState&=~state; }
-
-  ADJUSTMOD(XK_Shift_L,LEFTSHIFT)
-  ADJUSTMOD(XK_Shift_R,RIGHTSHIFT)
-  ADJUSTMOD(XK_Mode_switch,ALTGR)
-
-#ifdef KBDDEBUG
-    fprintf(stderr,"keyboard: down=%s, keySym=0x%lx (%s), ModState=0x%x\n",
-	    down?"down":"up",keySym,XKeysymToString(keySym),ModifierState);
-#endif
-
-  if(keySym>=' ' && keySym<0x100) {
-    KeyCode k;
-    if(down)
-       tweakModifiers(modifiers[keySym],True);
-    //tweakModifiers(modifiers[keySym],down);
-    //k = XKeysymToKeycode( dpy,keySym );
-    k = keycodes[keySym];
-    if(k!=NoSymbol) {
-      XTestFakeKeyEvent(dpy,k,down,CurrentTime);
-      gotInput = TRUE;
-    }
-    if(down)
-      tweakModifiers(modifiers[keySym],False);
-    gotInput = TRUE;
-  } else {
-    KeyCode k = XKeysymToKeycode( dpy,keySym );
-    if(k!=NoSymbol) {
-      XTestFakeKeyEvent(dpy,k,down,CurrentTime);
-      gotInput = TRUE;
-    }
-  }
-}
-
-int oldButtonMask = 0;
-
-void mouse(int buttonMask,int x,int y,rfbClientPtr cl)
-{
-  int i=0;
-
-  if(((int)cl->clientData)==-1) return; /* viewOnly */
-
-  XTestFakeMotionEvent(dpy,0,x,y,CurrentTime );
-  while(i<5) {
-    if ((oldButtonMask&(1<<i))!=(buttonMask&(1<<i)))
-      XTestFakeButtonEvent(dpy,i+1,(buttonMask&(1<<i))?True:False,CurrentTime);
-    i++;
-  }
-  oldButtonMask = buttonMask;
-  //fprintf(stderr,"-");
-  gotInput = TRUE;
-}
-
-/* the X11 interaction */
-
-#ifndef NO_SHM
-Bool useSHM = TRUE;
-XShmSegmentInfo shminfo;
-#else
-Bool useSHM = FALSE;
-#endif
-
-void getImage(int bpp,Display *dpy,int xscreen,XImage **i,int x,int y,int width,int height)
-{
-  if(width<=0) width=DisplayWidth(dpy,xscreen);
-  if(height<=0) height=DisplayHeight(dpy,xscreen);
-  if(useSHM && bpp>0) {
-    static Bool firstTime = TRUE;
-    if(firstTime) {
-      firstTime = FALSE;
-      *i = XShmCreateImage(dpy,
-			   DefaultVisual( dpy, xscreen ),
-			   bpp,
-			   ZPixmap,
-			   NULL,
-			   &shminfo,
-			   width,height);
-
-      if(*i == 0) {
-	useSHM = FALSE;
-	getImage(bpp,dpy,xscreen,i,x,y,width,height);
-	return;
-      }
-
-      shminfo.shmid = shmget( IPC_PRIVATE,
-			      (*i)->bytes_per_line * (*i)->height,
-			      IPC_CREAT | 0777 );
-      shminfo.shmaddr = (*i)->data = (char *) shmat( shminfo.shmid, 0, 0 );
-      shminfo.readOnly = False;
-      XShmAttach( dpy, &shminfo );
-    }
-
-    if(x==0 && y==0 && width==DisplayWidth(dpy,xscreen) && height==DisplayHeight(dpy,xscreen))
-      XShmGetImage(dpy,window,*i,0,0,AllPlanes);
-    else
-      XGetSubImage(dpy,window,x,y,width,height,AllPlanes,ZPixmap,*i,0,0);
-  } else {
-    *i = XGetImage(dpy,window,x,y,width,height,AllPlanes,ZPixmap );
-  }
-}
-
-void checkForImageUpdates(rfbScreenInfoPtr s,char *b,int rowstride,int x,int y,int width,int height)
-{
-   Bool changed;
-   int i,j,k,l1,l2,x1,y1;
-   int bpp=s->bitsPerPixel/8;
-
-   for(j=0;j<height;j+=blockLength)
-     for(i=0;i<width;i+=blockLength) {
-	y1=j+blockLength; if(y1>height) y1=height;
-	x1=i+blockLength; if(x1>width) x1=width;
-	y1*=rowstride;
-	x1*=bpp;
-	changed=FALSE;
-	for(l1=j*rowstride,l2=(j+y)*s->paddedWidthInBytes+x*bpp;l1<y1;l1+=rowstride,l2+=s->paddedWidthInBytes)
-	  for(k=i*bpp;k<x1;k++)
-	    if(s->frameBuffer[l2+k]!=b[l1+k]) {
-	      //	       fprintf(stderr,"changed: %d, %d\n",k,l);
-	       changed=TRUE;
-	       goto changed_p;
-	    }
-	if(changed) {
-	   changed_p:
-	  for(l1+=i*bpp,l2+=i*bpp;l1<y1;l1+=rowstride,l2+=s->paddedWidthInBytes)
-	    memcpy(/*b+l,*/s->frameBuffer+l2,b+l1,x1-i*bpp);
-	  rfbMarkRectAsModified(s,x+i,y+j,x+i+blockLength,y+j+blockLength);
-	}
-     }
-}
-
-int probeX=0,probeY=0;
-
-void probeScreen(rfbScreenInfoPtr s,int xscreen)
-{
-  int i,j,/*pixel,i1,*/j1,
-    bpp=s->rfbServerFormat.bitsPerPixel/8,/*mask=(1<<bpp)-1,*/
-    rstride=s->paddedWidthInBytes;
-  XImage* im;
-  //fprintf(stderr,"/%d,%d",probeX,probeY);
-#if 0
-  probeX++;
-  if(probeX>=tileWidth) {
-    probeX=0;
-    probeY++;
-    if(probeY>=tileHeight)
-      probeY=0;
-  }
-#else
-  probeX=(rand()%tileWidth);
-  probeY=(rand()%tileHeight);
-#endif
-
-  for(j=probeY;j<s->height;j+=tileHeight)
-    for(i=0/*probeX*/;i<s->width;i+=tileWidth) {
-      im=XGetImage(dpy,window,i,j,tileWidth/*1*/,1,AllPlanes,ZPixmap);
-      /*      for(i1=0;i1<bpp && im->data[i1]==(s->frameBuffer+i*bpp+j*rstride)[i1];i1++);
-	      if(i1<bpp) { */
-      if(memcmp(im->data,s->frameBuffer+i*bpp+j*rstride,tileWidth*bpp)) {
-	/* do update */
-	int x=i/*-probeX*/,w=(x+tileWidth>s->width)?s->width-x:tileWidth,
-	  y=j-probeY,h=(y+tileHeight>s->height)?s->height-y:tileHeight;
-
-	XDestroyImage(im);
-	//getImage(bpp,dpy,xscreen,&im,x,y,w,h);
-	//fprintf(stderr,"GetImage(%d,%d,%d,%d)",x,y,w,h);
-	im = XGetImage(dpy,window,x,y,w,h,AllPlanes,ZPixmap );
-	for(j1=0;j1<h;j1++)
-	  memcpy(s->frameBuffer+x*bpp+(y+j1)*rstride,
-		 im->data+j1*im->bytes_per_line,bpp*w);
-	//checkForImageUpdates(s,im->data,rstride,x,y,w,h);
-	//if(0 && !useSHM)
-	  XDestroyImage(im);
-	//memcpy(s->frameBuffer+i*bpp+j*rstride,&pixel,bpp);
-	rfbMarkRectAsModified(s,x,y,x+w,y+h);
-	//fprintf(stderr,"%d:%d:%x\n",i,j,pixel);
-	//fprintf(stderr,"*");
-      } else
-	XDestroyImage(im);
-    }
-}
-
-#define LOCAL_CONTROL
-
-#ifdef LOCAL_CONTROL
-#include "1instance.c"
-#endif
-
-/* the main program */
-
-int main(int argc,char** argv)
-{
-  //Screen *sc;
-  //Colormap cm;
-  XImage *framebufferImage;
-  char *backupImage;
-  int xscreen,i;
-  rfbScreenInfoPtr screen;
-  int maxMsecsToConnect = 5000; /* a maximum of 5 seconds to connect */
-  int updateCounter; /* about every 50 ms a screen update should be made. */
-
-#ifdef LOCAL_CONTROL
-  char message[1024];
-  single_instance_struct single_instance = { "/tmp/x11vnc_control" };
-
-  open_control_file(&single_instance);
-#endif
-
-  for(i=argc-1;i>0;i--)
-#ifdef LOCAL_CONTROL
-    if(i<argc-1 && !strcmp(argv[i],"-toggleviewonly")) {
-      if(strlen(argv[i+1])>1022)
-	argv[i+1][1022]=0;
-      sprintf(message,"t%s",argv[i+1]);
-      send_message(&single_instance,message);
-      exit(0);
-    } else if(!strcmp(argv[i],"-listclients")) {
-      fprintf(stderr,"list clients\n");
-      send_message(&single_instance,"l");
-      exit(0);
-    } else
-#ifdef BACKCHANNEL
-    if(i<argc-1 && !strcmp(argv[i],"-backchannel")) {
-      if(strlen(argv[i+1])>1022)
-	argv[i+1][1022]=0;
-      sprintf(message,"b%s",argv[i+1]);
-      send_message(&single_instance,message);
-      exit(0);
-    } else
-#endif
-#endif
-    if(i<argc-1 && strcmp(argv[i],"-display")==0) {
-      fprintf(stderr,"Using display %s\n",argv[i+1]);
-      dpy = XOpenDisplay(argv[i+1]);
-      if(dpy==0) {
-	fprintf(stderr,"Couldn't connect to display \"%s\".\n",argv[i+1]);
-	exit(1);
-      }
-    } else if(i<argc-1 && strcmp(argv[i],"-wait4client")==0) {
-      maxMsecsToConnect = atoi(argv[i+1]);
-    } else if(i<argc-1 && strcmp(argv[i],"-update")==0) {
-      updateCounter = atoi(argv[i+1]);
-    } else if(strcmp(argv[i],"-noshm")==0) {
-      useSHM = FALSE;
-    } else if(strcmp(argv[i],"-runforever")==0) {
-      disconnectAfterFirstClient = FALSE;
-    } else if(strcmp(argv[i],"-tile")==0) {
-      dontTile=FALSE;
-    } else if(strcmp(argv[i],"-viewonly")==0) {
-      viewOnly=TRUE;
-    } else if(strcmp(argv[i],"-shared")==0) {
-      sharedMode=TRUE;
-    }
-
-  updateCounter = dontTile?20:1;
-
-  if(dpy==0)
-    dpy = XOpenDisplay("");
-  if(dpy==0) {
-    fprintf(stderr,"Couldn't open display!\n");
-    exit(2);
-  }
-
-  xscreen = DefaultScreen(dpy);
-  window = RootWindow(dpy,xscreen);
-  //XTestGrabControl(dpy,True);
-
-  init_keycodes();
-
-  getImage(0,dpy,xscreen,&framebufferImage,0,0,-1,-1);
-
-  screen = rfbGetScreen(&argc,argv,framebufferImage->width,
-			framebufferImage->height,
-			framebufferImage->bits_per_pixel,
-			8,
-			framebufferImage->bits_per_pixel/8);
-   
-  screen->paddedWidthInBytes = framebufferImage->bytes_per_line;
-
-  screen->rfbServerFormat.bitsPerPixel = framebufferImage->bits_per_pixel;
-  screen->rfbServerFormat.depth = framebufferImage->depth;
-  //rfbEndianTest = framebufferImage->bitmap_bit_order != MSBFirst;
-  screen->rfbServerFormat.trueColour = TRUE;
-
-  if ( screen->rfbServerFormat.bitsPerPixel == 8 ) {
-     if(CellsOfScreen(ScreenOfDisplay(dpy,xscreen))) {
-	XColor color[256];
-	int i;
-        screen->colourMap.count = 256;
-	screen->rfbServerFormat.trueColour = FALSE;
-	screen->colourMap.is16 = TRUE;
-        for(i=0;i<256;i++)
-	  color[i].pixel=i;
-	XQueryColors(dpy,DefaultColormap(dpy,xscreen),color,256);
-	screen->colourMap.data.shorts = (unsigned short*)malloc(3*sizeof(short)*screen->colourMap.count);
-	for(i=0;i<screen->colourMap.count;i++) {
-	   screen->colourMap.data.shorts[i*3+0] = color[i].red;
-	   screen->colourMap.data.shorts[i*3+1] = color[i].green;
-	   screen->colourMap.data.shorts[i*3+2] = color[i].blue;
-	}
-     } else {
-	screen->rfbServerFormat.redShift = 0;
-	screen->rfbServerFormat.greenShift = 2;
-	screen->rfbServerFormat.blueShift = 5;
-	screen->rfbServerFormat.redMax   = 3;
-	screen->rfbServerFormat.greenMax = 7;
-	screen->rfbServerFormat.blueMax  = 3;
-     }
-  } else {
-    screen->rfbServerFormat.redShift = 0;
-    if ( framebufferImage->red_mask )
-      while ( ! ( framebufferImage->red_mask & (1 << screen->rfbServerFormat.redShift) ) )
-        screen->rfbServerFormat.redShift++;
-    screen->rfbServerFormat.greenShift = 0;
-    if ( framebufferImage->green_mask )
-      while ( ! ( framebufferImage->green_mask & (1 << screen->rfbServerFormat.greenShift) ) )
-        screen->rfbServerFormat.greenShift++;
-    screen->rfbServerFormat.blueShift = 0;
-    if ( framebufferImage->blue_mask )
-      while ( ! ( framebufferImage->blue_mask & (1 << screen->rfbServerFormat.blueShift) ) )
-      screen->rfbServerFormat.blueShift++;
-    screen->rfbServerFormat.redMax   = framebufferImage->red_mask   >> screen->rfbServerFormat.redShift;
-    screen->rfbServerFormat.greenMax = framebufferImage->green_mask >> screen->rfbServerFormat.greenShift;
-    screen->rfbServerFormat.blueMax  = framebufferImage->blue_mask  >> screen->rfbServerFormat.blueShift;
-  }
-
-  backupImage = malloc(screen->height*screen->paddedWidthInBytes);
-  memcpy(backupImage,framebufferImage->data,screen->height*screen->paddedWidthInBytes);
-
-  screen->frameBuffer = backupImage;
-  screen->cursor = 0;
-  screen->newClientHook = newClient;
-
-  screen->kbdAddEvent = keyboard;
-  screen->ptrAddEvent = mouse;
-
-  if(sharedMode) {
-    screen->rfbAlwaysShared = TRUE;
-  }
-
-  screen->rfbDeferUpdateTime = 1;
-  updateCounter /= screen->rfbDeferUpdateTime;
-
-  rfbInitServer(screen);
-
-  c=0;
-  while(1) {
-    if(screen->rfbClientHead)
-      maxMsecsToConnect = 1<<16;
-    else {
-      maxMsecsToConnect -= screen->rfbDeferUpdateTime;
-      if(maxMsecsToConnect<0) {
-	fprintf(stderr,"Maximum time to connect reached. Exiting.\n");
-	XTestDiscard(dpy);
-	exit(2);
-      }
-    }
-
-#ifdef LOCAL_CONTROL
-    if(get_next_message(message,1024,&single_instance,50)) {
-      if(message[0]=='l' && message[1]==0) {
-	rfbClientPtr cl;
-	int i;
-	for(i=0,cl=screen->rfbClientHead;cl;cl=cl->next,i++)
-	  fprintf(stderr,"%02d: %s\n",i,cl->host);
-      } else if(message[0]=='t') {
-	rfbClientPtr cl;
-	for(cl=screen->rfbClientHead;cl;cl=cl->next)
-	  if(!strcmp(message+1,cl->host)) {
-	    cl->clientData=(void*)((cl->clientData==0)?-1:0);
-	    break;
-	  }
-      }
-#ifdef BACKCHANNEL
-      else if(message[0]=='b')
-	rfbSendBackChannel(screen,message+1,strlen(message+1));
-#endif
-    }
-#endif
-
-    rfbProcessEvents(screen,-1);
-    if(shutDownServer) {
-      free(backupImage);
-      rfbScreenCleanup(screen);
-      XFree(dpy);
-#ifndef NO_SHM
-      XShmDetach(dpy,&shminfo);
-#endif
-      exit(0);
-    }
-
-    if(dontTile) {
-      if(gotInput) {
-	gotInput = FALSE;
-	c=updateCounter;
-      } else if(screen->rfbClientHead && c++>updateCounter) {
-	c=0;
-	//fprintf(stderr,"*");
-	if(!useSHM)
-	  framebufferImage->f.destroy_image(framebufferImage);
-	if(dontTile) {
-	  getImage(screen->rfbServerFormat.bitsPerPixel,dpy,xscreen,&framebufferImage,0,0,screen->width,screen->height);
-	  checkForImageUpdates(screen,framebufferImage->data,framebufferImage->bytes_per_line,
-			       0,0,screen->width,screen->height);
-	} else {
-	  /* old tile code. Eventually to be removed (TODO) */
-	  char isRightEdge = tileX+tileWidth>=screen->width;
-	  char isLowerEdge = tileY+tileHeight>=screen->height;
-	  getImage(screen->rfbServerFormat.bitsPerPixel,dpy,xscreen,&framebufferImage,tileX,tileY,
-		   isRightEdge?screen->width-tileX:tileWidth,
-		   isLowerEdge?screen->height-tileY:tileHeight);
-	  checkForImageUpdates(screen,framebufferImage->data,framebufferImage->bytes_per_line,
-			       tileX,tileY,
-			       isRightEdge?screen->width-tileX:tileWidth,
-			       isLowerEdge?screen->height-tileY:tileHeight);
-	  if(isRightEdge) {
-	    tileX=0;
-	    if(isLowerEdge)
-	      tileY=0;
-	    else
-	      tileY+=tileHeight;
-	  } else
-	    tileX+=tileWidth;
-	}
-      }
-    } else if(c++>updateCounter) {
-      c=0;
-      probeScreen(screen,xscreen);
-    }
-
-#ifdef WRITE_SNAPS
-       {
-	  int i,j,r,g,b;
-	  FILE* f=fopen("test.pnm","wb");
-	  fprintf(f,"P6\n%d %d\n255\n",screen->width,screen->height);
-	  for(j=0;j<screen->height;j++)
-	    for(i=0;i<screen->width;i++) {
-	      //r=screen->frameBuffer[j*screen->paddedWidthInBytes+i*2];
-	      r=framebufferImage->data[j*screen->paddedWidthInBytes+i*2];
-	       fputc(((r>>screen->rfbServerFormat.redShift)&screen->rfbServerFormat.redMax)*255/screen->rfbServerFormat.redMax,f);
-	       fputc(((r>>screen->rfbServerFormat.greenShift)&screen->rfbServerFormat.greenMax)*255/screen->rfbServerFormat.greenMax,f);
-	       fputc(((r>>screen->rfbServerFormat.blueShift)&screen->rfbServerFormat.blueMax)*255/screen->rfbServerFormat.blueMax,f);
-	    }
-	  fclose(f);
-       }
-#endif
-  }
-#ifndef NO_SHM
-  //XShmDetach(dpy,framebufferImage);
-#endif
-
-  return(0);
-}
diff --git a/zippy.c b/zippy.c
deleted file mode 100644
index 58ad3ee..0000000
--- a/zippy.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <rfb.h>
-#include <keysym.h>
-#include "radon.h"
-
-int maxx=400, maxy=400, bpp=4;
-/* odd maxx doesn't work (vncviewer bug) */
-
-/* Here we create a structure so that every client has it's own pointer */
-
-/* turns the framebuffer black */
-void blank_framebuffer(char* frame_buffer, int x1, int y1, int x2, int y2);
-/* displays a red bar, a green bar, and a blue bar */
-void draw_primary_colors (char* frame_buffer, int x1, int y1, int x2, int y2);
-void linecount (char* frame_buffer);
-/* handles mouse events */
-void on_mouse_event (int buttonMask,int x,int y,rfbClientPtr cl);
-/* handles keyboard events */
-void on_key_press (Bool down,KeySym key,rfbClientPtr cl);
-
-int main (int argc, char **argv)
-{
-	rfbScreenInfoPtr server;
-
-	rfbProcessSizeArguments(&maxx,&maxy,&bpp,&argc,argv);
-	  
-        server = rfbGetScreen (&argc, argv, maxx, maxy, 8, 3, bpp);
-	server->desktopName = "Zippy das wundersquirrel\'s VNC server";
-	server->frameBuffer = (char*)malloc(maxx*maxy*bpp);
-	server->rfbAlwaysShared = TRUE;
-        server->kbdAddEvent = on_key_press;
-	server->ptrAddEvent = on_mouse_event;
-
-	rfbInitServer (server);
-
-	blank_framebuffer(server->frameBuffer, 0, 0, maxx, maxy);
-	rfbRunEventLoop (server, -1, FALSE);
-	free(server->frameBuffer);
-	rfbScreenCleanup (server);
-	return 0;
-}
-
-void blank_framebuffer(char* frame_buffer, int x1, int y1, int x2, int y2)
-{
-	int i;
-        for (i=0; i < maxx * maxy * bpp; i++) frame_buffer[i]=(char) 0;
-}
-
-void draw_primary_colors (char* frame_buffer, int x1, int y1, int x2, int y2)
-{
-        int i, j, current_pixel;
-        for (i=y1; i < y2; i++){
-                for (j=x1; j < x2; j++) {
-                        current_pixel = (i*x2 + j) * bpp;
-                        if (i < y2 ) {
-                                frame_buffer[current_pixel+0] = (char) 128;
-                                frame_buffer[current_pixel+1] = (char) 0;
-                                frame_buffer[current_pixel+2] = (char) 0;
-                        }
-                        if (i < y2/3*2) {
-                                frame_buffer[current_pixel+0] = (char) 0;
-                                frame_buffer[current_pixel+1] = (char) 128;
-                                frame_buffer[current_pixel+2] = (char) 0;
-                        }
-                        if (i < y2/3) {
-                                frame_buffer[current_pixel+0] = (char) 0;
-                                frame_buffer[current_pixel+1] = (char) 0;
-                                frame_buffer[current_pixel+2] = (char) 128;
-                        }
-                }
-        }
- }
-
-/* Dscho's versions (slower, but works for bpp != 3 or 4) */
-void draw_primary_colours_generic(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
-{
-  rfbPixelFormat f=s->rfbServerFormat;
-  int i,j;
-  for(j=y1;j<y2;j++)
-    for(i=x1;i<x2;i++)
-      if(j<y1*2/3+y2/3)
-	rfbDrawPixel(s,i,j,f.redMax<<f.redShift);
-      else if(j<y1/3+y2*2/3)
-	rfbDrawPixel(s,i,j,f.greenMax<<f.greenShift);
-      else
-	rfbDrawPixel(s,i,j,f.blueMax<<f.blueShift);
-}
-
-void draw_primary_colours_generic_fast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
-{
-  rfbPixelFormat f=s->rfbServerFormat;
-  int i,j,y3=(y1*2+y2)/3,y4=(y1+y2*2)/3;
-  /* draw first pixel */
-  rfbDrawPixel(s,x1,y1,f.redMax<<f.redShift);
-  rfbDrawPixel(s,x1,y3,f.greenMax<<f.greenShift);
-  rfbDrawPixel(s,x1,y4,f.blueMax<<f.blueShift);
-  /* then copy stripes */
-  for(j=0;j<y2-y4;j++)
-    for(i=x1;i<x2;i++) {
-#define ADDR(x,y) s->frameBuffer+(x)*bpp+(y)*s->paddedWidthInBytes
-      memcpy(ADDR(i,j+y1),ADDR(x1,y1),bpp);
-      memcpy(ADDR(i,j+y3),ADDR(x1,y3),bpp);
-      memcpy(ADDR(i,j+y4),ADDR(x1,y4),bpp);
-    }
-}
-
-void draw_primary_colours_generic_ultrafast(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2)
-{
-  rfbPixelFormat f=s->rfbServerFormat;
-  int y3=(y1*2+y2)/3,y4=(y1+y2*2)/3;
-  /* fill rectangles */
-  rfbFillRect(s,x1,y1,x2,y3,f.redMax<<f.redShift);
-  rfbFillRect(s,x1,y3,x2,y4,f.greenMax<<f.greenShift);
-  rfbFillRect(s,x1,y4,x2,y2,f.blueMax<<f.blueShift);
-}
-
-void linecount (char* frame_buffer)
-{
-        int i,j,k, current_pixel;
-        for (i=maxy-4; i>maxy-20; i-=4)
-                for (j=0; j<4; j++) for (k=0; k < maxx; k++) {
-                        current_pixel = (i*j*maxx + k) * bpp;
-                        if (i%2 == 0) {
-                                frame_buffer[current_pixel+0] = (char) 0;
-                                frame_buffer[current_pixel+1] = (char) 0;
-                                frame_buffer[current_pixel+2] = (char) 128;
-                        }
-
-                        if (i%2 == 1) {
-                                frame_buffer[current_pixel+0] = (char) 128;
-                                frame_buffer[current_pixel+1] = (char) 0;
-                                frame_buffer[current_pixel+2] = (char) 0;
-                        }
-                }
-
-}
-
-
-void on_key_press (Bool down,KeySym key,rfbClientPtr cl)
-{
-        if (down)		//or else the action occurs on both the press and depress
-	switch (key) {
-
-        case XK_b:
-        case XK_B:
-                rfbUndrawCursor(cl->screen);
-                blank_framebuffer(cl->screen->frameBuffer, 0, 0, maxx, maxy);
-                rfbDrawString(cl->screen,&radonFont,20,maxy-20,"Hello, World!",0xffffff);
-                rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
-                fprintf (stderr, "Framebuffer blanked\n");
-                break;
-        case XK_p:
-        case XK_P:
-                rfbUndrawCursor(cl->screen);
-                /* draw_primary_colors (cl->screen->frameBuffer, 0, 0, maxx, maxy); */
-		draw_primary_colours_generic_ultrafast (cl->screen, 0, 0, maxx, maxy);
-                rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
-                fprintf (stderr, "Primary colors displayed\n");
-                break;
-        case XK_Q:
-        case XK_q:
-                fprintf (stderr, "Exiting now\n");
-                exit(0);
-        case XK_C:
-        case XK_c:
-                rfbUndrawCursor(cl->screen);
-		rfbDrawString(cl->screen,&radonFont,20,100,"Hello, World!",0xffffff);
-                rfbMarkRectAsModified(cl->screen,0, 0,maxx,maxy);
-                break;
-        default:
-                fprintf (stderr, "The %c key was pressed\n", (char) key);
-        }
-}
-
-
-void on_mouse_event (int buttonMask,int x,int y,rfbClientPtr cl)
-{
-	printf("buttonMask: %i\n"
-		"x: %i\n" "y: %i\n", buttonMask, x, y);
-}
-- 
cgit v1.2.3

