]> source.dussan.org Git - tigervnc.git/commitdiff
Send desktop layout changes separately
authorPierre Ossman <ossman@cendio.se>
Thu, 23 Apr 2009 12:31:42 +0000 (12:31 +0000)
committerPierre Ossman <ossman@cendio.se>
Thu, 23 Apr 2009 12:31:42 +0000 (12:31 +0000)
Make sure we send any modifications to the desktop layout in a message that
does not modify the framebuffer data. This is required to make sure we have
a valid state on the client as it drops the framebuffer when it recieves a
framebuffer dimension change.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3787 3789f03b-4d11-0410-bbf8-ca57d06f2519

common/rfb/SMsgWriter.cxx
common/rfb/SMsgWriter.h
common/rfb/SMsgWriterV3.cxx
common/rfb/SMsgWriterV3.h
common/rfb/VNCSConnectionST.cxx

index f3079eed9732edd6e39b237fcb3733906a6d795a..1695161f89cd295da41d191d46cd22b82ce4e3c6 100644 (file)
@@ -114,6 +114,11 @@ int SMsgWriter::getNumRects(const Rect &r)
   return encoders[encoding]->getNumRects(r);
 }
 
+bool SMsgWriter::needFakeUpdate()
+{
+  return false;
+}
+
 // FIXME: This functions is not used because it incorrectly computes
 //        the number of rectangles if the Tight encoder is used.
 /*
@@ -126,6 +131,17 @@ void SMsgWriter::writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
 }
 */
 
+bool SMsgWriter::needNoDataUpdate()
+{
+  return false;
+}
+
+void SMsgWriter::writeNoDataUpdate()
+{
+  // This class has no pseudo-rectangles so there is nothing to do here
+  vlog.error("writeNoDataUpdate() called");
+}
+
 void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
                             Region* updatedRegion)
 {
@@ -148,12 +164,6 @@ void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
   }
 }
 
-
-bool SMsgWriter::needFakeUpdate()
-{
-  return false;
-}
-
 bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
 {
   return writeRect(r, cp->currentEncoding(), ig, actual);
index 5df72704d9bb19f871b402943de5b7b1b9580454..44a391587792dbed753e48ad3bae15bfb0e03790 100644 (file)
@@ -98,8 +98,7 @@ namespace rfb {
                                 int hotspotY, void* data, void* mask)=0;
 
     // needFakeUpdate() returns true when an immediate update is needed in
-    // order to flush out setDesktopSize or setCursor pseudo-rectangles to the
-    // client.
+    // order to flush out pseudo-rectangles to the client.
     virtual bool needFakeUpdate();
 
     // writeFramebufferUpdate() writes a framebuffer update using the given
@@ -114,6 +113,16 @@ namespace rfb {
                                         Region* updatedRegion);
     */
 
+    // needNoDataUpdate() returns true when an update without any
+    // framebuffer changes need to be sent (using writeNoDataUpdate()).
+    // Commonly this is an update that modifies the size of the framebuffer
+    // or the screen layout.
+    virtual bool needNoDataUpdate();
+
+    // writeNoDataUpdate() write a framebuffer update containing only
+    // pseudo-rectangles.
+    virtual void writeNoDataUpdate();
+
     // writeRects() accepts an UpdateInfo (changed & copied regions) and an
     // ImageGetter to fetch pixels from.  It then calls writeCopyRect() and
     // writeRect() as appropriate.  writeFramebufferUpdateStart() must be used
index a11579b676c2f93e8b974712127639b8eb0b1001..6f0aed0a5af94fa71bba023f63f4ae391198343c 100644 (file)
@@ -144,35 +144,135 @@ void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
   }
 }
 
+bool SMsgWriterV3::needFakeUpdate()
+{
+  return wsccb || needSetDesktopName || needNoDataUpdate();
+}
+
+bool SMsgWriterV3::needNoDataUpdate()
+{
+  return needSetDesktopSize || needExtendedDesktopSize ||
+         !extendedDesktopSizeMsgs.empty();
+}
+
+void SMsgWriterV3::writeNoDataUpdate()
+{
+  int nRects;
+
+  nRects = 0;
+
+  if (needSetDesktopSize)
+    nRects++;
+  if (needExtendedDesktopSize)
+    nRects++;
+  if (!extendedDesktopSizeMsgs.empty())
+    nRects += extendedDesktopSizeMsgs.size();
+
+  writeFramebufferUpdateStart(nRects);
+  writeNoDataRects();
+  writeFramebufferUpdateEnd();
+}
+
 void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
 {
   startMsg(msgTypeFramebufferUpdate);
   os->pad(1);
-  if (wsccb) nRects++;
-  if (needSetDesktopSize) nRects++;
-  if (needExtendedDesktopSize) nRects++;
-  if (!extendedDesktopSizeMsgs.empty()) nRects += extendedDesktopSizeMsgs.size();
-  if (needSetDesktopName) nRects++;
+
+  if (wsccb)
+    nRects++;
+  if (needSetDesktopName)
+    nRects++;
+
   os->writeU16(nRects);
+
   nRectsInUpdate = 0;
   nRectsInHeader = nRects;
-  if (wsccb) {
-    wsccb->writeSetCursorCallback();
-    wsccb = 0;
-  }
+
+  writePseudoRects();
 }
 
 void SMsgWriterV3::writeFramebufferUpdateStart()
 {
   nRectsInUpdate = nRectsInHeader = 0;
+
   if (!updateOS)
     updateOS = new rdr::MemOutStream;
   os = updateOS;
+
+  writePseudoRects();
 }
 
 void SMsgWriterV3::writeFramebufferUpdateEnd()
 {
-  /* Start with specific ExtendedDesktopSize messages */
+  if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
+    throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
+                    "nRects out of sync");
+
+  if (os == updateOS) {
+    os = realOS;
+    startMsg(msgTypeFramebufferUpdate);
+    os->pad(1);
+    os->writeU16(nRectsInUpdate);
+    os->writeBytes(updateOS->data(), updateOS->length());
+    updateOS->clear();
+  }
+
+  updatesSent++;
+  endMsg();
+}
+
+void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
+{
+  if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+    throw Exception("SMsgWriterV3::startRect: nRects out of sync");
+
+  currentEncoding = encoding;
+  lenBeforeRect = os->length();
+  if (encoding != encodingCopyRect)
+    rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
+
+  os->writeS16(r.tl.x);
+  os->writeS16(r.tl.y);
+  os->writeU16(r.width());
+  os->writeU16(r.height());
+  os->writeU32(encoding);
+}
+
+void SMsgWriterV3::endRect()
+{
+  if (currentEncoding <= encodingMax) {
+    bytesSent[currentEncoding] += os->length() - lenBeforeRect;
+    rectsSent[currentEncoding]++;
+  }
+}
+
+void SMsgWriterV3::writePseudoRects()
+{
+  if (wsccb) {
+    wsccb->writeSetCursorCallback();
+    wsccb = 0;
+  }
+
+  if (needSetDesktopName) {
+    if (!cp->supportsDesktopRename)
+      throw Exception("Client does not support desktop rename");
+    if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+      throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
+
+    os->writeS16(0);
+    os->writeS16(0);
+    os->writeU16(0);
+    os->writeU16(0);
+    os->writeU32(pseudoEncodingDesktopName);
+    os->writeString(cp->name());
+
+    needSetDesktopName = false;
+  }
+}
+
+void SMsgWriterV3::writeNoDataRects()
+{
+  // Start with specific ExtendedDesktopSize messages
   if (!extendedDesktopSizeMsgs.empty()) {
     std::list<ExtendedDesktopSizeMsg>::const_iterator ri;
     ScreenSet::const_iterator si;
@@ -205,12 +305,13 @@ void SMsgWriterV3::writeFramebufferUpdateEnd()
     extendedDesktopSizeMsgs.clear();
   }
 
-  /* Send this before SetDesktopSize to make life easier on the clients */
+  // Send this before SetDesktopSize to make life easier on the clients
   if (needExtendedDesktopSize) {
     if (!cp->supportsExtendedDesktopSize)
       throw Exception("Client does not support extended desktop resize");
     if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
       throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
+
     os->writeU16(0);
     os->writeU16(0);
     os->writeU16(cp->width);
@@ -233,74 +334,21 @@ void SMsgWriterV3::writeFramebufferUpdateEnd()
     needExtendedDesktopSize = false;
   }
 
+  // Some clients assume this is the last rectangle so don't send anything
+  // more after this
   if (needSetDesktopSize) {
     if (!cp->supportsDesktopResize)
       throw Exception("Client does not support desktop resize");
     if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
       throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
+
     os->writeS16(0);
     os->writeS16(0);
     os->writeU16(cp->width);
     os->writeU16(cp->height);
     os->writeU32(pseudoEncodingDesktopSize);
-    needSetDesktopSize = false;
-  }
 
-  if (needSetDesktopName) {
-    if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
-      throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
-    os->writeS16(0);
-    os->writeS16(0);
-    os->writeU16(0);
-    os->writeU16(0);
-    os->writeU32(pseudoEncodingDesktopName);
-    os->writeString(cp->name());
-    needSetDesktopName = false;
-  }
-
-  if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
-    throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
-                    "nRects out of sync");
-  if (os == updateOS) {
-    os = realOS;
-    startMsg(msgTypeFramebufferUpdate);
-    os->pad(1);
-    os->writeU16(nRectsInUpdate);
-    os->writeBytes(updateOS->data(), updateOS->length());
-    updateOS->clear();
+    needSetDesktopSize = false;
   }
-
-  updatesSent++;
-  endMsg();
-}
-
-bool SMsgWriterV3::needFakeUpdate()
-{
-  return wsccb || needSetDesktopSize || needExtendedDesktopSize ||
-         !extendedDesktopSizeMsgs.empty() || needSetDesktopName;
-}
-
-void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
-{
-  if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
-    throw Exception("SMsgWriterV3::startRect: nRects out of sync");
-
-  currentEncoding = encoding;
-  lenBeforeRect = os->length();
-  if (encoding != encodingCopyRect)
-    rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
-
-  os->writeS16(r.tl.x);
-  os->writeS16(r.tl.y);
-  os->writeU16(r.width());
-  os->writeU16(r.height());
-  os->writeU32(encoding);
 }
 
-void SMsgWriterV3::endRect()
-{
-  if (currentEncoding <= encodingMax) {
-    bytesSent[currentEncoding] += os->length() - lenBeforeRect;
-    rectsSent[currentEncoding]++;
-  }
-}
index e86c828c6b63f0b82929f022f64fe23227420571..5e0a3f1b3c350d45f7c419b5758f3eea5f6cb0c5 100644 (file)
@@ -46,13 +46,19 @@ namespace rfb {
                                 void* data, void* mask);
     virtual void writeSetXCursor(int width, int height, int hotspotX,
                                 int hotspotY, void* data, void* mask);
+    virtual bool needFakeUpdate();
+    virtual bool needNoDataUpdate();
+    virtual void writeNoDataUpdate();
     virtual void writeFramebufferUpdateStart(int nRects);
     virtual void writeFramebufferUpdateStart();
     virtual void writeFramebufferUpdateEnd();
-    virtual bool needFakeUpdate();
     virtual void startRect(const Rect& r, unsigned int encoding);
     virtual void endRect();
 
+  protected:
+    virtual void writePseudoRects();
+    virtual void writeNoDataRects();
+
   private:
     rdr::MemOutStream* updateOS;
     rdr::OutStream* realOS;
index cc7c9e8e3927098e22a93ee60f245277678847e1..9b4d38ef390e83e13823134138414eacec222a30 100644 (file)
@@ -501,16 +501,22 @@ void VNCSConnectionST::clientCutText(const char* str, int len)
 
 void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
 {
+  Rect safeRect;
+
   if (!(accessRights & AccessView)) return;
 
   SConnection::framebufferUpdateRequest(r, incremental);
 
+  vlog.info("FramebufferUpdateRequest %dx%d at %d,%d %sincr",
+             r.width(), r.height(), r.tl.x, r.tl.y, incremental ? "" : "non-");
+
   // Check that the client isn't sending crappy requests
   if (!r.enclosed_by(Rect(0, 0, cp.width, cp.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);
-    // We crop the size later in writeFramebufferUpdate() so no need to
-    // do so now.
+    safeRect = r.intersect(Rect(0, 0, cp.width, cp.height));
+  } else {
+    safeRect = r;
   }
 
   // Just update the requested region.
@@ -623,12 +629,16 @@ void VNCSConnectionST::writeSetCursorCallback()
 
 void VNCSConnectionST::writeFramebufferUpdate()
 {
-  // The framebuffer might have changed size since the
-  // FramebufferUpdateRequest message was received. Clip it to the current
-  // size of the framebuffer.
-  requested = requested.intersect(Region(Rect(0, 0, cp.width, cp.height)));
+  if (state() != RFBSTATE_NORMAL || requested.is_empty())
+    return;
 
-  if (state() != RFBSTATE_NORMAL || requested.is_empty()) return;
+  // First take care of any updates that cannot contain framebuffer data
+  // changes.
+  if (writer()->needNoDataUpdate()) {
+    writer()->writeNoDataUpdate();
+    requested.clear();
+    return;
+  }
 
   updates.enable_copyrect(cp.useCopyRect);