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
//
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);
// 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()) {
void VNCServerST::blockUpdates()
{
blockCounter++;
+
+ stopFrameClock();
}
void VNCServerST::unblockUpdates()
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)
return;
comparer->add_changed(region);
- startDefer();
- tryUpdate();
+ startFrameClock();
}
void VNCServerST::add_copied(const Region& dest, const Point& delta)
return;
comparer->add_copied(dest, delta);
- startDefer();
- tryUpdate();
+ startFrameClock();
}
void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
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;
}
return false;
}
-inline void VNCServerST::startDefer()
+void VNCServerST::startFrameClock()
{
- if (deferUpdateTime == 0)
+ if (frameTimer.isStarted())
return;
-
- if (deferPending && !alwaysSetDeferUpdateTimer)
+ if (blockCounter > 0)
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;
+ frameTimer.start(1000/rfb::Server::frameRate);
}
-void VNCServerST::tryUpdate()
+void VNCServerST::stopFrameClock()
{
- 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.stop();
}
-// 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.
+// 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.
-bool VNCServerST::checkUpdate()
+void VNCServerST::writeUpdate()
{
UpdateInfo ui;
- comparer->getUpdateInfo(&ui, pb->getRect());
-
- bool renderCursor = needRenderedCursor();
-
- if (ui.is_empty() && !(renderCursor && renderedCursorInvalid))
- return true;
+ Region toCheck;
- // 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;
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
- deferPending = false;
+ assert(blockCounter == 0);
- Region toCheck = ui.changed.union_(ui.copied);
+ comparer->getUpdateInfo(&ui, pb->getRect());
+ toCheck = ui.changed.union_(ui.copied);
- if (renderCursor) {
+ if (needRenderedCursor()) {
Rect clippedCursorRect
= cursor.getRect(cursorPos.subtract(cursor.hotspot)).intersect(pb->getRect());
if (comparer->compare())
comparer->getUpdateInfo(&ui, pb->getRect());
- std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ comparer->clear();
+
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;
}