Use PixelBuffer objects as the interface for encoders and decoders

This avoid a lot of unnecessary middle men. This also pushes the
responsibility for pixel format conversion into the encoders and
decoders. The new bufferFromBuffer() is used for direct conversion,
rather than PixelTransformer/TransImageGetter.
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index 8b58e0e..8e3c84e 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -66,15 +66,6 @@
     virtual void bell() = 0;
     virtual void serverCutText(const char* str, rdr::U32 len) = 0;
 
-    virtual void fillRect(const Rect& r, Pixel pix) = 0;
-    virtual void imageRect(const Rect& r, void* pixels) = 0;
-    virtual void copyRect(const Rect& r, int srcX, int srcY) = 0;
-
-    virtual rdr::U8* getRawBufferRW(const Rect& r, int* stride) = 0;
-    virtual void releaseRawBuffer(const Rect& r) = 0;
-
-    virtual const PixelFormat &getPreferredPF(void) = 0;
-
     ConnParams cp;
   };
 }
diff --git a/common/rfb/CopyRectDecoder.cxx b/common/rfb/CopyRectDecoder.cxx
index bb3084f..4b10418 100644
--- a/common/rfb/CopyRectDecoder.cxx
+++ b/common/rfb/CopyRectDecoder.cxx
@@ -17,7 +17,6 @@
  */
 #include <rdr/InStream.h>
 #include <rfb/CConnection.h>
-#include <rfb/CMsgHandler.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/CopyRectDecoder.h>
 
@@ -31,9 +30,9 @@
 {
 }
 
-void CopyRectDecoder::readRect(const Rect& r, CMsgHandler* handler)
+void CopyRectDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb)
 {
   int srcX = conn->getInStream()->readU16();
   int srcY = conn->getInStream()->readU16();
-  handler->copyRect(r, srcX, srcY);
+  pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
 }
diff --git a/common/rfb/CopyRectDecoder.h b/common/rfb/CopyRectDecoder.h
index 5932066..d14bf92 100644
--- a/common/rfb/CopyRectDecoder.h
+++ b/common/rfb/CopyRectDecoder.h
@@ -26,7 +26,7 @@
   public:
     CopyRectDecoder(CConnection* conn);
     virtual ~CopyRectDecoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb);
   };
 }
 #endif
diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h
index 870fa80..ff67f57 100644
--- a/common/rfb/Decoder.h
+++ b/common/rfb/Decoder.h
@@ -23,13 +23,19 @@
 
 namespace rfb {
   class CConnection;
-  class CMsgHandler;
+  class ModifiablePixelBuffer;
 
   class Decoder {
   public:
     Decoder(CConnection* conn);
     virtual ~Decoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler)=0;
+
+    // readRect() is the main interface that decodes the given rectangle
+    // with data from the CConnection, given at decoder creation, 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 readRect(const Rect& r, ModifiablePixelBuffer* pb)=0;
 
     static bool supported(int encoding);
     static Decoder* createDecoder(int encoding, CConnection* conn);
diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h
index 2897f9f..aeeb5c3 100644
--- a/common/rfb/Encoder.h
+++ b/common/rfb/Encoder.h
@@ -21,11 +21,10 @@
 #define __RFB_ENCODER_H__
 
 #include <rfb/Rect.h>
-#include <rfb/TransImageGetter.h>
 
 namespace rfb {
   class SConnection;
-  class TransImageGetter;
+  class PixelBuffer;
 
   class Encoder {
   public:
@@ -38,9 +37,11 @@
     virtual int getNumRects(const Rect &r) { return 1; }
 
     // writeRect() is the main interface that encodes the given rectangle
-    // with data from the ImageGetter onto the SMsgWriter given at
-    // encoder creation.
-    virtual void writeRect(const Rect& r, TransImageGetter* ig)=0;
+    // with data from the PixelBuffer onto the SConnection given at
+    // encoder creation. The PixelFormat of the PixelBuffer might not
+    // match the ConnParams and it is up ot the encoder to do
+    // any necessary conversion.
+    virtual void writeRect(const Rect& r, PixelBuffer* pb)=0;
 
     static bool supported(int encoding);
     static Encoder* createEncoder(int encoding, SConnection* conn);
diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx
index 9b335fe..8b18b7b 100644
--- a/common/rfb/HextileDecoder.cxx
+++ b/common/rfb/HextileDecoder.cxx
@@ -17,7 +17,7 @@
  */
 #include <rfb/CMsgReader.h>
 #include <rfb/CConnection.h>
-#include <rfb/CMsgHandler.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/HextileDecoder.h>
 
 using namespace rfb;
@@ -40,13 +40,14 @@
 {
 }
 
-void HextileDecoder::readRect(const Rect& r, CMsgHandler* handler)
+void HextileDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb)
 {
   rdr::InStream* is = conn->getInStream();
   rdr::U8* buf = conn->reader()->getImageBuf(16 * 16 * 4);
-  switch (conn->cp.pf().bpp) {
-  case 8:  hextileDecode8 (r, is, (rdr::U8*) buf, handler); break;
-  case 16: hextileDecode16(r, is, (rdr::U16*)buf, handler); break;
-  case 32: hextileDecode32(r, is, (rdr::U32*)buf, handler); break;
+  const PixelFormat& pf = conn->cp.pf();
+  switch (pf.bpp) {
+  case 8:  hextileDecode8 (r, is, (rdr::U8*) buf, pf, pb); break;
+  case 16: hextileDecode16(r, is, (rdr::U16*)buf, pf, pb); break;
+  case 32: hextileDecode32(r, is, (rdr::U32*)buf, pf, pb); break;
   }
 }
diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h
index 67dc791..ffc495e 100644
--- a/common/rfb/HextileDecoder.h
+++ b/common/rfb/HextileDecoder.h
@@ -26,7 +26,7 @@
   public:
     HextileDecoder(CConnection* conn);
     virtual ~HextileDecoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb);
   };
 }
 #endif
diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx
index aa1b218..58cf741 100644
--- a/common/rfb/HextileEncoder.cxx
+++ b/common/rfb/HextileEncoder.cxx
@@ -16,11 +16,12 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
-#include <rfb/TransImageGetter.h>
 #include <rfb/encodings.h>
 #include <rfb/SMsgWriter.h>
 #include <rfb/SConnection.h>
 #include <rfb/HextileEncoder.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/Configuration.h>
 
 using namespace rfb;
@@ -52,30 +53,31 @@
 {
 }
 
-void HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig)
+void HextileEncoder::writeRect(const Rect& r, PixelBuffer* pb)
 {
   conn->writer()->startRect(r, encodingHextile);
   rdr::OutStream* os = conn->getOutStream();
-  switch (conn->cp.pf().bpp) {
+  const PixelFormat& pf = conn->cp.pf();
+  switch (pf.bpp) {
   case 8:
     if (improvedHextile) {
-      hextileEncodeBetter8(r, os, ig);
+      hextileEncodeBetter8(r, os, pf, pb);
     } else {
-      hextileEncode8(r, os, ig);
+      hextileEncode8(r, os, pf, pb);
     }
     break;
   case 16:
     if (improvedHextile) {
-      hextileEncodeBetter16(r, os, ig);
+      hextileEncodeBetter16(r, os, pf, pb);
     } else {
-      hextileEncode16(r, os, ig);
+      hextileEncode16(r, os, pf, pb);
     }
     break;
   case 32:
     if (improvedHextile) {
-      hextileEncodeBetter32(r, os, ig);
+      hextileEncodeBetter32(r, os, pf, pb);
     } else {
-      hextileEncode32(r, os, ig);
+      hextileEncode32(r, os, pf, pb);
     }
     break;
   }
diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h
index 723f539..82fa2ec 100644
--- a/common/rfb/HextileEncoder.h
+++ b/common/rfb/HextileEncoder.h
@@ -26,7 +26,7 @@
   public:
     HextileEncoder(SConnection* conn);
     virtual ~HextileEncoder();
-    virtual void writeRect(const Rect& r, TransImageGetter* ig);
+    virtual void writeRect(const Rect& r, PixelBuffer* pb);
   };
 }
 #endif
diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx
index ecc9713..8dc391a 100644
--- a/common/rfb/RREDecoder.cxx
+++ b/common/rfb/RREDecoder.cxx
@@ -17,7 +17,7 @@
  */
 #include <rfb/CMsgReader.h>
 #include <rfb/CConnection.h>
-#include <rfb/CMsgHandler.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/RREDecoder.h>
 
 using namespace rfb;
@@ -40,12 +40,13 @@
 {
 }
 
-void RREDecoder::readRect(const Rect& r, CMsgHandler* handler)
+void RREDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb)
 {
   rdr::InStream* is = conn->getInStream();
-  switch (conn->cp.pf().bpp) {
-  case 8:  rreDecode8 (r, is, handler); break;
-  case 16: rreDecode16(r, is, handler); break;
-  case 32: rreDecode32(r, is, handler); break;
+  const PixelFormat& pf = conn->cp.pf();
+  switch (pf.bpp) {
+  case 8:  rreDecode8 (r, is, pf, pb); break;
+  case 16: rreDecode16(r, is, pf, pb); break;
+  case 32: rreDecode32(r, is, pf, pb); break;
   }
 }
diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h
index 7b6cc45..b33bc55 100644
--- a/common/rfb/RREDecoder.h
+++ b/common/rfb/RREDecoder.h
@@ -26,7 +26,7 @@
   public:
     RREDecoder(CConnection* conn);
     virtual ~RREDecoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb);
   };
 }
 #endif
diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx
index a7af25d..6e23ad3 100644
--- a/common/rfb/RREEncoder.cxx
+++ b/common/rfb/RREEncoder.cxx
@@ -16,10 +16,11 @@
  * USA.
  */
 #include <rdr/OutStream.h>
-#include <rfb/TransImageGetter.h>
 #include <rfb/encodings.h>
 #include <rfb/SMsgWriter.h>
 #include <rfb/SConnection.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/RREEncoder.h>
 
 using namespace rfb;
@@ -42,12 +43,12 @@
 {
 }
 
-void RREEncoder::writeRect(const Rect& r, TransImageGetter* ig)
+void RREEncoder::writeRect(const Rect& r, PixelBuffer* pb)
 {
   int w = r.width();
   int h = r.height();
   rdr::U8* imageBuf = conn->writer()->getImageBuf(w*h);
-  ig->getImage(imageBuf, r);
+  pb->getImage(conn->cp.pf(), imageBuf, r);
 
   mos.clear();
 
@@ -59,7 +60,7 @@
   }
   
   if (nSubrects < 0) {
-    RawEncoder::writeRect(r, ig);
+    RawEncoder::writeRect(r, pb);
     return;
   }
 
diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h
index 487344f..57c1584 100644
--- a/common/rfb/RREEncoder.h
+++ b/common/rfb/RREEncoder.h
@@ -27,7 +27,7 @@
   public:
     RREEncoder(SConnection* conn);
     virtual ~RREEncoder();
-    virtual void writeRect(const Rect& r, TransImageGetter* ig);
+    virtual void writeRect(const Rect& r, PixelBuffer* pb);
   private:
     rdr::MemOutStream mos;
   };
diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx
index 6ca0202..d2b3d06 100644
--- a/common/rfb/RawDecoder.cxx
+++ b/common/rfb/RawDecoder.cxx
@@ -18,7 +18,7 @@
 #include <rdr/InStream.h>
 #include <rfb/CMsgReader.h>
 #include <rfb/CConnection.h>
-#include <rfb/CMsgHandler.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/RawDecoder.h>
 
 using namespace rfb;
@@ -31,7 +31,7 @@
 {
 }
 
-void RawDecoder::readRect(const Rect& r, CMsgHandler* handler)
+void RawDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb)
 {
   int x = r.tl.x;
   int y = r.tl.y;
@@ -39,12 +39,13 @@
   int h = r.height();
   int nPixels;
   rdr::U8* imageBuf = conn->reader()->getImageBuf(w, w*h, &nPixels);
-  int bytesPerRow = w * (conn->cp.pf().bpp / 8);
+  const PixelFormat& pf = conn->cp.pf();
+  int bytesPerRow = w * (pf.bpp / 8);
   while (h > 0) {
     int nRows = nPixels / w;
     if (nRows > h) nRows = h;
     conn->getInStream()->readBytes(imageBuf, nRows * bytesPerRow);
-    handler->imageRect(Rect(x, y, x+w, y+nRows), imageBuf);
+    pb->imageRect(pf, Rect(x, y, x+w, y+nRows), imageBuf);
     h -= nRows;
     y += nRows;
   }
diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h
index ca7c401..7a784c6 100644
--- a/common/rfb/RawDecoder.h
+++ b/common/rfb/RawDecoder.h
@@ -26,7 +26,7 @@
   public:
     RawDecoder(CConnection* conn);
     virtual ~RawDecoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb);
   };
 }
 #endif
diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx
index f7a4f3b..e50ebc7 100644
--- a/common/rfb/RawEncoder.cxx
+++ b/common/rfb/RawEncoder.cxx
@@ -16,10 +16,10 @@
  * USA.
  */
 #include <rdr/OutStream.h>
-#include <rfb/TransImageGetter.h>
 #include <rfb/encodings.h>
 #include <rfb/SMsgWriter.h>
 #include <rfb/SConnection.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/RawEncoder.h>
 
 using namespace rfb;
@@ -32,23 +32,13 @@
 {
 }
 
-void RawEncoder::writeRect(const Rect& r, TransImageGetter* ig)
+void RawEncoder::writeRect(const Rect& r, PixelBuffer* pb)
 {
-  int x = r.tl.x;
-  int y = r.tl.y;
-  int w = r.width();
-  int h = r.height();
-  int nPixels;
-  rdr::U8* imageBuf = conn->writer()->getImageBuf(w, w*h, &nPixels);
-  int bytesPerRow = w * (conn->cp.pf().bpp / 8);
+  rdr::U8* buf = conn->writer()->getImageBuf(r.area());
+
+  pb->getImage(conn->cp.pf(), buf, r);
+
   conn->writer()->startRect(r, encodingRaw);
-  while (h > 0) {
-    int nRows = nPixels / w;
-    if (nRows > h) nRows = h;
-    ig->getImage(imageBuf, Rect(x, y, x+w, y+nRows));
-    conn->getOutStream()->writeBytes(imageBuf, nRows * bytesPerRow);
-    h -= nRows;
-    y += nRows;
-  }
+  conn->getOutStream()->writeBytes(buf, r.area() * conn->cp.pf().bpp/8);
   conn->writer()->endRect();
 }
diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h
index 59e3a6d..c2d9f25 100644
--- a/common/rfb/RawEncoder.h
+++ b/common/rfb/RawEncoder.h
@@ -26,7 +26,7 @@
   public:
     RawEncoder(SConnection* conn);
     virtual ~RawEncoder();
-    virtual void writeRect(const Rect& r, TransImageGetter* ig);
+    virtual void writeRect(const Rect& r, PixelBuffer* pb);
   };
 }
 #endif
diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx
index bfc3352..5f4142b 100644
--- a/common/rfb/TightDecoder.cxx
+++ b/common/rfb/TightDecoder.cxx
@@ -19,7 +19,7 @@
  */
 #include <rfb/CMsgReader.h>
 #include <rfb/CConnection.h>
-#include <rfb/CMsgHandler.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/TightDecoder.h>
 
 using namespace rfb;
@@ -44,12 +44,12 @@
 {
 }
 
-void TightDecoder::readRect(const Rect& r, CMsgHandler* handler)
+void TightDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb)
 {
   is = conn->getInStream();
-  this->handler = handler;
-  clientpf = handler->getPreferredPF();
-  serverpf = handler->cp.pf();
+  this->pb = pb;
+  clientpf = pb->getPF();
+  serverpf = conn->cp.pf();
 
   if (clientpf.equal(serverpf)) {
     /* Decode directly into the framebuffer (fast path) */
diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h
index 2ca4ecd..66fa9a0 100644
--- a/common/rfb/TightDecoder.h
+++ b/common/rfb/TightDecoder.h
@@ -30,7 +30,7 @@
   public:
     TightDecoder(CConnection* conn);
     virtual ~TightDecoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb);
 
   private:
     rdr::U32 readCompact(rdr::InStream* is);
@@ -56,7 +56,7 @@
     void directFillRect16(const Rect& r, Pixel pix);
     void directFillRect32(const Rect& r, Pixel pix);
 
-    CMsgHandler* handler;
+    ModifiablePixelBuffer* pb;
     rdr::InStream* is;
     rdr::ZlibInStream zis[4];
     JpegDecompressor jd;
diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx
index c3f87da..cdc23c4 100644
--- a/common/rfb/TightEncoder.cxx
+++ b/common/rfb/TightEncoder.cxx
@@ -17,7 +17,6 @@
  * USA.
  */
 #include <rdr/OutStream.h>
-#include <rfb/TransImageGetter.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/encodings.h>
 #include <rfb/ConnParams.h>
@@ -287,10 +286,10 @@
   }
 }
 
-void TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig)
+void TightEncoder::writeRect(const Rect& _r, PixelBuffer* _pb)
 {
-  ig = _ig;
-  serverpf = ig->getPixelBuffer()->getPF();
+  pb = _pb;
+  serverpf = pb->getPF();
   ConnParams* cp = &conn->cp;
   clientpf = cp->pf();
 
@@ -366,7 +365,7 @@
         }
         if (bestr.tl.x != x) {
           sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height());
-          writeRect(sr, _ig);
+          writeRect(sr, _pb);
         }
 
         // Send solid-color rectangle.
@@ -376,11 +375,11 @@
         if (bestr.br.x != r.br.x) {
           sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x,
             bestr.height());
-          writeRect(sr, _ig);
+          writeRect(sr, _pb);
         }
         if (bestr.br.y != r.br.y) {
           sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y);
-          writeRect(sr, _ig);
+          writeRect(sr, _pb);
         }
 
         return;
diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h
index 8a58985..89d096b 100644
--- a/common/rfb/TightEncoder.h
+++ b/common/rfb/TightEncoder.h
@@ -33,7 +33,7 @@
 
 namespace rfb {
 
-  class TransImageGetter;
+  class PixelBuffer;
 
   struct TIGHT_CONF {
     unsigned int maxRectSize, maxRectWidth;
@@ -65,7 +65,7 @@
     virtual void setQualityLevel(int level);
     virtual void setFineQualityLevel(int quality, int subsampling);
     virtual int getNumRects(const Rect &r);
-    virtual void writeRect(const Rect& r, TransImageGetter* ig);
+    virtual void writeRect(const Rect& r, PixelBuffer* pb);
 
   private:
     bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor);
@@ -123,7 +123,7 @@
     rdr::MemOutStream mos;
     rdr::ZlibOutStream zos[4];
     JpegCompressor jc;
-    TransImageGetter *ig;
+    PixelBuffer *pb;
     PixelFormat serverpf, clientpf;
 
     bool pack24;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index e712300..e1424b7 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -71,8 +71,7 @@
     fenceDataLen(0), fenceData(NULL),
     baseRTT(-1), minRTT(-1), seenCongestion(false), pingCounter(0),
     ackedOffset(0), sentOffset(0), congWindow(0), congestionTimer(this),
-    server(server_),
-    updates(false), image_getter(server->useEconomicTranslate),
+    server(server_), updates(false),
     drawRenderedCursor(false), removeRenderedCursor(false),
     continuousUpdates(false),
     updateTimer(this), pointerEventTime(0),
@@ -233,8 +232,6 @@
     // work out what's actually changed.
     updates.clear();
     updates.add_changed(server->pb->getRect());
-    vlog.debug("pixel buffer changed - re-initialising image getter");
-    image_getter.init(server->pb, cp.pf(), writer());
     writeFramebufferUpdate();
   } catch(rdr::Exception &e) {
     close(e.str());
@@ -404,7 +401,6 @@
   char buffer[256];
   cp.pf().print(buffer, 256);
   vlog.info("Server default pixel format %s", buffer);
-  image_getter.init(server->pb, cp.pf(), 0);
 
   // - Mark the entire display as "dirty"
   updates.add_changed(server->pb->getRect());
@@ -478,7 +474,6 @@
   char buffer[256];
   pf.print(buffer, 256);
   vlog.info("Client pixel format %s", buffer);
-  image_getter.init(server->pb, pf, writer());
   setCursor();
 }
 
@@ -1036,16 +1031,20 @@
     std::vector<Rect>::const_iterator i;
     int encoding;
 
+    Encoder* encoder;
+    PixelBuffer* pb;
+
     // Make sure the encoder has the latest settings
     encoding = cp.currentEncoding();
 
     if (!encoders[encoding])
       encoders[encoding] = Encoder::createEncoder(encoding, this);
 
-    encoders[encoding]->setCompressLevel(cp.compressLevel);
-    encoders[encoding]->setQualityLevel(cp.qualityLevel);
-    encoders[encoding]->setFineQualityLevel(cp.fineQualityLevel,
-                                            cp.subsampling);
+    encoder = encoders[encoding];
+
+    encoder->setCompressLevel(cp.compressLevel);
+    encoder->setQualityLevel(cp.qualityLevel);
+    encoder->setFineQualityLevel(cp.fineQualityLevel, cp.subsampling);
 
     // Compute the number of rectangles. Tight encoder makes the things more
     // complicated as compared to the original VNC4.
@@ -1055,7 +1054,7 @@
     ui.changed.get_rects(&rects);
     for (i = rects.begin(); i != rects.end(); i++) {
       if (i->width() && i->height()) {
-        int nUpdateRects = encoders[encoding]->getNumRects(*i);
+        int nUpdateRects = encoder->getNumRects(*i);
         if (nUpdateRects == 0 && cp.currentEncoding() == encodingTight) {
           // With Tight encoding and LastRect support, the client does not
           // care about the number of rectangles in the update - it will
@@ -1077,14 +1076,15 @@
       writer()->writeCopyRect(*i, i->tl.x - ui.copy_delta.x,
                               i->tl.y - ui.copy_delta.y);
 
+    pb = server->getPixelBuffer();
+
     ui.changed.get_rects(&rects);
     for (i = rects.begin(); i != rects.end(); i++)
-      encoders[encoding]->writeRect(*i, &image_getter);
+      encoder->writeRect(*i, pb);
 
     if (drawRenderedCursor) {
-      image_getter.setPixelBuffer(&server->renderedCursor);
-      encoders[encoding]->writeRect(renderedCursorRect, &image_getter);
-      image_getter.setPixelBuffer(server->pb);
+      renderedCursorRect = server->renderedCursor.getEffectiveRect();
+      encoder->writeRect(renderedCursorRect, &server->renderedCursor);
 
       drawRenderedCursor = false;
     }
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index c918c59..6adeac2 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -30,7 +30,6 @@
 #include <set>
 #include <rfb/SConnection.h>
 #include <rfb/SMsgWriter.h>
-#include <rfb/TransImageGetter.h>
 #include <rfb/VNCServerST.h>
 #include <rfb/Timer.h>
 
@@ -193,7 +192,6 @@
 
     VNCServerST* server;
     SimpleUpdateTracker updates;
-    TransImageGetter image_getter;
     Region requested;
     bool drawRenderedCursor, removeRenderedCursor;
     Rect renderedCursorRect;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 27eb605..51cb86c 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -84,7 +84,6 @@
     name(strDup(name_)), pointerClient(0), comparer(0),
     renderedCursorInvalid(false),
     queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
-    useEconomicTranslate(false),
     lastConnectionTime(0), disableclients(false),
     deferTimer(this), deferPending(false)
 {
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index ede5223..1e055dd 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -177,12 +177,6 @@
     // Blacklist to be shared by multiple VNCServerST instances.
     void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;}
 
-    // setEconomicTranslate() determines (for new connections) whether pixels
-    // should be translated for <=16bpp clients using a large lookup table
-    // (fast) or separate, smaller R, G and B tables (slower).  If set to true,
-    // small tables are used, to save memory.
-    void setEconomicTranslate(bool et) { useEconomicTranslate = et; }
-
     // setKeyRemapper() replaces the VNCServerST's default key remapper.
     // NB: A null pointer is valid here.
     void setKeyRemapper(KeyRemapper* kr) { keyRemapper = kr; }
@@ -242,8 +236,7 @@
 
     QueryConnectionHandler* queryConnectionHandler;
     KeyRemapper* keyRemapper;
-    bool useEconomicTranslate;
-    
+
     time_t lastUserInputTime;
     time_t lastDisconnectTime;
     time_t lastConnectionTime;
diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx
index 7e933a8..60e5dd1 100644
--- a/common/rfb/ZRLEDecoder.cxx
+++ b/common/rfb/ZRLEDecoder.cxx
@@ -17,7 +17,7 @@
  */
 #include <rfb/CMsgReader.h>
 #include <rfb/CConnection.h>
-#include <rfb/CMsgHandler.h>
+#include <rfb/PixelBuffer.h>
 #include <rfb/ZRLEDecoder.h>
 
 using namespace rfb;
@@ -66,17 +66,16 @@
 {
 }
 
-void ZRLEDecoder::readRect(const Rect& r, CMsgHandler* handler)
+void ZRLEDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb)
 {
   rdr::InStream* is = conn->getInStream();
   rdr::U8* buf = conn->reader()->getImageBuf(64 * 64 * 4);
-  switch (conn->cp.pf().bpp) {
-  case 8:  zrleDecode8 (r, is, &zis, (rdr::U8*) buf, handler); break;
-  case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, handler); break;
+  const rfb::PixelFormat& pf = conn->cp.pf();
+  switch (pf.bpp) {
+  case 8:  zrleDecode8 (r, is, &zis, (rdr::U8*) buf, pf, pb); break;
+  case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, pf, pb); break;
   case 32:
     {
-      const rfb::PixelFormat& pf = handler->cp.pf();
-
       Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
       bool fitsInLS3Bytes = maxPixel < (1<<24);
       bool fitsInMS3Bytes = (maxPixel & 0xff) == 0;
@@ -84,16 +83,16 @@
       if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
           (fitsInMS3Bytes && pf.isBigEndian()))
       {
-        zrleDecode24A(r, is, &zis, (rdr::U32*)buf, handler);
+        zrleDecode24A(r, is, &zis, (rdr::U32*)buf, pf, pb);
       }
       else if ((fitsInLS3Bytes && pf.isBigEndian()) ||
                (fitsInMS3Bytes && pf.isLittleEndian()))
       {
-        zrleDecode24B(r, is, &zis, (rdr::U32*)buf, handler);
+        zrleDecode24B(r, is, &zis, (rdr::U32*)buf, pf, pb);
       }
       else
       {
-        zrleDecode32(r, is, &zis, (rdr::U32*)buf, handler);
+        zrleDecode32(r, is, &zis, (rdr::U32*)buf, pf, pb);
       }
       break;
     }
diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h
index e7e2b8c..492597e 100644
--- a/common/rfb/ZRLEDecoder.h
+++ b/common/rfb/ZRLEDecoder.h
@@ -27,7 +27,7 @@
   public:
     ZRLEDecoder(CConnection* conn);
     virtual ~ZRLEDecoder();
-    virtual void readRect(const Rect& r, CMsgHandler* handler);
+    virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb);
   private:
     rdr::ZlibInStream zis;
   };
diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx
index 968edcf..54613e2 100644
--- a/common/rfb/ZRLEEncoder.cxx
+++ b/common/rfb/ZRLEEncoder.cxx
@@ -17,7 +17,6 @@
  */
 #include <rdr/OutStream.h>
 #include <rfb/Exception.h>
-#include <rfb/TransImageGetter.h>
 #include <rfb/encodings.h>
 #include <rfb/ConnParams.h>
 #include <rfb/SMsgWriter.h>
@@ -69,22 +68,22 @@
 {
 }
 
-void ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig)
+void ZRLEEncoder::writeRect(const Rect& r, PixelBuffer* pb)
 {
+  const PixelFormat& pf = conn->cp.pf();
+
   rdr::U8* imageBuf = conn->writer()->getImageBuf(64 * 64 * 4 + 4);
   mos.clear();
 
-  switch (conn->cp.pf().bpp) {
+  switch (pf.bpp) {
   case 8:
-    zrleEncode8(r, &mos, &zos, imageBuf, ig);
+    zrleEncode8(r, &mos, &zos, imageBuf, pf, pb);
     break;
   case 16:
-    zrleEncode16(r, &mos, &zos, imageBuf, ig);
+    zrleEncode16(r, &mos, &zos, imageBuf, pf, pb);
     break;
   case 32:
     {
-      const PixelFormat& pf = conn->cp.pf();
-
       Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
       bool fitsInLS3Bytes = maxPixel < (1<<24);
       bool fitsInMS3Bytes = (maxPixel & 0xff) == 0;
@@ -92,16 +91,16 @@
       if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
           (fitsInMS3Bytes && pf.isBigEndian()))
       {
-        zrleEncode24A(r, &mos, &zos, imageBuf, ig);
+        zrleEncode24A(r, &mos, &zos, imageBuf, pf, pb);
       }
       else if ((fitsInLS3Bytes && pf.isBigEndian()) ||
                (fitsInMS3Bytes && pf.isLittleEndian()))
       {
-        zrleEncode24B(r, &mos, &zos, imageBuf, ig);
+        zrleEncode24B(r, &mos, &zos, imageBuf, pf, pb);
       }
       else
       {
-        zrleEncode32(r, &mos, &zos, imageBuf, ig);
+        zrleEncode32(r, &mos, &zos, imageBuf, pf, pb);
       }
       break;
     }
diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h
index d285967..b006821 100644
--- a/common/rfb/ZRLEEncoder.h
+++ b/common/rfb/ZRLEEncoder.h
@@ -28,7 +28,7 @@
   public:
     ZRLEEncoder(SConnection* conn);
     virtual ~ZRLEEncoder();
-    virtual void writeRect(const Rect& r, TransImageGetter* ig);
+    virtual void writeRect(const Rect& r, PixelBuffer* pb);
   private:
     rdr::ZlibOutStream zos;
     rdr::MemOutStream mos;
diff --git a/common/rfb/hextileDecode.h b/common/rfb/hextileDecode.h
index 518a606..56ba118 100644
--- a/common/rfb/hextileDecode.h
+++ b/common/rfb/hextileDecode.h
@@ -38,7 +38,7 @@
 #define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP)
 
 void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf,
-                     CMsgHandler* handler)
+                     const PixelFormat& pf, ModifiablePixelBuffer* pb)
 {
   Rect t;
   PIXEL_T bg = 0;
@@ -56,7 +56,7 @@
 
       if (tileType & hextileRaw) {
 	is->readBytes(buf, t.area() * (BPP/8));
-	handler->imageRect(t, buf);
+	pb->imageRect(pf, t, buf);
 	continue;
       }
 
@@ -94,7 +94,7 @@
           }
         }
       }
-      handler->imageRect(t, buf);
+      pb->imageRect(pf, t, buf);
     }
   }
 }
diff --git a/common/rfb/hextileEncode.h b/common/rfb/hextileEncode.h
index 7e5b2db..2efd74e 100644
--- a/common/rfb/hextileEncode.h
+++ b/common/rfb/hextileEncode.h
@@ -44,7 +44,8 @@
 int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType,
                          rdr::U8* encoded, PIXEL_T bg);
 
-void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, TransImageGetter *ig)
+void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os,
+                    const PixelFormat& pf, PixelBuffer* pb)
 {
   Rect t;
   PIXEL_T buf[256];
@@ -61,7 +62,7 @@
 
       t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
 
-      ig->getImage(buf, t);
+      pb->getImage(pf, buf, t);
 
       PIXEL_T bg = 0, fg = 0;
       int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg);
@@ -90,7 +91,7 @@
                                          encoded, bg);
 
         if (encodedLen < 0) {
-          ig->getImage(buf, t);
+          pb->getImage(pf, buf, t);
           os->writeU8(hextileRaw);
           os->writeBytes(buf, t.width() * t.height() * (BPP/8));
           oldBgValid = oldFgValid = false;
diff --git a/common/rfb/hextileEncodeBetter.h b/common/rfb/hextileEncodeBetter.h
index 3a96ab6..efb2d9c 100644
--- a/common/rfb/hextileEncodeBetter.h
+++ b/common/rfb/hextileEncodeBetter.h
@@ -275,7 +275,8 @@
 // Main encoding function.
 //
 
-void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, TransImageGetter *ig)
+void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os,
+                    const PixelFormat& pf, PixelBuffer* pb)
 {
   Rect t;
   PIXEL_T buf[256];
@@ -294,7 +295,7 @@
 
       t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
 
-      ig->getImage(buf, t);
+      pb->getImage(pf, buf, t);
 
       tile.newTile(buf, t.width(), t.height());
       int tileType = tile.getFlags();
diff --git a/common/rfb/rreDecode.h b/common/rfb/rreDecode.h
index d37461f..9dc0470 100644
--- a/common/rfb/rreDecode.h
+++ b/common/rfb/rreDecode.h
@@ -36,11 +36,12 @@
 #define READ_PIXEL CONCAT2E(readOpaque,BPP)
 #define RRE_DECODE CONCAT2E(rreDecode,BPP)
 
-void RRE_DECODE (const Rect& r, rdr::InStream* is, CMsgHandler* handler)
+void RRE_DECODE (const Rect& r, rdr::InStream* is,
+                 const PixelFormat& pf, ModifiablePixelBuffer* pb)
 {
   int nSubrects = is->readU32();
   PIXEL_T bg = is->READ_PIXEL();
-  handler->fillRect(r, bg);
+  pb->fillRect(pf, r, bg);
 
   for (int i = 0; i < nSubrects; i++) {
     PIXEL_T pix = is->READ_PIXEL();
@@ -48,7 +49,7 @@
     int y = is->readU16();
     int w = is->readU16();
     int h = is->readU16();
-    handler->fillRect(Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix);
+    pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix);
   }
 }
 
diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h
index a596311..53dbba7 100644
--- a/common/rfb/tightDecode.h
+++ b/common/rfb/tightDecode.h
@@ -77,7 +77,7 @@
     } else {
       pix = is->READ_PIXEL();
     }
-    handler->fillRect(r, pix);
+    pb->fillRect(serverpf, r, pix);
     return;
   }
 
@@ -153,7 +153,7 @@
 
   PIXEL_T *buf;
   int stride = r.width();
-  if (directDecode) buf = (PIXEL_T *)handler->getRawBufferRW(r, &stride);
+  if (directDecode) buf = (PIXEL_T *)pb->getBufferRW(r, &stride);
   else buf = (PIXEL_T *)conn->reader()->getImageBuf(r.area());
 
   if (palSize == 0) {
@@ -225,8 +225,8 @@
     }
   }
 
-  if (directDecode) handler->releaseRawBuffer(r);
-  else handler->imageRect(r, buf);
+  if (directDecode) pb->commitBufferRW(r);
+  else pb->imageRect(serverpf, r, buf);
 
   delete [] netbuf;
 
@@ -253,9 +253,9 @@
 
   // We always use direct decoding with JPEG images
   int stride;
-  rdr::U8 *buf = handler->getRawBufferRW(r, &stride);
+  rdr::U8 *buf = pb->getBufferRW(r, &stride);
   jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf);
-  handler->releaseRawBuffer(r);
+  pb->commitBufferRW(r);
 
   delete [] netbuf;
 }
diff --git a/common/rfb/tightEncode.h b/common/rfb/tightEncode.h
index 5d32cce..1d8acc0 100644
--- a/common/rfb/tightEncode.h
+++ b/common/rfb/tightEncode.h
@@ -114,7 +114,7 @@
 {
   int stride;
   rdr::U32 solidColor;
-  const PIXEL_T *rawPixels = (const PIXEL_T *)ig->getRawBufferR(r, &stride);
+  const PIXEL_T *rawPixels = (const PIXEL_T *)pb->getBuffer(r, &stride);
   PIXEL_T *pixels = NULL;
   bool grayScaleJPEG = (jpegSubsampling == subsampleGray && jpegQuality != -1);
 
@@ -126,7 +126,8 @@
 
   if (forceSolid) {
     // Subrectangle has already been determined to be solid.
-    ig->translatePixels(rawPixels, &solidColor, 1);
+    clientpf.bufferFromBuffer((rdr::U8*)&solidColor, serverpf,
+                              (const rdr::U8*)rawPixels, 1);
     pixels = (PIXEL_T *)&solidColor;
     palette.clear();
     palette.insert(solidColor, 1);
@@ -149,14 +150,14 @@
       if(palette.size() != 0 || jpegQuality == -1) {
         pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area());
         stride = r.width();
-        ig->getImage(pixels, r);
+        pb->getImage(clientpf, pixels, r);
       }
     } else {
       // Pixel translation will be required, so create an intermediate buffer,
       // translate the raw pixels into it, and count its colors.
       pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area());
       stride = r.width();
-      ig->getImage(pixels, r);
+      pb->getImage(clientpf, pixels, r);
 
       if (grayScaleJPEG) palette.clear();
       else FILL_PALETTE(pixels, r.area());
@@ -443,7 +444,7 @@
   int w = r.width(), h = r.height();
   const PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2,
     *dataend = &data[stride * h];
-  bool willTransform = ig->willTransform();
+  bool willTransform = !serverpf.equal(clientpf);
 
   serverpf.bufferFromPixel((rdr::U8*)&mask, ~0);
 
@@ -490,8 +491,8 @@
 
   monodone:
   if (willTransform) {
-    ig->translatePixels(&c0, &c0t, 1);
-    ig->translatePixels(&c1, &c1t, 1);
+    clientpf.bufferFromBuffer((rdr::U8*)&c0t, serverpf, (rdr::U8*)&c0, 1);
+    clientpf.bufferFromBuffer((rdr::U8*)&c1t, serverpf, (rdr::U8*)&c1, 1);
   }
   else {
     c0t = c0;  c1t = c1;
@@ -515,7 +516,7 @@
         ni++;
       } else {
         if (willTransform)
-          ig->translatePixels(&ci, &cit, 1);
+          clientpf.bufferFromBuffer((rdr::U8*)&cit, serverpf, (rdr::U8*)&ci, 1);
         else
           cit = ci;
         if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) {
@@ -529,7 +530,7 @@
     rowptr += stride;
     colptr = rowptr;
   }
-  ig->translatePixels(&ci, &cit, 1);
+  clientpf.bufferFromBuffer((rdr::U8*)&cit, serverpf, (rdr::U8*)&ci, 1);
   if (!palette.insert (cit, ni) || (palette.size() > palMaxColors))
     palette.clear();
 }
@@ -543,7 +544,7 @@
   int w = r.width(), h = r.height();
 
   int stride = w;
-  buf = (const PIXEL_T *)ig->getRawBufferR(r, &stride);
+  buf = (const PIXEL_T *)pb->getBuffer(r, &stride);
 
   colorValue = *buf;
   if (needSameColor && (rdr::U32)colorValue != *colorPtr)
diff --git a/common/rfb/zrleDecode.h b/common/rfb/zrleDecode.h
index 4bcbf1f..42b28b3 100644
--- a/common/rfb/zrleDecode.h
+++ b/common/rfb/zrleDecode.h
@@ -48,7 +48,7 @@
 
 void ZRLE_DECODE (const Rect& r, rdr::InStream* is,
                   rdr::ZlibInStream* zis, PIXEL_T* buf,
-                  CMsgHandler* handler)
+                  const PixelFormat& pf, ModifiablePixelBuffer* pb)
 {
   int length = is->readU32();
   zis->setUnderlying(is, length);
@@ -73,7 +73,7 @@
 
       if (palSize == 1) {
         PIXEL_T pix = palette[0];
-        handler->fillRect(t, pix);
+        pb->fillRect(pf, t, pix);
         continue;
       }
 
@@ -173,7 +173,7 @@
 
       //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
       //t.width(),t.height(),t.tl.x,t.tl.y);
-      handler->imageRect(t, buf);
+      pb->imageRect(pf, t, buf);
     }
   }
 
diff --git a/common/rfb/zrleEncode.h b/common/rfb/zrleEncode.h
index 8767d54..e546772 100644
--- a/common/rfb/zrleEncode.h
+++ b/common/rfb/zrleEncode.h
@@ -30,6 +30,7 @@
 #include <rdr/OutStream.h>
 #include <rdr/ZlibOutStream.h>
 #include <rfb/Palette.h>
+#include <rfb/PixelBuffer.h>
 #include <assert.h>
 
 namespace rfb {
@@ -66,7 +67,7 @@
 
 void ZRLE_ENCODE (const Rect& r, rdr::OutStream* os,
                   rdr::ZlibOutStream* zos, void* buf,
-                  TransImageGetter *ig)
+                  const PixelFormat& pf, PixelBuffer* pb)
 {
   zos->setUnderlying(os);
   // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block
@@ -83,7 +84,7 @@
 
       t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
 
-      ig->getImage(buf, t);
+      pb->getImage(pf, buf, t);
 
       ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos);
     }
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index c78bb89..305eddc 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -263,7 +263,6 @@
   // This initial update request is a bit of a corner case, so we need
   // to help out setting the correct format here.
   assert(pendingPFChange);
-  desktop->setServerPF(pendingPF);
   cp.setPF(pendingPF);
   pendingPFChange = false;
 }
@@ -330,7 +329,6 @@
   // 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) {
-    desktop->setServerPF(pendingPF);
     cp.setPF(pendingPF);
     pendingPFChange = false;
   }
@@ -405,26 +403,11 @@
       throw Exception("Unknown rect encoding");
     }
   }
-  decoders[encoding]->readRect(r, this);
+  decoders[encoding]->readRect(r, desktop->getFramebuffer());
 
   sock->inStream().stopTiming();
 }
 
-void CConn::fillRect(const rfb::Rect& r, rfb::Pixel p)
-{
-  desktop->fillRect(r,p);
-}
-
-void CConn::imageRect(const rfb::Rect& r, void* p)
-{
-  desktop->imageRect(r,p);
-}
-
-void CConn::copyRect(const rfb::Rect& r, int sx, int sy)
-{
-  desktop->copyRect(r,sx,sy);
-}
-
 void CConn::setCursor(int width, int height, const Point& hotspot,
                       void* data, void* mask)
 {
@@ -461,18 +444,10 @@
 
     pf.read(&memStream);
 
-    desktop->setServerPF(pf);
     cp.setPF(pf);
   }
 }
 
-rdr::U8* CConn::getRawBufferRW(const rfb::Rect& r, int* stride) {
-  return desktop->getBufferRW(r, stride);
-}
-void CConn::releaseRawBuffer(const rfb::Rect& r) {
-  desktop->commitBufferRW(r);
-}
-
 
 ////////////////////// Internal methods //////////////////////
 
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index f7f560b..709ca2f 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -64,18 +64,8 @@
 
   void framebufferUpdateStart();
   void framebufferUpdateEnd();
-
   void dataRect(const rfb::Rect& r, int encoding);
 
-  void fillRect(const rfb::Rect& r, rfb::Pixel p);
-  void imageRect(const rfb::Rect& r, void* p);
-  void copyRect(const rfb::Rect& r, int sx, int sy);
-
-  rdr::U8* getRawBufferRW(const rfb::Rect& r, int* stride);
-  void releaseRawBuffer(const rfb::Rect& r);
-
-  const rfb::PixelFormat &getPreferredPF() { return fullColourPF; }
-
   void setCursor(int width, int height, const rfb::Point& hotspot,
                  void* data, void* mask);
 
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index a64f02a..d57d57a 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -193,12 +193,6 @@
 }
 
 
-void DesktopWindow::setServerPF(const rfb::PixelFormat& pf)
-{
-  viewport->setServerPF(pf);
-}
-
-
 const rfb::PixelFormat &DesktopWindow::getPreferredPF()
 {
   return viewport->getPreferredPF();
@@ -216,24 +210,9 @@
 }
 
 
-void DesktopWindow::fillRect(const rfb::Rect& r, rfb::Pixel pix) {
-  viewport->fillRect(r, pix);
-}
-
-void DesktopWindow::imageRect(const rfb::Rect& r, void* pixels) {
-  viewport->imageRect(r, pixels);
-}
-
-void DesktopWindow::copyRect(const rfb::Rect& r, int srcX, int srcY) {
-  viewport->copyRect(r, srcX, srcY);
-}
-
-rdr::U8* DesktopWindow::getBufferRW(const rfb::Rect& r, int* stride) {
-  return viewport->getBufferRW(r, stride);
-}
-
-void DesktopWindow::commitBufferRW(const rfb::Rect& r) {
-  viewport->commitBufferRW(r);
+rfb::ModifiablePixelBuffer* DesktopWindow::getFramebuffer(void)
+{
+  return viewport->getFramebuffer();
 }
 
 
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index 83a8c76..8b91450 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -27,6 +27,8 @@
 
 #include <FL/Fl_Window.H>
 
+namespace rfb { class ModifiablePixelBuffer; }
+
 class CConn;
 class Viewport;
 
@@ -39,26 +41,22 @@
                 const rfb::PixelFormat& serverPF, CConn* cc_);
   ~DesktopWindow();
 
-  // PixelFormat of incoming write operations
-  void setServerPF(const rfb::PixelFormat& pf);
   // Most efficient format (from DesktopWindow's point of view)
   const rfb::PixelFormat &getPreferredPF();
 
   // Flush updates to screen
   void updateWindow();
 
-  // Methods forwarded from CConn
+  // Updated session title
   void setName(const char *name);
 
-  void fillRect(const rfb::Rect& r, rfb::Pixel pix);
-  void imageRect(const rfb::Rect& r, void* pixels);
-  void copyRect(const rfb::Rect& r, int srcX, int srcY);
+  // Return a pointer to the framebuffer for decoders to write into
+  rfb::ModifiablePixelBuffer* getFramebuffer(void);
 
-  rdr::U8* getBufferRW(const rfb::Rect& r, int* stride);
-  void commitBufferRW(const rfb::Rect& r);
-
+  // Resize the current framebuffer, but retain the contents
   void resizeFramebuffer(int new_w, int new_h);
 
+  // New image for the locally rendered cursor
   void setCursor(int width, int height, const rfb::Point& hotspot,
                  void* data, void* mask);
 
diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
index ced0446..5bd50d2 100644
--- a/vncviewer/PlatformPixelBuffer.cxx
+++ b/vncviewer/PlatformPixelBuffer.cxx
@@ -24,3 +24,19 @@
   FullFramePixelBuffer(pf, width, height, data, stride)
 {
 }
+
+void PlatformPixelBuffer::commitBufferRW(const rfb::Rect& r)
+{
+  FullFramePixelBuffer::commitBufferRW(r);
+  damage.assign_union(rfb::Region(r));
+}
+
+rfb::Rect PlatformPixelBuffer::getDamage(void)
+{
+  rfb::Rect r;
+
+  r = damage.get_bounding_rect();
+  damage.clear();
+
+  return r;
+}
diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h
index 03842ac..21b93be 100644
--- a/vncviewer/PlatformPixelBuffer.h
+++ b/vncviewer/PlatformPixelBuffer.h
@@ -20,14 +20,20 @@
 #define __PLATFORMPIXELBUFFER_H__
 
 #include <rfb/PixelBuffer.h>
+#include <rfb/Region.h>
 
 class PlatformPixelBuffer: public rfb::FullFramePixelBuffer {
 public:
   PlatformPixelBuffer(const rfb::PixelFormat& pf, int width, int height,
                       rdr::U8* data, int stride);
 
-  virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0;
+  virtual void commitBufferRW(const rfb::Rect& r);
 
+  virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0;
+  rfb::Rect getDamage(void);
+
+protected:
+  rfb::Region damage;
 };
 
 #endif
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 70964b7..cd8b1bc 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -27,7 +27,6 @@
 
 #include <rfb/CMsgWriter.h>
 #include <rfb/LogWriter.h>
-#include <rfb/PixelTransformer.h>
 
 // FLTK can pull in the X11 headers on some systems
 #ifndef XK_VoidSymbol
@@ -84,7 +83,7 @@
        ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS };
 
 Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_)
-  : Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL), pixelTrans(NULL),
+  : Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL),
     lastPointerPos(0, 0), lastButtonMask(0),
     cursor(NULL), menuCtrlKey(false), menuAltKey(false)
 {
@@ -101,8 +100,6 @@
   frameBuffer = createFramebuffer(w, h);
   assert(frameBuffer);
 
-  setServerPF(serverPF);
-
   contextMenu = new Fl_Menu_Button(0, 0, 0, 0);
   // Setting box type to FL_NO_BOX prevents it from trying to draw the
   // button component (which we don't want)
@@ -130,7 +127,6 @@
 {
   // Unregister all timeouts in case they get a change tro trigger
   // again later when this object is already gone.
-  Fl::remove_timeout(handleUpdateTimeout, this);
   Fl::remove_timeout(handlePointerTimeout, this);
 
 #ifdef HAVE_FLTK_CLIPBOARD
@@ -141,9 +137,6 @@
 
   delete frameBuffer;
 
-  if (pixelTrans)
-    delete pixelTrans;
-
   if (cursor) {
     if (!cursor->alloc_array)
       delete [] cursor->array;
@@ -155,40 +148,6 @@
 }
 
 
-void Viewport::setServerPF(const rfb::PixelFormat& pf)
-{
-  if (pixelTrans)
-    delete pixelTrans;
-  pixelTrans = NULL;
-
-  if (pf.equal(getPreferredPF()))
-    return;
-
-  pixelTrans = new PixelTransformer();
-
-  // FIXME: This is an ugly (temporary) hack to get around a corner
-  //        case during startup. The conversion routines cannot handle
-  //        non-native source formats, and we can sometimes get that
-  //        as the initial format. We will switch to a better format
-  //        before getting any updates, but we need something for now.
-  //        Our old client used something completely bogus and just
-  //        hoped nothing would ever go wrong. We try to at least match
-  //        the pixel size so that we don't get any memory access issues
-  //        should a stray update appear.
-  static rdr::U32 endianTest = 1;
-  static bool nativeBigEndian = *(rdr::U8*)(&endianTest) != 1;
-  if ((pf.bpp > 8) && (pf.bigEndian != nativeBigEndian)) {
-    PixelFormat fake_pf(pf.bpp, pf.depth, nativeBigEndian, pf.trueColour,
-                        pf.redMax, pf.greenMax, pf.blueMax,
-                        pf.redShift, pf.greenShift, pf.blueShift);
-    pixelTrans->init(fake_pf, getPreferredPF());
-    return;
-  }
-
-  pixelTrans->init(pf, getPreferredPF());
-}
-
-
 const rfb::PixelFormat &Viewport::getPreferredPF()
 {
   return frameBuffer->getPF();
@@ -197,65 +156,21 @@
 
 // Copy the areas of the framebuffer that have been changed (damaged)
 // to the displayed window.
+// FIXME: Make sure this gets called on slow updates
 
 void Viewport::updateWindow()
 {
   Rect r;
 
-  Fl::remove_timeout(handleUpdateTimeout, this);
-
-  r = damage.get_bounding_rect();
-  Fl_Widget::damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
-
-  damage.clear();
+  r = frameBuffer->getDamage();
+  damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
 }
 
-void Viewport::fillRect(const rfb::Rect& r, rfb::Pixel pix) {
-  if (pixelTrans) {
-    rfb::Pixel pix2;
-    pixelTrans->translatePixels(&pix, &pix2, 1);
-    pix = pix2;
-  }
-
-  frameBuffer->fillRect(r, pix);
-  damageRect(r);
+rfb::ModifiablePixelBuffer* Viewport::getFramebuffer(void)
+{
+  return frameBuffer;
 }
 
-void Viewport::imageRect(const rfb::Rect& r, void* pixels) {
-  if (pixelTrans) {
-    rdr::U8* buffer;
-    int stride;
-    buffer = frameBuffer->getBufferRW(r, &stride);
-    pixelTrans->translateRect(pixels, r.width(),
-                              rfb::Rect(0, 0, r.width(), r.height()),
-                              buffer, stride, rfb::Point(0, 0));
-    frameBuffer->commitBufferRW(r);
-  } else {
-    frameBuffer->imageRect(r, pixels);
-  }
-  damageRect(r);
-}
-
-void Viewport::copyRect(const rfb::Rect& r, int srcX, int srcY) {
-  frameBuffer->copyRect(r, rfb::Point(r.tl.x-srcX, r.tl.y-srcY));
-  damageRect(r);
-}
-
-rdr::U8* Viewport::getBufferRW(const rfb::Rect& r, int* stride) {
-  return frameBuffer->getBufferRW(r, stride);
-}
-
-void Viewport::commitBufferRW(const rfb::Rect& r) {
-  frameBuffer->commitBufferRW(r);
-  damageRect(r);
-}
-
-void Viewport::damageRect(const rfb::Rect& r) {
-  damage.assign_union(rfb::Region(r));
-  if (!Fl::has_timeout(handleUpdateTimeout, this))
-    Fl::add_timeout(0.500, handleUpdateTimeout, this);
-};
-
 #ifdef HAVE_FLTK_CURSOR
 static const char * dotcursor_xpm[] = {
   "5 5 2 1",
@@ -303,10 +218,7 @@
 
       const PixelFormat *pf;
       
-      if (pixelTrans)
-        pf = &pixelTrans->getInPF();
-      else
-        pf = &frameBuffer->getPF();
+      pf = &cc->cp.pf();
 
       i = (U8*)data;
       o = buffer;
@@ -530,16 +442,6 @@
 }
 
 
-void Viewport::handleUpdateTimeout(void *data)
-{
-  Viewport *self = (Viewport *)data;
-
-  assert(self);
-
-  self->updateWindow();
-}
-
-
 void Viewport::handleClipboardChange(int source, void *data)
 {
   Viewport *self = (Viewport *)data;
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index e112efd..0523cd1 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -22,10 +22,9 @@
 
 #include <map>
 
-#include <FL/Fl_Widget.H>
+namespace rfb { class ModifiablePixelBuffer; }
 
-#include <rfb/Region.h>
-#include <rfb/Pixel.h>
+#include <FL/Fl_Widget.H>
 
 class Fl_Menu_Button;
 class Fl_RGB_Image;
@@ -41,23 +40,16 @@
   Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_);
   ~Viewport();
 
-  // PixelFormat of incoming write operations
-  void setServerPF(const rfb::PixelFormat& pf);
   // Most efficient format (from Viewport's point of view)
   const rfb::PixelFormat &getPreferredPF();
 
   // Flush updates to screen
   void updateWindow();
 
-  // Methods forwarded from CConn
+  // Return a pointer to the framebuffer for decoders to write into
+  rfb::ModifiablePixelBuffer* getFramebuffer(void);
 
-  void fillRect(const rfb::Rect& r, rfb::Pixel pix);
-  void imageRect(const rfb::Rect& r, void* pixels);
-  void copyRect(const rfb::Rect& r, int srcX, int srcY);
-
-  rdr::U8* getBufferRW(const rfb::Rect& r, int* stride);
-  void commitBufferRW(const rfb::Rect& r);
-
+  // New image for the locally rendered cursor
   void setCursor(int width, int height, const rfb::Point& hotspot,
                  void* data, void* mask);
 
@@ -71,12 +63,8 @@
 
 private:
 
-  void damageRect(const rfb::Rect& r);
-
   PlatformPixelBuffer* createFramebuffer(int w, int h);
 
-  static void handleUpdateTimeout(void *data);
-
   static void handleClipboardChange(int source, void *data);
 
   void handlePointerEvent(const rfb::Point& pos, int buttonMask);
@@ -96,8 +84,6 @@
   CConn* cc;
 
   PlatformPixelBuffer* frameBuffer;
-  rfb::PixelTransformer *pixelTrans;
-  rfb::Region damage;
 
   rfb::Point lastPointerPos;
   int lastButtonMask;