diff options
-rw-r--r-- | common/rfb/CConnection.cxx | 166 | ||||
-rw-r--r-- | common/rfb/CConnection.h | 37 | ||||
-rw-r--r-- | vncviewer/CConn.cxx | 214 | ||||
-rw-r--r-- | vncviewer/CConn.h | 21 |
4 files changed, 239 insertions, 199 deletions
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 14ef221f..696a124a 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -43,6 +43,10 @@ CConnection::CConnection() : csecurity(0), is(0), os(0), reader_(0), writer_(0), shared(false), state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false), + pendingPFChange(false), preferredEncoding(encodingTight), + formatChange(false), encodingChange(false), + firstUpdate(true), pendingUpdate(false), continuousUpdates(false), + forceNonincremental(true), framebuffer(NULL), decoder(this) { } @@ -324,6 +328,11 @@ void CConnection::setDesktopSize(int w, int h) decoder.flush(); CMsgHandler::setDesktopSize(w,h); + + if (continuousUpdates) + writer()->writeEnableContinuousUpdates(true, 0, 0, + server.width(), + server.height()); } void CConnection::setExtendedDesktopSize(unsigned reason, @@ -334,6 +343,27 @@ void CConnection::setExtendedDesktopSize(unsigned reason, decoder.flush(); CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout); + + if (continuousUpdates) + writer()->writeEnableContinuousUpdates(true, 0, 0, + server.width(), + server.height()); +} + +void CConnection::endOfContinuousUpdates() +{ + CMsgHandler::endOfContinuousUpdates(); + + // We've gotten the marker for a format change, so make the pending + // one active + if (pendingPFChange) { + server.setPF(pendingPF); + pendingPFChange = false; + + // We might have another change pending + if (formatChange) + requestNewUpdate(); + } } void CConnection::serverInit(int width, int height, @@ -349,6 +379,18 @@ void CConnection::serverInit(int width, int height, assert(framebuffer != NULL); assert(framebuffer->width() == server.width()); assert(framebuffer->height() == server.height()); + + // We want to make sure we call SetEncodings at least once + encodingChange = true; + + requestNewUpdate(); + + // This initial update request is a bit of a corner case, so we need + // to help out setting the correct format here. + if (pendingPFChange) { + server.setPF(pendingPF); + pendingPFChange = false; + } } void CConnection::readAndDecodeRect(const Rect& r, int encoding, @@ -361,6 +403,13 @@ void CConnection::readAndDecodeRect(const Rect& r, int encoding, void CConnection::framebufferUpdateStart() { CMsgHandler::framebufferUpdateStart(); + + assert(framebuffer != NULL); + + // Note: This might not be true if continuous updates are supported + pendingUpdate = false; + + requestNewUpdate(); } void CConnection::framebufferUpdateEnd() @@ -368,6 +417,25 @@ void CConnection::framebufferUpdateEnd() decoder.flush(); CMsgHandler::framebufferUpdateEnd(); + + // A format change has been scheduled and we are now past the update + // with the old format. Time to active the new one. + if (pendingPFChange && !continuousUpdates) { + server.setPF(pendingPF); + pendingPFChange = false; + } + + if (firstUpdate) { + if (server.supportsContinuousUpdates) { + vlog.info("Enabling continuous updates"); + continuousUpdates = true; + writer()->writeEnableContinuousUpdates(true, 0, 0, + server.width(), + server.height()); + } + + firstUpdate = false; + } } void CConnection::dataRect(const Rect& r, int encoding) @@ -383,6 +451,57 @@ void CConnection::initDone() { } +void CConnection::refreshFramebuffer() +{ + forceNonincremental = true; + + // Without continuous updates we have to make sure we only have a + // single update in flight, so we'll have to wait to do the refresh + if (continuousUpdates) + requestNewUpdate(); +} + +void CConnection::setPreferredEncoding(int encoding) +{ + if (preferredEncoding == encoding) + return; + + preferredEncoding = encoding; + encodingChange = true; +} + +int CConnection::getPreferredEncoding() +{ + return preferredEncoding; +} + +void CConnection::setCompressLevel(int level) +{ + if (server.compressLevel == level) + return; + + server.compressLevel = level; + encodingChange = true; +} + +void CConnection::setQualityLevel(int level) +{ + if (server.qualityLevel == level) + return; + + server.qualityLevel = level; + encodingChange = true; +} + +void CConnection::setPF(const PixelFormat& pf) +{ + if (server.pf().equal(pf) && !formatChange) + return; + + nextPF = pf; + formatChange = true; +} + void CConnection::fence(rdr::U32 flags, unsigned len, const char data[]) { CMsgHandler::fence(flags, len, data); @@ -395,3 +514,50 @@ void CConnection::fence(rdr::U32 flags, unsigned len, const char data[]) writer()->writeFence(flags, len, data); } + +// requestNewUpdate() requests an update from the server, having set the +// format and encoding appropriately. +void CConnection::requestNewUpdate() +{ + if (formatChange && !pendingPFChange) { + /* Catch incorrect requestNewUpdate calls */ + assert(!pendingUpdate || continuousUpdates); + + // We have to make sure we switch the internal format at a safe + // time. For continuous updates we temporarily disable updates and + // look for a EndOfContinuousUpdates message to see when to switch. + // For classical updates we just got a new update right before this + // function was called, so we need to make sure we finish that + // update before we can switch. + + pendingPFChange = true; + pendingPF = nextPF; + + if (continuousUpdates) + writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0); + + writer()->writeSetPixelFormat(pendingPF); + + if (continuousUpdates) + writer()->writeEnableContinuousUpdates(true, 0, 0, + server.width(), + server.height()); + + formatChange = false; + } + + if (encodingChange) { + writer()->writeSetEncodings(preferredEncoding, true); + encodingChange = false; + } + + if (forceNonincremental || !continuousUpdates) { + pendingUpdate = true; + writer()->writeFramebufferUpdateRequest(Rect(0, 0, + server.width(), + server.height()), + !forceNonincremental); + } + + forceNonincremental = false; +} diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index 7623c02e..5f953ae1 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -100,6 +100,8 @@ namespace rfb { int w, int h, const ScreenSet& layout); + virtual void endOfContinuousUpdates(); + virtual void serverInit(int width, int height, const PixelFormat& pf, const char* name); @@ -128,6 +130,24 @@ namespace rfb { // Other methods + // refreshFramebuffer() forces a complete refresh of the entire + // framebuffer + void refreshFramebuffer(); + + // setPreferredEncoding()/getPreferredEncoding() adjusts which + // encoding is listed first as a hint to the server that it is the + // preferred one + void setPreferredEncoding(int encoding); + int getPreferredEncoding(); + // setCompressLevel()/setQualityLevel() controls the encoding hints + // sent to the server + void setCompressLevel(int level); + void setQualityLevel(int level); + // setPF() controls the pixel format requested from the server. + // server.pf() will automatically be adjusted once the new format + // is active. + void setPF(const PixelFormat& pf); + CMsgReader* reader() { return reader_; } CMsgWriter* writer() { return writer_; } @@ -180,6 +200,8 @@ namespace rfb { void throwConnFailedException(); void securityCompleted(); + void requestNewUpdate(); + rdr::InStream* is; rdr::OutStream* os; CMsgReader* reader_; @@ -192,6 +214,21 @@ namespace rfb { bool useProtocol3_3; + bool pendingPFChange; + rfb::PixelFormat pendingPF; + + int preferredEncoding; + + bool formatChange; + rfb::PixelFormat nextPF; + bool encodingChange; + + bool firstUpdate; + bool pendingUpdate; + bool continuousUpdates; + + bool forceNonincremental; + ModifiablePixelBuffer* framebuffer; DecodeManager decoder; }; diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index 3e156ad6..d2e85440 100644 --- a/vncviewer/CConn.cxx +++ b/vncviewer/CConn.cxx @@ -74,19 +74,12 @@ static const PixelFormat mediumColourPF(8, 8, false, true, CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) : serverHost(0), serverPort(0), desktop(NULL), - updateCount(0), pixelCount(0), pendingPFChange(false), - currentEncoding(encodingTight), lastServerEncoding((unsigned int)-1), - formatChange(false), encodingChange(false), - firstUpdate(true), pendingUpdate(false), continuousUpdates(false), - forceNonincremental(true) + updateCount(0), pixelCount(0), + lastServerEncoding((unsigned int)-1) { setShared(::shared); sock = socket; - int encNum = encodingNum(preferredEncoding); - if (encNum != -1) - currentEncoding = encNum; - server.supportsLocalCursor = true; server.supportsDesktopResize = true; @@ -96,14 +89,10 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) server.supportsLEDState = true; if (customCompressLevel) - server.compressLevel = compressLevel; - else - server.compressLevel = -1; + setCompressLevel(compressLevel); if (!noJpeg) - server.qualityLevel = qualityLevel; - else - server.qualityLevel = -1; + setQualityLevel(qualityLevel); if(sock == NULL) { try { @@ -156,16 +145,6 @@ CConn::~CConn() delete sock; } -void CConn::refreshFramebuffer() -{ - forceNonincremental = true; - - // Without continuous updates we have to make sure we only have a - // single update in flight, so we'll have to wait to do the refresh - if (continuousUpdates) - requestNewUpdate(); -} - const char *CConn::connectionInfo() { static char infoText[1024] = ""; @@ -209,7 +188,7 @@ const char *CConn::connectionInfo() strcat(infoText, "\n"); snprintf(scratch, sizeof(scratch), - _("Requested encoding: %s"), encodingName(currentEncoding)); + _("Requested encoding: %s"), encodingName(getPreferredEncoding())); strcat(infoText, scratch); strcat(infoText, "\n"); @@ -325,16 +304,10 @@ void CConn::initDone() fullColourPF = desktop->getPreferredPF(); // Force a switch to the format and encoding we'd like - formatChange = encodingChange = true; - - // And kick off the update cycle - requestNewUpdate(); - - // This initial update request is a bit of a corner case, so we need - // to help out setting the correct format here. - assert(pendingPFChange); - server.setPF(pendingPF); - pendingPFChange = false; + updatePixelFormat(); + int encNum = encodingNum(::preferredEncoding); + if (encNum != -1) + setPreferredEncoding(encNum); } // setDesktopSize() is called when the desktop size changes (including when @@ -374,11 +347,6 @@ void CConn::framebufferUpdateStart() { CConnection::framebufferUpdateStart(); - // Note: This might not be true if sync fences are supported - pendingUpdate = false; - - requestNewUpdate(); - // Update the screen prematurely for very slow updates Fl::add_timeout(1.0, handleUpdateTimeout, this); } @@ -396,25 +364,6 @@ void CConn::framebufferUpdateEnd() Fl::remove_timeout(handleUpdateTimeout, this); desktop->updateWindow(); - // A format change has been scheduled and we are now past the update - // with the old format. Time to active the new one. - if (pendingPFChange && !continuousUpdates) { - server.setPF(pendingPF); - pendingPFChange = false; - } - - if (firstUpdate) { - if (server.supportsContinuousUpdates) { - vlog.info(_("Enabling continuous updates")); - continuousUpdates = true; - writer()->writeEnableContinuousUpdates(true, 0, 0, - server.width(), - server.height()); - } - - firstUpdate = false; - } - // Compute new settings based on updated bandwidth values if (autoSelect) autoSelectFormatAndEncoding(); @@ -470,18 +419,6 @@ void CConn::fence(rdr::U32 flags, unsigned len, const char data[]) } } -void CConn::endOfContinuousUpdates() -{ - CConnection::endOfContinuousUpdates(); - - // We've gotten the marker for a format change, so make the pending - // one active - if (pendingPFChange) { - server.setPF(pendingPF); - pendingPFChange = false; - } -} - void CConn::setLEDState(unsigned int state) { CConnection::setLEDState(state); @@ -494,11 +431,6 @@ void CConn::setLEDState(unsigned int state) void CConn::resizeFramebuffer() { - if (continuousUpdates) - writer()->writeEnableContinuousUpdates(true, 0, 0, - server.width(), - server.height()); - desktop->resizeFramebuffer(server.width(), server.height()); } @@ -525,10 +457,7 @@ void CConn::autoSelectFormatAndEncoding() int newQualityLevel = qualityLevel; // Always use Tight - if (currentEncoding != encodingTight) { - currentEncoding = encodingTight; - encodingChange = true; - } + setPreferredEncoding(encodingTight); // Check that we have a decent bandwidth measurement if ((kbitsPerSecond == 0) || (timeWaited < 10000)) @@ -544,9 +473,8 @@ void CConn::autoSelectFormatAndEncoding() if (newQualityLevel != qualityLevel) { vlog.info(_("Throughput %d kbit/s - changing to quality %d"), kbitsPerSecond, newQualityLevel); - server.qualityLevel = newQualityLevel; qualityLevel.setParam(newQualityLevel); - encodingChange = true; + setQualityLevel(newQualityLevel); } } @@ -571,78 +499,31 @@ void CConn::autoSelectFormatAndEncoding() vlog.info(_("Throughput %d kbit/s - full color is now disabled"), kbitsPerSecond); fullColour.setParam(newFullColour); - formatChange = true; + updatePixelFormat(); } } -// checkEncodings() sends a setEncodings message if one is needed. -void CConn::checkEncodings() -{ - if (encodingChange && writer()) { - vlog.info(_("Using %s encoding"),encodingName(currentEncoding)); - writer()->writeSetEncodings(currentEncoding, true); - encodingChange = false; - } -} - // requestNewUpdate() requests an update from the server, having set the // format and encoding appropriately. -void CConn::requestNewUpdate() +void CConn::updatePixelFormat() { - if (formatChange && !pendingPFChange) { - PixelFormat pf; - - /* Catch incorrect requestNewUpdate calls */ - assert(!pendingUpdate || continuousUpdates); - - if (fullColour) { - pf = fullColourPF; - } else { - if (lowColourLevel == 0) - pf = verylowColourPF; - else if (lowColourLevel == 1) - pf = lowColourPF; - else - pf = mediumColourPF; - } - - // We have to make sure we switch the internal format at a safe - // time. For continuous updates we temporarily disable updates and - // look for a EndOfContinuousUpdates message to see when to switch. - // For classical updates we just got a new update right before this - // function was called, so we need to make sure we finish that - // update before we can switch. - - pendingPFChange = true; - pendingPF = pf; - - if (continuousUpdates) - writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0); - - char str[256]; - pf.print(str, 256); - vlog.info(_("Using pixel format %s"),str); - writer()->writeSetPixelFormat(pf); - - if (continuousUpdates) - writer()->writeEnableContinuousUpdates(true, 0, 0, - server.width(), - server.height()); + PixelFormat pf; - formatChange = false; + if (fullColour) { + pf = fullColourPF; + } else { + if (lowColourLevel == 0) + pf = verylowColourPF; + else if (lowColourLevel == 1) + pf = lowColourPF; + else + pf = mediumColourPF; } - checkEncodings(); - - if (forceNonincremental || !continuousUpdates) { - pendingUpdate = true; - writer()->writeFramebufferUpdateRequest(Rect(0, 0, - server.width(), - server.height()), - !forceNonincremental); - } - - forceNonincremental = false; + char str[256]; + pf.print(str, 256); + vlog.info(_("Using pixel format %s"),str); + setPF(pf); } void CConn::handleOptions(void *data) @@ -654,50 +535,23 @@ void CConn::handleOptions(void *data) // list is cheap. Avoid overriding what the auto logic has selected // though. if (!autoSelect) { - int encNum = encodingNum(preferredEncoding); + int encNum = encodingNum(::preferredEncoding); if (encNum != -1) - self->currentEncoding = encNum; + self->setPreferredEncoding(encNum); } - self->server.supportsLocalCursor = true; - if (customCompressLevel) - self->server.compressLevel = compressLevel; + self->setCompressLevel(compressLevel); else - self->server.compressLevel = -1; + self->setCompressLevel(-1); if (!noJpeg && !autoSelect) - self->server.qualityLevel = qualityLevel; + self->setQualityLevel(qualityLevel); else - self->server.qualityLevel = -1; + self->setQualityLevel(-1); - self->encodingChange = true; - - // Format changes refreshes the entire screen though and are therefore - // very costly. It's probably worth the effort to see if it is necessary - // here. - PixelFormat pf; - - if (fullColour) { - pf = self->fullColourPF; - } else { - if (lowColourLevel == 0) - pf = verylowColourPF; - else if (lowColourLevel == 1) - pf = lowColourPF; - else - pf = mediumColourPF; - } - - if (!pf.equal(self->server.pf())) { - self->formatChange = true; - - // Without fences, we cannot safely trigger an update request directly - // but must wait for the next update to arrive. - if (self->continuousUpdates) - self->requestNewUpdate(); - } + self->updatePixelFormat(); } void CConn::handleUpdateTimeout(void *data) diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h index 66ef1d02..2e3362ce 100644 --- a/vncviewer/CConn.h +++ b/vncviewer/CConn.h @@ -36,8 +36,6 @@ public: CConn(const char* vncServerName, network::Socket* sock); ~CConn(); - void refreshFramebuffer(); - const char *connectionInfo(); unsigned getUpdateCount(); @@ -74,8 +72,6 @@ public: void fence(rdr::U32 flags, unsigned len, const char data[]); - void endOfContinuousUpdates(); - void setLEDState(unsigned int state); private: @@ -83,8 +79,7 @@ private: void resizeFramebuffer(); void autoSelectFormatAndEncoding(); - void checkEncodings(); - void requestNewUpdate(); + void updatePixelFormat(); static void handleOptions(void *data); @@ -103,19 +98,7 @@ private: rfb::PixelFormat serverPF; rfb::PixelFormat fullColourPF; - bool pendingPFChange; - rfb::PixelFormat pendingPF; - - int currentEncoding, lastServerEncoding; - - bool formatChange; - bool encodingChange; - - bool firstUpdate; - bool pendingUpdate; - bool continuousUpdates; - - bool forceNonincremental; + int lastServerEncoding; }; #endif |