Merge branch 'fps' of https://github.com/CendioOssman/tigervnc
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 81eed37..ec5e962 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -66,12 +66,6 @@
static LogWriter slog("VNCServerST");
LogWriter VNCServerST::connectionsLog("Connections");
-rfb::IntParameter deferUpdateTime("DeferUpdate",
- "Time in milliseconds to defer updates",1);
-
-rfb::BoolParameter alwaysSetDeferUpdateTimer("AlwaysSetDeferUpdateTimer",
- "Always reset the defer update timer on every change",false);
-
//
// -=- VNCServerST Implementation
//
@@ -86,7 +80,7 @@
renderedCursorInvalid(false),
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
lastConnectionTime(0), disableclients(false),
- deferTimer(this), deferPending(false)
+ frameTimer(this)
{
lastUserInputTime = lastDisconnectTime = time(0);
slog.debug("creating single-threaded server %s", name.buf);
@@ -99,6 +93,9 @@
// Close any active clients, with appropriate logging & cleanup
closeClients("Server shutdown");
+ // Stop trying to render things
+ stopFrameClock();
+
// Delete all the clients, and their sockets, and any closing sockets
// NB: Deleting a client implicitly removes it from the clients list
while (!clients.empty()) {
@@ -286,6 +283,8 @@
void VNCServerST::blockUpdates()
{
blockCounter++;
+
+ stopFrameClock();
}
void VNCServerST::unblockUpdates()
@@ -294,9 +293,11 @@
blockCounter--;
- // Flush out any updates we might have blocked
- if (blockCounter == 0)
- tryUpdate();
+ // Restart the frame clock if we have updates
+ if (blockCounter == 0) {
+ if (!comparer->is_empty())
+ startFrameClock();
+ }
}
void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
@@ -417,8 +418,7 @@
return;
comparer->add_changed(region);
- startDefer();
- tryUpdate();
+ startFrameClock();
}
void VNCServerST::add_copied(const Region& dest, const Point& delta)
@@ -427,8 +427,7 @@
return;
comparer->add_copied(dest, delta);
- startDefer();
- tryUpdate();
+ startFrameClock();
}
void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
@@ -507,10 +506,14 @@
bool VNCServerST::handleTimeout(Timer* t)
{
- if (t != &deferTimer)
- return false;
+ if (t == &frameTimer) {
+ // We keep running until we go a full interval without any updates
+ if (comparer->is_empty())
+ return false;
- tryUpdate();
+ writeUpdate();
+ return true;
+ }
return false;
}
@@ -546,87 +549,47 @@
return false;
}
-inline void VNCServerST::startDefer()
+void VNCServerST::startFrameClock()
{
- if (deferUpdateTime == 0)
+ if (frameTimer.isStarted())
return;
-
- if (deferPending && !alwaysSetDeferUpdateTimer)
- return;
-
- gettimeofday(&deferStart, NULL);
- deferTimer.start(deferUpdateTime);
-
- deferPending = true;
-}
-
-inline bool VNCServerST::checkDefer()
-{
- if (!deferPending)
- return true;
-
- if (msSince(&deferStart) >= (unsigned)deferUpdateTime)
- return true;
-
- return false;
-}
-
-void VNCServerST::tryUpdate()
-{
- std::list<VNCSConnectionST*>::iterator ci, ci_next;
-
if (blockCounter > 0)
return;
- if (!checkDefer())
- return;
-
- for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
- ci_next = ci; ci_next++;
- (*ci)->writeFramebufferUpdateOrClose();
- }
+ frameTimer.start(1000/rfb::Server::frameRate);
}
-// checkUpdate() is called just before sending an update. It checks to see
-// what updates are pending and propagates them to the update tracker for each
-// client. It uses the ComparingUpdateTracker's compare() method to filter out
-// areas of the screen which haven't actually changed. It also checks the
-// state of the (server-side) rendered cursor, if necessary rendering it again
-// with the correct background.
+void VNCServerST::stopFrameClock()
+{
+ frameTimer.stop();
+}
-bool VNCServerST::checkUpdate()
+// writeUpdate() is called on a regular interval in order to see what
+// updates are pending and propagates them to the update tracker for
+// each client. It uses the ComparingUpdateTracker's compare() method
+// to filter out areas of the screen which haven't actually changed. It
+// also checks the state of the (server-side) rendered cursor, if
+// necessary rendering it again with the correct background.
+
+void VNCServerST::writeUpdate()
{
UpdateInfo ui;
+ Region toCheck;
+
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+
+ assert(blockCounter == 0);
+
comparer->getUpdateInfo(&ui, pb->getRect());
+ toCheck = ui.changed.union_(ui.copied);
- bool renderCursor = needRenderedCursor();
-
- if (ui.is_empty() && !(renderCursor && renderedCursorInvalid))
- return true;
-
- // Block clients as the frame buffer cannot be safely accessed
- if (blockCounter > 0)
- return false;
-
- // Block client from updating if we are currently deferring updates
- if (!checkDefer())
- return false;
-
- deferPending = false;
-
- Region toCheck = ui.changed.union_(ui.copied);
-
- if (renderCursor) {
+ if (needRenderedCursor()) {
Rect clippedCursorRect = Rect(0, 0, cursor->width(), cursor->height())
.translate(cursorPos.subtract(cursor->hotspot()))
.intersect(pb->getRect());
- if (!renderedCursorInvalid && (toCheck.intersect(clippedCursorRect)
- .is_empty())) {
- renderCursor = false;
- } else {
- toCheck.assign_union(clippedCursorRect);
- }
+ if (!toCheck.intersect(clippedCursorRect).is_empty())
+ renderedCursorInvalid = true;
}
pb->grabRegion(toCheck);
@@ -639,23 +602,42 @@
if (comparer->compare())
comparer->getUpdateInfo(&ui, pb->getRect());
- if (renderCursor) {
- renderedCursor.update(pb, cursor, cursorPos);
- renderedCursorInvalid = false;
- }
+ comparer->clear();
- std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++;
(*ci)->add_copied(ui.copied, ui.copy_delta);
(*ci)->add_changed(ui.changed);
+ (*ci)->writeFramebufferUpdateOrClose();
}
+}
- comparer->clear();
+// checkUpdate() is called by clients to see if it is safe to read from
+// the framebuffer at this time.
+
+bool VNCServerST::checkUpdate()
+{
+ // Block clients as the frame buffer cannot be safely accessed
+ if (blockCounter > 0)
+ return false;
+
+ // Block client from updating if there are pending updates
+ if (!comparer->is_empty())
+ return false;
return true;
}
+const RenderedCursor* VNCServerST::getRenderedCursor()
+{
+ if (renderedCursorInvalid) {
+ renderedCursor.update(pb, cursor, cursorPos);
+ renderedCursorInvalid = false;
+ }
+
+ return &renderedCursor;
+}
+
void VNCServerST::getConnInfo(ListConnInfo * listConn)
{
listConn->Clear();