Merge branch 'connparams' of https://github.com/CendioOssman/tigervnc
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
index fb95377..3ea217f 100644
--- a/common/rfb/CConnection.cxx
+++ b/common/rfb/CConnection.cxx
@@ -16,6 +16,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -24,6 +25,7 @@
 #include <rfb/CMsgReader.h>
 #include <rfb/CMsgWriter.h>
 #include <rfb/CSecurity.h>
+#include <rfb/Decoder.h>
 #include <rfb/Security.h>
 #include <rfb/SecurityClient.h>
 #include <rfb/CConnection.h>
@@ -39,9 +41,17 @@
 static LogWriter vlog("CConnection");
 
 CConnection::CConnection()
-  : csecurity(0), is(0), os(0), reader_(0), writer_(0),
+  : csecurity(0),
+    supportsLocalCursor(false), supportsDesktopResize(false),
+    supportsLEDState(false),
+    is(0), os(0), reader_(0), writer_(0),
     shared(false),
     state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
+    pendingPFChange(false), preferredEncoding(encodingTight),
+    compressLevel(2), qualityLevel(-1),
+    formatChange(false), encodingChange(false),
+    firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
+    forceNonincremental(true),
     framebuffer(NULL), decoder(this)
 {
 }
@@ -67,6 +77,11 @@
 {
   decoder.flush();
 
+  if (fb) {
+    assert(fb->width() == server.width());
+    assert(fb->height() == server.height());
+  }
+
   if ((framebuffer != NULL) && (fb != NULL)) {
     Rect rect;
 
@@ -128,35 +143,51 @@
 
 void CConnection::processVersionMsg()
 {
+  char verStr[13];
+  int majorVersion;
+  int minorVersion;
+
   vlog.debug("reading protocol version");
-  bool done;
-  if (!cp.readVersion(is, &done)) {
+
+  if (!is->checkNoWait(12))
+    return;
+
+  is->readBytes(verStr, 12);
+  verStr[12] = '\0';
+
+  if (sscanf(verStr, "RFB %03d.%03d\n",
+             &majorVersion, &minorVersion) != 2) {
     state_ = RFBSTATE_INVALID;
     throw Exception("reading version failed: not an RFB server?");
   }
-  if (!done) return;
+
+  server.setVersion(majorVersion, minorVersion);
 
   vlog.info("Server supports RFB protocol version %d.%d",
-            cp.majorVersion, cp.minorVersion);
+            server.majorVersion, server.minorVersion);
 
   // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
-  if (cp.beforeVersion(3,3)) {
+  if (server.beforeVersion(3,3)) {
     vlog.error("Server gave unsupported RFB protocol version %d.%d",
-               cp.majorVersion, cp.minorVersion);
+               server.majorVersion, server.minorVersion);
     state_ = RFBSTATE_INVALID;
     throw Exception("Server gave unsupported RFB protocol version %d.%d",
-                    cp.majorVersion, cp.minorVersion);
-  } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
-    cp.setVersion(3,3);
-  } else if (cp.afterVersion(3,8)) {
-    cp.setVersion(3,8);
+                    server.majorVersion, server.minorVersion);
+  } else if (useProtocol3_3 || server.beforeVersion(3,7)) {
+    server.setVersion(3,3);
+  } else if (server.afterVersion(3,8)) {
+    server.setVersion(3,8);
   }
 
-  cp.writeVersion(os);
+  sprintf(verStr, "RFB %03d.%03d\n",
+          server.majorVersion, server.minorVersion);
+  os->writeBytes(verStr, 12);
+  os->flush();
+
   state_ = RFBSTATE_SECURITY_TYPES;
 
   vlog.info("Using RFB protocol version %d.%d",
-            cp.majorVersion, cp.minorVersion);
+            server.majorVersion, server.minorVersion);
 }
 
 
@@ -169,7 +200,7 @@
   std::list<rdr::U8> secTypes;
   secTypes = security.GetEnabledSecTypes();
 
-  if (cp.isVersion(3,3)) {
+  if (server.isVersion(3,3)) {
 
     // legacy 3.3 server may only offer "vnc authentication" or "none"
 
@@ -252,7 +283,7 @@
 {
   vlog.debug("processing security result message");
   int result;
-  if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
+  if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
     result = secResultOK;
   } else {
     if (!is->checkNoWait(1)) return;
@@ -272,7 +303,7 @@
     throw Exception("Unknown security result from server");
   }
   state_ = RFBSTATE_INVALID;
-  if (cp.beforeVersion(3,8))
+  if (server.beforeVersion(3,8))
     throw AuthFailureException();
   CharArray reason(is->readString());
   throw AuthFailureException(reason.buf);
@@ -296,7 +327,7 @@
 {
   state_ = RFBSTATE_INITIALISATION;
   reader_ = new CMsgReader(this, is);
-  writer_ = new CMsgWriter(&cp, os);
+  writer_ = new CMsgWriter(&server, os);
   vlog.debug("Authentication success!");
   authSuccess();
   writer_->writeClientInit(shared);
@@ -307,6 +338,16 @@
   decoder.flush();
 
   CMsgHandler::setDesktopSize(w,h);
+
+  if (continuousUpdates)
+    writer()->writeEnableContinuousUpdates(true, 0, 0,
+                                           server.width(),
+                                           server.height());
+
+  resizeFramebuffer();
+  assert(framebuffer != NULL);
+  assert(framebuffer->width() == server.width());
+  assert(framebuffer->height() == server.height());
 }
 
 void CConnection::setExtendedDesktopSize(unsigned reason,
@@ -317,6 +358,59 @@
   decoder.flush();
 
   CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
+
+  if (continuousUpdates)
+    writer()->writeEnableContinuousUpdates(true, 0, 0,
+                                           server.width(),
+                                           server.height());
+
+  resizeFramebuffer();
+  assert(framebuffer != NULL);
+  assert(framebuffer->width() == server.width());
+  assert(framebuffer->height() == server.height());
+}
+
+void CConnection::endOfContinuousUpdates()
+{
+  CMsgHandler::endOfContinuousUpdates();
+
+  // We've gotten the marker for a format change, so make the pending
+  // one active
+  if (pendingPFChange) {
+    server.setPF(pendingPF);
+    pendingPFChange = false;
+
+    // We might have another change pending
+    if (formatChange)
+      requestNewUpdate();
+  }
+}
+
+void CConnection::serverInit(int width, int height,
+                             const PixelFormat& pf,
+                             const char* name)
+{
+  CMsgHandler::serverInit(width, height, pf, name);
+
+  state_ = RFBSTATE_NORMAL;
+  vlog.debug("initialisation done");
+
+  initDone();
+  assert(framebuffer != NULL);
+  assert(framebuffer->width() == server.width());
+  assert(framebuffer->height() == server.height());
+
+  // We want to make sure we call SetEncodings at least once
+  encodingChange = true;
+
+  requestNewUpdate();
+
+  // This initial update request is a bit of a corner case, so we need
+  // to help out setting the correct format here.
+  if (pendingPFChange) {
+    server.setPF(pendingPF);
+    pendingPFChange = false;
+  }
 }
 
 void CConnection::readAndDecodeRect(const Rect& r, int encoding,
@@ -329,6 +423,13 @@
 void CConnection::framebufferUpdateStart()
 {
   CMsgHandler::framebufferUpdateStart();
+
+  assert(framebuffer != NULL);
+
+  // Note: This might not be true if continuous updates are supported
+  pendingUpdate = false;
+
+  requestNewUpdate();
 }
 
 void CConnection::framebufferUpdateEnd()
@@ -336,6 +437,25 @@
   decoder.flush();
 
   CMsgHandler::framebufferUpdateEnd();
+
+  // A format change has been scheduled and we are now past the update
+  // with the old format. Time to active the new one.
+  if (pendingPFChange && !continuousUpdates) {
+    server.setPF(pendingPF);
+    pendingPFChange = false;
+  }
+
+  if (firstUpdate) {
+    if (server.supportsContinuousUpdates) {
+      vlog.info("Enabling continuous updates");
+      continuousUpdates = true;
+      writer()->writeEnableContinuousUpdates(true, 0, 0,
+                                             server.width(),
+                                             server.height());
+    }
+
+    firstUpdate = false;
+  }
 }
 
 void CConnection::dataRect(const Rect& r, int encoding)
@@ -347,10 +467,64 @@
 {
 }
 
-void CConnection::serverInit()
+void CConnection::initDone()
 {
-  state_ = RFBSTATE_NORMAL;
-  vlog.debug("initialisation done");
+}
+
+void CConnection::resizeFramebuffer()
+{
+  assert(false);
+}
+
+void CConnection::refreshFramebuffer()
+{
+  forceNonincremental = true;
+
+  // Without continuous updates we have to make sure we only have a
+  // single update in flight, so we'll have to wait to do the refresh
+  if (continuousUpdates)
+    requestNewUpdate();
+}
+
+void CConnection::setPreferredEncoding(int encoding)
+{
+  if (preferredEncoding == encoding)
+    return;
+
+  preferredEncoding = encoding;
+  encodingChange = true;
+}
+
+int CConnection::getPreferredEncoding()
+{
+  return preferredEncoding;
+}
+
+void CConnection::setCompressLevel(int level)
+{
+  if (compressLevel == level)
+    return;
+
+  compressLevel = level;
+  encodingChange = true;
+}
+
+void CConnection::setQualityLevel(int level)
+{
+  if (qualityLevel == level)
+    return;
+
+  qualityLevel = level;
+  encodingChange = true;
+}
+
+void CConnection::setPF(const PixelFormat& pf)
+{
+  if (server.pf().equal(pf) && !formatChange)
+    return;
+
+  nextPF = pf;
+  formatChange = true;
 }
 
 void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
@@ -365,3 +539,94 @@
 
   writer()->writeFence(flags, len, data);
 }
+
+// requestNewUpdate() requests an update from the server, having set the
+// format and encoding appropriately.
+void CConnection::requestNewUpdate()
+{
+  if (formatChange && !pendingPFChange) {
+    /* Catch incorrect requestNewUpdate calls */
+    assert(!pendingUpdate || continuousUpdates);
+
+    // We have to make sure we switch the internal format at a safe
+    // time. For continuous updates we temporarily disable updates and
+    // look for a EndOfContinuousUpdates message to see when to switch.
+    // For classical updates we just got a new update right before this
+    // function was called, so we need to make sure we finish that
+    // update before we can switch.
+
+    pendingPFChange = true;
+    pendingPF = nextPF;
+
+    if (continuousUpdates)
+      writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);
+
+    writer()->writeSetPixelFormat(pendingPF);
+
+    if (continuousUpdates)
+      writer()->writeEnableContinuousUpdates(true, 0, 0,
+                                             server.width(),
+                                             server.height());
+
+    formatChange = false;
+  }
+
+  if (encodingChange) {
+    updateEncodings();
+    encodingChange = false;
+  }
+
+  if (forceNonincremental || !continuousUpdates) {
+    pendingUpdate = true;
+    writer()->writeFramebufferUpdateRequest(Rect(0, 0,
+                                                 server.width(),
+                                                 server.height()),
+                                            !forceNonincremental);
+  }
+
+  forceNonincremental = false;
+}
+
+// Ask for encodings based on which decoders are supported.  Assumes higher
+// encoding numbers are more desirable.
+
+void CConnection::updateEncodings()
+{
+  std::list<rdr::U32> encodings;
+
+  if (supportsLocalCursor) {
+    encodings.push_back(pseudoEncodingCursorWithAlpha);
+    encodings.push_back(pseudoEncodingCursor);
+    encodings.push_back(pseudoEncodingXCursor);
+  }
+  if (supportsDesktopResize) {
+    encodings.push_back(pseudoEncodingDesktopSize);
+    encodings.push_back(pseudoEncodingExtendedDesktopSize);
+  }
+  if (supportsLEDState)
+    encodings.push_back(pseudoEncodingLEDState);
+
+  encodings.push_back(pseudoEncodingDesktopName);
+  encodings.push_back(pseudoEncodingLastRect);
+  encodings.push_back(pseudoEncodingContinuousUpdates);
+  encodings.push_back(pseudoEncodingFence);
+  encodings.push_back(pseudoEncodingQEMUKeyEvent);
+
+  if (Decoder::supported(preferredEncoding)) {
+    encodings.push_back(preferredEncoding);
+  }
+
+  encodings.push_back(encodingCopyRect);
+
+  for (int i = encodingMax; i >= 0; i--) {
+    if ((i != preferredEncoding) && Decoder::supported(i))
+      encodings.push_back(i);
+  }
+
+  if (compressLevel >= 0 && compressLevel <= 9)
+      encodings.push_back(pseudoEncodingCompressLevel0 + compressLevel);
+  if (qualityLevel >= 0 && qualityLevel <= 9)
+      encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel);
+
+  writer()->writeSetEncodings(encodings);
+}
diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h
index e29c033..5a3ef91 100644
--- a/common/rfb/CConnection.h
+++ b/common/rfb/CConnection.h
@@ -100,6 +100,12 @@
                                         int w, int h,
                                         const ScreenSet& layout);
 
+    virtual void endOfContinuousUpdates();
+
+    virtual void serverInit(int width, int height,
+                            const PixelFormat& pf,
+                            const char* name);
+
     virtual void readAndDecodeRect(const Rect& r, int encoding,
                                    ModifiablePixelBuffer* pb);
 
@@ -110,20 +116,43 @@
 
     // Methods to be overridden in a derived class
 
-    // getIdVerifier() returns the identity verifier associated with the connection.
-    // Ownership of the IdentityVerifier is retained by the CConnection instance.
-    virtual IdentityVerifier* getIdentityVerifier() {return 0;}
-
     // authSuccess() is called when authentication has succeeded.
     virtual void authSuccess();
 
-    // serverInit() is called when the ServerInit message is received.  The
-    // derived class must call on to CConnection::serverInit().
-    virtual void serverInit();
+    // initDone() is called when the connection is fully established
+    // and standard messages can be sent. This is called before the
+    // initial FramebufferUpdateRequest giving a derived class the
+    // chance to modify pixel format and settings. The derived class
+    // must also make sure it has provided a valid framebuffer before
+    // returning.
+    virtual void initDone() = 0;
+
+    // resizeFramebuffer() is called whenever the framebuffer
+    // dimensions or the screen layout changes. A subclass must make
+    // sure the pixel buffer has been updated once this call returns.
+    virtual void resizeFramebuffer();
 
 
     // Other methods
 
+    // refreshFramebuffer() forces a complete refresh of the entire
+    // framebuffer
+    void refreshFramebuffer();
+
+    // setPreferredEncoding()/getPreferredEncoding() adjusts which
+    // encoding is listed first as a hint to the server that it is the
+    // preferred one
+    void setPreferredEncoding(int encoding);
+    int getPreferredEncoding();
+    // setCompressLevel()/setQualityLevel() controls the encoding hints
+    // sent to the server
+    void setCompressLevel(int level);
+    void setQualityLevel(int level);
+    // setPF() controls the pixel format requested from the server.
+    // server.pf() will automatically be adjusted once the new format
+    // is active.
+    void setPF(const PixelFormat& pf);
+
     CMsgReader* reader() { return reader_; }
     CMsgWriter* writer() { return writer_; }
 
@@ -159,6 +188,13 @@
 
     ModifiablePixelBuffer* getFramebuffer() { return framebuffer; }
 
+  protected:
+    // Optional capabilities that a subclass is expected to set to true
+    // if supported
+    bool supportsLocalCursor;
+    bool supportsDesktopResize;
+    bool supportsLEDState;
+
   private:
     // This is a default implementation of fences that automatically
     // responds to requests, stating no support for synchronisation.
@@ -176,6 +212,9 @@
     void throwConnFailedException();
     void securityCompleted();
 
+    void requestNewUpdate();
+    void updateEncodings();
+
     rdr::InStream* is;
     rdr::OutStream* os;
     CMsgReader* reader_;
@@ -188,6 +227,23 @@
 
     bool useProtocol3_3;
 
+    bool pendingPFChange;
+    rfb::PixelFormat pendingPF;
+
+    int preferredEncoding;
+    int compressLevel;
+    int qualityLevel;
+
+    bool formatChange;
+    rfb::PixelFormat nextPF;
+    bool encodingChange;
+
+    bool firstUpdate;
+    bool pendingUpdate;
+    bool continuousUpdates;
+
+    bool forceNonincremental;
+
     ModifiablePixelBuffer* framebuffer;
     DecodeManager decoder;
   };
diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt
index b8d0813..8e532a2 100644
--- a/common/rfb/CMakeLists.txt
+++ b/common/rfb/CMakeLists.txt
@@ -11,9 +11,9 @@
   CSecurityStack.cxx
   CSecurityVeNCrypt.cxx
   CSecurityVncAuth.cxx
+  ClientParams.cxx
   ComparingUpdateTracker.cxx
   Configuration.cxx
-  ConnParams.cxx
   CopyRectDecoder.cxx
   Cursor.cxx
   DecodeManager.cxx
@@ -43,6 +43,7 @@
   SMsgReader.cxx
   SMsgWriter.cxx
   ServerCore.cxx
+  ServerParams.cxx
   Security.cxx
   SecurityServer.cxx
   SecurityClient.cxx
diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx
index b89bc18..4fe5041 100644
--- a/common/rfb/CMsgHandler.cxx
+++ b/common/rfb/CMsgHandler.cxx
@@ -34,50 +34,53 @@
 
 void CMsgHandler::setDesktopSize(int width, int height)
 {
-  cp.width = width;
-  cp.height = height;
+  server.setDimensions(width, height);
 }
 
 void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result,
                                          int width, int height,
                                          const ScreenSet& layout)
 {
-  cp.supportsSetDesktopSize = true;
+  server.supportsSetDesktopSize = true;
 
   if ((reason == reasonClient) && (result != resultSuccess))
     return;
 
-  if (!layout.validate(width, height))
-    fprintf(stderr, "Server sent us an invalid screen layout\n");
-
-  cp.width = width;
-  cp.height = height;
-  cp.screenLayout = layout;
+  server.setDimensions(width, height, layout);
 }
 
 void CMsgHandler::setPixelFormat(const PixelFormat& pf)
 {
-  cp.setPF(pf);
+  server.setPF(pf);
 }
 
 void CMsgHandler::setName(const char* name)
 {
-  cp.setName(name);
+  server.setName(name);
 }
 
 void CMsgHandler::fence(rdr::U32 flags, unsigned len, const char data[])
 {
-  cp.supportsFence = true;
+  server.supportsFence = true;
 }
 
 void CMsgHandler::endOfContinuousUpdates()
 {
-  cp.supportsContinuousUpdates = true;
+  server.supportsContinuousUpdates = true;
 }
 
 void CMsgHandler::supportsQEMUKeyEvent()
 {
-  cp.supportsQEMUKeyEvent = true;
+  server.supportsQEMUKeyEvent = true;
+}
+
+void CMsgHandler::serverInit(int width, int height,
+                             const PixelFormat& pf,
+                             const char* name)
+{
+  server.setDimensions(width, height);
+  server.setPF(pf);
+  server.setName(name);
 }
 
 void CMsgHandler::framebufferUpdateStart()
@@ -90,5 +93,5 @@
 
 void CMsgHandler::setLEDState(unsigned int state)
 {
-  cp.setLEDState(state);
+  server.setLEDState(state);
 }
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index 903ee15..effdaab 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -26,7 +26,7 @@
 
 #include <rdr/types.h>
 #include <rfb/Pixel.h>
-#include <rfb/ConnParams.h>
+#include <rfb/ServerParams.h>
 #include <rfb/Rect.h>
 #include <rfb/ScreenSet.h>
 
@@ -41,9 +41,9 @@
 
     // The following methods are called as corresponding messages are read.  A
     // derived class should override these methods as desired.  Note that for
-    // the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat() and
-    // setName() methods, a derived class should call on to CMsgHandler's
-    // methods to set the members of cp appropriately.
+    // the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(),
+    // setName() and serverInit() methods, a derived class should call on to
+    // CMsgHandler's methods to set the members of "server" appropriately.
 
     virtual void setDesktopSize(int w, int h);
     virtual void setExtendedDesktopSize(unsigned reason, unsigned result,
@@ -56,7 +56,9 @@
     virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
     virtual void endOfContinuousUpdates();
     virtual void supportsQEMUKeyEvent();
-    virtual void serverInit() = 0;
+    virtual void serverInit(int width, int height,
+                            const PixelFormat& pf,
+                            const char* name) = 0;
 
     virtual void readAndDecodeRect(const Rect& r, int encoding,
                                    ModifiablePixelBuffer* pb) = 0;
@@ -72,7 +74,7 @@
 
     virtual void setLEDState(unsigned int state);
 
-    ConnParams cp;
+    ServerParams server;
   };
 }
 #endif
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index e42546d..3422ebf 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -43,13 +43,10 @@
 {
   int width = is->readU16();
   int height = is->readU16();
-  handler->setDesktopSize(width, height);
   PixelFormat pf;
   pf.read(is);
-  handler->setPixelFormat(pf);
   CharArray name(is->readString());
-  handler->setName(name.buf);
-  handler->serverInit();
+  handler->serverInit(width, height, pf, name.buf);
 }
 
 void CMsgReader::readMsg()
@@ -192,10 +189,11 @@
 
 void CMsgReader::readRect(const Rect& r, int encoding)
 {
-  if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) {
+  if ((r.br.x > handler->server.width()) ||
+      (r.br.y > handler->server.height())) {
     fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n",
 	    r.width(), r.height(), r.tl.x, r.tl.y,
-            handler->cp.width, handler->cp.height);
+            handler->server.width(), handler->server.height());
     throw Exception("Rect too big");
   }
 
@@ -269,7 +267,7 @@
   if (width > maxCursorSize || height > maxCursorSize)
     throw Exception("Too big cursor");
 
-  int data_len = width * height * (handler->cp.pf().bpp/8);
+  int data_len = width * height * (handler->server.pf().bpp/8);
   int mask_len = ((width+7)/8) * height;
   rdr::U8Array data(data_len);
   rdr::U8Array mask(mask_len);
@@ -290,14 +288,14 @@
       int byte = y * maskBytesPerRow + x / 8;
       int bit = 7 - x % 8;
 
-      handler->cp.pf().rgbFromBuffer(out, in, 1);
+      handler->server.pf().rgbFromBuffer(out, in, 1);
 
       if (mask.buf[byte] & (1 << bit))
         out[3] = 255;
       else
         out[3] = 0;
 
-      in += handler->cp.pf().bpp/8;
+      in += handler->server.pf().bpp/8;
       out += 4;
     }
   }
@@ -321,10 +319,10 @@
 
   encoding = is->readS32();
 
-  origPF = handler->cp.pf();
-  handler->cp.setPF(rgbaPF);
+  origPF = handler->server.pf();
+  handler->server.setPF(rgbaPF);
   handler->readAndDecodeRect(pb.getRect(), encoding, &pb);
-  handler->cp.setPF(origPF);
+  handler->server.setPF(origPF);
 
   // On-wire data has pre-multiplied alpha, but we store it
   // non-pre-multiplied
diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx
index 44b73da..d357c97 100644
--- a/common/rfb/CMsgWriter.cxx
+++ b/common/rfb/CMsgWriter.cxx
@@ -20,19 +20,17 @@
 #include <rdr/OutStream.h>
 #include <rfb/msgTypes.h>
 #include <rfb/fenceTypes.h>
-#include <rfb/encodings.h>
 #include <rfb/qemuTypes.h>
 #include <rfb/Exception.h>
 #include <rfb/PixelFormat.h>
 #include <rfb/Rect.h>
-#include <rfb/ConnParams.h>
-#include <rfb/Decoder.h>
+#include <rfb/ServerParams.h>
 #include <rfb/CMsgWriter.h>
 
 using namespace rfb;
 
-CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
-  : cp(cp_), os(os_)
+CMsgWriter::CMsgWriter(ServerParams* server_, rdr::OutStream* os_)
+  : server(server_), os(os_)
 {
 }
 
@@ -54,96 +52,21 @@
   endMsg();
 }
 
-void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
+void CMsgWriter::writeSetEncodings(const std::list<rdr::U32> encodings)
 {
+  std::list<rdr::U32>::const_iterator iter;
   startMsg(msgTypeSetEncodings);
   os->skip(1);
-  os->writeU16(nEncodings);
-  for (int i = 0; i < nEncodings; i++)
-    os->writeU32(encodings[i]);
+  os->writeU16(encodings.size());
+  for (iter = encodings.begin(); iter != encodings.end(); ++iter)
+    os->writeU32(*iter);
   endMsg();
 }
 
-// Ask for encodings based on which decoders are supported.  Assumes higher
-// encoding numbers are more desirable.
-
-void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
-{
-  int nEncodings = 0;
-  rdr::U32 encodings[encodingMax+3];
-
-  if (cp->supportsLocalCursor) {
-    encodings[nEncodings++] = pseudoEncodingCursorWithAlpha;
-    encodings[nEncodings++] = pseudoEncodingCursor;
-    encodings[nEncodings++] = pseudoEncodingXCursor;
-  }
-  if (cp->supportsDesktopResize)
-    encodings[nEncodings++] = pseudoEncodingDesktopSize;
-  if (cp->supportsExtendedDesktopSize)
-    encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize;
-  if (cp->supportsDesktopRename)
-    encodings[nEncodings++] = pseudoEncodingDesktopName;
-  if (cp->supportsLEDState)
-    encodings[nEncodings++] = pseudoEncodingLEDState;
-
-  encodings[nEncodings++] = pseudoEncodingLastRect;
-  encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
-  encodings[nEncodings++] = pseudoEncodingFence;
-  encodings[nEncodings++] = pseudoEncodingQEMUKeyEvent;
-
-  if (Decoder::supported(preferredEncoding)) {
-    encodings[nEncodings++] = preferredEncoding;
-  }
-
-  if (useCopyRect) {
-    encodings[nEncodings++] = encodingCopyRect;
-  }
-
-  /*
-   * Prefer encodings in this order:
-   *
-   *   Tight, ZRLE, Hextile, *
-   */
-
-  if ((preferredEncoding != encodingTight) &&
-      Decoder::supported(encodingTight))
-    encodings[nEncodings++] = encodingTight;
-
-  if ((preferredEncoding != encodingZRLE) &&
-      Decoder::supported(encodingZRLE))
-    encodings[nEncodings++] = encodingZRLE;
-
-  if ((preferredEncoding != encodingHextile) &&
-      Decoder::supported(encodingHextile))
-    encodings[nEncodings++] = encodingHextile;
-
-  // Remaining encodings
-  for (int i = encodingMax; i >= 0; i--) {
-    switch (i) {
-    case encodingCopyRect:
-    case encodingTight:
-    case encodingZRLE:
-    case encodingHextile:
-      /* These have already been sent earlier */
-      break;
-    default:
-      if ((i != preferredEncoding) && Decoder::supported(i))
-        encodings[nEncodings++] = i;
-    }
-  }
-
-  if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
-      encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
-  if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
-      encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
-
-  writeSetEncodings(nEncodings, encodings);
-}
-
 void CMsgWriter::writeSetDesktopSize(int width, int height,
                                      const ScreenSet& layout)
 {
-  if (!cp->supportsSetDesktopSize)
+  if (!server->supportsSetDesktopSize)
     throw Exception("Server does not support SetDesktopSize");
 
   startMsg(msgTypeSetDesktopSize);
@@ -182,7 +105,7 @@
 void CMsgWriter::writeEnableContinuousUpdates(bool enable,
                                               int x, int y, int w, int h)
 {
-  if (!cp->supportsContinuousUpdates)
+  if (!server->supportsContinuousUpdates)
     throw Exception("Server does not support continuous updates");
 
   startMsg(msgTypeEnableContinuousUpdates);
@@ -199,7 +122,7 @@
 
 void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
 {
-  if (!cp->supportsFence)
+  if (!server->supportsFence)
     throw Exception("Server does not support fences");
   if (len > 64)
     throw Exception("Too large fence payload");
@@ -219,7 +142,7 @@
 
 void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
 {
-  if (!cp->supportsQEMUKeyEvent || !keycode) {
+  if (!server->supportsQEMUKeyEvent || !keycode) {
     /* This event isn't meaningful without a valid keysym */
     if (!keysym)
       return;
@@ -245,8 +168,8 @@
   Point p(pos);
   if (p.x < 0) p.x = 0;
   if (p.y < 0) p.y = 0;
-  if (p.x >= cp->width) p.x = cp->width - 1;
-  if (p.y >= cp->height) p.y = cp->height - 1;
+  if (p.x >= server->width()) p.x = server->width() - 1;
+  if (p.y >= server->height()) p.y = server->height() - 1;
 
   startMsg(msgTypePointerEvent);
   os->writeU8(buttonMask);
diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h
index 1322186..4d533d4 100644
--- a/common/rfb/CMsgWriter.h
+++ b/common/rfb/CMsgWriter.h
@@ -23,6 +23,8 @@
 #ifndef __RFB_CMSGWRITER_H__
 #define __RFB_CMSGWRITER_H__
 
+#include <list>
+
 #include <rdr/types.h>
 
 namespace rdr { class OutStream; }
@@ -30,21 +32,20 @@
 namespace rfb {
 
   class PixelFormat;
-  class ConnParams;
+  class ServerParams;
   struct ScreenSet;
   struct Point;
   struct Rect;
 
   class CMsgWriter {
   public:
-    CMsgWriter(ConnParams* cp, rdr::OutStream* os);
+    CMsgWriter(ServerParams* server, rdr::OutStream* os);
     virtual ~CMsgWriter();
 
     void writeClientInit(bool shared);
 
     void writeSetPixelFormat(const PixelFormat& pf);
-    void writeSetEncodings(int nEncodings, rdr::U32* encodings);
-    void writeSetEncodings(int preferredEncoding, bool useCopyRect);
+    void writeSetEncodings(const std::list<rdr::U32> encodings);
     void writeSetDesktopSize(int width, int height, const ScreenSet& layout);
 
     void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
@@ -60,7 +61,7 @@
     void startMsg(int type);
     void endMsg();
 
-    ConnParams* cp;
+    ServerParams* server;
     rdr::OutStream* os;
   };
 }
diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
index d6a8d7f..c6d1e31 100644
--- a/common/rfb/CSecurityTLS.cxx
+++ b/common/rfb/CSecurityTLS.cxx
@@ -34,7 +34,6 @@
 #endif
 
 #include <rfb/CSecurityTLS.h>
-#include <rfb/SSecurityVeNCrypt.h> 
 #include <rfb/CConnection.h>
 #include <rfb/LogWriter.h>
 #include <rfb/Exception.h>
diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h
index 4932c07..476d0ef 100644
--- a/common/rfb/CSecurityTLS.h
+++ b/common/rfb/CSecurityTLS.h
@@ -31,7 +31,6 @@
 #endif
 
 #include <rfb/CSecurity.h>
-#include <rfb/SSecurityVeNCrypt.h>
 #include <rfb/Security.h>
 #include <rfb/UserMsgBox.h>
 #include <rdr/InStream.h>
diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx
new file mode 100644
index 0000000..2f8783b
--- /dev/null
+++ b/common/rfb/ClientParams.cxx
@@ -0,0 +1,178 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
+ * Copyright 2014-2018 Pierre Ossman for Cendio AB
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#include <rfb/Exception.h>
+#include <rfb/encodings.h>
+#include <rfb/ledStates.h>
+#include <rfb/ClientParams.h>
+
+using namespace rfb;
+
+ClientParams::ClientParams()
+  : majorVersion(0), minorVersion(0),
+    compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
+    subsampling(subsampleUndefined),
+    width_(0), height_(0), name_(0),
+    ledState_(ledUnknown)
+{
+  setName("");
+  cursor_ = new Cursor(0, 0, Point(), NULL);
+}
+
+ClientParams::~ClientParams()
+{
+  delete [] name_;
+  delete cursor_;
+}
+
+void ClientParams::setDimensions(int width, int height)
+{
+  ScreenSet layout;
+  layout.add_screen(rfb::Screen(0, 0, 0, width, height, 0));
+  setDimensions(width, height, layout);
+}
+
+void ClientParams::setDimensions(int width, int height, const ScreenSet& layout)
+{
+  if (!layout.validate(width, height))
+    throw Exception("Attempted to configure an invalid screen layout");
+
+  width_ = width;
+  height_ = height;
+  screenLayout_ = layout;
+}
+
+void ClientParams::setPF(const PixelFormat& pf)
+{
+  pf_ = pf;
+
+  if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
+    throw Exception("setPF: not 8, 16 or 32 bpp?");
+}
+
+void ClientParams::setName(const char* name)
+{
+  delete [] name_;
+  name_ = strDup(name);
+}
+
+void ClientParams::setCursor(const Cursor& other)
+{
+  delete cursor_;
+  cursor_ = new Cursor(other);
+}
+
+bool ClientParams::supportsEncoding(rdr::S32 encoding) const
+{
+  return encodings_.count(encoding) != 0;
+}
+
+void ClientParams::setEncodings(int nEncodings, const rdr::S32* encodings)
+{
+  compressLevel = -1;
+  qualityLevel = -1;
+  fineQualityLevel = -1;
+  subsampling = subsampleUndefined;
+
+  encodings_.clear();
+  encodings_.insert(encodingRaw);
+
+  for (int i = nEncodings-1; i >= 0; i--) {
+    switch (encodings[i]) {
+    case pseudoEncodingSubsamp1X:
+      subsampling = subsampleNone;
+      break;
+    case pseudoEncodingSubsampGray:
+      subsampling = subsampleGray;
+      break;
+    case pseudoEncodingSubsamp2X:
+      subsampling = subsample2X;
+      break;
+    case pseudoEncodingSubsamp4X:
+      subsampling = subsample4X;
+      break;
+    case pseudoEncodingSubsamp8X:
+      subsampling = subsample8X;
+      break;
+    case pseudoEncodingSubsamp16X:
+      subsampling = subsample16X;
+      break;
+    }
+
+    if (encodings[i] >= pseudoEncodingCompressLevel0 &&
+        encodings[i] <= pseudoEncodingCompressLevel9)
+      compressLevel = encodings[i] - pseudoEncodingCompressLevel0;
+
+    if (encodings[i] >= pseudoEncodingQualityLevel0 &&
+        encodings[i] <= pseudoEncodingQualityLevel9)
+      qualityLevel = encodings[i] - pseudoEncodingQualityLevel0;
+
+    if (encodings[i] >= pseudoEncodingFineQualityLevel0 &&
+        encodings[i] <= pseudoEncodingFineQualityLevel100)
+      fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;
+
+    encodings_.insert(encodings[i]);
+  }
+}
+
+void ClientParams::setLEDState(unsigned int state)
+{
+  ledState_ = state;
+}
+
+bool ClientParams::supportsLocalCursor() const
+{
+  if (supportsEncoding(pseudoEncodingCursorWithAlpha))
+    return true;
+  if (supportsEncoding(pseudoEncodingCursor))
+    return true;
+  if (supportsEncoding(pseudoEncodingXCursor))
+    return true;
+  return false;
+}
+
+bool ClientParams::supportsDesktopSize() const
+{
+  if (supportsEncoding(pseudoEncodingExtendedDesktopSize))
+    return true;
+  if (supportsEncoding(pseudoEncodingDesktopSize))
+    return true;
+  return false;
+}
+
+bool ClientParams::supportsLEDState() const
+{
+  if (supportsEncoding(pseudoEncodingLEDState))
+    return true;
+  return false;
+}
+
+bool ClientParams::supportsFence() const
+{
+  if (supportsEncoding(pseudoEncodingFence))
+    return true;
+  return false;
+}
+
+bool ClientParams::supportsContinuousUpdates() const
+{
+  if (supportsEncoding(pseudoEncodingContinuousUpdates))
+    return true;
+  return false;
+}
diff --git a/common/rfb/ConnParams.h b/common/rfb/ClientParams.h
similarity index 73%
rename from common/rfb/ConnParams.h
rename to common/rfb/ClientParams.h
index b322293..f7a7044 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ClientParams.h
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2018 Pierre Ossman for Cendio AB
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,11 +17,11 @@
  * USA.
  */
 //
-// ConnParams - structure containing the connection parameters.
+// ClientParams - structure describing the current state of the remote client
 //
 
-#ifndef __RFB_CONNPARAMS_H__
-#define __RFB_CONNPARAMS_H__
+#ifndef __RFB_CLIENTPARAMS_H__
+#define __RFB_CLIENTPARAMS_H__
 
 #include <set>
 
@@ -30,8 +30,6 @@
 #include <rfb/PixelFormat.h>
 #include <rfb/ScreenSet.h>
 
-namespace rdr { class InStream; }
-
 namespace rfb {
 
   const int subsampleUndefined = -1;
@@ -42,13 +40,10 @@
   const int subsample8X = 4;
   const int subsample16X = 5;
 
-  class ConnParams {
+  class ClientParams {
   public:
-    ConnParams();
-    ~ConnParams();
-
-    bool readVersion(rdr::InStream* is, bool* done);
-    void writeVersion(rdr::OutStream* os);
+    ClientParams();
+    ~ClientParams();
 
     int majorVersion;
     int minorVersion;
@@ -67,9 +62,11 @@
       return !beforeVersion(major,minor+1);
     }
 
-    int width;
-    int height;
-    ScreenSet screenLayout;
+    const int width() const { return width_; }
+    const int height() const { return height_; }
+    const ScreenSet& screenLayout() const { return screenLayout_; }
+    void setDimensions(int width, int height);
+    void setDimensions(int width, int height, const ScreenSet& layout);
 
     const PixelFormat& pf() const { return pf_; }
     void setPF(const PixelFormat& pf);
@@ -87,21 +84,13 @@
     unsigned int ledState() { return ledState_; }
     void setLEDState(unsigned int state);
 
-    bool useCopyRect;
-
-    bool supportsLocalCursor;
-    bool supportsLocalXCursor;
-    bool supportsLocalCursorWithAlpha;
-    bool supportsDesktopResize;
-    bool supportsExtendedDesktopSize;
-    bool supportsDesktopRename;
-    bool supportsLastRect;
-    bool supportsLEDState;
-    bool supportsQEMUKeyEvent;
-
-    bool supportsSetDesktopSize;
-    bool supportsFence;
-    bool supportsContinuousUpdates;
+    // Wrappers to check for functionality rather than specific
+    // encodings
+    bool supportsLocalCursor() const;
+    bool supportsDesktopSize() const;
+    bool supportsLEDState() const;
+    bool supportsFence() const;
+    bool supportsContinuousUpdates() const;
 
     int compressLevel;
     int qualityLevel;
@@ -110,12 +99,14 @@
 
   private:
 
+    int width_;
+    int height_;
+    ScreenSet screenLayout_;
+
     PixelFormat pf_;
     char* name_;
     Cursor* cursor_;
     std::set<rdr::S32> encodings_;
-    char verStr[13];
-    int verStrPos;
     unsigned int ledState_;
   };
 }
diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
deleted file mode 100644
index 80b4a5a..0000000
--- a/common/rfb/ConnParams.cxx
+++ /dev/null
@@ -1,200 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
- * 
- * 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/InStream.h>
-#include <rdr/OutStream.h>
-#include <rfb/Exception.h>
-#include <rfb/encodings.h>
-#include <rfb/ledStates.h>
-#include <rfb/ConnParams.h>
-#include <rfb/util.h>
-
-using namespace rfb;
-
-ConnParams::ConnParams()
-  : majorVersion(0), minorVersion(0),
-    width(0), height(0), useCopyRect(false),
-    supportsLocalCursor(false), supportsLocalXCursor(false),
-    supportsLocalCursorWithAlpha(false),
-    supportsDesktopResize(false), supportsExtendedDesktopSize(false),
-    supportsDesktopRename(false), supportsLastRect(false),
-    supportsLEDState(false), supportsQEMUKeyEvent(false),
-    supportsSetDesktopSize(false), supportsFence(false),
-    supportsContinuousUpdates(false),
-    compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
-    subsampling(subsampleUndefined), name_(0), verStrPos(0),
-    ledState_(ledUnknown)
-{
-  setName("");
-  cursor_ = new Cursor(0, 0, Point(), NULL);
-}
-
-ConnParams::~ConnParams()
-{
-  delete [] name_;
-  delete cursor_;
-}
-
-bool ConnParams::readVersion(rdr::InStream* is, bool* done)
-{
-  if (verStrPos >= 12) return false;
-  while (is->checkNoWait(1) && verStrPos < 12) {
-    verStr[verStrPos++] = is->readU8();
-  }
-
-  if (verStrPos < 12) {
-    *done = false;
-    return true;
-  }
-  *done = true;
-  verStr[12] = 0;
-  return (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion,&minorVersion) == 2);
-}
-
-void ConnParams::writeVersion(rdr::OutStream* os)
-{
-  char str[13];
-  sprintf(str, "RFB %03d.%03d\n", majorVersion, minorVersion);
-  os->writeBytes(str, 12);
-  os->flush();
-}
-
-void ConnParams::setPF(const PixelFormat& pf)
-{
-  pf_ = pf;
-
-  if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
-    throw Exception("setPF: not 8, 16 or 32 bpp?");
-}
-
-void ConnParams::setName(const char* name)
-{
-  delete [] name_;
-  name_ = strDup(name);
-}
-
-void ConnParams::setCursor(const Cursor& other)
-{
-  delete cursor_;
-  cursor_ = new Cursor(other);
-}
-
-bool ConnParams::supportsEncoding(rdr::S32 encoding) const
-{
-  return encodings_.count(encoding) != 0;
-}
-
-void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
-{
-  useCopyRect = false;
-  supportsLocalCursor = false;
-  supportsLocalCursorWithAlpha = false;
-  supportsDesktopResize = false;
-  supportsExtendedDesktopSize = false;
-  supportsLocalXCursor = false;
-  supportsLastRect = false;
-  supportsQEMUKeyEvent = false;
-  compressLevel = -1;
-  qualityLevel = -1;
-  fineQualityLevel = -1;
-  subsampling = subsampleUndefined;
-
-  encodings_.clear();
-  encodings_.insert(encodingRaw);
-
-  for (int i = nEncodings-1; i >= 0; i--) {
-    switch (encodings[i]) {
-    case encodingCopyRect:
-      useCopyRect = true;
-      break;
-    case pseudoEncodingCursor:
-      supportsLocalCursor = true;
-      break;
-    case pseudoEncodingXCursor:
-      supportsLocalXCursor = true;
-      break;
-    case pseudoEncodingCursorWithAlpha:
-      supportsLocalCursorWithAlpha = true;
-      break;
-    case pseudoEncodingDesktopSize:
-      supportsDesktopResize = true;
-      break;
-    case pseudoEncodingExtendedDesktopSize:
-      supportsExtendedDesktopSize = true;
-      break;
-    case pseudoEncodingDesktopName:
-      supportsDesktopRename = true;
-      break;
-    case pseudoEncodingLastRect:
-      supportsLastRect = true;
-      break;
-    case pseudoEncodingLEDState:
-      supportsLEDState = true;
-      break;
-    case pseudoEncodingQEMUKeyEvent:
-      supportsQEMUKeyEvent = true;
-      break;
-    case pseudoEncodingFence:
-      supportsFence = true;
-      break;
-    case pseudoEncodingContinuousUpdates:
-      supportsContinuousUpdates = true;
-      break;
-    case pseudoEncodingSubsamp1X:
-      subsampling = subsampleNone;
-      break;
-    case pseudoEncodingSubsampGray:
-      subsampling = subsampleGray;
-      break;
-    case pseudoEncodingSubsamp2X:
-      subsampling = subsample2X;
-      break;
-    case pseudoEncodingSubsamp4X:
-      subsampling = subsample4X;
-      break;
-    case pseudoEncodingSubsamp8X:
-      subsampling = subsample8X;
-      break;
-    case pseudoEncodingSubsamp16X:
-      subsampling = subsample16X;
-      break;
-    }
-
-    if (encodings[i] >= pseudoEncodingCompressLevel0 &&
-        encodings[i] <= pseudoEncodingCompressLevel9)
-      compressLevel = encodings[i] - pseudoEncodingCompressLevel0;
-
-    if (encodings[i] >= pseudoEncodingQualityLevel0 &&
-        encodings[i] <= pseudoEncodingQualityLevel9)
-      qualityLevel = encodings[i] - pseudoEncodingQualityLevel0;
-
-    if (encodings[i] >= pseudoEncodingFineQualityLevel0 &&
-        encodings[i] <= pseudoEncodingFineQualityLevel100)
-      fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;
-
-    if (encodings[i] > 0)
-      encodings_.insert(encodings[i]);
-  }
-}
-
-void ConnParams::setLEDState(unsigned int state)
-{
-  ledState_ = state;
-}
diff --git a/common/rfb/CopyRectDecoder.cxx b/common/rfb/CopyRectDecoder.cxx
index 23949a8..ecf5032 100644
--- a/common/rfb/CopyRectDecoder.cxx
+++ b/common/rfb/CopyRectDecoder.cxx
@@ -32,7 +32,7 @@
 }
 
 void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is,
-                               const ConnParams& cp, rdr::OutStream* os)
+                               const ServerParams& server, rdr::OutStream* os)
 {
   os->copyBytes(is, 4);
 }
@@ -41,21 +41,21 @@
 void CopyRectDecoder::getAffectedRegion(const Rect& rect,
                                         const void* buffer,
                                         size_t buflen,
-                                        const ConnParams& cp,
+                                        const ServerParams& server,
                                         Region* region)
 {
   rdr::MemInStream is(buffer, buflen);
   int srcX = is.readU16();
   int srcY = is.readU16();
 
-  Decoder::getAffectedRegion(rect, buffer, buflen, cp, region);
+  Decoder::getAffectedRegion(rect, buffer, buflen, server, region);
 
   region->assign_union(Region(rect.translate(Point(srcX-rect.tl.x,
                                                    srcY-rect.tl.y))));
 }
 
 void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer,
-                                 size_t buflen, const ConnParams& cp,
+                                 size_t buflen, const ServerParams& server,
                                  ModifiablePixelBuffer* pb)
 {
   rdr::MemInStream is(buffer, buflen);
diff --git a/common/rfb/CopyRectDecoder.h b/common/rfb/CopyRectDecoder.h
index 1d2ce53..546266e 100644
--- a/common/rfb/CopyRectDecoder.h
+++ b/common/rfb/CopyRectDecoder.h
@@ -27,12 +27,12 @@
     CopyRectDecoder();
     virtual ~CopyRectDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os);
+                          const ServerParams& server, rdr::OutStream* os);
     virtual void getAffectedRegion(const Rect& rect, const void* buffer,
-                                   size_t buflen, const ConnParams& cp,
+                                   size_t buflen, const ServerParams& server,
                                    Region* region);
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb);
   };
 }
diff --git a/common/rfb/DecodeManager.cxx b/common/rfb/DecodeManager.cxx
index c509db0..98b6e79 100644
--- a/common/rfb/DecodeManager.cxx
+++ b/common/rfb/DecodeManager.cxx
@@ -132,9 +132,9 @@
   if (threads.empty()) {
     bufferStream = freeBuffers.front();
     bufferStream->clear();
-    decoder->readRect(r, conn->getInStream(), conn->cp, bufferStream);
+    decoder->readRect(r, conn->getInStream(), conn->server, bufferStream);
     decoder->decodeRect(r, bufferStream->data(), bufferStream->length(),
-                        conn->cp, pb);
+                        conn->server, pb);
     return;
   }
 
@@ -155,7 +155,7 @@
 
   // Read the rect
   bufferStream->clear();
-  decoder->readRect(r, conn->getInStream(), conn->cp, bufferStream);
+  decoder->readRect(r, conn->getInStream(), conn->server, bufferStream);
 
   // Then try to put it on the queue
   entry = new QueueEntry;
@@ -164,12 +164,12 @@
   entry->rect = r;
   entry->encoding = encoding;
   entry->decoder = decoder;
-  entry->cp = &conn->cp;
+  entry->server = &conn->server;
   entry->pb = pb;
   entry->bufferStream = bufferStream;
 
   decoder->getAffectedRegion(r, bufferStream->data(),
-                             bufferStream->length(), conn->cp,
+                             bufferStream->length(), conn->server,
                              &entry->affectedRegion);
 
   queueMutex->lock();
@@ -276,7 +276,7 @@
     try {
       entry->decoder->decodeRect(entry->rect, entry->bufferStream->data(),
                                  entry->bufferStream->length(),
-                                 *entry->cp, entry->pb);
+                                 *entry->server, entry->pb);
     } catch (rdr::Exception& e) {
       manager->setThreadException(e);
     } catch(...) {
@@ -346,7 +346,7 @@
                                             (*iter2)->rect,
                                             (*iter2)->bufferStream->data(),
                                             (*iter2)->bufferStream->length(),
-                                            *entry->cp))
+                                            *entry->server))
           goto next;
       }
     }
diff --git a/common/rfb/DecodeManager.h b/common/rfb/DecodeManager.h
index 2098063..058d824 100644
--- a/common/rfb/DecodeManager.h
+++ b/common/rfb/DecodeManager.h
@@ -65,7 +65,7 @@
       Rect rect;
       int encoding;
       Decoder* decoder;
-      const ConnParams* cp;
+      const ServerParams* server;
       ModifiablePixelBuffer* pb;
       rdr::MemOutStream* bufferStream;
       Region affectedRegion;
diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx
index 370e1f9..9827a73 100644
--- a/common/rfb/Decoder.cxx
+++ b/common/rfb/Decoder.cxx
@@ -38,7 +38,7 @@
 }
 
 void Decoder::getAffectedRegion(const Rect& rect, const void* buffer,
-                                size_t buflen, const ConnParams& cp,
+                                size_t buflen, const ServerParams& server,
                                 Region* region)
 {
   region->reset(rect);
@@ -47,7 +47,7 @@
 bool Decoder::doRectsConflict(const Rect& rectA, const void* bufferA,
                               size_t buflenA, const Rect& rectB,
                               const void* bufferB, size_t buflenB,
-                              const ConnParams& cp)
+                              const ServerParams& server)
 {
   return false;
 }
diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h
index 86ee4ef..e074f3e 100644
--- a/common/rfb/Decoder.h
+++ b/common/rfb/Decoder.h
@@ -25,7 +25,7 @@
 }
 
 namespace rfb {
-  class ConnParams;
+  class ServerParams;
   class ModifiablePixelBuffer;
   class Region;
 
@@ -53,7 +53,7 @@
     // make it easier to decode. This function will always be called in
     // a serial manner on the main thread.
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os)=0;
+                          const ServerParams& server, rdr::OutStream* os)=0;
 
     // These functions will be called from any of the worker threads.
     // A lock will be held whilst these are called so it is safe to
@@ -63,7 +63,7 @@
     // be either read from or written do when decoding this rect. The
     // default implementation simply returns the given rectangle.
     virtual void getAffectedRegion(const Rect& rect, const void* buffer,
-                                   size_t buflen, const ConnParams& cp,
+                                   size_t buflen, const ServerParams& server,
                                    Region* region);
 
     // doesRectsConflict() determines if two rectangles must be decoded
@@ -75,14 +75,14 @@
                                  const Rect& rectB,
                                  const void* bufferB,
                                  size_t buflenB,
-                                 const ConnParams& cp);
+                                 const ServerParams& server);
 
     // decodeRect() decodes the given rectangle with data from the
     // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of
     // the PixelBuffer might not match the ConnParams and it is up to
     // the decoder to do any necessary conversion.
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb)=0;
 
   public:
diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx
index 02128f7..735be07 100644
--- a/common/rfb/EncodeManager.cxx
+++ b/common/rfb/EncodeManager.cxx
@@ -325,6 +325,9 @@
 
     changed = changed_;
 
+    if (!conn->client.supportsEncoding(encodingCopyRect))
+      changed.assign_union(copied);
+
     /*
      * We need to render the cursor seperately as it has its own
      * magical pixel buffer, so split it out from the changed region.
@@ -334,7 +337,7 @@
       changed.assign_subtract(renderedCursor->getEffectiveRect());
     }
 
-    if (conn->cp.supportsLastRect)
+    if (conn->client.supportsEncoding(pseudoEncodingLastRect))
       nRects = 0xFFFF;
     else {
       nRects = copied.numRects();
@@ -344,13 +347,14 @@
 
     conn->writer()->writeFramebufferUpdateStart(nRects);
 
-    writeCopyRects(copied, copyDelta);
+    if (conn->client.supportsEncoding(encodingCopyRect))
+      writeCopyRects(copied, copyDelta);
 
     /*
      * We start by searching for solid rects, which are then removed
      * from the changed region.
      */
-    if (conn->cp.supportsLastRect)
+    if (conn->client.supportsEncoding(pseudoEncodingLastRect))
       writeSolidRects(&changed, pb);
 
     writeRects(changed, pb);
@@ -373,7 +377,7 @@
   solid = bitmap = bitmapRLE = encoderRaw;
   indexed = indexedRLE = fullColour = encoderRaw;
 
-  allowJPEG = conn->cp.pf().bpp >= 16;
+  allowJPEG = conn->client.pf().bpp >= 16;
   if (!allowLossy) {
     if (encoders[encoderTightJPEG]->losslessQuality == -1)
       allowJPEG = false;
@@ -447,7 +451,7 @@
   }
 
   // JPEG is the only encoder that can reduce things to grayscale
-  if ((conn->cp.subsampling == subsampleGray) &&
+  if ((conn->client.subsampling == subsampleGray) &&
       encoders[encoderTightJPEG]->isSupported() && allowLossy) {
     solid = bitmap = bitmapRLE = encoderTightJPEG;
     indexed = indexedRLE = fullColour = encoderTightJPEG;
@@ -465,14 +469,14 @@
 
     encoder = encoders[*iter];
 
-    encoder->setCompressLevel(conn->cp.compressLevel);
+    encoder->setCompressLevel(conn->client.compressLevel);
 
     if (allowLossy) {
-      encoder->setQualityLevel(conn->cp.qualityLevel);
-      encoder->setFineQualityLevel(conn->cp.fineQualityLevel,
-                                   conn->cp.subsampling);
+      encoder->setQualityLevel(conn->client.qualityLevel);
+      encoder->setFineQualityLevel(conn->client.fineQualityLevel,
+                                   conn->client.subsampling);
     } else {
-      int level = __rfbmax(conn->cp.qualityLevel,
+      int level = __rfbmax(conn->client.qualityLevel,
                            encoder->losslessQuality);
       encoder->setQualityLevel(level);
       encoder->setFineQualityLevel(-1, subsampleUndefined);
@@ -575,7 +579,7 @@
 
   stats[klass][activeType].rects++;
   stats[klass][activeType].pixels += rect.area();
-  equiv = 12 + rect.area() * (conn->cp.pf().bpp/8);
+  equiv = 12 + rect.area() * (conn->client.pf().bpp/8);
   stats[klass][activeType].equivalent += equiv;
 
   encoder = encoders[klass];
@@ -623,7 +627,7 @@
 
     copyStats.rects++;
     copyStats.pixels += rect->area();
-    equiv = 12 + rect->area() * (conn->cp.pf().bpp/8);
+    equiv = 12 + rect->area() * (conn->client.pf().bpp/8);
     copyStats.equivalent += equiv;
 
     conn->writer()->writeCopyRect(*rect, rect->tl.x - delta.x,
@@ -710,11 +714,11 @@
           rdr::U32 _buffer2;
           rdr::U8* converted = (rdr::U8*)&_buffer2;
 
-          conn->cp.pf().bufferFromBuffer(converted, pb->getPF(),
+          conn->client.pf().bufferFromBuffer(converted, pb->getPF(),
                                          colourValue, 1);
 
           encoder->writeSolidRect(erp.width(), erp.height(),
-                                  conn->cp.pf(), converted);
+                                  conn->client.pf(), converted);
         }
         endRect();
 
@@ -808,10 +812,10 @@
   //        compression setting means spending less effort in building
   //        a palette. It might be that they figured the increase in
   //        zlib setting compensated for the loss.
-  if (conn->cp.compressLevel == -1)
+  if (conn->client.compressLevel == -1)
     divisor = 2 * 8;
   else
-    divisor = conn->cp.compressLevel * 8;
+    divisor = conn->client.compressLevel * 8;
   if (divisor < 4)
     divisor = 4;
 
@@ -819,7 +823,7 @@
 
   // Special exception inherited from the Tight encoder
   if (activeEncoders[encoderFullColour] == encoderTightJPEG) {
-    if ((conn->cp.compressLevel != -1) && (conn->cp.compressLevel < 2))
+    if ((conn->client.compressLevel != -1) && (conn->client.compressLevel < 2))
       maxColours = 24;
     else
       maxColours = 96;
@@ -992,8 +996,8 @@
   int stride;
 
   // Do wo need to convert the data?
-  if (convert && !conn->cp.pf().equal(pb->getPF())) {
-    convertedPixelBuffer.setPF(conn->cp.pf());
+  if (convert && !conn->client.pf().equal(pb->getPF())) {
+    convertedPixelBuffer.setPF(conn->client.pf());
     convertedPixelBuffer.setSize(rect.width(), rect.height());
 
     buffer = pb->getBuffer(rect, &stride);
diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx
index eae0040..742dfb2 100644
--- a/common/rfb/HextileDecoder.cxx
+++ b/common/rfb/HextileDecoder.cxx
@@ -20,7 +20,7 @@
 #include <rdr/MemInStream.h>
 #include <rdr/OutStream.h>
 
-#include <rfb/ConnParams.h>
+#include <rfb/ServerParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/HextileDecoder.h>
 
@@ -45,12 +45,12 @@
 }
 
 void HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
-                              const ConnParams& cp, rdr::OutStream* os)
+                              const ServerParams& server, rdr::OutStream* os)
 {
   Rect t;
   size_t bytesPerPixel;
 
-  bytesPerPixel = cp.pf().bpp/8;
+  bytesPerPixel = server.pf().bpp/8;
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
@@ -91,11 +91,11 @@
 }
 
 void HextileDecoder::decodeRect(const Rect& r, const void* buffer,
-                                size_t buflen, const ConnParams& cp,
+                                size_t buflen, const ServerParams& server,
                                 ModifiablePixelBuffer* pb)
 {
   rdr::MemInStream is(buffer, buflen);
-  const PixelFormat& pf = cp.pf();
+  const PixelFormat& pf = server.pf();
   switch (pf.bpp) {
   case 8:  hextileDecode8 (r, &is, pf, pb); break;
   case 16: hextileDecode16(r, &is, pf, pb); break;
diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h
index bdc76bc..b8515bf 100644
--- a/common/rfb/HextileDecoder.h
+++ b/common/rfb/HextileDecoder.h
@@ -27,9 +27,9 @@
     HextileDecoder();
     virtual ~HextileDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os);
+                          const ServerParams& server, rdr::OutStream* os);
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb);
   };
 }
diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx
index 47e5251..1e20eb9 100644
--- a/common/rfb/HextileEncoder.cxx
+++ b/common/rfb/HextileEncoder.cxx
@@ -55,7 +55,7 @@
 
 bool HextileEncoder::isSupported()
 {
-  return conn->cp.supportsEncoding(encodingHextile);
+  return conn->client.supportsEncoding(encodingHextile);
 }
 
 void HextileEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx
index 27cb9de..23b8f8c 100644
--- a/common/rfb/JpegCompressor.cxx
+++ b/common/rfb/JpegCompressor.cxx
@@ -22,7 +22,7 @@
 #include <rdr/Exception.h>
 #include <rfb/Rect.h>
 #include <rfb/PixelFormat.h>
-#include <rfb/ConnParams.h>
+#include <rfb/ClientParams.h>
 
 #include <stdio.h>
 extern "C" {
diff --git a/common/rfb/Logger.cxx b/common/rfb/Logger.cxx
index 3daf248..ad10a4c 100644
--- a/common/rfb/Logger.cxx
+++ b/common/rfb/Logger.cxx
@@ -47,7 +47,16 @@
   char buf1[4096];
   vsnprintf(buf1, sizeof(buf1)-1, format, ap);
   buf1[sizeof(buf1)-1] = 0;
-  write(level, logname, buf1);
+  char *buf = buf1;
+  while (true) {
+    char *end = strchr(buf, '\n');
+    if (end)
+      *end = '\0';
+    write(level, logname, buf);
+    if (!end)
+      break;
+    buf = end + 1;
+  }
 }
 
 void
diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx
index 218c9b0..70a7ddb 100644
--- a/common/rfb/RREDecoder.cxx
+++ b/common/rfb/RREDecoder.cxx
@@ -20,7 +20,7 @@
 #include <rdr/MemInStream.h>
 #include <rdr/OutStream.h>
 
-#include <rfb/ConnParams.h>
+#include <rfb/ServerParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/RREDecoder.h>
 
@@ -45,22 +45,22 @@
 }
 
 void RREDecoder::readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os)
+                          const ServerParams& server, rdr::OutStream* os)
 {
   rdr::U32 numRects;
 
   numRects = is->readU32();
   os->writeU32(numRects);
 
-  os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8));
+  os->copyBytes(is, server.pf().bpp/8 + numRects * (server.pf().bpp/8 + 8));
 }
 
 void RREDecoder::decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb)
 {
   rdr::MemInStream is(buffer, buflen);
-  const PixelFormat& pf = cp.pf();
+  const PixelFormat& pf = server.pf();
   switch (pf.bpp) {
   case 8:  rreDecode8 (r, &is, pf, pb); break;
   case 16: rreDecode16(r, &is, pf, pb); break;
diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h
index f89fef4..f47edda 100644
--- a/common/rfb/RREDecoder.h
+++ b/common/rfb/RREDecoder.h
@@ -27,9 +27,9 @@
     RREDecoder();
     virtual ~RREDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os);
+                          const ServerParams& server, rdr::OutStream* os);
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb);
   };
 }
diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx
index 7287e7e..8358549 100644
--- a/common/rfb/RREEncoder.cxx
+++ b/common/rfb/RREEncoder.cxx
@@ -47,7 +47,7 @@
 
 bool RREEncoder::isSupported()
 {
-  return conn->cp.supportsEncoding(encodingRRE);
+  return conn->client.supportsEncoding(encodingRRE);
 }
 
 void RREEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx
index ec0c68e..6123504 100644
--- a/common/rfb/RawDecoder.cxx
+++ b/common/rfb/RawDecoder.cxx
@@ -19,7 +19,7 @@
 #include <assert.h>
 
 #include <rdr/OutStream.h>
-#include <rfb/ConnParams.h>
+#include <rfb/ServerParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/RawDecoder.h>
 
@@ -34,15 +34,15 @@
 }
 
 void RawDecoder::readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os)
+                          const ServerParams& server, rdr::OutStream* os)
 {
-  os->copyBytes(is, r.area() * (cp.pf().bpp/8));
+  os->copyBytes(is, r.area() * (server.pf().bpp/8));
 }
 
 void RawDecoder::decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb)
 {
-  assert(buflen >= (size_t)r.area() * (cp.pf().bpp/8));
-  pb->imageRect(cp.pf(), r, buffer);
+  assert(buflen >= (size_t)r.area() * (server.pf().bpp/8));
+  pb->imageRect(server.pf(), r, buffer);
 }
diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h
index 21ea738..4ab8071 100644
--- a/common/rfb/RawDecoder.h
+++ b/common/rfb/RawDecoder.h
@@ -26,9 +26,9 @@
     RawDecoder();
     virtual ~RawDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os);
+                          const ServerParams& server, rdr::OutStream* os);
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb);
   };
 }
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index a79abee..690653a 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -59,7 +59,7 @@
   if (rfb::Server::protocol3_3)
     defaultMinorVersion = 3;
 
-  cp.setVersion(defaultMajorVersion, defaultMinorVersion);
+  client.setVersion(defaultMajorVersion, defaultMinorVersion);
 }
 
 SConnection::~SConnection()
@@ -80,7 +80,12 @@
 
 void SConnection::initialiseProtocol()
 {
-  cp.writeVersion(os);
+  char str[13];
+
+  sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion);
+  os->writeBytes(str, 12);
+  os->flush();
+
   state_ = RFBSTATE_PROTOCOL_VERSION;
 }
 
@@ -104,35 +109,47 @@
 
 void SConnection::processVersionMsg()
 {
+  char verStr[13];
+  int majorVersion;
+  int minorVersion;
+
   vlog.debug("reading protocol version");
-  bool done;
-  if (!cp.readVersion(is, &done)) {
+
+  if (!is->checkNoWait(12))
+    return;
+
+  is->readBytes(verStr, 12);
+  verStr[12] = '\0';
+
+  if (sscanf(verStr, "RFB %03d.%03d\n",
+             &majorVersion, &minorVersion) != 2) {
     state_ = RFBSTATE_INVALID;
     throw Exception("reading version failed: not an RFB client?");
   }
-  if (!done) return;
+
+  client.setVersion(majorVersion, minorVersion);
 
   vlog.info("Client needs protocol version %d.%d",
-            cp.majorVersion, cp.minorVersion);
+            client.majorVersion, client.minorVersion);
 
-  if (cp.majorVersion != 3) {
+  if (client.majorVersion != 3) {
     // unknown protocol version
     throwConnFailedException("Client needs protocol version %d.%d, server has %d.%d",
-                             cp.majorVersion, cp.minorVersion,
+                             client.majorVersion, client.minorVersion,
                              defaultMajorVersion, defaultMinorVersion);
   }
 
-  if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
+  if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) {
     vlog.error("Client uses unofficial protocol version %d.%d",
-               cp.majorVersion,cp.minorVersion);
-    if (cp.minorVersion >= 8)
-      cp.minorVersion = 8;
-    else if (cp.minorVersion == 7)
-      cp.minorVersion = 7;
+               client.majorVersion,client.minorVersion);
+    if (client.minorVersion >= 8)
+      client.minorVersion = 8;
+    else if (client.minorVersion == 7)
+      client.minorVersion = 7;
     else
-      cp.minorVersion = 3;
+      client.minorVersion = 3;
     vlog.error("Assuming compatibility with version %d.%d",
-               cp.majorVersion,cp.minorVersion);
+               client.majorVersion,client.minorVersion);
   }
 
   versionReceived();
@@ -141,7 +158,7 @@
   std::list<rdr::U8>::iterator i;
   secTypes = security.GetEnabledSecTypes();
 
-  if (cp.isVersion(3,3)) {
+  if (client.isVersion(3,3)) {
 
     // cope with legacy 3.3 client only if "no authentication" or "vnc
     // authentication" is supported.
@@ -150,7 +167,7 @@
     }
     if (i == secTypes.end()) {
       throwConnFailedException("No supported security type for %d.%d client",
-                               cp.majorVersion, cp.minorVersion);
+                               client.majorVersion, client.minorVersion);
     }
 
     os->writeU32(*i);
@@ -220,7 +237,7 @@
   } catch (AuthFailureException& e) {
     vlog.error("AuthFailureException: %s", e.str());
     os->writeU32(secResultFailed);
-    if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+    if (!client.beforeVersion(3,8)) // 3.8 onwards have failure message
       os->writeString(e.str());
     os->flush();
     throw;
@@ -245,7 +262,7 @@
   vlog.info("Connection failed: %s", str);
 
   if (state_ == RFBSTATE_PROTOCOL_VERSION) {
-    if (cp.majorVersion == 3 && cp.minorVersion == 3) {
+    if (client.majorVersion == 3 && client.minorVersion == 3) {
       os->writeU32(0);
       os->writeString(str);
       os->flush();
@@ -308,12 +325,12 @@
   if (state_ != RFBSTATE_QUERYING)
     throw Exception("SConnection::approveConnection: invalid state");
 
-  if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
+  if (!client.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
     if (accept) {
       os->writeU32(secResultOK);
     } else {
       os->writeU32(secResultFailed);
-      if (!cp.beforeVersion(3,8)) { // 3.8 onwards have failure message
+      if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message
         if (reason)
           os->writeString(reason);
         else
@@ -326,7 +343,7 @@
   if (accept) {
     state_ = RFBSTATE_INITIALISATION;
     reader_ = new SMsgReader(this, is);
-    writer_ = new SMsgWriter(&cp, os);
+    writer_ = new SMsgWriter(&client, os);
     authSuccess();
   } else {
     state_ = RFBSTATE_INVALID;
@@ -339,7 +356,8 @@
 
 void SConnection::clientInit(bool shared)
 {
-  writer_->writeServerInit();
+  writer_->writeServerInit(client.width(), client.height(),
+                           client.pf(), client.name());
   state_ = RFBSTATE_NORMAL;
 }
 
@@ -360,7 +378,7 @@
 {
   if (!readyForSetColourMapEntries) {
     readyForSetColourMapEntries = true;
-    if (!cp.pf().trueColour) {
+    if (!client.pf().trueColour) {
       writeFakeColourMap();
     }
   }
@@ -388,7 +406,7 @@
   rdr::U16 red[256], green[256], blue[256];
 
   for (i = 0;i < 256;i++)
-    cp.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);
+    client.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);
 
   writer()->writeSetColourMapEntries(0, 256, red, green, blue);
 }
diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
index c38458c..f952ec2 100644
--- a/common/rfb/SMsgHandler.cxx
+++ b/common/rfb/SMsgHandler.cxx
@@ -19,6 +19,7 @@
 #include <rfb/Exception.h>
 #include <rfb/SMsgHandler.h>
 #include <rfb/ScreenSet.h>
+#include <rfb/encodings.h>
 
 using namespace rfb;
 
@@ -36,7 +37,7 @@
 
 void SMsgHandler::setPixelFormat(const PixelFormat& pf)
 {
-  cp.setPF(pf);
+  client.setPF(pf);
 }
 
 void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
@@ -44,22 +45,22 @@
   bool firstFence, firstContinuousUpdates, firstLEDState,
        firstQEMUKeyEvent;
 
-  firstFence = !cp.supportsFence;
-  firstContinuousUpdates = !cp.supportsContinuousUpdates;
-  firstLEDState = !cp.supportsLEDState;
-  firstQEMUKeyEvent = !cp.supportsQEMUKeyEvent;
+  firstFence = !client.supportsFence();
+  firstContinuousUpdates = !client.supportsContinuousUpdates();
+  firstLEDState = !client.supportsLEDState();
+  firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent);
 
-  cp.setEncodings(nEncodings, encodings);
+  client.setEncodings(nEncodings, encodings);
 
   supportsLocalCursor();
 
-  if (cp.supportsFence && firstFence)
+  if (client.supportsFence() && firstFence)
     supportsFence();
-  if (cp.supportsContinuousUpdates && firstContinuousUpdates)
+  if (client.supportsContinuousUpdates() && firstContinuousUpdates)
     supportsContinuousUpdates();
-  if (cp.supportsLEDState && firstLEDState)
+  if (client.supportsLEDState() && firstLEDState)
     supportsLEDState();
-  if (cp.supportsQEMUKeyEvent && firstQEMUKeyEvent)
+  if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent)
     supportsQEMUKeyEvent();
 }
 
@@ -82,12 +83,3 @@
 void SMsgHandler::supportsQEMUKeyEvent()
 {
 }
-
-void SMsgHandler::setDesktopSize(int fb_width, int fb_height,
-                                 const ScreenSet& layout)
-{
-  cp.width = fb_width;
-  cp.height = fb_height;
-  cp.screenLayout = layout;
-}
-
diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h
index 749f056..8548d91 100644
--- a/common/rfb/SMsgHandler.h
+++ b/common/rfb/SMsgHandler.h
@@ -25,7 +25,7 @@
 
 #include <rdr/types.h>
 #include <rfb/PixelFormat.h>
-#include <rfb/ConnParams.h>
+#include <rfb/ClientParams.h>
 #include <rfb/InputHandler.h>
 #include <rfb/ScreenSet.h>
 
@@ -40,8 +40,8 @@
 
     // The following methods are called as corresponding messages are read.  A
     // derived class should override these methods as desired.  Note that for
-    // the setPixelFormat(), setEncodings() and setDesktopSize() methods, a
-    // derived class must call on to SMsgHandler's methods.
+    // the setPixelFormat(), and setEncodings() methods, a derived class must
+    // call on to SMsgHandler's methods.
 
     virtual void clientInit(bool shared);
 
@@ -85,7 +85,7 @@
     // handler will send a pseudo-rect back, signalling server support.
     virtual void supportsQEMUKeyEvent();
 
-    ConnParams cp;
+    ClientParams client;
   };
 }
 #endif
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index 3da9413..a12a6d4 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -22,7 +22,7 @@
 #include <rfb/msgTypes.h>
 #include <rfb/fenceTypes.h>
 #include <rfb/Exception.h>
-#include <rfb/ConnParams.h>
+#include <rfb/ClientParams.h>
 #include <rfb/UpdateTracker.h>
 #include <rfb/Encoder.h>
 #include <rfb/SMsgWriter.h>
@@ -33,12 +33,10 @@
 
 static LogWriter vlog("SMsgWriter");
 
-SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
-  : cp(cp_), os(os_),
+SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_)
+  : client(client_), os(os_),
     nRectsInUpdate(0), nRectsInHeader(0),
-    needSetDesktopSize(false), needExtendedDesktopSize(false),
-    needSetDesktopName(false), needSetCursor(false),
-    needSetXCursor(false), needSetCursorWithAlpha(false),
+    needSetDesktopName(false), needCursor(false),
     needLEDState(false), needQEMUKeyEvent(false)
 {
 }
@@ -47,12 +45,13 @@
 {
 }
 
-void SMsgWriter::writeServerInit()
+void SMsgWriter::writeServerInit(rdr::U16 width, rdr::U16 height,
+                                 const PixelFormat& pf, const char* name)
 {
-  os->writeU16(cp->width);
-  os->writeU16(cp->height);
-  cp->pf().write(os);
-  os->writeString(cp->name());
+  os->writeU16(width);
+  os->writeU16(height);
+  pf.write(os);
+  os->writeString(name);
   endMsg();
 }
 
@@ -90,7 +89,7 @@
 
 void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
 {
-  if (!cp->supportsFence)
+  if (!client->supportsEncoding(pseudoEncodingFence))
     throw Exception("Client does not support fences");
   if (len > 64)
     throw Exception("Too large fence payload");
@@ -112,116 +111,68 @@
 
 void SMsgWriter::writeEndOfContinuousUpdates()
 {
-  if (!cp->supportsContinuousUpdates)
+  if (!client->supportsEncoding(pseudoEncodingContinuousUpdates))
     throw Exception("Client does not support continuous updates");
 
   startMsg(msgTypeEndOfContinuousUpdates);
   endMsg();
 }
 
-bool SMsgWriter::writeSetDesktopSize() {
-  if (!cp->supportsDesktopResize)
-    return false;
-
-  needSetDesktopSize = true;
-
-  return true;
-}
-
-bool SMsgWriter::writeExtendedDesktopSize() {
-  if (!cp->supportsExtendedDesktopSize)
-    return false;
-
-  needExtendedDesktopSize = true;
-
-  return true;
-}
-
-bool SMsgWriter::writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result,
-                                          int fb_width, int fb_height,
-                                          const ScreenSet& layout) {
+void SMsgWriter::writeDesktopSize(rdr::U16 reason, rdr::U16 result)
+{
   ExtendedDesktopSizeMsg msg;
 
-  if (!cp->supportsExtendedDesktopSize)
-    return false;
+  if (!client->supportsEncoding(pseudoEncodingDesktopSize) &&
+      !client->supportsEncoding(pseudoEncodingExtendedDesktopSize))
+    throw Exception("Client does not support desktop size changes");
 
   msg.reason = reason;
   msg.result = result;
-  msg.fb_width = fb_width;
-  msg.fb_height = fb_height;
-  msg.layout = layout;
 
   extendedDesktopSizeMsgs.push_back(msg);
-
-  return true;
 }
 
-bool SMsgWriter::writeSetDesktopName() {
-  if (!cp->supportsDesktopRename)
-    return false;
+void SMsgWriter::writeSetDesktopName()
+{
+  if (!client->supportsEncoding(pseudoEncodingDesktopName))
+    throw Exception("Client does not support desktop name changes");
 
   needSetDesktopName = true;
-
-  return true;
 }
 
-bool SMsgWriter::writeSetCursor()
+void SMsgWriter::writeCursor()
 {
-  if (!cp->supportsLocalCursor)
-    return false;
+  if (!client->supportsEncoding(pseudoEncodingCursor) &&
+      !client->supportsEncoding(pseudoEncodingXCursor) &&
+      !client->supportsEncoding(pseudoEncodingCursorWithAlpha))
+    throw Exception("Client does not support local cursor");
 
-  needSetCursor = true;
-
-  return true;
+  needCursor = true;
 }
 
-bool SMsgWriter::writeSetXCursor()
+void SMsgWriter::writeLEDState()
 {
-  if (!cp->supportsLocalXCursor)
-    return false;
-
-  needSetXCursor = true;
-
-  return true;
-}
-
-bool SMsgWriter::writeSetCursorWithAlpha()
-{
-  if (!cp->supportsLocalCursorWithAlpha)
-    return false;
-
-  needSetCursorWithAlpha = true;
-
-  return true;
-}
-
-bool SMsgWriter::writeLEDState()
-{
-  if (!cp->supportsLEDState)
-    return false;
-  if (cp->ledState() == ledUnknown)
-    return false;
+  if (!client->supportsEncoding(pseudoEncodingLEDState))
+    throw Exception("Client does not support LED state");
+  if (client->ledState() == ledUnknown)
+    throw Exception("Server has not specified LED state");
 
   needLEDState = true;
-
-  return true;
 }
 
-bool SMsgWriter::writeQEMUKeyEvent()
+void SMsgWriter::writeQEMUKeyEvent()
 {
-  if (!cp->supportsQEMUKeyEvent)
-    return false;
+  if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent))
+    throw Exception("Client does not support QEMU key events");
 
   needQEMUKeyEvent = true;
-
-  return true;
 }
 
 bool SMsgWriter::needFakeUpdate()
 {
   if (needSetDesktopName)
     return true;
-  if (needSetCursor || needSetXCursor || needSetCursorWithAlpha)
+  if (needCursor)
     return true;
   if (needLEDState)
     return true;
@@ -235,9 +186,7 @@
 
 bool SMsgWriter::needNoDataUpdate()
 {
-  if (needSetDesktopSize)
-    return true;
-  if (needExtendedDesktopSize || !extendedDesktopSizeMsgs.empty())
+  if (!extendedDesktopSizeMsgs.empty())
     return true;
 
   return false;
@@ -249,12 +198,12 @@
 
   nRects = 0;
 
-  if (needSetDesktopSize)
-    nRects++;
-  if (needExtendedDesktopSize)
-    nRects++;
-  if (!extendedDesktopSizeMsgs.empty())
-    nRects += extendedDesktopSizeMsgs.size();
+  if (!extendedDesktopSizeMsgs.empty()) {
+    if (client->supportsEncoding(pseudoEncodingExtendedDesktopSize))
+      nRects += extendedDesktopSizeMsgs.size();
+    else
+      nRects++;
+  }
 
   writeFramebufferUpdateStart(nRects);
   writeNoDataRects();
@@ -269,11 +218,7 @@
   if (nRects != 0xFFFF) {
     if (needSetDesktopName)
       nRects++;
-    if (needSetCursor)
-      nRects++;
-    if (needSetXCursor)
-      nRects++;
-    if (needSetCursorWithAlpha)
+    if (needCursor)
       nRects++;
     if (needLEDState)
       nRects++;
@@ -347,56 +292,52 @@
 
 void SMsgWriter::writePseudoRects()
 {
-  if (needSetCursor) {
-    const Cursor& cursor = cp->cursor();
+  if (needCursor) {
+    const Cursor& cursor = client->cursor();
 
-    rdr::U8Array data(cursor.width()*cursor.height() * (cp->pf().bpp/8));
-    rdr::U8Array mask(cursor.getMask());
+    if (client->supportsEncoding(pseudoEncodingCursorWithAlpha)) {
+      writeSetCursorWithAlphaRect(cursor.width(), cursor.height(),
+                                  cursor.hotspot().x, cursor.hotspot().y,
+                                  cursor.getBuffer());
+    } else if (client->supportsEncoding(pseudoEncodingCursor)) {
+      rdr::U8Array data(cursor.width()*cursor.height() * (client->pf().bpp/8));
+      rdr::U8Array mask(cursor.getMask());
 
-    const rdr::U8* in;
-    rdr::U8* out;
+      const rdr::U8* in;
+      rdr::U8* out;
 
-    in = cursor.getBuffer();
-    out = data.buf;
-    for (int i = 0;i < cursor.width()*cursor.height();i++) {
-      cp->pf().bufferFromRGB(out, in, 1);
-      in += 4;
-      out += cp->pf().bpp/8;
+      in = cursor.getBuffer();
+      out = data.buf;
+      for (int i = 0;i < cursor.width()*cursor.height();i++) {
+        client->pf().bufferFromRGB(out, in, 1);
+        in += 4;
+        out += client->pf().bpp/8;
+      }
+
+      writeSetCursorRect(cursor.width(), cursor.height(),
+                         cursor.hotspot().x, cursor.hotspot().y,
+                         data.buf, mask.buf);
+    } else if (client->supportsEncoding(pseudoEncodingXCursor)) {
+      rdr::U8Array bitmap(cursor.getBitmap());
+      rdr::U8Array mask(cursor.getMask());
+
+      writeSetXCursorRect(cursor.width(), cursor.height(),
+                          cursor.hotspot().x, cursor.hotspot().y,
+                          bitmap.buf, mask.buf);
+    } else {
+      throw Exception("Client does not support local cursor");
     }
 
-    writeSetCursorRect(cursor.width(), cursor.height(),
-                       cursor.hotspot().x, cursor.hotspot().y,
-                       data.buf, mask.buf);
-    needSetCursor = false;
-  }
-
-  if (needSetXCursor) {
-    const Cursor& cursor = cp->cursor();
-    rdr::U8Array bitmap(cursor.getBitmap());
-    rdr::U8Array mask(cursor.getMask());
-
-    writeSetXCursorRect(cursor.width(), cursor.height(),
-                        cursor.hotspot().x, cursor.hotspot().y,
-                        bitmap.buf, mask.buf);
-    needSetXCursor = false;
-  }
-
-  if (needSetCursorWithAlpha) {
-    const Cursor& cursor = cp->cursor();
-
-    writeSetCursorWithAlphaRect(cursor.width(), cursor.height(),
-                                cursor.hotspot().x, cursor.hotspot().y,
-                                cursor.getBuffer());
-    needSetCursorWithAlpha = false;
+    needCursor = false;
   }
 
   if (needSetDesktopName) {
-    writeSetDesktopNameRect(cp->name());
+    writeSetDesktopNameRect(client->name());
     needSetDesktopName = false;
   }
 
   if (needLEDState) {
-    writeLEDStateRect(cp->ledState());
+    writeLEDStateRect(client->ledState());
     needLEDState = false;
   }
 
@@ -408,36 +349,30 @@
 
 void SMsgWriter::writeNoDataRects()
 {
-  // Start with specific ExtendedDesktopSize messages
   if (!extendedDesktopSizeMsgs.empty()) {
-    std::list<ExtendedDesktopSizeMsg>::const_iterator ri;
-
-    for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) {
-      writeExtendedDesktopSizeRect(ri->reason, ri->result,
-                                   ri->fb_width, ri->fb_height, ri->layout);
+    if (client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) {
+      std::list<ExtendedDesktopSizeMsg>::const_iterator ri;
+      for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) {
+        // FIXME: We can probably skip multiple reasonServer entries
+        writeExtendedDesktopSizeRect(ri->reason, ri->result,
+                                     client->width(), client->height(),
+                                     client->screenLayout());
+      }
+    } else if (client->supportsEncoding(pseudoEncodingDesktopSize)) {
+      // Some clients assume this is the last rectangle so don't send anything
+      // more after this
+      writeSetDesktopSizeRect(client->width(), client->height());
+    } else {
+      throw Exception("Client does not support desktop size changes");
     }
 
     extendedDesktopSizeMsgs.clear();
   }
-
-  // Send this before SetDesktopSize to make life easier on the clients
-  if (needExtendedDesktopSize) {
-    writeExtendedDesktopSizeRect(0, 0, cp->width, cp->height,
-                                 cp->screenLayout);
-    needExtendedDesktopSize = false;
-  }
-
-  // Some clients assume this is the last rectangle so don't send anything
-  // more after this
-  if (needSetDesktopSize) {
-    writeSetDesktopSizeRect(cp->width, cp->height);
-    needSetDesktopSize = false;
-  }
 }
 
 void SMsgWriter::writeSetDesktopSizeRect(int width, int height)
 {
-  if (!cp->supportsDesktopResize)
+  if (!client->supportsEncoding(pseudoEncodingDesktopSize))
     throw Exception("Client does not support desktop resize");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeSetDesktopSizeRect: nRects out of sync");
@@ -457,7 +392,7 @@
 {
   ScreenSet::const_iterator si;
 
-  if (!cp->supportsExtendedDesktopSize)
+  if (!client->supportsEncoding(pseudoEncodingExtendedDesktopSize))
     throw Exception("Client does not support extended desktop resize");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeExtendedDesktopSizeRect: nRects out of sync");
@@ -483,7 +418,7 @@
 
 void SMsgWriter::writeSetDesktopNameRect(const char *name)
 {
-  if (!cp->supportsDesktopRename)
+  if (!client->supportsEncoding(pseudoEncodingDesktopName))
     throw Exception("Client does not support desktop rename");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeSetDesktopNameRect: nRects out of sync");
@@ -500,7 +435,7 @@
                                     int hotspotX, int hotspotY,
                                     const void* data, const void* mask)
 {
-  if (!cp->supportsLocalCursor)
+  if (!client->supportsEncoding(pseudoEncodingCursor))
     throw Exception("Client does not support local cursors");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeSetCursorRect: nRects out of sync");
@@ -510,7 +445,7 @@
   os->writeU16(width);
   os->writeU16(height);
   os->writeU32(pseudoEncodingCursor);
-  os->writeBytes(data, width * height * (cp->pf().bpp/8));
+  os->writeBytes(data, width * height * (client->pf().bpp/8));
   os->writeBytes(mask, (width+7)/8 * height);
 }
 
@@ -518,7 +453,7 @@
                                      int hotspotX, int hotspotY,
                                      const void* data, const void* mask)
 {
-  if (!cp->supportsLocalXCursor)
+  if (!client->supportsEncoding(pseudoEncodingXCursor))
     throw Exception("Client does not support local cursors");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeSetXCursorRect: nRects out of sync");
@@ -544,7 +479,7 @@
                                              int hotspotX, int hotspotY,
                                              const rdr::U8* data)
 {
-  if (!cp->supportsLocalCursorWithAlpha)
+  if (!client->supportsEncoding(pseudoEncodingCursorWithAlpha))
     throw Exception("Client does not support local cursors");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeSetCursorWithAlphaRect: nRects out of sync");
@@ -570,9 +505,9 @@
 
 void SMsgWriter::writeLEDStateRect(rdr::U8 state)
 {
-  if (!cp->supportsLEDState)
+  if (!client->supportsEncoding(pseudoEncodingLEDState))
     throw Exception("Client does not support LED state updates");
-  if (cp->ledState() == ledUnknown)
+  if (client->ledState() == ledUnknown)
     throw Exception("Server does not support LED state updates");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeLEDStateRect: nRects out of sync");
@@ -587,7 +522,7 @@
 
 void SMsgWriter::writeQEMUKeyEventRect()
 {
-  if (!cp->supportsQEMUKeyEvent)
+  if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent))
     throw Exception("Client does not support QEMU extended key events");
   if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
     throw Exception("SMsgWriter::writeQEMUKeyEventRect: nRects out of sync");
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index e985941..80f6de9 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -31,17 +31,19 @@
 
 namespace rfb {
 
-  class ConnParams;
+  class ClientParams;
+  class PixelFormat;
   struct ScreenSet;
 
   class SMsgWriter {
   public:
-    SMsgWriter(ConnParams* cp, rdr::OutStream* os);
+    SMsgWriter(ClientParams* client, rdr::OutStream* os);
     virtual ~SMsgWriter();
 
     // writeServerInit() must only be called at the appropriate time in the
     // protocol initialisation.
-    void writeServerInit();
+    void writeServerInit(rdr::U16 width, rdr::U16 height,
+                         const PixelFormat& pf, const char* name);
 
     // Methods to write normal protocol messages
 
@@ -63,30 +65,21 @@
     // updates mode.
     void writeEndOfContinuousUpdates();
 
-    // writeSetDesktopSize() won't actually write immediately, but will
+    // writeDesktopSize() won't actually write immediately, but will
     // write the relevant pseudo-rectangle as part of the next update.
-    bool writeSetDesktopSize();
-    // Same thing for the extended version. The first version queues up a
-    // generic update of the current server state, but the second queues a
-    // specific message.
-    bool writeExtendedDesktopSize();
-    bool writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result,
-                                  int fb_width, int fb_height,
-                                  const ScreenSet& layout);
+    void writeDesktopSize(rdr::U16 reason, rdr::U16 result=0);
 
-    bool writeSetDesktopName();
+    void writeSetDesktopName();
 
     // Like setDesktopSize, we can't just write out a cursor message
     // immediately. 
-    bool writeSetCursor();
-    bool writeSetXCursor();
-    bool writeSetCursorWithAlpha();
+    void writeCursor();
 
     // Same for LED state message
-    bool writeLEDState();
+    void writeLEDState();
 
     // And QEMU keyboard event handshake
-    bool writeQEMUKeyEvent();
+    void writeQEMUKeyEvent();
 
     // needFakeUpdate() returns true when an immediate update is needed in
     // order to flush out pseudo-rectangles to the client.
@@ -140,25 +133,19 @@
     void writeLEDStateRect(rdr::U8 state);
     void writeQEMUKeyEventRect();
 
-    ConnParams* cp;
+    ClientParams* client;
     rdr::OutStream* os;
 
     int nRectsInUpdate;
     int nRectsInHeader;
 
-    bool needSetDesktopSize;
-    bool needExtendedDesktopSize;
     bool needSetDesktopName;
-    bool needSetCursor;
-    bool needSetXCursor;
-    bool needSetCursorWithAlpha;
+    bool needCursor;
     bool needLEDState;
     bool needQEMUKeyEvent;
 
     typedef struct {
       rdr::U16 reason, result;
-      int fb_width, fb_height;
-      ScreenSet layout;
     } ExtendedDesktopSizeMsg;
 
     std::list<ExtendedDesktopSizeMsg> extendedDesktopSizeMsgs;
diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx
new file mode 100644
index 0000000..bfeb80d
--- /dev/null
+++ b/common/rfb/ServerParams.cxx
@@ -0,0 +1,84 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
+ * Copyright 2014-2018 Pierre Ossman for Cendio AB
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+#include <rfb/Exception.h>
+#include <rfb/ledStates.h>
+#include <rfb/ServerParams.h>
+
+using namespace rfb;
+
+ServerParams::ServerParams()
+  : majorVersion(0), minorVersion(0),
+    supportsQEMUKeyEvent(false),
+    supportsSetDesktopSize(false), supportsFence(false),
+    supportsContinuousUpdates(false),
+    width_(0), height_(0), name_(0),
+    ledState_(ledUnknown)
+{
+  setName("");
+  cursor_ = new Cursor(0, 0, Point(), NULL);
+}
+
+ServerParams::~ServerParams()
+{
+  delete [] name_;
+  delete cursor_;
+}
+
+void ServerParams::setDimensions(int width, int height)
+{
+  ScreenSet layout;
+  layout.add_screen(rfb::Screen(0, 0, 0, width, height, 0));
+  setDimensions(width, height, layout);
+}
+
+void ServerParams::setDimensions(int width, int height, const ScreenSet& layout)
+{
+  if (!layout.validate(width, height))
+    throw Exception("Attempted to configure an invalid screen layout");
+
+  width_ = width;
+  height_ = height;
+  screenLayout_ = layout;
+}
+
+void ServerParams::setPF(const PixelFormat& pf)
+{
+  pf_ = pf;
+
+  if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
+    throw Exception("setPF: not 8, 16 or 32 bpp?");
+}
+
+void ServerParams::setName(const char* name)
+{
+  delete [] name_;
+  name_ = strDup(name);
+}
+
+void ServerParams::setCursor(const Cursor& other)
+{
+  delete cursor_;
+  cursor_ = new Cursor(other);
+}
+
+void ServerParams::setLEDState(unsigned int state)
+{
+  ledState_ = state;
+}
diff --git a/common/rfb/ConnParams.h b/common/rfb/ServerParams.h
similarity index 62%
copy from common/rfb/ConnParams.h
copy to common/rfb/ServerParams.h
index b322293..7a58ea3 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ServerParams.h
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2018 Pierre Ossman for Cendio AB
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,38 +17,22 @@
  * USA.
  */
 //
-// ConnParams - structure containing the connection parameters.
+// ServerParams - structure describing the current state of the remote server
 //
 
-#ifndef __RFB_CONNPARAMS_H__
-#define __RFB_CONNPARAMS_H__
+#ifndef __RFB_SERVERPARAMS_H__
+#define __RFB_SERVERPARAMS_H__
 
-#include <set>
-
-#include <rdr/types.h>
 #include <rfb/Cursor.h>
 #include <rfb/PixelFormat.h>
 #include <rfb/ScreenSet.h>
 
-namespace rdr { class InStream; }
-
 namespace rfb {
 
-  const int subsampleUndefined = -1;
-  const int subsampleNone = 0;
-  const int subsampleGray = 1;
-  const int subsample2X = 2;
-  const int subsample4X = 3;
-  const int subsample8X = 4;
-  const int subsample16X = 5;
-
-  class ConnParams {
+  class ServerParams {
   public:
-    ConnParams();
-    ~ConnParams();
-
-    bool readVersion(rdr::InStream* is, bool* done);
-    void writeVersion(rdr::OutStream* os);
+    ServerParams();
+    ~ServerParams();
 
     int majorVersion;
     int minorVersion;
@@ -67,9 +51,11 @@
       return !beforeVersion(major,minor+1);
     }
 
-    int width;
-    int height;
-    ScreenSet screenLayout;
+    const int width() const { return width_; }
+    const int height() const { return height_; }
+    const ScreenSet& screenLayout() const { return screenLayout_; }
+    void setDimensions(int width, int height);
+    void setDimensions(int width, int height, const ScreenSet& layout);
 
     const PixelFormat& pf() const { return pf_; }
     void setPF(const PixelFormat& pf);
@@ -80,42 +66,23 @@
     const Cursor& cursor() const { return *cursor_; }
     void setCursor(const Cursor& cursor);
 
-    bool supportsEncoding(rdr::S32 encoding) const;
-
-    void setEncodings(int nEncodings, const rdr::S32* encodings);
-
     unsigned int ledState() { return ledState_; }
     void setLEDState(unsigned int state);
 
-    bool useCopyRect;
-
-    bool supportsLocalCursor;
-    bool supportsLocalXCursor;
-    bool supportsLocalCursorWithAlpha;
-    bool supportsDesktopResize;
-    bool supportsExtendedDesktopSize;
-    bool supportsDesktopRename;
-    bool supportsLastRect;
-    bool supportsLEDState;
     bool supportsQEMUKeyEvent;
-
     bool supportsSetDesktopSize;
     bool supportsFence;
     bool supportsContinuousUpdates;
 
-    int compressLevel;
-    int qualityLevel;
-    int fineQualityLevel;
-    int subsampling;
-
   private:
 
+    int width_;
+    int height_;
+    ScreenSet screenLayout_;
+
     PixelFormat pf_;
     char* name_;
     Cursor* cursor_;
-    std::set<rdr::S32> encodings_;
-    char verStr[13];
-    int verStrPos;
     unsigned int ledState_;
   };
 }
diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx
index 548c190..5b7c553 100644
--- a/common/rfb/TightDecoder.cxx
+++ b/common/rfb/TightDecoder.cxx
@@ -25,7 +25,7 @@
 #include <rdr/MemInStream.h>
 #include <rdr/OutStream.h>
 
-#include <rfb/ConnParams.h>
+#include <rfb/ServerParams.h>
 #include <rfb/Exception.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/TightConstants.h>
@@ -55,7 +55,7 @@
 }
 
 void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
-                            const ConnParams& cp, rdr::OutStream* os)
+                            const ServerParams& server, rdr::OutStream* os)
 {
   rdr::U8 comp_ctl;
 
@@ -66,10 +66,10 @@
 
   // "Fill" compression type.
   if (comp_ctl == tightFill) {
-    if (cp.pf().is888())
+    if (server.pf().is888())
       os->copyBytes(is, 3);
     else
-      os->copyBytes(is, cp.pf().bpp/8);
+      os->copyBytes(is, server.pf().bpp/8);
     return;
   }
 
@@ -106,13 +106,13 @@
       palSize = is->readU8() + 1;
       os->writeU8(palSize - 1);
 
-      if (cp.pf().is888())
+      if (server.pf().is888())
         os->copyBytes(is, palSize * 3);
       else
-        os->copyBytes(is, palSize * cp.pf().bpp/8);
+        os->copyBytes(is, palSize * server.pf().bpp/8);
       break;
     case tightFilterGradient:
-      if (cp.pf().bpp == 8)
+      if (server.pf().bpp == 8)
         throw Exception("TightDecoder: invalid BPP for gradient filter");
       break;
     case tightFilterCopy:
@@ -129,10 +129,10 @@
       rowSize = (r.width() + 7) / 8;
     else
       rowSize = r.width();
-  } else if (cp.pf().is888()) {
+  } else if (server.pf().is888()) {
     rowSize = r.width() * 3;
   } else {
-    rowSize = r.width() * cp.pf().bpp/8;
+    rowSize = r.width() * server.pf().bpp/8;
   }
 
   dataSize = r.height() * rowSize;
@@ -154,7 +154,7 @@
                                    const Rect& rectB,
                                    const void* bufferB,
                                    size_t buflenB,
-                                   const ConnParams& cp)
+                                   const ServerParams& server)
 {
   rdr::U8 comp_ctl_a, comp_ctl_b;
 
@@ -177,11 +177,11 @@
 }
 
 void TightDecoder::decodeRect(const Rect& r, const void* buffer,
-                              size_t buflen, const ConnParams& cp,
+                              size_t buflen, const ServerParams& server,
                               ModifiablePixelBuffer* pb)
 {
   const rdr::U8* bufptr;
-  const PixelFormat& pf = cp.pf();
+  const PixelFormat& pf = server.pf();
 
   rdr::U8 comp_ctl;
 
diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h
index 6eb93d2..28b6c30 100644
--- a/common/rfb/TightDecoder.h
+++ b/common/rfb/TightDecoder.h
@@ -32,16 +32,16 @@
     TightDecoder();
     virtual ~TightDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os);
+                          const ServerParams& server, rdr::OutStream* os);
     virtual bool doRectsConflict(const Rect& rectA,
                                  const void* bufferA,
                                  size_t buflenA,
                                  const Rect& rectB,
                                  const void* bufferB,
                                  size_t buflenB,
-                                 const ConnParams& cp);
+                                 const ServerParams& server);
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb);
 
   private:
diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx
index 0d428f1..1b0792c 100644
--- a/common/rfb/TightEncoder.cxx
+++ b/common/rfb/TightEncoder.cxx
@@ -23,7 +23,6 @@
 #include <rfb/PixelBuffer.h>
 #include <rfb/Palette.h>
 #include <rfb/encodings.h>
-#include <rfb/ConnParams.h>
 #include <rfb/SConnection.h>
 #include <rfb/TightEncoder.h>
 #include <rfb/TightConstants.h>
@@ -68,7 +67,7 @@
 
 bool TightEncoder::isSupported()
 {
-  return conn->cp.supportsEncoding(encodingTight);
+  return conn->client.supportsEncoding(encodingTight);
 }
 
 void TightEncoder::setCompressLevel(int level)
diff --git a/common/rfb/TightJPEGEncoder.cxx b/common/rfb/TightJPEGEncoder.cxx
index 38cb4eb..7557538 100644
--- a/common/rfb/TightJPEGEncoder.cxx
+++ b/common/rfb/TightJPEGEncoder.cxx
@@ -76,15 +76,15 @@
 
 bool TightJPEGEncoder::isSupported()
 {
-  if (!conn->cp.supportsEncoding(encodingTight))
+  if (!conn->client.supportsEncoding(encodingTight))
     return false;
 
   // Any one of these indicates support for JPEG
-  if (conn->cp.qualityLevel != -1)
+  if (conn->client.qualityLevel != -1)
     return true;
-  if (conn->cp.fineQualityLevel != -1)
+  if (conn->client.fineQualityLevel != -1)
     return true;
-  if (conn->cp.subsampling != -1)
+  if (conn->client.subsampling != -1)
     return true;
 
   // Tight support, but not JPEG
diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx
index b53b850..28e916d 100644
--- a/common/rfb/UpdateTracker.cxx
+++ b/common/rfb/UpdateTracker.cxx
@@ -60,32 +60,17 @@
 
 // SimpleUpdateTracker
 
-SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
-  copy_enabled = use_copyrect;
+SimpleUpdateTracker::SimpleUpdateTracker() {
 }
 
 SimpleUpdateTracker::~SimpleUpdateTracker() {
 }
 
-void SimpleUpdateTracker::enable_copyrect(bool enable) {
-  if (!enable && copy_enabled) {
-    add_changed(copied);
-    copied.clear();
-  }
-  copy_enabled=enable;
-}
-
 void SimpleUpdateTracker::add_changed(const Region &region) {
   changed.assign_union(region);
 }
 
 void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
-  // Do we support copyrect?
-  if (!copy_enabled) {
-    add_changed(dest);
-    return;
-  }
-
   // Is there anything to do?
   if (dest.is_empty()) return;
 
diff --git a/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h
index 8e96d55..8983b37 100644
--- a/common/rfb/UpdateTracker.h
+++ b/common/rfb/UpdateTracker.h
@@ -68,11 +68,9 @@
 
   class SimpleUpdateTracker : public UpdateTracker {
   public:
-    SimpleUpdateTracker(bool use_copyrect=true);
+    SimpleUpdateTracker();
     virtual ~SimpleUpdateTracker();
 
-    virtual void enable_copyrect(bool enable);
-
     virtual void add_changed(const Region &region);
     virtual void add_copied(const Region &dest, const Point &delta);
     virtual void subtract(const Region& region);
@@ -94,7 +92,6 @@
     Region changed;
     Region copied;
     Point copy_delta;
-    bool copy_enabled;
   };
 
 }
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index dbbf1d8..ea5c52a 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -49,7 +49,7 @@
     inProcessMessages(false),
     pendingSyncFence(false), syncFence(false), fenceFlags(0),
     fenceDataLen(0), fenceData(NULL), congestionTimer(this),
-    losslessTimer(this), server(server_), updates(false),
+    losslessTimer(this), server(server_),
     updateRenderedCursor(false), removeRenderedCursor(false),
     continuousUpdates(false), encodeManager(this), idleTimer(this),
     pointerEventTime(0), clientHasCursor(false)
@@ -199,9 +199,9 @@
 {
   try {
     if (!authenticated()) return;
-    if (cp.width && cp.height &&
-        (server->getPixelBuffer()->width() != cp.width ||
-         server->getPixelBuffer()->height() != cp.height))
+    if (client.width() && client.height() &&
+        (server->getPixelBuffer()->width() != client.width() ||
+         server->getPixelBuffer()->height() != client.height()))
     {
       // We need to clip the next update to the new size, but also add any
       // extra bits if it's bigger.  If we wanted to do this exactly, something
@@ -211,26 +211,24 @@
 
       //updates.intersect(server->pb->getRect());
       //
-      //if (server->pb->width() > cp.width)
-      //  updates.add_changed(Rect(cp.width, 0, server->pb->width(),
+      //if (server->pb->width() > client.width())
+      //  updates.add_changed(Rect(client.width(), 0, server->pb->width(),
       //                           server->pb->height()));
-      //if (server->pb->height() > cp.height)
-      //  updates.add_changed(Rect(0, cp.height, cp.width,
+      //if (server->pb->height() > client.height())
+      //  updates.add_changed(Rect(0, client.height(), client.width(),
       //                           server->pb->height()));
 
       damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());
 
-      cp.width = server->getPixelBuffer()->width();
-      cp.height = server->getPixelBuffer()->height();
-      cp.screenLayout = server->getScreenLayout();
+      client.setDimensions(server->getPixelBuffer()->width(),
+                           server->getPixelBuffer()->height(),
+                           server->getScreenLayout());
       if (state() == RFBSTATE_NORMAL) {
-        // We should only send EDS to client asking for both
-        if (!writer()->writeExtendedDesktopSize()) {
-          if (!writer()->writeSetDesktopSize()) {
-            close("Client does not support desktop resize");
-            return;
-          }
+        if (!client.supportsDesktopSize()) {
+          close("Client does not support desktop resize");
+          return;
         }
+        writer()->writeDesktopSize(reasonServer);
       }
 
       // Drop any lossy tracking that is now outside the framebuffer
@@ -325,7 +323,7 @@
   // We interpret a low compression level as an indication that the client
   // wants to prioritise CPU usage over bandwidth, and hence disable the
   // comparing update tracker.
-  return (cp.compressLevel == -1) || (cp.compressLevel > 1);
+  return (client.compressLevel == -1) || (client.compressLevel > 1);
 }
 
 
@@ -363,8 +361,7 @@
   if (state() != RFBSTATE_NORMAL)
     return false;
 
-  if (!cp.supportsLocalCursorWithAlpha &&
-      !cp.supportsLocalCursor && !cp.supportsLocalXCursor)
+  if (!client.supportsLocalCursor())
     return true;
   if (!server->getCursorPos().equals(pointerEventPos) &&
       (time(0) - pointerEventTime) > 0)
@@ -394,16 +391,16 @@
     idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
 
   // - Set the connection parameters appropriately
-  cp.width = server->getPixelBuffer()->width();
-  cp.height = server->getPixelBuffer()->height();
-  cp.screenLayout = server->getScreenLayout();
-  cp.setName(server->getName());
-  cp.setLEDState(server->getLEDState());
+  client.setDimensions(server->getPixelBuffer()->width(),
+                       server->getPixelBuffer()->height(),
+                       server->getScreenLayout());
+  client.setName(server->getName());
+  client.setLEDState(server->getLEDState());
   
   // - Set the default pixel format
-  cp.setPF(server->getPixelBuffer()->getPF());
+  client.setPF(server->getPixelBuffer()->getPF());
   char buffer[256];
-  cp.pf().print(buffer, 256);
+  client.pf().print(buffer, 256);
   vlog.info("Server default pixel format %s", buffer);
 
   // - Mark the entire display as "dirty"
@@ -492,7 +489,7 @@
 
   // Lock key heuristics
   // (only for clients that do not support the LED state extension)
-  if (!cp.supportsLEDState) {
+  if (!client.supportsLEDState()) {
     // Always ignore ScrollLock as we don't have a heuristic
     // for that
     if (keysym == XK_Scroll_Lock) {
@@ -597,10 +594,11 @@
   SConnection::framebufferUpdateRequest(r, incremental);
 
   // Check that the client isn't sending crappy requests
-  if (!r.enclosed_by(Rect(0, 0, cp.width, cp.height))) {
+  if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) {
     vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
-               r.width(), r.height(), r.tl.x, r.tl.y, cp.width, cp.height);
-    safeRect = r.intersect(Rect(0, 0, cp.width, cp.height));
+               r.width(), r.height(), r.tl.x, r.tl.y,
+               client.width(), client.height());
+    safeRect = r.intersect(Rect(0, 0, client.width(), client.height()));
   } else {
     safeRect = r;
   }
@@ -617,7 +615,8 @@
 
     // And send the screen layout to the client (which, unlike the
     // framebuffer dimensions, the client doesn't get during init)
-    writer()->writeExtendedDesktopSize();
+    if (client.supportsEncoding(pseudoEncodingExtendedDesktopSize))
+      writer()->writeDesktopSize(reasonServer);
 
     // We do not send a DesktopSize since it only contains the
     // framebuffer size (which the client already should know) and
@@ -635,8 +634,7 @@
   if (!rfb::Server::acceptSetDesktopSize) return;
 
   result = server->setDesktopSize(this, fb_width, fb_height, layout);
-  writer()->writeExtendedDesktopSize(reasonClient, result,
-                                     fb_width, fb_height, layout);
+  writer()->writeDesktopSize(reasonClient, result);
 }
 
 void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
@@ -688,7 +686,7 @@
 {
   Rect rect;
 
-  if (!cp.supportsFence || !cp.supportsContinuousUpdates)
+  if (!client.supportsFence() || !client.supportsContinuousUpdates())
     throw Exception("Client tried to enable continuous updates when not allowed");
 
   continuousUpdates = enable;
@@ -704,7 +702,7 @@
 }
 
 // supportsLocalCursor() is called whenever the status of
-// cp.supportsLocalCursor has changed.  If the client does now support local
+// client.supportsLocalCursor() has changed.  If the client does now support local
 // cursor, we make sure that the old server-side rendered cursor is cleaned up
 // and the cursor is sent to the client.
 
@@ -726,7 +724,7 @@
 {
   // We refuse to use continuous updates if we cannot monitor the buffer
   // usage using fences.
-  if (!cp.supportsFence)
+  if (!client.supportsFence())
     return;
 
   writer()->writeEndOfContinuousUpdates();
@@ -734,6 +732,9 @@
 
 void VNCSConnectionST::supportsLEDState()
 {
+  if (client.ledState() == ledUnknown)
+    return;
+
   writer()->writeLEDState();
 }
 
@@ -772,7 +773,7 @@
 {
   char type;
 
-  if (!cp.supportsFence)
+  if (!client.supportsFence())
     return;
 
   congestion.updatePosition(sock->outStream().length());
@@ -799,7 +800,7 @@
   if (sock->outStream().bufferUsage() > 0)
     return true;
 
-  if (!cp.supportsFence)
+  if (!client.supportsFence())
     return false;
 
   congestion.updatePosition(sock->outStream().length());
@@ -876,8 +877,6 @@
   bool needNewUpdateInfo;
   const RenderedCursor *cursor;
 
-  updates.enable_copyrect(cp.useCopyRect);
-
   // See what the client has requested (if anything)
   if (continuousUpdates)
     req = cuRegion.union_(requested);
@@ -1063,13 +1062,13 @@
   if (!authenticated())
     return;
 
-  cp.screenLayout = server->getScreenLayout();
+  client.setDimensions(client.width(), client.height(),
+                       server->getScreenLayout());
 
   if (state() != RFBSTATE_NORMAL)
     return;
 
-  writer()->writeExtendedDesktopSize(reason, 0, cp.width, cp.height,
-                                     cp.screenLayout);
+  writer()->writeDesktopSize(reason);
 }
 
 
@@ -1084,34 +1083,26 @@
 
   // We need to blank out the client's cursor or there will be two
   if (needRenderedCursor()) {
-    cp.setCursor(emptyCursor);
+    client.setCursor(emptyCursor);
     clientHasCursor = false;
   } else {
-    cp.setCursor(*server->getCursor());
+    client.setCursor(*server->getCursor());
     clientHasCursor = true;
   }
 
-  if (!writer()->writeSetCursorWithAlpha()) {
-    if (!writer()->writeSetCursor()) {
-      if (!writer()->writeSetXCursor()) {
-        // No client support
-        return;
-      }
-    }
-  }
+  if (client.supportsLocalCursor())
+    writer()->writeCursor();
 }
 
 void VNCSConnectionST::setDesktopName(const char *name)
 {
-  cp.setName(name);
+  client.setName(name);
 
   if (state() != RFBSTATE_NORMAL)
     return;
 
-  if (!writer()->writeSetDesktopName()) {
-    fprintf(stderr, "Client does not support desktop rename\n");
-    return;
-  }
+  if (client.supportsEncoding(pseudoEncodingDesktopName))
+    writer()->writeSetDesktopName();
 }
 
 void VNCSConnectionST::setLEDState(unsigned int ledstate)
@@ -1119,9 +1110,10 @@
   if (state() != RFBSTATE_NORMAL)
     return;
 
-  cp.setLEDState(ledstate);
+  client.setLEDState(ledstate);
 
-  writer()->writeLEDState();
+  if (client.supportsLEDState())
+    writer()->writeLEDState();
 }
 
 void VNCSConnectionST::setSocketTimeouts()
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 40580b1..c95c14f 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -255,8 +255,6 @@
   delete comparer;
   comparer = 0;
 
-  screenLayout = layout;
-
   if (!pb) {
     screenLayout = ScreenSet();
 
@@ -266,16 +264,17 @@
     return;
   }
 
+  if (!layout.validate(pb->width(), pb->height()))
+    throw Exception("setPixelBuffer: invalid screen layout");
+
+  screenLayout = layout;
+
   // Assume the framebuffer contents wasn't saved and reset everything
   // that tracks its contents
   comparer = new ComparingUpdateTracker(pb);
   renderedCursorInvalid = true;
   add_changed(pb->getRect());
 
-  // Make sure that we have at least one screen
-  if (screenLayout.num_screens() == 0)
-    screenLayout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));
-
   std::list<VNCSConnectionST*>::iterator ci, ci_next;
   for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
     ci_next = ci; ci_next++;
@@ -309,6 +308,10 @@
     }
   }
 
+  // Make sure that we have at least one screen
+  if (layout.num_screens() == 0)
+    layout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));
+
   setPixelBuffer(pb_, layout);
 }
 
diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx
index 1dfb72a..9d1ff6b 100644
--- a/common/rfb/ZRLEDecoder.cxx
+++ b/common/rfb/ZRLEDecoder.cxx
@@ -21,7 +21,7 @@
 #include <rdr/MemInStream.h>
 #include <rdr/OutStream.h>
 
-#include <rfb/ConnParams.h>
+#include <rfb/ServerParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/ZRLEDecoder.h>
 
@@ -72,7 +72,7 @@
 }
 
 void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is,
-                           const ConnParams& cp, rdr::OutStream* os)
+                           const ServerParams& server, rdr::OutStream* os)
 {
   rdr::U32 len;
 
@@ -82,11 +82,11 @@
 }
 
 void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer,
-                             size_t buflen, const ConnParams& cp,
+                             size_t buflen, const ServerParams& server,
                              ModifiablePixelBuffer* pb)
 {
   rdr::MemInStream is(buffer, buflen);
-  const rfb::PixelFormat& pf = cp.pf();
+  const rfb::PixelFormat& pf = server.pf();
   switch (pf.bpp) {
   case 8:  zrleDecode8 (r, &is, &zis, pf, pb); break;
   case 16: zrleDecode16(r, &is, &zis, pf, pb); break;
diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h
index 1e33851..a530586 100644
--- a/common/rfb/ZRLEDecoder.h
+++ b/common/rfb/ZRLEDecoder.h
@@ -28,9 +28,9 @@
     ZRLEDecoder();
     virtual ~ZRLEDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, rdr::OutStream* os);
+                          const ServerParams& server, rdr::OutStream* os);
     virtual void decodeRect(const Rect& r, const void* buffer,
-                            size_t buflen, const ConnParams& cp,
+                            size_t buflen, const ServerParams& server,
                             ModifiablePixelBuffer* pb);
   private:
     rdr::ZlibInStream zis;
diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx
index 8917d8f..92fd13d 100644
--- a/common/rfb/ZRLEEncoder.cxx
+++ b/common/rfb/ZRLEEncoder.cxx
@@ -19,7 +19,6 @@
 #include <rdr/OutStream.h>
 #include <rfb/Exception.h>
 #include <rfb/encodings.h>
-#include <rfb/ConnParams.h>
 #include <rfb/Palette.h>
 #include <rfb/SConnection.h>
 #include <rfb/ZRLEEncoder.h>
@@ -43,7 +42,7 @@
 
 bool ZRLEEncoder::isSupported()
 {
-  return conn->cp.supportsEncoding(encodingZRLE);
+  return conn->client.supportsEncoding(encodingZRLE);
 }
 
 void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
diff --git a/tests/decperf.cxx b/tests/decperf.cxx
index 9061cb5..301e45e 100644
--- a/tests/decperf.cxx
+++ b/tests/decperf.cxx
@@ -47,7 +47,7 @@
   CConn(const char *filename);
   ~CConn();
 
-  virtual void setDesktopSize(int w, int h);
+  virtual void initDone();
   virtual void setPixelFormat(const rfb::PixelFormat& pf);
   virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
   virtual void framebufferUpdateStart();
@@ -81,11 +81,11 @@
   delete in;
 }
 
-void CConn::setDesktopSize(int w, int h)
+void CConn::initDone()
 {
-  CConnection::setDesktopSize(w, h);
-
-  setFramebuffer(new rfb::ManagedPixelBuffer(filePF, cp.width, cp.height));
+  setFramebuffer(new rfb::ManagedPixelBuffer(filePF,
+                                             server.width(),
+                                             server.height()));
 }
 
 void CConn::setPixelFormat(const rfb::PixelFormat& pf)
diff --git a/tests/encperf.cxx b/tests/encperf.cxx
index 733d55b..6523eb7 100644
--- a/tests/encperf.cxx
+++ b/tests/encperf.cxx
@@ -89,7 +89,7 @@
   void getStats(double& ratio, unsigned long long& bytes,
                 unsigned long long& rawEquivalent);
 
-  virtual void setDesktopSize(int w, int h);
+  virtual void initDone();
   virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
   virtual void framebufferUpdateStart();
   virtual void framebufferUpdateEnd();
@@ -180,7 +180,7 @@
   setDesktopSize(width, height);
 
   sc = new SConn();
-  sc->cp.setPF((bool)translate ? fbPF : pf);
+  sc->client.setPF((bool)translate ? fbPF : pf);
   sc->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings);
 }
 
@@ -196,14 +196,12 @@
   sc->getStats(ratio, bytes, rawEquivalent);
 }
 
-void CConn::setDesktopSize(int w, int h)
+void CConn::initDone()
 {
   rfb::ModifiablePixelBuffer *pb;
 
-  CConnection::setDesktopSize(w, h);
-
-  pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : cp.pf(),
-                                   cp.width, cp.height);
+  pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : server.pf(),
+                                   server.width(), server.height());
   setFramebuffer(pb);
 }
 
@@ -290,7 +288,7 @@
   out = new DummyOutStream;
   setStreams(NULL, out);
 
-  setWriter(new rfb::SMsgWriter(&cp, out));
+  setWriter(new rfb::SMsgWriter(&client, out));
 
   manager = new Manager(this);
 }
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index 1fdc9e2..564b2d5 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -423,8 +423,27 @@
 
   layout = ::computeScreenLayout(&outputIdMap);
   XRRFreeScreenResources(res);
+
+  // Adjust the layout relative to the geometry
+  ScreenSet::iterator iter, iter_next;
+  Point offset(-geometry->offsetLeft(), -geometry->offsetTop());
+  for (iter = layout.begin();iter != layout.end();iter = iter_next) {
+    iter_next = iter; ++iter_next;
+    iter->dimensions = iter->dimensions.translate(offset);
+    if (iter->dimensions.enclosed_by(geometry->getRect()))
+        continue;
+    iter->dimensions = iter->dimensions.intersect(geometry->getRect());
+    if (iter->dimensions.is_empty()) {
+      layout.remove_screen(iter->id);
+    }
+  }
 #endif
 
+  // Make sure that we have at least one screen
+  if (layout.num_screens() == 0)
+    layout.add_screen(rfb::Screen(0, 0, 0, geometry->width(),
+                                  geometry->height(), 0));
+
   return layout;
 }
 
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 69186c5..b4610e6 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -36,8 +36,6 @@
 #include <rfb/screenTypes.h>
 #include <rfb/fenceTypes.h>
 #include <rfb/Timer.h>
-#include <rdr/MemInStream.h>
-#include <rdr/MemOutStream.h>
 #include <network/TcpSocket.h>
 #ifndef WIN32
 #include <network/UnixSocket.h>
@@ -76,36 +74,21 @@
 
 CConn::CConn(const char* vncServerName, network::Socket* socket=NULL)
   : serverHost(0), serverPort(0), desktop(NULL),
-    updateCount(0), pixelCount(0), pendingPFChange(false),
-    currentEncoding(encodingTight), lastServerEncoding((unsigned int)-1),
-    formatChange(false), encodingChange(false),
-    firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
-    forceNonincremental(true), supportsSyncFence(false)
+    updateCount(0), pixelCount(0),
+    lastServerEncoding((unsigned int)-1)
 {
   setShared(::shared);
   sock = socket;
 
-  int encNum = encodingNum(preferredEncoding);
-  if (encNum != -1)
-    currentEncoding = encNum;
-
-  cp.supportsLocalCursor = true;
-
-  cp.supportsDesktopResize = true;
-  cp.supportsExtendedDesktopSize = true;
-  cp.supportsDesktopRename = true;
-
-  cp.supportsLEDState = true;
+  supportsLocalCursor = true;
+  supportsDesktopResize = true;
+  supportsLEDState = true;
 
   if (customCompressLevel)
-    cp.compressLevel = compressLevel;
-  else
-    cp.compressLevel = -1;
+    setCompressLevel(::compressLevel);
 
   if (!noJpeg)
-    cp.qualityLevel = qualityLevel;
-  else
-    cp.qualityLevel = -1;
+    setQualityLevel(::qualityLevel);
 
   if(sock == NULL) {
     try {
@@ -158,16 +141,6 @@
   delete sock;
 }
 
-void CConn::refreshFramebuffer()
-{
-  forceNonincremental = true;
-
-  // Without fences, we cannot safely trigger an update request directly
-  // but must wait for the next update to arrive.
-  if (supportsSyncFence)
-    requestNewUpdate();
-}
-
 const char *CConn::connectionInfo()
 {
   static char infoText[1024] = "";
@@ -181,7 +154,7 @@
   infoText[0] = '\0';
 
   snprintf(scratch, sizeof(scratch),
-           _("Desktop name: %.80s"), cp.name());
+           _("Desktop name: %.80s"), server.name());
   strcat(infoText, scratch);
   strcat(infoText, "\n");
 
@@ -191,13 +164,13 @@
   strcat(infoText, "\n");
 
   snprintf(scratch, sizeof(scratch),
-           _("Size: %d x %d"), cp.width, cp.height);
+           _("Size: %d x %d"), server.width(), server.height());
   strcat(infoText, scratch);
   strcat(infoText, "\n");
 
   // TRANSLATORS: Will be filled in with a string describing the
   // protocol pixel format in a fairly language neutral way
-  cp.pf().print(pfStr, 100);
+  server.pf().print(pfStr, 100);
   snprintf(scratch, sizeof(scratch),
            _("Pixel format: %s"), pfStr);
   strcat(infoText, scratch);
@@ -211,7 +184,7 @@
   strcat(infoText, "\n");
 
   snprintf(scratch, sizeof(scratch),
-           _("Requested encoding: %s"), encodingName(currentEncoding));
+           _("Requested encoding: %s"), encodingName(getPreferredEncoding()));
   strcat(infoText, scratch);
   strcat(infoText, "\n");
 
@@ -226,7 +199,7 @@
   strcat(infoText, "\n");
 
   snprintf(scratch, sizeof(scratch),
-           _("Protocol version: %d.%d"), cp.majorVersion, cp.minorVersion);
+           _("Protocol version: %d.%d"), server.majorVersion, server.minorVersion);
   strcat(infoText, scratch);
   strcat(infoText, "\n");
 
@@ -310,34 +283,27 @@
 
 ////////////////////// CConnection callback methods //////////////////////
 
-// serverInit() is called when the serverInit message has been received.  At
+// initDone() is called when the serverInit message has been received.  At
 // this point we create the desktop window and display it.  We also tell the
 // server the pixel format and encodings to use and request the first update.
-void CConn::serverInit()
+void CConn::initDone()
 {
-  CConnection::serverInit();
-
   // If using AutoSelect with old servers, start in FullColor
   // mode. See comment in autoSelectFormatAndEncoding. 
-  if (cp.beforeVersion(3, 8) && autoSelect)
+  if (server.beforeVersion(3, 8) && autoSelect)
     fullColour.setParam(true);
 
-  serverPF = cp.pf();
+  serverPF = server.pf();
 
-  desktop = new DesktopWindow(cp.width, cp.height, cp.name(), serverPF, this);
+  desktop = new DesktopWindow(server.width(), server.height(),
+                              server.name(), serverPF, this);
   fullColourPF = desktop->getPreferredPF();
 
   // Force a switch to the format and encoding we'd like
-  formatChange = encodingChange = true;
-
-  // And kick off the update cycle
-  requestNewUpdate();
-
-  // This initial update request is a bit of a corner case, so we need
-  // to help out setting the correct format here.
-  assert(pendingPFChange);
-  cp.setPF(pendingPF);
-  pendingPFChange = false;
+  updatePixelFormat();
+  int encNum = encodingNum(::preferredEncoding);
+  if (encNum != -1)
+    setPreferredEncoding(encNum);
 }
 
 // setDesktopSize() is called when the desktop size changes (including when
@@ -366,8 +332,7 @@
 void CConn::setName(const char* name)
 {
   CConnection::setName(name);
-  if (desktop)
-    desktop->setName(name);
+  desktop->setName(name);
 }
 
 // framebufferUpdateStart() is called at the beginning of an update.
@@ -378,11 +343,6 @@
 {
   CConnection::framebufferUpdateStart();
 
-  // Note: This might not be true if sync fences are supported
-  pendingUpdate = false;
-
-  requestNewUpdate();
-
   // Update the screen prematurely for very slow updates
   Fl::add_timeout(1.0, handleUpdateTimeout, this);
 }
@@ -400,22 +360,6 @@
   Fl::remove_timeout(handleUpdateTimeout, this);
   desktop->updateWindow();
 
-  if (firstUpdate) {
-    // We need fences to make extra update requests and continuous
-    // updates "safe". See fence() for the next step.
-    if (cp.supportsFence)
-      writer()->writeFence(fenceFlagRequest | fenceFlagSyncNext, 0, NULL);
-
-    firstUpdate = false;
-  }
-
-  // A format change has been scheduled and we are now past the update
-  // with the old format. Time to active the new one.
-  if (pendingPFChange) {
-    cp.setPF(pendingPF);
-    pendingPFChange = false;
-  }
-
   // Compute new settings based on updated bandwidth values
   if (autoSelect)
     autoSelectFormatAndEncoding();
@@ -469,27 +413,6 @@
     writer()->writeFence(flags, len, data);
     return;
   }
-
-  if (len == 0) {
-    // Initial probe
-    if (flags & fenceFlagSyncNext) {
-      supportsSyncFence = true;
-
-      if (cp.supportsContinuousUpdates) {
-        vlog.info(_("Enabling continuous updates"));
-        continuousUpdates = true;
-        writer()->writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);
-      }
-    }
-  } else {
-    // Pixel format change
-    rdr::MemInStream memStream(data, len);
-    PixelFormat pf;
-
-    pf.read(&memStream);
-
-    cp.setPF(pf);
-  }
 }
 
 void CConn::setLEDState(unsigned int state)
@@ -504,13 +427,7 @@
 
 void CConn::resizeFramebuffer()
 {
-  if (!desktop)
-    return;
-
-  if (continuousUpdates)
-    writer()->writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);
-
-  desktop->resizeFramebuffer(cp.width, cp.height);
+  desktop->resizeFramebuffer(server.width(), server.height());
 }
 
 // autoSelectFormatAndEncoding() chooses the format and encoding appropriate
@@ -533,13 +450,10 @@
   int kbitsPerSecond = sock->inStream().kbitsPerSecond();
   unsigned int timeWaited = sock->inStream().timeWaited();
   bool newFullColour = fullColour;
-  int newQualityLevel = qualityLevel;
+  int newQualityLevel = ::qualityLevel;
 
   // Always use Tight
-  if (currentEncoding != encodingTight) {
-    currentEncoding = encodingTight;
-    encodingChange = true;
-  }
+  setPreferredEncoding(encodingTight);
 
   // Check that we have a decent bandwidth measurement
   if ((kbitsPerSecond == 0) || (timeWaited < 10000))
@@ -552,16 +466,15 @@
     else
       newQualityLevel = 6;
 
-    if (newQualityLevel != qualityLevel) {
+    if (newQualityLevel != ::qualityLevel) {
       vlog.info(_("Throughput %d kbit/s - changing to quality %d"),
                 kbitsPerSecond, newQualityLevel);
-      cp.qualityLevel = newQualityLevel;
-      qualityLevel.setParam(newQualityLevel);
-      encodingChange = true;
+      ::qualityLevel.setParam(newQualityLevel);
+      setQualityLevel(newQualityLevel);
     }
   }
 
-  if (cp.beforeVersion(3, 8)) {
+  if (server.beforeVersion(3, 8)) {
     // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
     // cursors "asynchronously". If this happens in the middle of a
     // pixel format change, the server will encode the cursor with
@@ -582,76 +495,31 @@
       vlog.info(_("Throughput %d kbit/s - full color is now disabled"),
                 kbitsPerSecond);
     fullColour.setParam(newFullColour);
-    formatChange = true;
+    updatePixelFormat();
   } 
 }
 
-// checkEncodings() sends a setEncodings message if one is needed.
-void CConn::checkEncodings()
-{
-  if (encodingChange && writer()) {
-    vlog.info(_("Using %s encoding"),encodingName(currentEncoding));
-    writer()->writeSetEncodings(currentEncoding, true);
-    encodingChange = false;
-  }
-}
-
 // requestNewUpdate() requests an update from the server, having set the
 // format and encoding appropriately.
-void CConn::requestNewUpdate()
+void CConn::updatePixelFormat()
 {
-  if (formatChange) {
-    PixelFormat pf;
+  PixelFormat pf;
 
-    /* Catch incorrect requestNewUpdate calls */
-    assert(!pendingUpdate || supportsSyncFence);
-
-    if (fullColour) {
-      pf = fullColourPF;
-    } else {
-      if (lowColourLevel == 0)
-        pf = verylowColourPF;
-      else if (lowColourLevel == 1)
-        pf = lowColourPF;
-      else
-        pf = mediumColourPF;
-    }
-
-    if (supportsSyncFence) {
-      // We let the fence carry the pixel format and switch once we
-      // get the response back. That way we will be synchronised with
-      // when the server switches.
-      rdr::MemOutStream memStream;
-
-      pf.write(&memStream);
-
-      writer()->writeFence(fenceFlagRequest | fenceFlagSyncNext,
-                           memStream.length(), (const char*)memStream.data());
-    } else {
-      // New requests are sent out at the start of processing the last
-      // one, so we cannot switch our internal format right now (doing so
-      // would mean misdecoding the current update).
-      pendingPFChange = true;
-      pendingPF = pf;
-    }
-
-    char str[256];
-    pf.print(str, 256);
-    vlog.info(_("Using pixel format %s"),str);
-    writer()->writeSetPixelFormat(pf);
-
-    formatChange = false;
+  if (fullColour) {
+    pf = fullColourPF;
+  } else {
+    if (lowColourLevel == 0)
+      pf = verylowColourPF;
+    else if (lowColourLevel == 1)
+      pf = lowColourPF;
+    else
+      pf = mediumColourPF;
   }
 
-  checkEncodings();
-
-  if (forceNonincremental || !continuousUpdates) {
-    pendingUpdate = true;
-    writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
-                                            !forceNonincremental);
-  }
- 
-  forceNonincremental = false;
+  char str[256];
+  pf.print(str, 256);
+  vlog.info(_("Using pixel format %s"),str);
+  setPF(pf);
 }
 
 void CConn::handleOptions(void *data)
@@ -663,50 +531,23 @@
   // list is cheap. Avoid overriding what the auto logic has selected
   // though.
   if (!autoSelect) {
-    int encNum = encodingNum(preferredEncoding);
+    int encNum = encodingNum(::preferredEncoding);
 
     if (encNum != -1)
-      self->currentEncoding = encNum;
+      self->setPreferredEncoding(encNum);
   }
 
-  self->cp.supportsLocalCursor = true;
-
   if (customCompressLevel)
-    self->cp.compressLevel = compressLevel;
+    self->setCompressLevel(::compressLevel);
   else
-    self->cp.compressLevel = -1;
+    self->setCompressLevel(-1);
 
   if (!noJpeg && !autoSelect)
-    self->cp.qualityLevel = qualityLevel;
+    self->setQualityLevel(::qualityLevel);
   else
-    self->cp.qualityLevel = -1;
+    self->setQualityLevel(-1);
 
-  self->encodingChange = true;
-
-  // Format changes refreshes the entire screen though and are therefore
-  // very costly. It's probably worth the effort to see if it is necessary
-  // here.
-  PixelFormat pf;
-
-  if (fullColour) {
-    pf = self->fullColourPF;
-  } else {
-    if (lowColourLevel == 0)
-      pf = verylowColourPF;
-    else if (lowColourLevel == 1)
-      pf = lowColourPF;
-    else
-      pf = mediumColourPF;
-  }
-
-  if (!pf.equal(self->cp.pf())) {
-    self->formatChange = true;
-
-    // Without fences, we cannot safely trigger an update request directly
-    // but must wait for the next update to arrive.
-    if (self->supportsSyncFence)
-      self->requestNewUpdate();
-  }
+  self->updatePixelFormat();
 }
 
 void CConn::handleUpdateTimeout(void *data)
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index dd4ae89..2e3362c 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -36,8 +36,6 @@
   CConn(const char* vncServerName, network::Socket* sock);
   ~CConn();
 
-  void refreshFramebuffer();
-
   const char *connectionInfo();
 
   unsigned getUpdateCount();
@@ -51,7 +49,7 @@
   static void socketEvent(FL_SOCKET fd, void *data);
 
   // CConnection callback methods
-  void serverInit();
+  void initDone();
 
   void setDesktopSize(int w, int h);
   void setExtendedDesktopSize(unsigned reason, unsigned result,
@@ -81,8 +79,7 @@
   void resizeFramebuffer();
 
   void autoSelectFormatAndEncoding();
-  void checkEncodings();
-  void requestNewUpdate();
+  void updatePixelFormat();
 
   static void handleOptions(void *data);
 
@@ -101,21 +98,7 @@
   rfb::PixelFormat serverPF;
   rfb::PixelFormat fullColourPF;
 
-  bool pendingPFChange;
-  rfb::PixelFormat pendingPF;
-
-  int currentEncoding, lastServerEncoding;
-
-  bool formatChange;
-  bool encodingChange;
-
-  bool firstUpdate;
-  bool pendingUpdate;
-  bool continuousUpdates;
-
-  bool forceNonincremental;
-
-  bool supportsSyncFence;
+  int lastServerEncoding;
 };
 
 #endif
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 1843485..150c39b 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -235,7 +235,7 @@
 void DesktopWindow::updateWindow()
 {
   if (firstUpdate) {
-    if (cc->cp.supportsSetDesktopSize) {
+    if (cc->server.supportsSetDesktopSize) {
       // Hack: Wait until we're in the proper mode and position until
       // resizing things, otherwise we might send the wrong thing.
       if (delayedFullscreen)
@@ -487,7 +487,7 @@
     // d) We're not still waiting for startup fullscreen to kick in
     //
     if (not firstUpdate and not delayedFullscreen and
-        ::remoteResize and cc->cp.supportsSetDesktopSize) {
+        ::remoteResize and cc->server.supportsSetDesktopSize) {
       // We delay updating the remote desktop as we tend to get a flood
       // of resize events as the user is dragging the window.
       Fl::remove_timeout(handleResizeTimeout, this);
@@ -1014,14 +1014,14 @@
 void DesktopWindow::remoteResize(int width, int height)
 {
   ScreenSet layout;
-  ScreenSet::iterator iter;
+  ScreenSet::const_iterator iter;
 
   if (!fullscreen_active() || (width > w()) || (height > h())) {
     // In windowed mode (or the framebuffer is so large that we need
     // to scroll) we just report a single virtual screen that covers
     // the entire framebuffer.
 
-    layout = cc->cp.screenLayout;
+    layout = cc->server.screenLayout();
 
     // Not sure why we have no screens, but adding a new one should be
     // safe as there is nothing to conflict with...
@@ -1077,8 +1077,8 @@
       sy -= viewport_rect.tl.y;
 
       // Look for perfectly matching existing screen...
-      for (iter = cc->cp.screenLayout.begin();
-           iter != cc->cp.screenLayout.end(); ++iter) {
+      for (iter = cc->server.screenLayout().begin();
+           iter != cc->server.screenLayout().end(); ++iter) {
         if ((iter->dimensions.tl.x == sx) &&
             (iter->dimensions.tl.y == sy) &&
             (iter->dimensions.width() == sw) &&
@@ -1087,7 +1087,7 @@
       }
 
       // Found it?
-      if (iter != cc->cp.screenLayout.end()) {
+      if (iter != cc->server.screenLayout().end()) {
         layout.add_screen(*iter);
         continue;
       }
@@ -1095,13 +1095,13 @@
       // Need to add a new one, which means we need to find an unused id
       while (true) {
         id = rand();
-        for (iter = cc->cp.screenLayout.begin();
-             iter != cc->cp.screenLayout.end(); ++iter) {
+        for (iter = cc->server.screenLayout().begin();
+             iter != cc->server.screenLayout().end(); ++iter) {
           if (iter->id == id)
             break;
         }
 
-        if (iter == cc->cp.screenLayout.end())
+        if (iter == cc->server.screenLayout().end())
           break;
       }
 
@@ -1115,14 +1115,14 @@
   }
 
   // Do we actually change anything?
-  if ((width == cc->cp.width) &&
-      (height == cc->cp.height) &&
-      (layout == cc->cp.screenLayout))
+  if ((width == cc->server.width()) &&
+      (height == cc->server.height()) &&
+      (layout == cc->server.screenLayout()))
     return;
 
   char buffer[2048];
   vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d",
-             cc->cp.width, cc->cp.height, width, height);
+             cc->server.width(), cc->server.height(), width, height);
   layout.print(buffer, sizeof(buffer));
   vlog.debug("%s", buffer);
 
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 18ed69e..425cb9f 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -425,7 +425,7 @@
   unsigned int state;
 
   // Server support?
-  if (cc->cp.ledState() == ledUnknown)
+  if (cc->server.ledState() == ledUnknown)
     return;
 
   state = 0;
@@ -458,7 +458,7 @@
     state |= ledNumLock;
 
   // No support for Scroll Lock //
-  state |= (cc->cp.ledState() & ledScrollLock);
+  state |= (cc->server.ledState() & ledScrollLock);
 
 #else
   unsigned int mask;
@@ -484,17 +484,17 @@
     state |= ledScrollLock;
 #endif
 
-  if ((state & ledCapsLock) != (cc->cp.ledState() & ledCapsLock)) {
+  if ((state & ledCapsLock) != (cc->server.ledState() & ledCapsLock)) {
     vlog.debug("Inserting fake CapsLock to get in sync with server");
     handleKeyPress(0x3a, XK_Caps_Lock);
     handleKeyRelease(0x3a);
   }
-  if ((state & ledNumLock) != (cc->cp.ledState() & ledNumLock)) {
+  if ((state & ledNumLock) != (cc->server.ledState() & ledNumLock)) {
     vlog.debug("Inserting fake NumLock to get in sync with server");
     handleKeyPress(0x45, XK_Num_Lock);
     handleKeyRelease(0x45);
   }
-  if ((state & ledScrollLock) != (cc->cp.ledState() & ledScrollLock)) {
+  if ((state & ledScrollLock) != (cc->server.ledState() & ledScrollLock)) {
     vlog.debug("Inserting fake ScrollLock to get in sync with server");
     handleKeyPress(0x46, XK_Scroll_Lock);
     handleKeyRelease(0x46);