Send lossless refresh even with pending updates

There might be parts of the screen that haven't changed and can
therefore be refreshed. Figure which parts these are and send just
those.
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 3f92a42..126fb4e 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -965,18 +965,13 @@
 
 void VNCSConnectionST::writeDataUpdate()
 {
-  Region req;
+  Region req, pending;
   UpdateInfo ui;
   bool needNewUpdateInfo;
   const RenderedCursor *cursor;
 
   updates.enable_copyrect(cp.useCopyRect);
 
-  // See if we are allowed to send anything right now (the framebuffer
-  // might have changed in ways we haven't yet been informed of).
-  if (!server->checkUpdate())
-    return;
-
   // See what the client has requested (if anything)
   if (continuousUpdates)
     req = cuRegion.union_(requested);
@@ -986,6 +981,9 @@
   if (req.is_empty())
     return;
 
+  // Get any framebuffer changes we haven't yet been informed of
+  pending = server->getPendingRegion();
+
   // Get the lists of updates. Prior to exporting the data to the `ui' object,
   // getUpdateInfo() will normalize the `updates' object such way that its
   // `changed' and `copied' regions would not intersect.
@@ -1027,17 +1025,24 @@
     updateRenderedCursor = false;
   }
 
-  // Return if there is nothing to send the client.
-
-  if (updates.is_empty() && !writer()->needFakeUpdate() &&
-      !encodeManager.needsLosslessRefresh(req))
-    return;
-
   // The `updates' object could change, make sure we have valid update info.
 
   if (needNewUpdateInfo)
     updates.getUpdateInfo(&ui, req);
 
+  // If there are queued updates then we cannot safely send an update
+  // without risking a partially updated screen
+
+  if (!pending.is_empty()) {
+    // However we might still be able to send a lossless refresh
+    req.assign_subtract(pending);
+    req.assign_subtract(ui.changed);
+    req.assign_subtract(ui.copied);
+
+    ui.changed.clear();
+    ui.copied.clear();
+  }
+
   // Does the client need a server-side rendered cursor?
 
   cursor = NULL;
@@ -1059,6 +1064,8 @@
     damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect));
   }
 
+  // Return if there is nothing to send the client.
+
   if (ui.is_empty() && !writer()->needFakeUpdate() &&
       !encodeManager.needsLosslessRefresh(req))
     return;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 15df71b..95870c9 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -656,17 +656,21 @@
 // checkUpdate() is called by clients to see if it is safe to read from
 // the framebuffer at this time.
 
-bool VNCServerST::checkUpdate()
+Region VNCServerST::getPendingRegion()
 {
+  UpdateInfo ui;
+
   // Block clients as the frame buffer cannot be safely accessed
   if (blockCounter > 0)
-    return false;
+    return pb->getRect();
 
   // Block client from updating if there are pending updates
-  if (!comparer->is_empty())
-    return false;
+  if (comparer->is_empty())
+    return Region();
 
-  return true;
+  comparer->getUpdateInfo(&ui, pb->getRect());
+
+  return ui.changed.union_(ui.copied);
 }
 
 const RenderedCursor* VNCServerST::getRenderedCursor()
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 9a1a44d..b7845dd 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -229,7 +229,7 @@
     void stopFrameClock();
     int msToNextUpdate();
     void writeUpdate();
-    bool checkUpdate();
+    Region getPendingRegion();
     const RenderedCursor* getRenderedCursor();
 
     void notifyScreenLayoutChange(VNCSConnectionST *requester);