Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@590 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/unix/vncconfig/Makefile.in b/unix/vncconfig/Makefile.in
new file mode 100644
index 0000000..4891fcd
--- /dev/null
+++ b/unix/vncconfig/Makefile.in
@@ -0,0 +1,23 @@
+
+SRCS = vncExt.c vncconfig.cxx QueryConnectDialog.cxx
+
+OBJS = vncExt.o vncconfig.o QueryConnectDialog.o
+
+program = vncconfig
+
+DEP_LIBS = ../tx/libtx.a ../rfb/librfb.a ../network/libnetwork.a \
+           ../rdr/librdr.a
+
+EXTRA_LIBS = @X_PRE_LIBS@ @X_LIBS@ -lX11 -lXext @X_EXTRA_LIBS@
+
+DIR_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tx @X_CFLAGS@ # X_CFLAGS are really CPPFLAGS
+
+all:: $(program)
+
+$(program): $(OBJS) buildtime.o $(DEP_LIBS)
+	rm -f $(program)
+	$(CXXLD) $(CXXFLAGS) $(LDFLAGS) -o $@ $(OBJS) buildtime.o $(DEP_LIBS) $(LIBS) $(EXTRA_LIBS)
+
+buildtime.o: $(OBJS) $(DEP_LIBS)
+
+# followed by boilerplate.mk
diff --git a/unix/vncconfig/QueryConnectDialog.cxx b/unix/vncconfig/QueryConnectDialog.cxx
new file mode 100644
index 0000000..c154051
--- /dev/null
+++ b/unix/vncconfig/QueryConnectDialog.cxx
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+
+#include <stdio.h>
+#include <rdr/Exception.h>
+#include "QueryConnectDialog.h"
+#include "vncExt.h"
+
+QueryConnectDialog::QueryConnectDialog(Display* dpy,
+                                       const char* address_,
+                                       const char* user_,
+                                       int timeout_,
+                                       QueryResultCallback* cb)
+  : TXDialog(dpy, 300, 100, "VNC Server : Accept Connection?"),
+    addressLbl(dpy, "Host:",this),
+    address(dpy, address_, this),
+    userLbl(dpy, "User:", this),
+    user(dpy, user_, this),
+    timeoutLbl(dpy, "Seconds until automatic reject:", this),
+    timeout(dpy, "0000000000", this),
+    accept(dpy, "Accept", this, this, 60),
+    reject(dpy, "Reject", this, this, 60),
+    callback(cb), timeUntilReject(timeout_), timer(this)
+{
+  const int pad = 4;
+  int y=pad;
+  int lblWidth = __rfbmax(addressLbl.width(), userLbl.width());
+  userLbl.move(pad+lblWidth-userLbl.width(), y);
+  user.move(pad+lblWidth, y);
+  addressLbl.move(pad+lblWidth-addressLbl.width(), y+=userLbl.height());
+  address.move(pad+lblWidth, y);
+  timeoutLbl.move(pad, y+=addressLbl.height());
+  timeout.move(pad+timeoutLbl.width(), y);
+  accept.move(pad, y+=addressLbl.height());
+  int maxWidth = __rfbmax(user.width(), address.width()+pad+lblWidth);
+  maxWidth = __rfbmax(maxWidth, accept.width()*3);
+  maxWidth = __rfbmax(maxWidth, timeoutLbl.width()+timeout.width()+pad);
+  reject.move(maxWidth-reject.width(), y);
+  resize(maxWidth + pad, y+reject.height()+pad);
+  setBorderWidth(1);
+  refreshTimeout();
+  timer.start(1000);
+}
+
+void QueryConnectDialog::deleteWindow(TXWindow*) {
+  unmap();
+  callback->queryRejected();
+}
+
+void QueryConnectDialog::buttonActivate(TXButton* b) {
+  unmap();
+  if (b == &accept)
+    callback->queryApproved();
+  else if (b == &reject)
+    callback->queryRejected();
+}
+  
+bool QueryConnectDialog::handleTimeout(rfb::Timer* t) {
+  if (timeUntilReject-- == 0) {
+    unmap();
+    callback->queryTimedOut();
+    return false;
+  } else {
+    refreshTimeout();
+    return true;
+  }
+}
+
+void QueryConnectDialog::refreshTimeout() {
+  char buf[16];
+  sprintf(buf, "%d", timeUntilReject);
+  timeout.setText(buf);
+}
diff --git a/unix/vncconfig/QueryConnectDialog.h b/unix/vncconfig/QueryConnectDialog.h
new file mode 100644
index 0000000..f685dc3
--- /dev/null
+++ b/unix/vncconfig/QueryConnectDialog.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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 __QUERYCONNECTDIALOG_H__
+#define __QUERYCONNECTDIALOG_H__
+
+#include <rfb/Timer.h>
+#include "TXLabel.h"
+#include "TXButton.h"
+#include "TXDialog.h"
+
+class QueryResultCallback {
+ public:
+  virtual ~QueryResultCallback() {}
+  virtual void queryApproved() = 0;
+  virtual void queryRejected() = 0;
+  virtual void queryTimedOut() { queryRejected(); };
+};
+
+class QueryConnectDialog : public TXDialog, public TXEventHandler,
+                           public TXButtonCallback,
+                           public rfb::Timer::Callback
+{
+ public:
+  QueryConnectDialog(Display* dpy, const char* address_,
+                     const char* user_, int timeout_,
+                     QueryResultCallback* cb);
+  void handleEvent(TXWindow*, XEvent* ) { }
+  void deleteWindow(TXWindow*);
+  void buttonActivate(TXButton* b);
+  bool handleTimeout(rfb::Timer* t);
+ private:
+  void refreshTimeout();
+  TXLabel addressLbl, address, userLbl, user, timeoutLbl, timeout;
+  TXButton accept, reject;
+  QueryResultCallback* callback;
+  int timeUntilReject;
+  rfb::Timer timer;
+};
+
+#endif
diff --git a/unix/vncconfig/buildtime.c b/unix/vncconfig/buildtime.c
new file mode 100644
index 0000000..3f4c369
--- /dev/null
+++ b/unix/vncconfig/buildtime.c
@@ -0,0 +1,18 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+char buildtime[] = __DATE__ " " __TIME__;
diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c
new file mode 100644
index 0000000..ff5532b
--- /dev/null
+++ b/unix/vncconfig/vncExt.c
@@ -0,0 +1,384 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+
+#define NEED_REPLIES
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#define _VNCEXT_PROTO_
+#include "vncExt.h"
+
+static Bool XVncExtClientCutTextNotifyWireToEvent(Display* dpy, XEvent* e,
+                                                  xEvent* w);
+static Bool XVncExtSelectionChangeNotifyWireToEvent(Display* dpy, XEvent* e,
+                                                    xEvent* w);
+static Bool XVncExtQueryConnectNotifyWireToEvent(Display* dpy, XEvent* e,
+                                                 xEvent* w);
+
+static Bool extensionInited = False;
+static XExtCodes* codes = 0;
+
+static Bool checkExtension(Display* dpy)
+{
+  if (!extensionInited) {
+    extensionInited = True;
+    codes = XInitExtension(dpy, VNCEXTNAME);
+    if (!codes) return False;
+    XESetWireToEvent(dpy, codes->first_event + VncExtClientCutTextNotify,
+                     XVncExtClientCutTextNotifyWireToEvent);
+    XESetWireToEvent(dpy, codes->first_event + VncExtSelectionChangeNotify,
+                     XVncExtSelectionChangeNotifyWireToEvent);
+    XESetWireToEvent(dpy, codes->first_event + VncExtQueryConnectNotify,
+                     XVncExtQueryConnectNotifyWireToEvent);
+  }
+  return codes != 0;
+}
+
+Bool XVncExtQueryExtension(Display* dpy, int* event_basep, int* error_basep)
+{
+  if (!checkExtension(dpy)) return False;
+  *event_basep = codes->first_event;
+  *error_basep = codes->first_error;
+  return True;
+}
+
+Bool XVncExtSetParam(Display* dpy, const char* param)
+{
+  xVncExtSetParamReq* req;
+  xVncExtSetParamReply rep;
+
+  int paramLen = strlen(param);
+  if (paramLen > 255) return False;
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtSetParam, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtSetParam;
+  req->length += (paramLen + 3) >> 2;
+  req->paramLen = paramLen;
+  Data(dpy, param, paramLen);
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return rep.success;
+}
+
+Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len)
+{
+  xVncExtGetParamReq* req;
+  xVncExtGetParamReply rep;
+
+  int paramLen = strlen(param);
+  *value = 0;
+  *len = 0;
+  if (paramLen > 255) return False;
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtGetParam, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtGetParam;
+  req->length += (paramLen + 3) >> 2;
+  req->paramLen = paramLen;
+  Data(dpy, param, paramLen);
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  if (rep.success) {
+    *len = rep.valueLen;
+    *value = (char*) Xmalloc (*len+1);
+    _XReadPad(dpy, *value, *len);
+    (*value)[*len] = 0;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return rep.success;
+}
+
+char* XVncExtGetParamDesc(Display* dpy, const char* param)
+{
+  xVncExtGetParamDescReq* req;
+  xVncExtGetParamDescReply rep;
+  char* desc = 0;
+
+  int paramLen = strlen(param);
+  if (paramLen > 255) return False;
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtGetParamDesc, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtGetParamDesc;
+  req->length += (paramLen + 3) >> 2;
+  req->paramLen = paramLen;
+  Data(dpy, param, paramLen);
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  if (rep.success) {
+    desc = (char*)Xmalloc(rep.descLen+1);
+    _XReadPad(dpy, desc, rep.descLen);
+    desc[rep.descLen] = 0;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return desc;
+}
+
+char** XVncExtListParams(Display* dpy, int* nParams)
+{
+  xVncExtListParamsReq* req;
+  xVncExtListParamsReply rep;
+  char** list = 0;
+  char* ch;
+  int rlen, paramLen, i;
+
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtListParams, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtListParams;
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+  if (rep.nParams) {
+    list = (char**)Xmalloc(rep.nParams * sizeof(char*));
+    rlen = rep.length << 2;
+    ch = (char*)Xmalloc(rlen + 1);
+    if (!list || !ch) {
+      if (list) Xfree((char*)list);
+      if (ch) Xfree(ch);
+      _XEatData(dpy, rlen);
+      UnlockDisplay(dpy);
+      SyncHandle();
+      return 0;
+    }
+    _XReadPad(dpy, ch, rlen);
+    paramLen = *ch++;
+    for (i = 0; i < rep.nParams; i++) {
+      list[i] = ch;
+      ch += paramLen;
+      paramLen = *ch;
+      *ch++ = 0;
+    }
+  }
+  *nParams = rep.nParams;
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return list;
+}
+
+void XVncExtFreeParamList(char** list)
+{
+  if (list) {
+    Xfree(list[0]-1);
+    Xfree((char*)list);
+  }
+}
+
+Bool XVncExtSetServerCutText(Display* dpy, const char* str, int len)
+{
+  xVncExtSetServerCutTextReq* req;
+
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtSetServerCutText, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtSetServerCutText;
+  req->length += (len + 3) >> 2;
+  req->textLen = len;
+  Data(dpy, str, len);
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return True;
+}
+
+Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len)
+{
+  xVncExtGetClientCutTextReq* req;
+  xVncExtGetClientCutTextReply rep;
+
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtGetClientCutText, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtGetClientCutText;
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+  *len = rep.textLen;
+  *str = (char*) Xmalloc (*len+1);
+  _XReadPad(dpy, *str, *len);
+  (*str)[*len] = 0;
+  return True;
+}
+
+Bool XVncExtSelectInput(Display* dpy, Window w, int mask)
+{
+  xVncExtSelectInputReq* req;
+
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtSelectInput, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtSelectInput;
+  req->window = w;
+  req->mask = mask;
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return True;
+}
+
+Bool XVncExtConnect(Display* dpy, char* hostAndPort)
+{
+  xVncExtConnectReq* req;
+  xVncExtConnectReply rep;
+
+  int strLen = strlen(hostAndPort);
+  if (strLen > 255) return False;
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtConnect, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtConnect;
+  req->length += (strLen + 3) >> 2;
+  req->strLen = strLen;
+  Data(dpy, hostAndPort, strLen);
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return rep.success;
+}
+
+Bool XVncExtGetQueryConnect(Display* dpy, char** addr, char** user,
+                            int* timeout, void** opaqueId)
+{
+  xVncExtGetQueryConnectReq* req;
+  xVncExtGetQueryConnectReply rep;
+
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtGetQueryConnect, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtGetQueryConnect;
+  if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+    UnlockDisplay(dpy);
+    SyncHandle();
+    return False;
+  }
+  UnlockDisplay(dpy);
+  SyncHandle();
+
+  *addr = Xmalloc(rep.addrLen+1);
+  _XReadPad(dpy, *addr, rep.addrLen);
+  (*addr)[rep.addrLen] = 0;
+  *user = Xmalloc(rep.userLen+1);
+  _XReadPad(dpy, *user, rep.userLen);
+  (*user)[rep.userLen] = 0;
+  *timeout = rep.timeout;
+  *opaqueId = (void*)rep.opaqueId;
+  return True;
+}
+
+Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve)
+{
+  xVncExtApproveConnectReq* req;
+
+  if (!checkExtension(dpy)) return False;
+
+  LockDisplay(dpy);
+  GetReq(VncExtApproveConnect, req);
+  req->reqType = codes->major_opcode;
+  req->vncExtReqType = X_VncExtApproveConnect;
+  req->approve = approve;
+  req->opaqueId = (CARD32)opaqueId;
+  UnlockDisplay(dpy);
+  SyncHandle();
+  return True;
+}
+
+
+static Bool XVncExtClientCutTextNotifyWireToEvent(Display* dpy, XEvent* e,
+                                                  xEvent* w)
+{
+  XVncExtClientCutTextEvent* ev = (XVncExtClientCutTextEvent*)e;
+  xVncExtClientCutTextNotifyEvent* wire = (xVncExtClientCutTextNotifyEvent*)w;
+  ev->type = wire->type & 0x7f;
+  ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire);
+  ev->send_event = (wire->type & 0x80) != 0;
+  ev->display = dpy;
+  ev->window = wire->window;
+  ev->time = wire->time;
+  return True;
+}
+
+static Bool XVncExtSelectionChangeNotifyWireToEvent(Display* dpy, XEvent* e,
+                                                    xEvent* w)
+{
+  XVncExtSelectionChangeEvent* ev = (XVncExtSelectionChangeEvent*)e;
+  xVncExtSelectionChangeNotifyEvent* wire
+    = (xVncExtSelectionChangeNotifyEvent*)w;
+  ev->type = wire->type & 0x7f;
+  ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire);
+  ev->send_event = (wire->type & 0x80) != 0;
+  ev->display = dpy;
+  ev->window = wire->window;
+  ev->selection = wire->selection;
+  return True;
+}
+
+static Bool XVncExtQueryConnectNotifyWireToEvent(Display* dpy, XEvent* e,
+                                                    xEvent* w)
+{
+  XVncExtQueryConnectEvent* ev = (XVncExtQueryConnectEvent*)e;
+  xVncExtQueryConnectNotifyEvent* wire
+    = (xVncExtQueryConnectNotifyEvent*)w;
+  ev->type = wire->type & 0x7f;
+  ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire);
+  ev->send_event = (wire->type & 0x80) != 0;
+  ev->display = dpy;
+  ev->window = wire->window;
+  return True;
+}
diff --git a/unix/vncconfig/vncExt.h b/unix/vncconfig/vncExt.h
new file mode 100644
index 0000000..f1502c4
--- /dev/null
+++ b/unix/vncconfig/vncExt.h
@@ -0,0 +1,343 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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 _VNCEXT_H_
+#define _VNCEXT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define X_VncExtSetParam 0
+#define X_VncExtGetParam 1
+#define X_VncExtGetParamDesc 2
+#define X_VncExtListParams 3
+#define X_VncExtSetServerCutText 4
+#define X_VncExtGetClientCutText 5
+#define X_VncExtSelectInput 6
+#define X_VncExtConnect 7
+#define X_VncExtGetQueryConnect 8
+#define X_VncExtApproveConnect 9
+
+#define VncExtClientCutTextNotify 0
+#define VncExtSelectionChangeNotify 1
+#define VncExtQueryConnectNotify 2
+#define VncExtClientCutTextMask (1 << VncExtClientCutTextNotify)
+#define VncExtSelectionChangeMask (1 << VncExtSelectionChangeNotify)
+#define VncExtQueryConnectMask (1 << VncExtQueryConnectNotify)
+
+#define VncExtNumberEvents 3
+#define VncExtNumberErrors 0
+
+#ifndef _VNCEXT_SERVER_
+
+Bool XVncExtQueryExtension(Display* dpy, int* event_basep, int* error_basep);
+Bool XVncExtSetParam(Display* dpy, const char* param);
+Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len);
+char* XVncExtGetParamDesc(Display* dpy, const char* param);
+char** XVncExtListParams(Display* dpy, int* nParams);
+void XVncExtFreeParamList(char** list);
+Bool XVncExtSetServerCutText(Display* dpy, const char* str, int len);
+Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len);
+Bool XVncExtSelectInput(Display* dpy, Window w, int mask);
+Bool XVncExtConnect(Display* dpy, char* hostAndPort);
+Bool XVncExtGetQueryConnect(Display* dpy, char** addr,
+                            char** user, int* timeout, void** opaqueId);
+Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve);
+
+
+typedef struct {
+  int type;
+  unsigned long serial;
+  Bool send_event;
+  Display *display;
+  Window window;
+  Time time;
+} XVncExtClientCutTextEvent;
+
+typedef struct {
+  int type;
+  unsigned long serial;
+  Bool send_event;
+  Display *display;
+  Window window;
+  Atom selection;
+} XVncExtSelectionChangeEvent;
+
+typedef struct {
+  int type;
+  unsigned long serial;
+  Bool send_event;
+  Display *display;
+  Window window;
+} XVncExtQueryConnectEvent;
+
+#endif
+
+#ifdef _VNCEXT_PROTO_
+
+#define VNCEXTNAME "VNC-EXTENSION"
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtSetParam */
+  CARD16 length B16;
+  CARD8 paramLen;
+  CARD8 pad0;
+  CARD16 pad1 B16;
+} xVncExtSetParamReq;
+#define sz_xVncExtSetParamReq 8
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE success;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 pad0 B32;
+ CARD32 pad1 B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVncExtSetParamReply;
+#define sz_xVncExtSetParamReply 32
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtGetParam */
+  CARD16 length B16;
+  CARD8 paramLen;
+  CARD8 pad0;
+  CARD16 pad1 B16;
+} xVncExtGetParamReq;
+#define sz_xVncExtGetParamReq 8
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE success;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD16 valueLen B16;
+ CARD16 pad0 B16;
+ CARD32 pad1 B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVncExtGetParamReply;
+#define sz_xVncExtGetParamReply 32
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtGetParamDesc */
+  CARD16 length B16;
+  CARD8 paramLen;
+  CARD8 pad0;
+  CARD16 pad1 B16;
+} xVncExtGetParamDescReq;
+#define sz_xVncExtGetParamDescReq 8
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE success;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD16 descLen B16;
+ CARD16 pad0 B16;
+ CARD32 pad1 B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVncExtGetParamDescReply;
+#define sz_xVncExtGetParamDescReply 32
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtListParams */
+  CARD16 length B16;
+} xVncExtListParamsReq;
+#define sz_xVncExtListParamsReq 4
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE pad0;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD16 nParams B16;
+ CARD16 pad1 B16;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+ CARD32 pad6 B32;
+} xVncExtListParamsReply;
+#define sz_xVncExtListParamsReply 32
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtSetServerCutText */
+  CARD16 length B16;
+  CARD32 textLen B32;
+} xVncExtSetServerCutTextReq;
+#define sz_xVncExtSetServerCutTextReq 8
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtGetClientCutText */
+  CARD16 length B16;
+} xVncExtGetClientCutTextReq;
+#define sz_xVncExtGetClientCutTextReq 4
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE pad0;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 textLen B32;
+ CARD32 pad1 B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVncExtGetClientCutTextReply;
+#define sz_xVncExtGetClientCutTextReply 32
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtSelectInput */
+  CARD16 length B16;
+  CARD32 window B32;
+  CARD32 mask B32;
+} xVncExtSelectInputReq;
+#define sz_xVncExtSelectInputReq 12
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtConnect */
+  CARD16 length B16;
+  CARD8 strLen;
+  CARD8 pad0;
+  CARD16 pad1 B16;
+} xVncExtConnectReq;
+#define sz_xVncExtConnectReq 8
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE success;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 pad0 B32;
+ CARD32 pad1 B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVncExtConnectReply;
+#define sz_xVncExtConnectReply 32
+
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtGetQueryConnect */
+  CARD16 length B16;
+} xVncExtGetQueryConnectReq;
+#define sz_xVncExtGetQueryConnectReq 4
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE pad0;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 addrLen B32;
+ CARD32 userLen B32;
+ CARD32 timeout B32;
+ CARD32 opaqueId B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVncExtGetQueryConnectReply;
+#define sz_xVncExtGetQueryConnectReply 32
+
+typedef struct {
+  CARD8 reqType;       /* always VncExtReqCode */
+  CARD8 vncExtReqType; /* always VncExtApproveConnect */
+  CARD16 length B16;
+  CARD8 approve;
+  CARD8 pad0;
+  CARD16 pad1;
+  CARD32 opaqueId B32;
+} xVncExtApproveConnectReq;
+#define sz_xVncExtApproveConnectReq 12
+
+
+
+typedef struct {
+  BYTE type;    /* always eventBase + VncExtClientCutTextNotify */
+  BYTE pad0;
+  CARD16 sequenceNumber B16;
+  CARD32 window B32;
+  CARD32 time B32;
+  CARD32 pad1 B32;
+  CARD32 pad2 B32;
+  CARD32 pad3 B32;
+  CARD32 pad4 B32;
+  CARD32 pad5 B32;
+} xVncExtClientCutTextNotifyEvent;
+#define sz_xVncExtClientCutTextNotifyEvent 32
+
+typedef struct {
+  BYTE type;    /* always eventBase + VncExtSelectionChangeNotify */
+  BYTE pad0;
+  CARD16 sequenceNumber B16;
+  CARD32 window B32;
+  CARD32 selection B32;
+  CARD32 pad1 B32;
+  CARD32 pad2 B32;
+  CARD32 pad3 B32;
+  CARD32 pad4 B32;
+  CARD32 pad5 B32;
+} xVncExtSelectionChangeNotifyEvent;
+#define sz_xVncExtSelectionChangeNotifyEvent 32
+
+typedef struct {
+  BYTE type;    /* always eventBase + VncExtQueryConnectNotify */
+  BYTE pad0;
+  CARD16 sequenceNumber B16;
+  CARD32 window B32;
+  CARD32 pad6 B32;
+  CARD32 pad1 B32;
+  CARD32 pad2 B32;
+  CARD32 pad3 B32;
+  CARD32 pad4 B32;
+  CARD32 pad5 B32;
+} xVncExtQueryConnectNotifyEvent;
+#define sz_xVncExtQueryConnectNotifyEvent 32
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
new file mode 100644
index 0000000..c901d19
--- /dev/null
+++ b/unix/vncconfig/vncconfig.cxx
@@ -0,0 +1,438 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
+//
+// VNC server configuration utility
+//
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <signal.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include "vncExt.h"
+#include <rdr/Exception.h>
+#include <rfb/Configuration.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Timer.h>
+#include "TXWindow.h"
+#include "TXCheckbox.h"
+#include "TXLabel.h"
+#include "QueryConnectDialog.h"
+
+using namespace rfb;
+
+LogWriter vlog("vncconfig");
+
+StringParameter displayname("display", "The X display", "");
+BoolParameter noWindow("nowin", "Don't display a window", 0);
+BoolParameter iconic("iconic", "Start with window iconified", 0);
+BoolParameter sendPrimary("SendPrimary", "Send the PRIMARY as well as the "
+                          "CLIPBOARD selection", true);
+IntParameter pollTime("poll",
+                      "How often to poll for clipboard changes in ms", 0);
+
+inline const char* selectionName(Atom sel) {
+  if (sel == xaCLIPBOARD) return "CLIPBOARD";
+  if (sel == XA_PRIMARY) return "PRIMARY";
+  return "unknown";
+}
+
+#define ACCEPT_CUT_TEXT "AcceptCutText"
+#define SEND_CUT_TEXT "SendCutText"
+
+char* programName = 0;
+Display* dpy;
+int vncExtEventBase, vncExtErrorBase;
+
+static bool getBoolParam(Display* dpy, const char* param) {
+  char* data;
+  int len;
+  if (XVncExtGetParam(dpy, param, &data, &len)) {
+    if (strcmp(data,"1") == 0) return true;
+  }
+  return false;
+}
+
+class VncConfigWindow : public TXWindow, public TXEventHandler,
+                        public TXDeleteWindowCallback,
+                        public TXCheckboxCallback,
+                        public rfb::Timer::Callback,
+                        public QueryResultCallback {
+public:
+  VncConfigWindow(Display* dpy)
+    : TXWindow(dpy, 300, 100), cutText(0), cutTextLen(0),
+      acceptClipboard(dpy, "Accept clipboard from viewers", this, false, this),
+      sendClipboard(dpy, "Send clipboard to viewers", this, false, this),
+      sendPrimaryCB(dpy, "Send primary selection to viewers", this,false,this),
+      pollTimer(this),
+      queryConnectDialog(0)
+  {
+    selection[0] = selection[1] = 0;
+    selectionLen[0] = selectionLen[1] = 0;
+    int y = yPad;
+    acceptClipboard.move(xPad, y);
+    acceptClipboard.checked(getBoolParam(dpy, ACCEPT_CUT_TEXT));
+    y += acceptClipboard.height();
+    sendClipboard.move(xPad, y);
+    sendClipboard.checked(getBoolParam(dpy, SEND_CUT_TEXT));
+    y += sendClipboard.height();
+    sendPrimaryCB.move(xPad, y);
+    sendPrimaryCB.checked(sendPrimary);
+    sendPrimaryCB.disabled(!sendClipboard.checked());
+    y += sendPrimaryCB.height();
+    setEventHandler(this);
+    toplevel("VNC config", this, 0, 0, 0, iconic);
+    XVncExtSelectInput(dpy, win(),
+                       VncExtClientCutTextMask|
+                       VncExtSelectionChangeMask|
+                       VncExtQueryConnectMask);
+    XConvertSelection(dpy, XA_PRIMARY, XA_STRING,
+                      XA_PRIMARY, win(), CurrentTime);
+    XConvertSelection(dpy, xaCLIPBOARD, XA_STRING,
+                      xaCLIPBOARD, win(), CurrentTime);
+    if (pollTime != 0)
+      pollTimer.start(pollTime);
+  }
+
+  // handleEvent(). If we get a ClientCutTextNotify event from Xvnc, set the
+  // primary and clipboard selections to the clientCutText. If we get a
+  // SelectionChangeNotify event from Xvnc, set the serverCutText to the value
+  // of the new selection.
+
+  virtual void handleEvent(TXWindow* w, XEvent* ev) {
+    if (acceptClipboard.checked()) {
+      if (ev->type == vncExtEventBase + VncExtClientCutTextNotify) {
+        XVncExtClientCutTextEvent* cutEv = (XVncExtClientCutTextEvent*)ev;
+        if (cutText)
+          XFree(cutText);
+        cutText = 0;
+        if (XVncExtGetClientCutText(dpy, &cutText, &cutTextLen)) {
+          vlog.debug("Got client cut text: '%.*s%s'",
+                     cutTextLen<9?cutTextLen:8, cutText,
+                     cutTextLen<9?"":"...");
+          XStoreBytes(dpy, cutText, cutTextLen);
+          ownSelection(XA_PRIMARY, cutEv->time);
+          ownSelection(xaCLIPBOARD, cutEv->time);
+          delete [] selection[0];
+          delete [] selection[1];
+          selection[0] = selection[1] = 0;
+          selectionLen[0] = selectionLen[1] = 0;
+        }
+      }
+    }
+    if (sendClipboard.checked()) {
+      if (ev->type == vncExtEventBase + VncExtSelectionChangeNotify) {
+        vlog.debug("selection change event");
+        XVncExtSelectionChangeEvent* selEv = (XVncExtSelectionChangeEvent*)ev;
+        if (selEv->selection == xaCLIPBOARD ||
+            (selEv->selection == XA_PRIMARY && sendPrimaryCB.checked())) {
+          if (!selectionOwner(selEv->selection))
+            XConvertSelection(dpy, selEv->selection, XA_STRING,
+                              selEv->selection, win(), CurrentTime);
+        }
+      }
+    }
+    if (ev->type == vncExtEventBase + VncExtQueryConnectNotify) {
+       vlog.debug("query connection event");
+       if (queryConnectDialog)
+         delete queryConnectDialog;
+       queryConnectDialog = 0;
+       char* qcAddress;
+       char* qcUser;
+       int qcTimeout;
+       if (XVncExtGetQueryConnect(dpy, &qcAddress, &qcUser,
+                                  &qcTimeout, &queryConnectId)) {
+         if (qcTimeout)
+           queryConnectDialog = new QueryConnectDialog(dpy, qcAddress,
+                                                       qcUser, qcTimeout,
+                                                       this);
+         if (queryConnectDialog)
+           queryConnectDialog->map();
+         XFree(qcAddress);
+         XFree(qcUser);
+       }
+    }
+  }
+  
+
+  // selectionRequest() is called when we are the selection owner and another X
+  // client has requested the selection.  We simply put the server's cut text
+  // into the requested property.  TXWindow will handle the rest.
+  bool selectionRequest(Window requestor, Atom selection, Atom property)
+  {
+    if (cutText)
+      XChangeProperty(dpy, requestor, property, XA_STRING, 8,
+                      PropModeReplace, (unsigned char*)cutText,
+                      cutTextLen);
+    return cutText;
+  }
+
+  // selectionNotify() is called when we have requested the selection from the
+  // selection owner.
+  void selectionNotify(XSelectionEvent* ev, Atom type, int format,
+                       int nitems, void* data)
+  {
+    if (ev->requestor != win() || ev->target != XA_STRING)
+      return;
+
+    if (data && format == 8) {
+      int i = (ev->selection == XA_PRIMARY ? 0 : 1);
+      if (selectionLen[i] == nitems && memcmp(selection[i], data, nitems) == 0)
+        return;
+      delete [] selection[i];
+      selection[i] = new char[nitems];
+      memcpy(selection[i], data, nitems);
+      selectionLen[i] = nitems;
+      if (cutTextLen == nitems && memcmp(cutText, data, nitems) == 0) {
+        vlog.debug("ignoring duplicate cut text");
+        return;
+      }
+      if (cutText)
+        XFree(cutText);
+      cutText = (char*)malloc(nitems); // assuming XFree() same as free()
+      memcpy(cutText, data, nitems);
+      cutTextLen = nitems;
+      vlog.debug("sending %s selection as server cut text: '%.*s%s'",
+                 selectionName(ev->selection),cutTextLen<9?cutTextLen:8,
+                 cutText, cutTextLen<9?"":"...");
+      XVncExtSetServerCutText(dpy, cutText, cutTextLen);
+    }
+  }
+
+  // TXDeleteWindowCallback method
+  virtual void deleteWindow(TXWindow* w) {
+    exit(1);
+  }
+
+  // TXCheckboxCallback method
+  virtual void checkboxSelect(TXCheckbox* checkbox) {
+    if (checkbox == &acceptClipboard) {
+      XVncExtSetParam(dpy, (acceptClipboard.checked()
+                            ? ACCEPT_CUT_TEXT "=1" : ACCEPT_CUT_TEXT "=0"));
+    } else if (checkbox == &sendClipboard) {
+      XVncExtSetParam(dpy, (sendClipboard.checked()
+                            ? SEND_CUT_TEXT "=1" : SEND_CUT_TEXT "=0"));
+      sendPrimaryCB.disabled(!sendClipboard.checked());
+    }
+  }
+
+  // rfb::Timer::Callback interface
+  virtual bool handleTimeout(rfb::Timer* timer) {
+    if (sendPrimaryCB.checked() && !selectionOwner(XA_PRIMARY))
+      XConvertSelection(dpy, XA_PRIMARY, XA_STRING,
+                        XA_PRIMARY, win(), CurrentTime);
+    if (!selectionOwner(xaCLIPBOARD))
+      XConvertSelection(dpy, xaCLIPBOARD, XA_STRING,
+                        xaCLIPBOARD, win(), CurrentTime);
+    return true;
+  }
+
+  // QueryResultCallback interface
+  virtual void queryApproved() {
+    XVncExtApproveConnect(dpy, queryConnectId, 1);
+  }
+  virtual void queryRejected() {
+    XVncExtApproveConnect(dpy, queryConnectId, 0);
+  }
+
+private:
+  char* cutText;
+  int cutTextLen;
+  char* selection[2];
+  int selectionLen[2];
+  TXCheckbox acceptClipboard, sendClipboard, sendPrimaryCB;
+  rfb::Timer pollTimer;
+
+  QueryConnectDialog* queryConnectDialog;
+  void* queryConnectId;
+};
+
+static void usage()
+{
+  fprintf(stderr,"usage: %s [parameters]\n",
+          programName);
+  fprintf(stderr,"       %s [parameters] -connect <host>[:<port>]\n",
+          programName);
+  fprintf(stderr,"       %s [parameters] -disconnect\n", programName);
+  fprintf(stderr,"       %s [parameters] [-set] <Xvnc-param>=<value> ...\n",
+          programName);
+  fprintf(stderr,"       %s [parameters] -list\n", programName);
+  fprintf(stderr,"       %s [parameters] -get <param>\n", programName);
+  fprintf(stderr,"       %s [parameters] -desc <param>\n",programName);
+  fprintf(stderr,"\n"
+          "Parameters can be turned on with -<param> or off with -<param>=0\n"
+          "Parameters which take a value can be specified as "
+          "-<param> <value>\n"
+          "Other valid forms are <param>=<value> -<param>=<value> "
+          "--<param>=<value>\n"
+          "Parameter names are case-insensitive.  The parameters are:\n\n");
+  Configuration::listParams(79, 14);
+  exit(1);
+}
+
+void removeArgs(int* argc, char** argv, int first, int n)
+{
+  if (first + n > *argc) return;
+  for (int i = first + n; i < *argc; i++)
+    argv[i-n] = argv[i];
+  *argc -= n;
+}
+
+int main(int argc, char** argv)
+{
+  programName = argv[0];
+  rfb::initStdIOLoggers();
+  rfb::LogWriter::setLogParams("*:stderr:30");
+
+  // Process vncconfig's own parameters first, then we process the
+  // other arguments when we have the X display.
+  int i;
+  for (i = 1; i < argc; i++) {
+    if (Configuration::setParam(argv[i]))
+      continue;
+
+    if (argv[i][0] == '-' && i+1 < argc &&
+        Configuration::setParam(&argv[i][1], argv[i+1])) {
+      i++;
+      continue;
+    }
+    break;
+  }
+
+  CharArray displaynameStr(displayname.getData());
+  if (!(dpy = XOpenDisplay(displaynameStr.buf))) {
+    fprintf(stderr,"%s: unable to open display \"%s\"\n",
+            programName, XDisplayName(displaynameStr.buf));
+    exit(1);
+  }
+
+  if (!XVncExtQueryExtension(dpy, &vncExtEventBase, &vncExtErrorBase)) {
+    fprintf(stderr,"No VNC extension on display %s\n",
+            XDisplayName(displaynameStr.buf));
+    exit(1);
+  }
+
+  if (i < argc) {
+    for (; i < argc; i++) {
+      if (strcmp(argv[i], "-connect") == 0) {
+        i++;
+        if (i >= argc) usage();
+        if (!XVncExtConnect(dpy, argv[i])) {
+          fprintf(stderr,"connecting to %s failed\n",argv[i]);
+        }
+      } else if (strcmp(argv[i], "-disconnect") == 0) {
+        if (!XVncExtConnect(dpy, "")) {
+          fprintf(stderr,"disconnecting all clients failed\n");
+        }
+      } else if (strcmp(argv[i], "-get") == 0) {
+        i++;
+        if (i >= argc) usage();
+        char* data;
+        int len;
+        if (XVncExtGetParam(dpy, argv[i], &data, &len)) {
+          printf("%.*s\n",len,data);
+        } else {
+          fprintf(stderr,"getting param %s failed\n",argv[i]);
+        }
+        XFree(data);
+      } else if (strcmp(argv[i], "-desc") == 0) {
+        i++;
+        if (i >= argc) usage();
+        char* desc = XVncExtGetParamDesc(dpy, argv[i]);
+        if (desc) {
+          printf("%s\n",desc);
+        } else {
+          fprintf(stderr,"getting description for param %s failed\n",argv[i]);
+        }
+        XFree(desc);
+      } else if (strcmp(argv[i], "-list") == 0) {
+        int nParams;
+        char** list = XVncExtListParams(dpy, &nParams);
+        for (int i = 0; i < nParams; i++) {
+          printf("%s\n",list[i]);
+        }
+        XVncExtFreeParamList(list);
+      } else if (strcmp(argv[i], "-set") == 0) {
+        i++;
+        if (i >= argc) usage();
+        if (!XVncExtSetParam(dpy, argv[i])) {
+          fprintf(stderr,"setting param %s failed\n",argv[i]);
+        }
+      } else if (XVncExtSetParam(dpy, argv[i])) {
+        fprintf(stderr,"set parameter %s\n",argv[i]);
+      } else {
+        usage();
+      }
+    }
+
+    return 0;
+  }
+
+  try {
+    TXWindow::init(dpy,"Vncconfig");
+
+    VncConfigWindow w(dpy);
+    if (!noWindow) w.map();
+
+    while (true) {
+      struct timeval tv;
+      struct timeval* tvp = 0;
+
+      // Process any incoming X events
+      TXWindow::handleXEvents(dpy);
+      
+      // Process expired timers and get the time until the next one
+      int timeoutMs = Timer::checkTimeouts();
+      if (timeoutMs) {
+        tv.tv_sec = timeoutMs / 1000;
+        tv.tv_usec = (timeoutMs % 1000) * 1000;
+        tvp = &tv;
+      }
+      
+      // If there are X requests pending then poll, don't wait!
+      if (XPending(dpy)) {
+        tv.tv_usec = tv.tv_sec = 0;
+        tvp = &tv;
+      }
+      
+      // Wait for X events, VNC traffic, or the next timer expiry
+      fd_set rfds;
+      FD_ZERO(&rfds);
+      FD_SET(ConnectionNumber(dpy), &rfds);
+      int n = select(FD_SETSIZE, &rfds, 0, 0, tvp);
+      if (n < 0) throw rdr::SystemException("select",errno);
+    }
+
+    XCloseDisplay(dpy);
+
+  } catch (rdr::Exception &e) {
+    vlog.error(e.str());
+  }
+
+  return 0;
+}
diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man
new file mode 100644
index 0000000..e24753d
--- /dev/null
+++ b/unix/vncconfig/vncconfig.man
@@ -0,0 +1,128 @@
+.TH vncconfig 1 "17 Apr 2006" "TightVNC" "Virtual Network Computing"
+.SH NAME
+vncconfig \- configure and control a VNC server
+.SH SYNOPSIS
+.B vncconfig
+.RI [ parameters ] 
+.br
+.B vncconfig
+.RI [ parameters ] 
+.B \-connect
+.IR host [: port ]
+.br
+.B vncconfig
+.RI [ parameters ] 
+.B \-disconnect
+.br
+.B vncconfig
+.RI [ parameters ] 
+.RB [ -set ] 
+.IR Xvnc-param = value " ..."
+.br
+.B vncconfig
+.RI [ parameters ] 
+.B \-list
+.br
+.B vncconfig
+.RI [ parameters ] 
+\fB\-get\fP \fIXvnc-param\fP
+.br
+.B vncconfig
+.RI [ parameters ] 
+\fB\-desc\fP \fIXvnc-param\fP
+.SH DESCRIPTION
+.B vncconfig
+is used to configure and control a running instance of Xvnc, or any other X
+server with the VNC extension.  Note that it cannot be used to control VNC
+servers prior to version 4.
+
+When run with no options, it runs as a kind of "helper" application for Xvnc.
+Its main purpose when run in this mode is to support clipboard transfer to and
+from the VNC viewer(s).  Note that without a running instance of
+\fBvncconfig\fP there will be no clipboard support.  It puts up a window with
+some checkboxes which can be used to disable clipboard transfers if required
+(in the future there may be more functions available from this window).  The
+\fB-nowin\fP flag can be used if you always want clipboard support but don't
+wish to clutter the desktop with this window - alternatively the \fB-iconic\fP
+option can be used to make it iconified by default.
+
+When run in any other mode, \fBvncconfig\fP is a one-shot program used to
+configure or control Xvnc as appropriate.  It can be used to tell Xvnc to
+connect or disconnect from listening viewers, and to set and retrieve Xvnc's
+parameters.
+
+Note that the DISPLAY environment variable or the \fB\-display\fP option
+must be set as appropriate to control Xvnc.  If you run it on an ordinary X
+server (or on a version 3 Xvnc) you will get an error message saying that there
+is no VNC extension.
+
+.SH OPTIONS
+.TP
+.B \-connect \fIhost\fP[:\fIport\fP]
+Tells an Xvnc server to make a "reverse" connection to a listening VNC viewer
+(normally connections are made the other way round - the viewer connects to the
+server). \fIhost\fP is the host where the listening viewer is running. If it's
+not listening on the default port of 5500, you can specify \fIhost:port\fP
+instead.
+
+.TP
+.B \-disconnect
+This causes Xvnc to disconnect from all viewers so that the VNC desktop is not
+displayed anywhere.
+
+.TP
+[\fB-set\fP] \fIXvnc-param\fP=\fIvalue\fP
+Sets an Xvnc parameter to the given value.  Note that some of Xvnc's parameters
+are read only once at startup so that changing them in this way may not have
+any effect.
+
+.TP
+.B \-list
+Lists all the parameters supported by Xvnc.
+
+.TP
+.B \-get \fIXvnc-param\fP
+Prints the current value of the given Xvnc parameter.
+
+.TP
+.B \-desc \fIXvnc-param\fP
+Prints a short description of the given Xvnc parameter.
+
+.SH PARAMETERS
+.B vncconfig
+also has parameters of its own which can be set on the command line.  These
+should not be confused with Xvnc's parameters which are manipulated with the
+\fB-set\fP, \fB-get\fP, \fB-list\fP and \fB-desc\fP options.
+
+Parameters can be turned on with -\fIparam\fP or off with -\fIparam\fP=0.
+Parameters which take a value can be specified as -\fIparam\fP \fIvalue\fP.
+Other valid forms are \fIparam\fP\fB=\fP\fIvalue\fP -\fIparam\fP=\fIvalue\fP
+--\fIparam\fP=\fIvalue\fP.  Parameter names are case-insensitive.
+
+.TP
+.B \-display \fIXdisplay\fP
+Specifies the Xvnc server to control.
+
+.TP
+.B \-nowin
+When run as a "helper" app, don't put up a window.
+
+.TP
+.B \-iconic
+When run as a "helper" app, make the window iconified at startup.
+
+.SH SEE ALSO
+.BR vncpasswd (1),
+.BR vncviewer (1),
+.BR vncserver (1),
+.BR Xvnc (1)
+.br
+http://www.tightvnc.com
+
+.SH AUTHOR
+Tristan Richardson, RealVNC Ltd.
+
+VNC was originally developed by the RealVNC team while at Olivetti
+Research Ltd / AT&T Laboratories Cambridge.  TightVNC additions was
+implemented by Constantin Kaplinsky. Many other people participated in
+development, testing and support.