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),
if (cursorVisible) {
cursorVisible = false;
im->imageRect(cursorBackingRect, cursorBacking.data);
- im->put(win(), gc, cursorBackingRect);
}
}
im->getImage(cursorBacking.data, cursorBackingRect);
im->maskRect(cursorRect, cursor.data, cursor.mask.buf);
- im->put(win(), gc, cursorBackingRect);
}
}
}
-// 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();
}
}
}
}
- im->put(win(), gc, r);
+ damageRect(r);
}
}
+// 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) {
if (!viewOnly) {
cc->writer()->pointerEvent(lastPointerPos, lastButtonMask);
}
+ } else if (timer == &updateTimer) {
+ updateWindow();
}
return false;
}
#include <rfb/Cursor.h>
#include <rfb/Rect.h>
+#include <rfb/Region.h>
#include <rfb/Timer.h>
#include "TXWindow.h"
#include "TXViewport.h"
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) {
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);
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;