]> source.dussan.org Git - tigervnc.git/commitdiff
Try to update an entire FramebufferUpdate in one go, avoiding tears.
authorPierre Ossman <ossman@cendio.se>
Wed, 25 Mar 2009 10:32:07 +0000 (10:32 +0000)
committerPierre Ossman <ossman@cendio.se>
Wed, 25 Mar 2009 10:32:07 +0000 (10:32 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3717 3789f03b-4d11-0410-bbf8-ca57d06f2519

unix/vncviewer/DesktopWindow.cxx
unix/vncviewer/DesktopWindow.h

index 891985960e2dce2e0d30d1c0bcce31e4722fcbe0..36f96fc76e3a206f2fb29689f35f4f11e6b61d13 100644 (file)
@@ -65,7 +65,7 @@ static rfb::LogWriter vlog("DesktopWindow");
 DesktopWindow::DesktopWindow(Display* dpy, int w, int h,
                              const rfb::PixelFormat& serverPF,
                              CConn* cc_, TXWindow* parent)
-  : TXWindow(dpy, w, h, parent), cc(cc_), im(0),
+  : TXWindow(dpy, w, h, parent), cc(cc_), im(0), updateTimer(this),
     cursorVisible(false), cursorAvailable(false), currentSelectionTime(0),
     newSelection(0), gettingInitialSelectionTime(true),
     newServerCutText(false), serverCutText_(0),
@@ -216,7 +216,6 @@ void DesktopWindow::hideLocalCursor()
   if (cursorVisible) {
     cursorVisible = false;
     im->imageRect(cursorBackingRect, cursorBacking.data);
-    im->put(win(), gc, cursorBackingRect);
   }
 }
 
@@ -238,7 +237,6 @@ void DesktopWindow::showLocalCursor()
     im->getImage(cursorBacking.data, cursorBackingRect);
 
     im->maskRect(cursorRect, cursor.data, cursor.mask.buf);
-    im->put(win(), gc, cursorBackingRect);
   }
 }
 
@@ -266,19 +264,11 @@ void DesktopWindow::serverCutText(const char* str, rdr::U32 len)
 }
 
 
-// Call XSync() at the end of an update.  We do this because we'd like to
-// ensure that the current update has actually been drawn by the X server
-// before the next update arrives - this is necessary for copyRect to
-// behave correctly.  In particular, if part of the source of a copyRect is
-// not actually displayed in the window, then XCopyArea results in
-// GraphicsExpose events, which require us to draw from the off-screen
-// image.  By the time XSync returns, the GraphicsExpose events will be in
-// Xlib's queue, so hopefully will be processed before the next update.
-// Possibly we should process the GraphicsExpose events here explicitly?
+// Update the actual window with the changed parts of the framebuffer.
 
 void DesktopWindow::framebufferUpdateEnd()
 {
-  XSync(dpy, False);
+  updateWindow();
 }
 
 
@@ -297,7 +287,7 @@ void DesktopWindow::invertRect(const Rect& r)
       }
     }
   }
-  im->put(win(), gc, r);
+  damageRect(r);
 }
 
 
@@ -311,6 +301,22 @@ void DesktopWindow::resize(int w, int h)
 }
 
 
+// Copy the areas of the framebuffer that have been changed (damaged)
+// to the displayed window.
+
+void DesktopWindow::updateWindow()
+{
+  Rect r;
+
+  updateTimer.stop();
+
+  r = damage.get_bounding_rect();
+  damage.clear();
+
+  im->put(win(), gc, r);
+}
+
+
 bool DesktopWindow::handleTimeout(rfb::Timer* timer)
 {
   if (timer == &setColourMapEntriesTimer) {
@@ -320,6 +326,8 @@ bool DesktopWindow::handleTimeout(rfb::Timer* timer)
     if (!viewOnly) {
       cc->writer()->pointerEvent(lastPointerPos, lastButtonMask);
     }
+  } else if (timer == &updateTimer) {
+    updateWindow();
   }
   return false;
 }
index fe5ef82a306a9e97ca47b6fe910a0c406aad1613..433ac33b55ff9df78011ed8e7e8b8324ea7d586e 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <rfb/Cursor.h>
 #include <rfb/Rect.h>
+#include <rfb/Region.h>
 #include <rfb/Timer.h>
 #include "TXWindow.h"
 #include "TXViewport.h"
@@ -61,13 +62,13 @@ public:
   void fillRect(const rfb::Rect& r, rfb::Pixel pix) {
     if (r.overlaps(cursorBackingRect)) hideLocalCursor();
     im->fillRect(r, pix);
-    im->put(win(), gc, r);
+    damageRect(r);
     showLocalCursor();
   }
   void imageRect(const rfb::Rect& r, void* pixels) {
     if (r.overlaps(cursorBackingRect)) hideLocalCursor();
     im->imageRect(r, pixels);
-    im->put(win(), gc, r);
+    damageRect(r);
     showLocalCursor();
   }
   void copyRect(const rfb::Rect& r, int srcX, int srcY) {
@@ -75,11 +76,8 @@ public:
         cursorBackingRect.overlaps(rfb::Rect(srcX, srcY,
                                              srcX+r.width(), srcY+r.height())))
       hideLocalCursor();
-    if (im->usingShm())
-      XSync(dpy, False);
     im->copyRect(r, rfb::Point(r.tl.x-srcX, r.tl.y-srcY));
-    XCopyArea(dpy, win(), win(), gc, srcX, srcY,
-              r.width(), r.height(), r.tl.x, r.tl.y);
+    damageRect(r);
     showLocalCursor();
   }
   void invertRect(const rfb::Rect& r);
@@ -97,12 +95,20 @@ private:
   void createXCursors();
   void hideLocalCursor();
   void showLocalCursor();
+  void damageRect(const rfb::Rect& r) {
+    damage.assign_union(rfb::Region(r));
+    if (!updateTimer.isStarted())
+      updateTimer.start(100);
+  };
+  void updateWindow();
   bool handleTimeout(rfb::Timer* timer);
   void handlePointerEvent(const rfb::Point& pos, int buttonMask);
 
   CConn* cc;
   TXImage* im;
   GC gc;
+  rfb::Region damage;
+  rfb::Timer updateTimer;
   ::Cursor dotCursor, noCursor, localXCursor;
 
   rfb::Cursor cursor;