Special handling of a rectangular video area in the UpdateTracker and derived/related classes.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2327 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx
index ce3d68a..ec32302 100644
--- a/common/rfb/ComparingUpdateTracker.cxx
+++ b/common/rfb/ComparingUpdateTracker.cxx
@@ -38,6 +38,14 @@
 
 void ComparingUpdateTracker::compare()
 {
+  // First of all, exclude video area from both changed and copied regions.
+  // We handle video area separately and do not compare it -- we know it's
+  // being changed continuously.
+  if (!video_area.is_empty()) {
+    changed.assign_subtract(video_area);
+    copied.assign_subtract(video_area);
+  }
+
   std::vector<Rect> rects;
   std::vector<Rect>::iterator i;
 
diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx
index 14ac49d..79f43f6 100644
--- a/common/rfb/UpdateTracker.cxx
+++ b/common/rfb/UpdateTracker.cxx
@@ -60,6 +60,10 @@
     ut->add_changed(tmp);
 }
 
+void ClippingUpdateTracker::set_video_area(const Rect &rect) {
+  ut->set_video_area(rect.intersect(clipRect));
+}
+
 // SimpleUpdateTracker
 
 SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
@@ -135,6 +139,18 @@
   return;
 }
 
+void SimpleUpdateTracker::set_video_area(const Rect &rect)
+{
+  video_area = rect;
+}
+
+//
+// subtract() is called to mark some region as unchanged. We just remove that
+// region from both `copied' and `changed' regions. Note that `video_area' is
+// not affected intentionally; we assume that video is continuously changing,
+// so it should always be treated as "changed".
+//
+
 void SimpleUpdateTracker::subtract(const Region& region) {
   copied.assign_subtract(region);
   changed.assign_subtract(region);
@@ -142,10 +158,15 @@
 
 void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
 {
-  copied.assign_subtract(changed);
+  changed.assign_subtract(video_area);
+  copied.assign_subtract(changed.union_(video_area));
   info->changed = changed.intersect(clip);
   info->copied = copied.intersect(clip);
   info->copy_delta = copy_delta;
+  // FIXME: Using get_bounding_rect() is not what should actually be done!
+  //        We should use the biggest inner rectangle of the `clip' instead.
+  //        From the other side, `clip' is usually just a sole rectangle.
+  info->video_area = video_area.intersect(clip.get_bounding_rect());
 }
 
 void SimpleUpdateTracker::copyTo(UpdateTracker* to) const {
@@ -153,4 +174,5 @@
     to->add_copied(copied, copy_delta);
   if (!changed.is_empty())
     to->add_changed(changed);
+  to->set_video_area(video_area);
 }
diff --git a/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h
index 8e96d55..b6a7d74 100644
--- a/common/rfb/UpdateTracker.h
+++ b/common/rfb/UpdateTracker.h
@@ -30,14 +30,15 @@
     Region changed;
     Region copied;
     Point copy_delta;
+    Rect video_area;
     bool is_empty() const {
-      return copied.is_empty() && changed.is_empty();
+      return copied.is_empty() && changed.is_empty() && video_area.is_empty();
     }
     // NOTE: We do not ever use UpdateInfo::numRects(), because Tight encoding
     //       complicates computing the number of rectangles.
     /*
     int numRects() const {
-      return copied.numRects() + changed.numRects();
+      return copied.numRects() + changed.numRects() + !video_area.is_empty();
     }
     */
   };
@@ -49,6 +50,7 @@
 
     virtual void add_changed(const Region &region) = 0;
     virtual void add_copied(const Region &dest, const Point &delta) = 0;
+    virtual void set_video_area(const Rect &rect) = 0;
   };
 
   class ClippingUpdateTracker : public UpdateTracker {
@@ -61,6 +63,7 @@
 
     virtual void add_changed(const Region &region);
     virtual void add_copied(const Region &dest, const Point &delta);
+    virtual void set_video_area(const Rect &rect);
   protected:
     UpdateTracker* ut;
     Rect clipRect;
@@ -75,6 +78,7 @@
 
     virtual void add_changed(const Region &region);
     virtual void add_copied(const Region &dest, const Point &delta);
+    virtual void set_video_area(const Rect &rect);
     virtual void subtract(const Region& region);
 
     // Fill the supplied UpdateInfo structure with update information
@@ -85,16 +89,33 @@
     virtual void copyTo(UpdateTracker* to) const;
 
     // Move the entire update region by an offset
-    void translate(const Point& p) {changed.translate(p); copied.translate(p);}
+    void translate(const Point& p) {
+      changed.translate(p);
+      copied.translate(p);
+      video_area.translate(p);
+    }
 
-    virtual bool is_empty() const {return changed.is_empty() && copied.is_empty();}
+    virtual bool is_empty() const {
+      return changed.is_empty() && copied.is_empty() && video_area.is_empty();
+    }
 
-    virtual void clear() {changed.clear(); copied.clear();};
+    // NOTE: We do not clear video_area intentionally.
+    virtual void clear() {
+      changed.clear();
+      copied.clear();
+    }
+
   protected:
     Region changed;
     Region copied;
     Point copy_delta;
     bool copy_enabled;
+
+    // We can track one rectangle on the screen as a "video area". We assume
+    // it is changing continuously, in whole. Thus, we don't need to detect
+    // and track individual changes in the video area -- we can assume it's
+    // always in the changed state.
+    Rect video_area;
   };
 
 }
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 9055017..5237c1b 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -574,7 +574,7 @@
 
   // 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.
+  // `changed', `copied' and `video_area' regions would not intersect.
 
   UpdateInfo ui;
   updates.getUpdateInfo(&ui, requested);
@@ -645,7 +645,11 @@
     // Compute the number of rectangles. Tight encoder makes the things more
     // complicated as compared to the original VNC4.
     writer()->setupCurrentEncoder();
-    int nRects = ui.copied.numRects() + (drawRenderedCursor ? 1 : 0);
+    int nRects = (ui.copied.numRects() +
+                  /* FIXME: Sending video area is not yet enabled.
+                  (ui.video_area.is_empty() ? 0 : 1) +
+                  */
+                  (drawRenderedCursor ? 1 : 0));
     std::vector<Rect> rects;
     std::vector<Rect>::const_iterator i;
     ui.changed.get_rects(&rects);
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 7fe2e32..a388873 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -93,6 +93,7 @@
     void add_copied(const Region& dest, const Point& delta) {
       updates.add_copied(dest, delta);
     }
+    void set_video_area(const Rect &rect) { updates.set_video_area(rect); }
 
     const char* getPeerEndpoint() const {return peerEndpoint.buf;}
 
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index c02c2eb..e5354a4 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -314,6 +314,11 @@
   comparer->add_copied(dest, delta);
 }
 
+void VNCServerST::set_video_area(const Rect &rect)
+{
+  comparer->set_video_area(rect);
+}
+
 bool VNCServerST::clientsReadyForUpdate()
 {
   std::list<VNCSConnectionST*>::iterator ci;
@@ -459,7 +464,7 @@
   if (ui.is_empty() && !(renderCursor && renderedCursorInvalid))
     return;
 
-  Region toCheck = ui.changed.union_(ui.copied);
+  Region toCheck = ui.changed.union_(ui.copied).union_(ui.video_area);
 
   if (renderCursor) {
     Rect clippedCursorRect
@@ -495,6 +500,7 @@
     ci_next = ci; ci_next++;
     (*ci)->add_copied(ui.copied, ui.copy_delta);
     (*ci)->add_changed(ui.changed);
+    (*ci)->set_video_area(ui.video_area);
   }
 
   comparer->clear();
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index bc15b7f..37b75ea 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -83,6 +83,7 @@
     virtual void serverCutText(const char* str, int len);
     virtual void add_changed(const Region &region);
     virtual void add_copied(const Region &dest, const Point &delta);
+    virtual void set_video_area(const Rect &rect);
     virtual bool clientsReadyForUpdate();
     virtual void tryUpdate();
     virtual void setCursor(int width, int height, const Point& hotspot,